@etus/bhono-app 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/templates/base/.claude/commands/check-skill-rules.md +112 -29
- package/templates/base/.claude/commands/linear/implement-issue.md +383 -55
- package/templates/base/.claude/commands/ship.md +77 -13
- package/templates/base/.claude/hooks/package-lock.json +0 -419
- package/templates/base/.claude/hooks/skill-activation-prompt.ts +185 -113
- package/templates/base/.claude/hooks/skill-tool-guard.sh +6 -0
- package/templates/base/.claude/hooks/skill-tool-guard.ts +198 -0
- package/templates/base/.claude/scripts/validate-skill-rules.sh +55 -32
- package/templates/base/.claude/settings.json +18 -11
- package/templates/base/.claude/skills/skill-rules.json +326 -173
- package/templates/base/.env.example +3 -0
- package/templates/base/README.md +9 -7
- package/templates/base/config/eslint.config.js +1 -0
- package/templates/base/config/wrangler.json +16 -17
- package/templates/base/docs/SETUP-GUIDE.md +566 -0
- package/templates/base/docs/architecture/README.md +162 -8
- package/templates/base/docs/architecture/api-catalog.md +575 -0
- package/templates/base/docs/architecture/c4-component.md +309 -0
- package/templates/base/docs/architecture/c4-container.md +183 -0
- package/templates/base/docs/architecture/c4-context.md +106 -0
- package/templates/base/docs/architecture/dependencies.md +327 -0
- package/templates/base/docs/architecture/tech-debt.md +184 -0
- package/templates/base/package.json +20 -15
- package/templates/base/scripts/capture-prod-session.ts +2 -2
- package/templates/base/scripts/sync-template.sh +104 -0
- package/templates/base/src/server/db/sql.ts +24 -4
- package/templates/base/src/server/index.ts +1 -0
- package/templates/base/src/server/lib/audited-db.ts +10 -10
- package/templates/base/src/server/middleware/account.ts +1 -1
- package/templates/base/src/server/middleware/auth.ts +11 -11
- package/templates/base/src/server/middleware/rate-limit.ts +3 -6
- package/templates/base/src/server/routes/auth/handlers.ts +5 -5
- package/templates/base/src/server/routes/auth/test-login.ts +9 -9
- package/templates/base/src/server/routes/index.ts +9 -0
- package/templates/base/src/server/routes/invitations/handlers.ts +6 -6
- package/templates/base/src/server/routes/openapi.ts +1 -1
- package/templates/base/src/server/services/accounts.ts +9 -9
- package/templates/base/src/server/services/audits.ts +12 -12
- package/templates/base/src/server/services/auth.ts +15 -15
- package/templates/base/src/server/services/invitations.ts +16 -16
- package/templates/base/src/server/services/users.ts +13 -13
- package/templates/base/src/shared/types/api.ts +66 -198
- package/templates/base/tests/e2e/auth.setup.ts +1 -1
- package/templates/base/tests/unit/server/auth/guards.test.ts +1 -1
- package/templates/base/tests/unit/server/middleware/auth.test.ts +273 -0
- package/templates/base/tests/unit/server/routes/auth/handlers.test.ts +111 -0
- package/templates/base/tests/unit/server/routes/users/handlers.test.ts +69 -5
- package/templates/base/tests/unit/server/services/accounts.test.ts +148 -0
- package/templates/base/tests/unit/server/services/audits.test.ts +219 -0
- package/templates/base/tests/unit/server/services/auth.test.ts +480 -3
- package/templates/base/tests/unit/server/services/invitations.test.ts +178 -0
- package/templates/base/tests/unit/server/services/users.test.ts +363 -8
- package/templates/base/tests/unit/shared/schemas.test.ts +1 -1
- package/templates/base/vite.config.ts +3 -1
- package/templates/base/.github/workflows/test.yml +0 -127
- package/templates/base/.husky/pre-push +0 -26
- package/templates/base/auth-setup-error.png +0 -0
- package/templates/base/pnpm-lock.yaml +0 -8052
- package/templates/base/tests/e2e/_auth/.gitkeep +0 -0
- package/templates/base/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
# API Catalog - BHono Platform
|
|
2
|
+
|
|
3
|
+
> Complete REST API endpoint documentation with OpenAPI 3.0 support.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
| Attribute | Value | Confidence |
|
|
8
|
+
|-----------|-------|------------|
|
|
9
|
+
| **Base URL** | `/api` (authenticated), `/auth` (public) | HIGH |
|
|
10
|
+
| **Format** | REST/JSON | HIGH |
|
|
11
|
+
| **Documentation** | OpenAPI 3.0 at `/api/doc` | HIGH |
|
|
12
|
+
| **Swagger UI** | Available at `/api/swagger` | HIGH |
|
|
13
|
+
| **Total Endpoints** | 30 | HIGH |
|
|
14
|
+
|
|
15
|
+
## Authentication
|
|
16
|
+
|
|
17
|
+
All `/api/*` endpoints require authentication via session cookie (`__Host-sid`).
|
|
18
|
+
|
|
19
|
+
| Header/Cookie | Purpose |
|
|
20
|
+
|---------------|---------|
|
|
21
|
+
| `Cookie: __Host-sid=<session_id>` | Session authentication |
|
|
22
|
+
| `X-Account-Id` | Multi-tenant account context |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Auth Endpoints [HIGH]
|
|
27
|
+
|
|
28
|
+
Base path: `/auth`
|
|
29
|
+
|
|
30
|
+
| Method | Path | Description | Auth Required |
|
|
31
|
+
|--------|------|-------------|---------------|
|
|
32
|
+
| `GET` | `/auth/login` | Initiate Google OAuth flow | No |
|
|
33
|
+
| `GET` | `/auth/callback` | OAuth callback handler | No |
|
|
34
|
+
| `POST` | `/auth/logout` | Destroy session | Yes |
|
|
35
|
+
| `GET` | `/auth/me` | Get current user info | Yes |
|
|
36
|
+
| `POST` | `/auth/refresh` | Refresh session token | Yes |
|
|
37
|
+
| `GET` | `/auth/invite/{token}` | Get invitation details | No |
|
|
38
|
+
|
|
39
|
+
### GET /auth/login
|
|
40
|
+
|
|
41
|
+
Initiates Google OAuth 2.0 authorization flow.
|
|
42
|
+
|
|
43
|
+
**Response**: Redirect to Google OAuth consent screen
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
302 Found
|
|
47
|
+
Location: https://accounts.google.com/o/oauth2/v2/auth?...
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### GET /auth/callback
|
|
51
|
+
|
|
52
|
+
Handles OAuth callback from Google.
|
|
53
|
+
|
|
54
|
+
**Query Parameters**:
|
|
55
|
+
| Parameter | Type | Description |
|
|
56
|
+
|-----------|------|-------------|
|
|
57
|
+
| `code` | string | Authorization code from Google |
|
|
58
|
+
| `state` | string | CSRF state token |
|
|
59
|
+
|
|
60
|
+
**Response**: Redirect to dashboard with session cookie set
|
|
61
|
+
|
|
62
|
+
### POST /auth/logout
|
|
63
|
+
|
|
64
|
+
Destroys the current session.
|
|
65
|
+
|
|
66
|
+
**Response**:
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"success": true
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### GET /auth/me
|
|
74
|
+
|
|
75
|
+
Returns current authenticated user information.
|
|
76
|
+
|
|
77
|
+
**Response**:
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"id": "01234567-89ab-cdef-0123-456789abcdef",
|
|
81
|
+
"email": "user@example.com",
|
|
82
|
+
"name": "John Doe",
|
|
83
|
+
"avatarUrl": "https://...",
|
|
84
|
+
"isSuperAdmin": false,
|
|
85
|
+
"accounts": [
|
|
86
|
+
{
|
|
87
|
+
"id": "account-uuid",
|
|
88
|
+
"name": "My Workspace",
|
|
89
|
+
"role": "ADMIN"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### POST /auth/refresh
|
|
96
|
+
|
|
97
|
+
Refreshes the session token.
|
|
98
|
+
|
|
99
|
+
**Response**:
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"success": true,
|
|
103
|
+
"expiresAt": "2025-01-15T12:00:00Z"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### GET /auth/invite/{token}
|
|
108
|
+
|
|
109
|
+
Gets invitation details for acceptance page.
|
|
110
|
+
|
|
111
|
+
**Path Parameters**:
|
|
112
|
+
| Parameter | Type | Description |
|
|
113
|
+
|-----------|------|-------------|
|
|
114
|
+
| `token` | string | Invitation token |
|
|
115
|
+
|
|
116
|
+
**Response**:
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"id": "invitation-uuid",
|
|
120
|
+
"email": "invitee@example.com",
|
|
121
|
+
"accountName": "Workspace Name",
|
|
122
|
+
"inviterName": "John Doe",
|
|
123
|
+
"role": "EDITOR",
|
|
124
|
+
"expiresAt": "2025-01-20T12:00:00Z"
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Users Endpoints [HIGH]
|
|
131
|
+
|
|
132
|
+
Base path: `/api/users`
|
|
133
|
+
|
|
134
|
+
| Method | Path | Description | Auth | Permission |
|
|
135
|
+
|--------|------|-------------|------|------------|
|
|
136
|
+
| `GET` | `/api/users` | List users (paginated) | Yes | VIEWER+ |
|
|
137
|
+
| `GET` | `/api/users/{id}` | Get user by ID | Yes | VIEWER+ |
|
|
138
|
+
| `POST` | `/api/users` | Create user | Yes | ADMIN |
|
|
139
|
+
| `PATCH` | `/api/users/{id}` | Update user | Yes | ADMIN |
|
|
140
|
+
| `DELETE` | `/api/users/{id}` | Soft delete user | Yes | ADMIN |
|
|
141
|
+
| `POST` | `/api/users/{id}/restore` | Restore deleted user | Yes | ADMIN |
|
|
142
|
+
| `GET` | `/api/users/{id}/accounts` | Get user's accounts | Yes | VIEWER+ |
|
|
143
|
+
| `POST` | `/api/users/bulk/accounts` | Bulk add to accounts | Yes | ADMIN |
|
|
144
|
+
|
|
145
|
+
### GET /api/users
|
|
146
|
+
|
|
147
|
+
List users with pagination.
|
|
148
|
+
|
|
149
|
+
**Query Parameters**:
|
|
150
|
+
| Parameter | Type | Default | Description |
|
|
151
|
+
|-----------|------|---------|-------------|
|
|
152
|
+
| `page` | integer | 1 | Page number |
|
|
153
|
+
| `limit` | integer | 20 | Items per page (max 100) |
|
|
154
|
+
| `search` | string | - | Search by name/email |
|
|
155
|
+
| `status` | string | - | Filter by status |
|
|
156
|
+
|
|
157
|
+
**Response**:
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"data": [
|
|
161
|
+
{
|
|
162
|
+
"id": "user-uuid",
|
|
163
|
+
"email": "user@example.com",
|
|
164
|
+
"name": "John Doe",
|
|
165
|
+
"status": "active",
|
|
166
|
+
"createdAt": "2025-01-01T00:00:00Z"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
"pagination": {
|
|
170
|
+
"page": 1,
|
|
171
|
+
"limit": 20,
|
|
172
|
+
"total": 100,
|
|
173
|
+
"totalPages": 5
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### POST /api/users
|
|
179
|
+
|
|
180
|
+
Create a new user.
|
|
181
|
+
|
|
182
|
+
**Request Body**:
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"email": "newuser@example.com",
|
|
186
|
+
"name": "New User",
|
|
187
|
+
"role": "EDITOR"
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Response**: `201 Created`
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"id": "new-user-uuid",
|
|
195
|
+
"email": "newuser@example.com",
|
|
196
|
+
"name": "New User",
|
|
197
|
+
"status": "active",
|
|
198
|
+
"createdAt": "2025-01-01T00:00:00Z"
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### PATCH /api/users/{id}
|
|
203
|
+
|
|
204
|
+
Update user properties.
|
|
205
|
+
|
|
206
|
+
**Request Body**:
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"name": "Updated Name",
|
|
210
|
+
"status": "inactive"
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### DELETE /api/users/{id}
|
|
215
|
+
|
|
216
|
+
Soft delete a user (sets `deleted_at`).
|
|
217
|
+
|
|
218
|
+
**Response**: `204 No Content`
|
|
219
|
+
|
|
220
|
+
### POST /api/users/{id}/restore
|
|
221
|
+
|
|
222
|
+
Restore a soft-deleted user.
|
|
223
|
+
|
|
224
|
+
**Response**: `200 OK`
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Accounts Endpoints [HIGH]
|
|
229
|
+
|
|
230
|
+
Base path: `/api/accounts`
|
|
231
|
+
|
|
232
|
+
| Method | Path | Description | Auth | Permission |
|
|
233
|
+
|--------|------|-------------|------|------------|
|
|
234
|
+
| `GET` | `/api/accounts` | List accounts | Yes | VIEWER+ |
|
|
235
|
+
| `GET` | `/api/accounts/{id}` | Get account | Yes | VIEWER+ |
|
|
236
|
+
| `POST` | `/api/accounts` | Create account | Yes | Auth only |
|
|
237
|
+
| `PATCH` | `/api/accounts/{id}` | Update account | Yes | ADMIN |
|
|
238
|
+
| `DELETE` | `/api/accounts/{id}` | Soft delete account | Yes | ADMIN |
|
|
239
|
+
| `POST` | `/api/accounts/{id}/restore` | Restore account | Yes | ADMIN |
|
|
240
|
+
|
|
241
|
+
### GET /api/accounts
|
|
242
|
+
|
|
243
|
+
List accounts the current user has access to.
|
|
244
|
+
|
|
245
|
+
**Query Parameters**:
|
|
246
|
+
| Parameter | Type | Default | Description |
|
|
247
|
+
|-----------|------|---------|-------------|
|
|
248
|
+
| `page` | integer | 1 | Page number |
|
|
249
|
+
| `limit` | integer | 20 | Items per page |
|
|
250
|
+
|
|
251
|
+
**Response**:
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"data": [
|
|
255
|
+
{
|
|
256
|
+
"id": "account-uuid",
|
|
257
|
+
"name": "My Workspace",
|
|
258
|
+
"description": "Team workspace",
|
|
259
|
+
"domain": "myworkspace",
|
|
260
|
+
"memberCount": 5,
|
|
261
|
+
"createdAt": "2025-01-01T00:00:00Z"
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
"pagination": {
|
|
265
|
+
"page": 1,
|
|
266
|
+
"limit": 20,
|
|
267
|
+
"total": 3,
|
|
268
|
+
"totalPages": 1
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### POST /api/accounts
|
|
274
|
+
|
|
275
|
+
Create a new account (workspace).
|
|
276
|
+
|
|
277
|
+
**Request Body**:
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"name": "New Workspace",
|
|
281
|
+
"description": "Description of the workspace",
|
|
282
|
+
"domain": "new-workspace"
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Response**: `201 Created`
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Invitations Endpoints [HIGH]
|
|
291
|
+
|
|
292
|
+
Base path: `/api/invitations`
|
|
293
|
+
|
|
294
|
+
| Method | Path | Description | Auth | Permission |
|
|
295
|
+
|--------|------|-------------|------|------------|
|
|
296
|
+
| `POST` | `/api/invitations` | Send invitation | Yes | MANAGER+ |
|
|
297
|
+
| `GET` | `/api/invitations` | List invitations | Yes | MANAGER+ |
|
|
298
|
+
| `DELETE` | `/api/invitations/{id}` | Revoke invitation | Yes | MANAGER+ |
|
|
299
|
+
|
|
300
|
+
### POST /api/invitations
|
|
301
|
+
|
|
302
|
+
Send a team invitation email.
|
|
303
|
+
|
|
304
|
+
**Request Body**:
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"email": "newmember@example.com",
|
|
308
|
+
"role": "EDITOR",
|
|
309
|
+
"accountId": "account-uuid"
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Response**: `201 Created`
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"id": "invitation-uuid",
|
|
317
|
+
"email": "newmember@example.com",
|
|
318
|
+
"role": "EDITOR",
|
|
319
|
+
"status": "pending",
|
|
320
|
+
"expiresAt": "2025-01-08T00:00:00Z"
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### GET /api/invitations
|
|
325
|
+
|
|
326
|
+
List pending invitations for an account.
|
|
327
|
+
|
|
328
|
+
**Query Parameters**:
|
|
329
|
+
| Parameter | Type | Description |
|
|
330
|
+
|-----------|------|-------------|
|
|
331
|
+
| `accountId` | string | Filter by account |
|
|
332
|
+
| `status` | string | Filter by status (pending, accepted, expired) |
|
|
333
|
+
|
|
334
|
+
### DELETE /api/invitations/{id}
|
|
335
|
+
|
|
336
|
+
Revoke a pending invitation.
|
|
337
|
+
|
|
338
|
+
**Response**: `204 No Content`
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Audits Endpoints [HIGH]
|
|
343
|
+
|
|
344
|
+
Base path: `/api/audits`
|
|
345
|
+
|
|
346
|
+
| Method | Path | Description | Auth | Permission |
|
|
347
|
+
|--------|------|-------------|------|------------|
|
|
348
|
+
| `GET` | `/api/audits` | List audit logs | Yes | ANALYTICS/ADMIN |
|
|
349
|
+
|
|
350
|
+
### GET /api/audits
|
|
351
|
+
|
|
352
|
+
Query audit logs with filtering.
|
|
353
|
+
|
|
354
|
+
**Query Parameters**:
|
|
355
|
+
| Parameter | Type | Description |
|
|
356
|
+
|-----------|------|-------------|
|
|
357
|
+
| `page` | integer | Page number |
|
|
358
|
+
| `limit` | integer | Items per page |
|
|
359
|
+
| `action` | string | Filter by action (CREATE, UPDATE, DELETE, LOGIN, LOGOUT) |
|
|
360
|
+
| `resourceType` | string | Filter by resource type |
|
|
361
|
+
| `resourceId` | string | Filter by resource ID |
|
|
362
|
+
| `userId` | string | Filter by user ID |
|
|
363
|
+
| `startDate` | string | Filter from date (ISO 8601) |
|
|
364
|
+
| `endDate` | string | Filter to date (ISO 8601) |
|
|
365
|
+
|
|
366
|
+
**Response**:
|
|
367
|
+
```json
|
|
368
|
+
{
|
|
369
|
+
"data": [
|
|
370
|
+
{
|
|
371
|
+
"id": "audit-uuid",
|
|
372
|
+
"action": "UPDATE",
|
|
373
|
+
"resourceType": "user",
|
|
374
|
+
"resourceId": "user-uuid",
|
|
375
|
+
"userId": "actor-uuid",
|
|
376
|
+
"changes": {
|
|
377
|
+
"before": { "name": "Old Name" },
|
|
378
|
+
"after": { "name": "New Name" }
|
|
379
|
+
},
|
|
380
|
+
"ipAddress": "192.168.1.1",
|
|
381
|
+
"userAgent": "Mozilla/5.0...",
|
|
382
|
+
"transactionId": "txn-uuid",
|
|
383
|
+
"createdAt": "2025-01-01T12:00:00Z"
|
|
384
|
+
}
|
|
385
|
+
],
|
|
386
|
+
"pagination": {
|
|
387
|
+
"page": 1,
|
|
388
|
+
"limit": 20,
|
|
389
|
+
"total": 150,
|
|
390
|
+
"totalPages": 8
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Storage Endpoints [HIGH]
|
|
398
|
+
|
|
399
|
+
Base path: `/api/storage`
|
|
400
|
+
|
|
401
|
+
| Method | Path | Description | Auth | Permission |
|
|
402
|
+
|--------|------|-------------|------|------------|
|
|
403
|
+
| `POST` | `/api/storage/upload-url` | Get presigned upload URL | Yes | AUTHOR+ |
|
|
404
|
+
| `PUT` | `/api/storage/upload/{key}` | Upload file directly | Yes | AUTHOR+ |
|
|
405
|
+
| `DELETE` | `/api/storage/{key}` | Delete file | Yes | EDITOR+ |
|
|
406
|
+
|
|
407
|
+
### POST /api/storage/upload-url
|
|
408
|
+
|
|
409
|
+
Generate a presigned URL for client-side upload.
|
|
410
|
+
|
|
411
|
+
**Request Body**:
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"filename": "document.pdf",
|
|
415
|
+
"contentType": "application/pdf",
|
|
416
|
+
"size": 1048576
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Response**:
|
|
421
|
+
```json
|
|
422
|
+
{
|
|
423
|
+
"uploadUrl": "https://r2.cloudflarestorage.com/...",
|
|
424
|
+
"key": "accounts/uuid/files/uuid/document.pdf",
|
|
425
|
+
"expiresAt": "2025-01-01T12:15:00Z"
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### PUT /api/storage/upload/{key}
|
|
430
|
+
|
|
431
|
+
Direct file upload (alternative to presigned URL).
|
|
432
|
+
|
|
433
|
+
**Headers**:
|
|
434
|
+
- `Content-Type`: File MIME type
|
|
435
|
+
- `Content-Length`: File size in bytes
|
|
436
|
+
|
|
437
|
+
**Response**: `200 OK`
|
|
438
|
+
```json
|
|
439
|
+
{
|
|
440
|
+
"key": "accounts/uuid/files/uuid/document.pdf",
|
|
441
|
+
"url": "https://storage.example.com/...",
|
|
442
|
+
"size": 1048576
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### DELETE /api/storage/{key}
|
|
447
|
+
|
|
448
|
+
Delete a file from R2 storage.
|
|
449
|
+
|
|
450
|
+
**Response**: `204 No Content`
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Health Endpoints [HIGH]
|
|
455
|
+
|
|
456
|
+
Base path: `/health`
|
|
457
|
+
|
|
458
|
+
| Method | Path | Description | Auth |
|
|
459
|
+
|--------|------|-------------|------|
|
|
460
|
+
| `GET` | `/health` | Basic health check | No |
|
|
461
|
+
| `GET` | `/health/ready` | Readiness probe | No |
|
|
462
|
+
| `GET` | `/health/live` | Liveness probe | No |
|
|
463
|
+
|
|
464
|
+
### GET /health
|
|
465
|
+
|
|
466
|
+
Basic health check endpoint.
|
|
467
|
+
|
|
468
|
+
**Response**:
|
|
469
|
+
```json
|
|
470
|
+
{
|
|
471
|
+
"status": "healthy",
|
|
472
|
+
"timestamp": "2025-01-01T12:00:00Z"
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### GET /health/ready
|
|
477
|
+
|
|
478
|
+
Kubernetes readiness probe - checks database connectivity.
|
|
479
|
+
|
|
480
|
+
**Response**:
|
|
481
|
+
```json
|
|
482
|
+
{
|
|
483
|
+
"status": "ready",
|
|
484
|
+
"checks": {
|
|
485
|
+
"database": "ok",
|
|
486
|
+
"kv": "ok"
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### GET /health/live
|
|
492
|
+
|
|
493
|
+
Kubernetes liveness probe - basic process health.
|
|
494
|
+
|
|
495
|
+
**Response**:
|
|
496
|
+
```json
|
|
497
|
+
{
|
|
498
|
+
"status": "alive"
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## Error Responses
|
|
505
|
+
|
|
506
|
+
All endpoints return consistent error responses:
|
|
507
|
+
|
|
508
|
+
```json
|
|
509
|
+
{
|
|
510
|
+
"error": {
|
|
511
|
+
"code": "ERROR_CODE",
|
|
512
|
+
"message": "Human-readable error message",
|
|
513
|
+
"details": {}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### HTTP Status Codes
|
|
519
|
+
|
|
520
|
+
| Code | Meaning |
|
|
521
|
+
|------|---------|
|
|
522
|
+
| `200` | Success |
|
|
523
|
+
| `201` | Created |
|
|
524
|
+
| `204` | No Content |
|
|
525
|
+
| `400` | Bad Request (validation error) |
|
|
526
|
+
| `401` | Unauthorized (not authenticated) |
|
|
527
|
+
| `403` | Forbidden (insufficient permissions) |
|
|
528
|
+
| `404` | Not Found |
|
|
529
|
+
| `409` | Conflict (duplicate resource) |
|
|
530
|
+
| `429` | Too Many Requests (rate limited) |
|
|
531
|
+
| `500` | Internal Server Error |
|
|
532
|
+
|
|
533
|
+
### Common Error Codes
|
|
534
|
+
|
|
535
|
+
| Code | Description |
|
|
536
|
+
|------|-------------|
|
|
537
|
+
| `VALIDATION_ERROR` | Request body/params failed validation |
|
|
538
|
+
| `UNAUTHORIZED` | No valid session |
|
|
539
|
+
| `FORBIDDEN` | Insufficient role/permissions |
|
|
540
|
+
| `NOT_FOUND` | Resource doesn't exist |
|
|
541
|
+
| `DUPLICATE_EMAIL` | Email already registered |
|
|
542
|
+
| `INVITATION_EXPIRED` | Invitation token expired |
|
|
543
|
+
| `RATE_LIMITED` | Too many requests |
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Rate Limiting
|
|
548
|
+
|
|
549
|
+
| Endpoint Type | Limit | Window |
|
|
550
|
+
|---------------|-------|--------|
|
|
551
|
+
| Auth endpoints | 10 req | 1 minute |
|
|
552
|
+
| API endpoints | 100 req | 1 minute |
|
|
553
|
+
| Upload endpoints | 20 req | 1 minute |
|
|
554
|
+
|
|
555
|
+
Rate limit headers:
|
|
556
|
+
```
|
|
557
|
+
X-RateLimit-Limit: 100
|
|
558
|
+
X-RateLimit-Remaining: 95
|
|
559
|
+
X-RateLimit-Reset: 1704110400
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## OpenAPI Specification
|
|
565
|
+
|
|
566
|
+
Full OpenAPI 3.0 specification available at:
|
|
567
|
+
|
|
568
|
+
- **JSON**: `GET /api/doc`
|
|
569
|
+
- **Swagger UI**: `GET /api/swagger`
|
|
570
|
+
|
|
571
|
+
The specification includes:
|
|
572
|
+
- All request/response schemas (Zod-generated)
|
|
573
|
+
- Authentication requirements
|
|
574
|
+
- Example requests and responses
|
|
575
|
+
- Error schemas
|