# Backend API Fix - Component Groups Require status_page_id

## Issue

The backend API was updated with a **required parameter** that wasn't initially documented. The `GET /user/api/component-groups` endpoint now **requires** a `status_page_id` query parameter.

## Backend Behavior

### `GET /user/api/component-groups`

❌ **Without `status_page_id` (400 Bad Request):**
```bash
curl -X GET "https://YOUR_DOMAIN/user/api/component-groups" \
  -H "X-API-Key: YOUR_API_KEY"
```

Response:
```json
{
  "error": "status_page_id is required"
}
```

✅ **With `status_page_id` (200 OK):**
```bash
curl -X GET "https://YOUR_DOMAIN/user/api/component-groups?status_page_id=550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: YOUR_API_KEY"
```

Response:
```json
{
  "data": [
    {
      "id": "group-123",
      "name": "Infrastructure",
      "components": [...]
    }
  ]
}
```

### `GET /user/api/components`

✅ **Optional parameter** - works with or without `status_page_id`:

```bash
# All components across status pages
curl -X GET "https://YOUR_DOMAIN/user/api/components" \
  -H "X-API-Key: YOUR_API_KEY"

# Filtered by status page (recommended)
curl -X GET "https://YOUR_DOMAIN/user/api/components?status_page_id=550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: YOUR_API_KEY"
```

## Code Changes Made

### StatusPageAPI.swift

#### Before (Incorrect - would cause 400 error)
```swift
public func fetchGroups() async throws -> [ComponentGroup] {
    return try await request(endpoint: "/component-groups", useFeatureAPI: true)
}
```

#### After (Correct - passes required parameter)
```swift
public func fetchGroups(statusPageId: String) async throws -> [ComponentGroup] {
    return try await request(endpoint: "/component-groups?status_page_id=\(statusPageId)", useFeatureAPI: true)
}
```

#### Also Updated `createGroup()`:
```swift
public func createGroup(statusPageId: String, name: String) async throws -> ComponentGroup {
    var params: [String: Any] = ["name": name, "status_page_id": statusPageId]
    let body = try JSONSerialization.data(withJSONObject: params)
    return try await request(endpoint: "/component-groups", method: "POST", body: body, useFeatureAPI: true)
}
```

### StatusPageDetailView.swift

#### Before (Incorrect - missing parameter)
```swift
let groups = try await StatusPageAPI.shared.fetchGroups()
```

#### After (Correct - passes pageId)
```swift
let groups = try await StatusPageAPI.shared.fetchGroups(statusPageId: pageId)
```

#### Also Updated `loadGroups()`:
```swift
private func loadGroups() async {
    do {
        groups = try await StatusPageAPI.shared.fetchGroups(statusPageId: pageId)
    } catch {
        groups = []
    }
}
```

### Enhanced Error Handling

Added specific handling for 400 errors:

```swift
} catch let apiError as StatusPageAPI.APIError {
    // ... other error cases ...
    } else if case .httpStatus(400) = apiError {
        errorMessage = "Bad request. The status page ID may be invalid."
    } else {
        errorMessage = apiError.localizedDescription
    }
}
```

## API Summary

| Endpoint | status_page_id | Behavior |
|----------|----------------|----------|
| `GET /component-groups` | ⚠️ **Required** | Returns 400 if missing |
| `POST /component-groups` | ⚠️ **Required** | In request body |
| `GET /components` | ✅ Optional | Filter if provided |
| `POST /components` | ✅ Optional | Associates component with page |
| `PUT /component-groups/:id` | ❌ Not needed | Updates by group ID |
| `DELETE /component-groups/:id` | ❌ Not needed | Deletes by group ID |
| `PUT /components/:id` | ❌ Not needed | Updates by component ID |
| `DELETE /components/:id` | ❌ Not needed | Deletes by component ID |

## Impact

### Files Modified: 2
1. ✅ **StatusPageAPI.swift** - Updated `fetchGroups()` and `createGroup()`
2. ✅ **StatusPageDetailView.swift** - Updated all calls to `fetchGroups()`

