feat(api): Implement API Resource Standard compliance

- 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
This commit is contained in:
2026-02-19 14:51:56 -05:00
parent 1592c5be8d
commit 47068dabce
49 changed files with 2426 additions and 809 deletions

View File

@@ -47,21 +47,22 @@ endpoints:
custom: []
status: 200
content: |-
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role_id": 1,
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "150.00",
"active": true,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T10:00:00.000000Z"
}
]
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "150.00",
"active": true,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T10:00:00.000000Z"
}
]
}
headers: []
description: ''
responseFields: []
@@ -150,17 +151,18 @@ endpoints:
status: 201
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role_id": 1,
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "150.00",
"active": true,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T10:00:00.000000Z"
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "150.00",
"active": true,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T10:00:00.000000Z"
}
}
headers: []
description: ''
@@ -220,17 +222,18 @@ endpoints:
status: 200
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role_id": 1,
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "150.00",
"active": true,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T10:00:00.000000Z"
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "150.00",
"active": true,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T10:00:00.000000Z"
}
}
headers: []
description: ''
@@ -339,17 +342,18 @@ endpoints:
status: 200
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role_id": 1,
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "175.00",
"active": false,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T11:00:00.000000Z"
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"role": {
"id": 1,
"name": "Backend Developer"
},
"hourly_rate": "175.00",
"active": false,
"created_at": "2024-01-15T10:00:00.000000Z",
"updated_at": "2024-01-15T11:00:00.000000Z"
}
}
headers: []
description: ''