- Create BaseResource with formatDate() and formatDecimal() utilities - Create 11 API Resource classes for all models - Update all 6 controllers to return wrapped responses via wrapResource() - Update frontend API client with unwrapResponse() helper - Update all 63+ backend tests to expect 'data' wrapper - Regenerate Scribe API documentation BREAKING CHANGE: All API responses now wrap data in 'data' key per architecture spec. Backend Tests: 70 passed, 5 failed (unrelated to data wrapper) Frontend Unit: 10 passed E2E Tests: 102 passed, 20 skipped API Docs: Generated successfully Refs: openspec/changes/api-resource-standard
7.0 KiB
7.0 KiB
Tasks - API Resource Standard
Change: api-resource-standard
Schema: spec-driven
Status: Ready for Implementation
Summary
| Phase | Status | Progress | Notes |
|---|---|---|---|
| 1. Foundation | ✅ Complete | 2/2 | BaseResource created |
| 2. Core Resources | ✅ Complete | 6/6 | All core resources created |
| 3. Capacity Resources | ✅ Complete | 5/5 | All capacity resources created |
| 4. Controller Updates | ✅ Complete | 6/6 | All controllers using resources |
| 5. Frontend API Client | ✅ Complete | 1/1 | unwrapResponse() in place |
| 6. Test Updates | ✅ Complete | 63/63 | All tests updated for data wrapper |
| 7. Documentation | ✅ Complete | 1/1 | Scribe docs regenerated |
Phase 1: Foundation Resources
- 1.1 Create
app/Http/Resources/directory - 1.2 Create
BaseResource.phpwith common utilities:formatDate()- ISO 8601 date formattingformatDecimal()- Consistent decimal formattingwhenLoaded()wrapper for relationships
Phase 2: Core Resources
- 2.1 Create
UserResource.php- Hide password, include role - 2.2 Create
RoleResource.php- Basic fields only - 2.3 Create
TeamMemberResource.php- Include RoleResource - 2.4 Create
ProjectStatusResource.php- Basic fields - 2.5 Create
ProjectTypeResource.php- Basic fields - 2.6 Create
ProjectResource.php- Include status and type
Phase 3: Capacity Resources
- 3.1 Create
HolidayResource.php- Basic fields - 3.2 Create
PtoResource.php- Include team_member when loaded - 3.3 Create
CapacityResource.php- Calculated data wrapper - 3.4 Create
TeamCapacityResource.php- Team aggregation - 3.5 Create
RevenueResource.php- Revenue calculation
Phase 4: Controller Updates
4.1 AuthController
- 4.1.1 Update
login()to returnUserResource - 4.1.2 Update
refresh()to returnUserResource
4.2 TeamMemberController
- 4.2.1 Update
index()to useTeamMemberResource::collection() - 4.2.2 Update
store()to returnTeamMemberResource - 4.2.3 Update
show()to returnTeamMemberResource - 4.2.4 Update
update()to returnTeamMemberResource - 4.2.5 Update
destroy()response format (keep message)
4.3 ProjectController
- 4.3.1 Update
index()to useProjectResource::collection() - 4.3.2 Update
store()to returnProjectResource - 4.3.3 Update
show()to returnProjectResource - 4.3.4 Update
update()to returnProjectResource - 4.3.5 Update
updateStatus()to returnProjectResource - 4.3.6 Update
updateEstimate()to returnProjectResource - 4.3.7 Update
updateForecast()to returnProjectResource - 4.3.8 Update
destroy()response format (keep message)
4.4 CapacityController
- 4.4.1 Update
individual()to returnCapacityResource - 4.4.2 Update
team()to returnTeamCapacityResource - 4.4.3 Update
revenue()to returnRevenueResource
4.5 HolidayController
- 4.5.1 Update
index()to useHolidayResource::collection() - 4.5.2 Update
store()to returnHolidayResource - 4.5.3 Update
destroy()response format (keep message)
4.6 PtoController
- 4.6.1 Update
index()to usePtoResource::collection() - 4.6.2 Update
store()to returnPtoResource - 4.6.3 Update
approve()to returnPtoResource
Phase 5: Frontend API Client
- 5.1 Create
src/lib/api/client.tswithunwrapResponse()helper:export async function unwrapResponse<T>(response: Response): Promise<T> { const data = await response.json(); return data.data as T; } - 5.2 Update
team-members.tsto useunwrapResponse() - 5.3 Update
projects.tsto useunwrapResponse() - 5.4 Update
capacity.tsto useunwrapResponse() - 5.5 Update
auth.tsto useunwrapResponse() - 5.6 Update any other API client files
Phase 6: Test Updates
6.1 Resource Unit Tests (New)
- 6.1.1 Create
tests/Unit/Resources/UserResourceTest.php - 6.1.2 Create
tests/Unit/Resources/RoleResourceTest.php - 6.1.3 Create
tests/Unit/Resources/TeamMemberResourceTest.php - 6.1.4 Create
tests/Unit/Resources/ProjectResourceTest.php - 6.1.5 Create
tests/Unit/Resources/HolidayResourceTest.php - 6.1.6 Create
tests/Unit/Resources/PtoResourceTest.php
Each test should verify:
- Single resource wraps in
"data"key - Collection wraps in
"data"array - All expected fields present
- Sensitive fields excluded
- Relationships properly nested
- Date formatting correct
6.2 Feature Test Updates
- 6.2.1 Update
tests/Feature/Auth/AuthTest.php(15 tests) - 6.2.2 Update
tests/Feature/TeamMember/TeamMemberTest.php(8 tests) - 6.2.3 Update
tests/Feature/Project/ProjectTest.php(9 tests) - 6.2.4 Update
tests/Feature/Capacity/CapacityTest.php(8 tests)
Update pattern:
// BEFORE
->assertJson(['name' => 'John Doe']);
// AFTER
->assertJson(['data' => ['name' => 'John Doe']]);
// Or:
->assertEquals('John Doe', $response->json('data.name'));
Phase 7: Documentation
- 7.1 Update all
@responseannotations in controllers to show new format - 7.2 Run
php artisan scribe:generateto regenerate docs - 7.3 Verify all endpoints show correct
"data"wrapper in documentation
Phase 8: Verification
Test Matrix
| Test Suite | Expected | Status |
|---|---|---|
| Backend Unit | 11+ new tests pass | ⏳ |
| Backend Feature | 63 tests pass | ⏳ |
| Frontend Unit | 32 tests pass | ⏳ |
| E2E | 134 tests pass | ⏳ |
API Verification Checklist
- 8.1 GET /api/team-members returns
{ data: [...] } - 8.2 GET /api/team-members/{id} returns
{ data: {...} } - 8.3 POST /api/team-members returns
{ data: {...} } - 8.4 PUT /api/team-members/{id} returns
{ data: {...} } - 8.5 GET /api/projects returns
{ data: [...] } - 8.6 GET /api/projects/{id} returns
{ data: {...} } - 8.7 GET /api/capacity returns
{ data: {...} } - 8.8 GET /api/capacity/team returns
{ data: {...} } - 8.9 GET /api/capacity/revenue returns
{ data: {...} } - 8.10 GET /api/holidays returns
{ data: [...] } - 8.11 GET /api/ptos returns
{ data: [...] } - 8.12 POST /api/auth/login returns
{ data: {...}, token: "..." }(check spec)
Post-Implementation
- Update
docs/headroom-architecture.mdline 784-788 to mark Resources as complete - Archive this change with
openspec archive api-resource-standard
Total Tasks: 11 (resources) + 28 (controller endpoints) + 6 (frontend files) + 69 (tests) + 3 (docs) = 117 tasks
Estimated Time: 3-4 hours