### Documentation Updated: 2
1. ✅ **API_QUICK_REFERENCE.md** - Updated component groups section
2. ✅ **QUICK_START.md** - Updated examples and troubleshooting

### New Documentation: 1
1. ✅ **BACKEND_API_FIX.md** (this file)

## Testing

To verify the fix works correctly:

```swift
// This should now work without 400 errors
Task {
    do {
        let statusPageId = "your-status-page-id"
        
        // Fetch groups (requires pageId)
        let groups = try await StatusPageAPI.shared.fetchGroups(statusPageId: statusPageId)
        print("✅ Groups loaded: \(groups.count)")
        
        // Create group (requires pageId)
        let newGroup = try await StatusPageAPI.shared.createGroup(
            statusPageId: statusPageId,
            name: "Test Group"
        )
        print("✅ Group created: \(newGroup.name)")
        
        // Fetch components (optional pageId, but recommended)
        let components = try await StatusPageAPI.shared.fetchComponents(statusPageId: statusPageId)
        print("✅ Components loaded: \(components.count)")
        
    } catch StatusPageAPI.APIError.httpStatus(400) {
        print("❌ 400 Bad Request - Missing required parameter")
    } catch {
        print("❌ Error: \(error)")
    }
}
```

## Common Errors

### Error: "status_page_id is required" (400)

**Cause:** Calling `fetchGroups()` or `createGroup()` without `statusPageId`

**Fix:** Always pass the status page ID:
```swift
// ❌ Wrong
let groups = try await StatusPageAPI.shared.fetchGroups()

// ✅ Correct
let groups = try await StatusPageAPI.shared.fetchGroups(statusPageId: pageId)
```

### Error: "Bad request. The status page ID may be invalid" (400)

**Cause:** Passing an invalid or non-existent status page ID

**Fix:** Verify the status page ID exists:
```swift
// Get valid page IDs first
let pages = try await StatusPageAPI.shared.fetchStatusPages()
if let pageId = pages.first?.id {
    let groups = try await StatusPageAPI.shared.fetchGroups(statusPageId: pageId)
}
```

## Migration Notes

If you have existing code that calls `fetchGroups()` or `createGroup()`:

### Migration Checklist

- [ ] Update all `fetchGroups()` calls to include `statusPageId` parameter
- [ ] Update all `createGroup()` calls to include `statusPageId` parameter
- [ ] Ensure `statusPageId` is available in the calling context
- [ ] Add error handling for 400 Bad Request errors
- [ ] Test that groups load correctly
- [ ] Test that group creation works
- [ ] Update any cached group logic to key by status page ID

### Example Migration

**Before:**
```swift
class ComponentsViewModel {
    func load() async {
        // ❌ Will cause 400 error
        groups = try await StatusPageAPI.shared.fetchGroups()
    }
}
```

**After:**
```swift
class ComponentsViewModel {
    let pageId: String
    
    init(pageId: String) {
        self.pageId = pageId
    }
    
    func load() async {
        // ✅ Passes required parameter
        groups = try await StatusPageAPI.shared.fetchGroups(statusPageId: pageId)
    }
}
```

## API Design Rationale

The backend requires `status_page_id` for component groups because:

1. **Scoping** - Component groups are scoped to specific status pages
2. **Multi-tenancy** - Users may have multiple status pages
3. **Performance** - Filtering at the API level is more efficient
4. **Security** - Ensures users only see groups for their accessible status pages
5. **Consistency** - Aligns with how components work (optional filter)

## Conclusion

The backend API now correctly requires `status_page_id` for component group operations. All code has been updated to pass this required parameter, and the UI will no longer receive 400 Bad Request errors when fetching or creating component groups.

### Key Takeaways

1. ⚠️ **`fetchGroups(statusPageId:)` is now a required parameter**
2. ⚠️ **`createGroup(statusPageId:, name:)` requires statusPageId**
3. ✅ **`fetchComponents(statusPageId:)` is optional but recommended**
4. ✅ **Component/group updates by ID don't need statusPageId**
5. ✅ **All UI code has been updated to pass required parameters**
6. ✅ **Enhanced error handling for 400 errors**

The fix is complete and the app is ready to use! 🎉
