@comfanion/workflow 4.36.40 → 4.36.42
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/README.md +1 -1
- package/package.json +1 -1
- package/src/build-info.json +2 -2
- package/src/opencode/FLOW.yaml +1 -1
- package/src/opencode/agents/architect.md +7 -5
- package/src/opencode/checklists/architecture-checklist.md +4 -5
- package/src/opencode/checklists/code-review-checklist.md +4 -4
- package/src/opencode/commands/architecture.md +1 -1
- package/src/opencode/opencode.json +1 -1
- package/src/opencode/skills/adr-writing/SKILL.md +3 -2
- package/src/opencode/skills/api-design/SKILL.md +527 -0
- package/src/opencode/skills/architecture-design/SKILL.md +313 -10
- package/src/opencode/skills/architecture-design/template.md +3 -3
- package/src/opencode/skills/architecture-validation/SKILL.md +4 -4
- package/src/opencode/skills/code-review/SKILL.md +3 -3
- package/src/opencode/skills/coding-standards/SKILL.md +5 -6
- package/src/opencode/skills/database-design/SKILL.md +820 -0
- package/src/opencode/skills/diagram-creation/SKILL.md +384 -10
- package/src/opencode/skills/prd-writing/template.md +1 -1
- package/src/opencode/skills/story-writing/template.md +4 -4
- package/src/opencode/skills/unit-writing/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Development: /dev-story ↔ /code-review (loop until done)
|
|
|
38
38
|
|
|
39
39
|
- **requirements-gathering** - Extract FR/NFR through interviews
|
|
40
40
|
- **prd-writing** - Product requirements documents
|
|
41
|
-
- **architecture-design** -
|
|
41
|
+
- **architecture-design** - System architecture patterns
|
|
42
42
|
- **story-writing** - User stories with Given/When/Then AC
|
|
43
43
|
- **dev-story** - Red-green-refactor implementation cycle
|
|
44
44
|
- **jira-integration** - Bidirectional sync with Jira
|
package/package.json
CHANGED
package/src/build-info.json
CHANGED
package/src/opencode/FLOW.yaml
CHANGED
|
@@ -370,7 +370,7 @@ agents:
|
|
|
370
370
|
file: agents/architect.md
|
|
371
371
|
expertise:
|
|
372
372
|
- Distributed systems
|
|
373
|
-
-
|
|
373
|
+
- Architecture patterns (chooses based on context)
|
|
374
374
|
- System design
|
|
375
375
|
personality: Technical, precise, patterns-focused
|
|
376
376
|
skills_used:
|
|
@@ -109,7 +109,7 @@ permission:
|
|
|
109
109
|
|
|
110
110
|
<persona>
|
|
111
111
|
<role>System Architect + Technical Design Leader</role>
|
|
112
|
-
<identity>Senior architect with expertise in distributed systems, cloud infrastructure, API design.
|
|
112
|
+
<identity>Senior architect with expertise in distributed systems, cloud infrastructure, API design. Chooses architecture patterns based on project needs, not dogma.</identity>
|
|
113
113
|
<communication_style>Calm, pragmatic, balancing 'what could be' with 'what should be.' Technical but accessible. Always considers trade-offs.</communication_style>
|
|
114
114
|
<principles>
|
|
115
115
|
- Channel expert lean architecture: distributed systems, cloud patterns, scalability
|
|
@@ -129,12 +129,14 @@ permission:
|
|
|
129
129
|
</skills>
|
|
130
130
|
|
|
131
131
|
<design-principles>
|
|
132
|
-
1.
|
|
132
|
+
1. Right Pattern for Context - Choose architecture style based on project needs (see architecture-design skill)
|
|
133
133
|
2. Single Responsibility - Each module has one job
|
|
134
134
|
3. Explicit Contracts - Clear interfaces between modules
|
|
135
|
-
4.
|
|
136
|
-
5.
|
|
137
|
-
6.
|
|
135
|
+
4. Separation of Concerns - Isolate business logic from infrastructure
|
|
136
|
+
5. Event-Driven Where Appropriate - Loose coupling via events when justified
|
|
137
|
+
6. Idempotency - Operations should be safely retryable
|
|
138
|
+
7. Observability First - Design for debugging and monitoring
|
|
139
|
+
8. Trade-off Aware - Document decisions with pros/cons in ADRs
|
|
138
140
|
</design-principles>
|
|
139
141
|
|
|
140
142
|
<documentation-structure hint="For unit-writing skill">
|
|
@@ -56,8 +56,8 @@ Use this checklist to validate architecture before proceeding to epic/story crea
|
|
|
56
56
|
## Design Quality
|
|
57
57
|
|
|
58
58
|
### Architecture Patterns
|
|
59
|
-
- [ ] Chosen
|
|
60
|
-
- [ ] Pattern choice justified
|
|
59
|
+
- [ ] Chosen pattern documented (Layered, Hexagonal, Clean, Microservices, etc.)
|
|
60
|
+
- [ ] Pattern choice justified with ADR
|
|
61
61
|
- [ ] Consistent pattern application
|
|
62
62
|
|
|
63
63
|
### Module Design
|
|
@@ -93,9 +93,8 @@ Use this checklist to validate architecture before proceeding to epic/story crea
|
|
|
93
93
|
|
|
94
94
|
## Coding Standards Alignment
|
|
95
95
|
|
|
96
|
-
- [ ] Architecture follows
|
|
97
|
-
- [ ]
|
|
98
|
-
- [ ] Use case pattern applicable
|
|
96
|
+
- [ ] Architecture follows AGENTS.md patterns
|
|
97
|
+
- [ ] Chosen architecture pattern consistently applied
|
|
99
98
|
- [ ] Testing strategy fits architecture
|
|
100
99
|
|
|
101
100
|
## ADR Quality
|
|
@@ -18,11 +18,11 @@ Use this checklist when reviewing implemented code before marking story as "done
|
|
|
18
18
|
## Code Quality
|
|
19
19
|
|
|
20
20
|
### Architecture Compliance
|
|
21
|
-
- [ ] Follows
|
|
22
|
-
- [ ]
|
|
23
|
-
- [ ]
|
|
21
|
+
- [ ] Follows project's chosen architecture pattern (AGENTS.md)
|
|
22
|
+
- [ ] Business logic isolated from infrastructure
|
|
23
|
+
- [ ] Clear separation of concerns
|
|
24
24
|
- [ ] Explicit mapping (no reflection libraries)
|
|
25
|
-
- [ ] Dependencies flow correctly
|
|
25
|
+
- [ ] Dependencies flow correctly per chosen pattern
|
|
26
26
|
|
|
27
27
|
### Code Structure
|
|
28
28
|
- [ ] Single responsibility principle followed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: adr-writing
|
|
3
|
-
description:
|
|
3
|
+
description: Use when documenting significant architectural decisions - database choice, framework selection, pattern adoption, or any decision with long-term consequences
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: opencode
|
|
6
6
|
metadata:
|
|
@@ -175,7 +175,8 @@ ADR-[NNN]-[short-title].md
|
|
|
175
175
|
|
|
176
176
|
Examples:
|
|
177
177
|
- ADR-001-postgresql-database.md
|
|
178
|
-
- ADR-002-
|
|
178
|
+
- ADR-002-architecture-pattern.md
|
|
179
|
+
- ADR-003-api-versioning.md
|
|
179
180
|
```
|
|
180
181
|
|
|
181
182
|
### IDs
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: Use when designing REST, GraphQL, or gRPC APIs, defining contracts, versioning strategy, or documenting endpoints
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: opencode
|
|
6
|
+
metadata:
|
|
7
|
+
domain: software-architecture
|
|
8
|
+
patterns: rest, graphql, grpc, openapi
|
|
9
|
+
artifacts: docs/architecture/*/api/*.yaml
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# API Design Skill
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
Use this skill when you need to:
|
|
17
|
+
- Design REST API endpoints for a module/service
|
|
18
|
+
- Define GraphQL schema and resolvers
|
|
19
|
+
- Design gRPC service definitions
|
|
20
|
+
- Plan API versioning strategy
|
|
21
|
+
- Document API contracts (OpenAPI/Swagger)
|
|
22
|
+
- Design error responses and status codes
|
|
23
|
+
- Plan authentication/authorization for APIs
|
|
24
|
+
|
|
25
|
+
## Reference
|
|
26
|
+
|
|
27
|
+
Always check project standards: `@CLAUDE.md`
|
|
28
|
+
|
|
29
|
+
## Templates
|
|
30
|
+
|
|
31
|
+
- OpenAPI: `@.opencode/skills/api-design/template-openapi.yaml`
|
|
32
|
+
- GraphQL: `@.opencode/skills/api-design/template-graphql.md`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## API Type Selection
|
|
37
|
+
|
|
38
|
+
| Type | Use When | Avoid When |
|
|
39
|
+
|------|----------|------------|
|
|
40
|
+
| **REST** | CRUD operations, public APIs, caching needed | Complex queries, real-time |
|
|
41
|
+
| **GraphQL** | Flexible queries, mobile clients, nested data | Simple CRUD, caching critical |
|
|
42
|
+
| **gRPC** | Service-to-service, high performance, streaming | Browser clients, public APIs |
|
|
43
|
+
| **WebSocket** | Real-time, bidirectional, live updates | Request-response patterns |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## REST API Design
|
|
48
|
+
|
|
49
|
+
### URL Structure
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
# Collection
|
|
53
|
+
GET /api/v1/tasks # List
|
|
54
|
+
POST /api/v1/tasks # Create
|
|
55
|
+
|
|
56
|
+
# Resource
|
|
57
|
+
GET /api/v1/tasks/{id} # Read
|
|
58
|
+
PUT /api/v1/tasks/{id} # Replace
|
|
59
|
+
PATCH /api/v1/tasks/{id} # Partial update
|
|
60
|
+
DELETE /api/v1/tasks/{id} # Delete
|
|
61
|
+
|
|
62
|
+
# Nested resources (when child belongs to parent)
|
|
63
|
+
GET /api/v1/projects/{id}/tasks
|
|
64
|
+
POST /api/v1/projects/{id}/tasks
|
|
65
|
+
|
|
66
|
+
# Actions (non-CRUD operations)
|
|
67
|
+
POST /api/v1/tasks/{id}/archive
|
|
68
|
+
POST /api/v1/tasks/{id}/assign
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Naming Conventions
|
|
72
|
+
|
|
73
|
+
| Rule | Good | Bad |
|
|
74
|
+
|------|------|-----|
|
|
75
|
+
| Plural nouns | `/tasks` | `/task`, `/getTask` |
|
|
76
|
+
| Lowercase, hyphens | `/user-profiles` | `/userProfiles`, `/user_profiles` |
|
|
77
|
+
| No verbs in URL | `POST /tasks` | `/createTask` |
|
|
78
|
+
| No trailing slash | `/tasks` | `/tasks/` |
|
|
79
|
+
| Consistent casing | `userId` | `user_id` in JSON |
|
|
80
|
+
|
|
81
|
+
### Query Parameters
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
# Filtering
|
|
85
|
+
GET /tasks?status=active&assignee_id=123
|
|
86
|
+
|
|
87
|
+
# Sorting
|
|
88
|
+
GET /tasks?sort=created_at:desc,title:asc
|
|
89
|
+
|
|
90
|
+
# Pagination (cursor-based preferred)
|
|
91
|
+
GET /tasks?cursor=eyJpZCI6MTIzfQ&limit=20
|
|
92
|
+
|
|
93
|
+
# Pagination (offset-based)
|
|
94
|
+
GET /tasks?page=2&per_page=20
|
|
95
|
+
|
|
96
|
+
# Field selection
|
|
97
|
+
GET /tasks?fields=id,title,status
|
|
98
|
+
|
|
99
|
+
# Expansion/embedding
|
|
100
|
+
GET /tasks?expand=assignee,project
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### HTTP Methods & Status Codes
|
|
104
|
+
|
|
105
|
+
| Method | Success | Created | No Content | Client Error | Not Found |
|
|
106
|
+
|--------|---------|---------|------------|--------------|-----------|
|
|
107
|
+
| GET | 200 | - | - | 400 | 404 |
|
|
108
|
+
| POST | - | 201 | - | 400, 422 | - |
|
|
109
|
+
| PUT | 200 | 201 | 204 | 400, 422 | 404 |
|
|
110
|
+
| PATCH | 200 | - | 204 | 400, 422 | 404 |
|
|
111
|
+
| DELETE | - | - | 204 | 400 | 404 |
|
|
112
|
+
|
|
113
|
+
### Response Format
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
// Success (single resource)
|
|
117
|
+
{
|
|
118
|
+
"data": {
|
|
119
|
+
"id": "123",
|
|
120
|
+
"type": "task",
|
|
121
|
+
"attributes": {
|
|
122
|
+
"title": "Fix bug",
|
|
123
|
+
"status": "active"
|
|
124
|
+
},
|
|
125
|
+
"relationships": {
|
|
126
|
+
"assignee": { "id": "456", "type": "user" }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Success (collection)
|
|
132
|
+
{
|
|
133
|
+
"data": [...],
|
|
134
|
+
"meta": {
|
|
135
|
+
"total": 100,
|
|
136
|
+
"page": 1,
|
|
137
|
+
"per_page": 20
|
|
138
|
+
},
|
|
139
|
+
"links": {
|
|
140
|
+
"next": "/tasks?cursor=abc",
|
|
141
|
+
"prev": null
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Error
|
|
146
|
+
{
|
|
147
|
+
"error": {
|
|
148
|
+
"code": "VALIDATION_ERROR",
|
|
149
|
+
"message": "Validation failed",
|
|
150
|
+
"details": [
|
|
151
|
+
{ "field": "title", "message": "is required" },
|
|
152
|
+
{ "field": "due_date", "message": "must be in future" }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Error Codes
|
|
159
|
+
|
|
160
|
+
| HTTP | Code | When |
|
|
161
|
+
|------|------|------|
|
|
162
|
+
| 400 | `BAD_REQUEST` | Malformed JSON, missing required params |
|
|
163
|
+
| 401 | `UNAUTHORIZED` | Missing or invalid auth token |
|
|
164
|
+
| 403 | `FORBIDDEN` | Valid auth but no permission |
|
|
165
|
+
| 404 | `NOT_FOUND` | Resource doesn't exist |
|
|
166
|
+
| 409 | `CONFLICT` | Duplicate, version conflict |
|
|
167
|
+
| 422 | `VALIDATION_ERROR` | Business rule violation |
|
|
168
|
+
| 429 | `RATE_LIMITED` | Too many requests |
|
|
169
|
+
| 500 | `INTERNAL_ERROR` | Server error (log, don't expose details) |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Versioning Strategy
|
|
174
|
+
|
|
175
|
+
### URL Versioning (Recommended)
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
/api/v1/tasks
|
|
179
|
+
/api/v2/tasks
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Pros:** Clear, cacheable, easy routing
|
|
183
|
+
**Cons:** URL changes on version bump
|
|
184
|
+
|
|
185
|
+
### Header Versioning
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
GET /api/tasks
|
|
189
|
+
Accept: application/vnd.api+json; version=2
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Pros:** Clean URLs
|
|
193
|
+
**Cons:** Harder to test, cache
|
|
194
|
+
|
|
195
|
+
### Version Lifecycle
|
|
196
|
+
|
|
197
|
+
| Status | Meaning | Support |
|
|
198
|
+
|--------|---------|---------|
|
|
199
|
+
| `current` | Latest stable | Full support |
|
|
200
|
+
| `deprecated` | Being phased out | 6-12 months |
|
|
201
|
+
| `sunset` | Removal scheduled | Returns 410 Gone |
|
|
202
|
+
|
|
203
|
+
### Breaking vs Non-Breaking Changes
|
|
204
|
+
|
|
205
|
+
| Non-Breaking (OK) | Breaking (New Version) |
|
|
206
|
+
|-------------------|------------------------|
|
|
207
|
+
| Add optional field | Remove field |
|
|
208
|
+
| Add new endpoint | Change field type |
|
|
209
|
+
| Add optional param | Rename field |
|
|
210
|
+
| Expand enum values | Change URL structure |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Authentication & Authorization
|
|
215
|
+
|
|
216
|
+
### Auth Methods
|
|
217
|
+
|
|
218
|
+
| Method | Use For | Header |
|
|
219
|
+
|--------|---------|--------|
|
|
220
|
+
| Bearer Token (JWT) | User sessions, mobile | `Authorization: Bearer <token>` |
|
|
221
|
+
| API Key | Service-to-service, public APIs | `X-API-Key: <key>` |
|
|
222
|
+
| OAuth 2.0 | Third-party integrations | OAuth flow |
|
|
223
|
+
| mTLS | High-security service mesh | Certificate |
|
|
224
|
+
|
|
225
|
+
### Authorization Patterns
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
# Resource-based
|
|
229
|
+
GET /tasks/{id} # Check: user can read task
|
|
230
|
+
|
|
231
|
+
# Scope-based (OAuth)
|
|
232
|
+
Authorization: Bearer <token>
|
|
233
|
+
# Token has scopes: ["tasks:read", "tasks:write"]
|
|
234
|
+
|
|
235
|
+
# Role-based
|
|
236
|
+
# Admin: all operations
|
|
237
|
+
# User: own tasks only
|
|
238
|
+
# Viewer: read-only
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## GraphQL Design
|
|
244
|
+
|
|
245
|
+
### Schema Structure
|
|
246
|
+
|
|
247
|
+
```graphql
|
|
248
|
+
type Query {
|
|
249
|
+
task(id: ID!): Task
|
|
250
|
+
tasks(filter: TaskFilter, pagination: Pagination): TaskConnection!
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
type Mutation {
|
|
254
|
+
createTask(input: CreateTaskInput!): TaskPayload!
|
|
255
|
+
updateTask(id: ID!, input: UpdateTaskInput!): TaskPayload!
|
|
256
|
+
deleteTask(id: ID!): DeletePayload!
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
type Subscription {
|
|
260
|
+
taskUpdated(projectId: ID!): Task!
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
type Task {
|
|
264
|
+
id: ID!
|
|
265
|
+
title: String!
|
|
266
|
+
status: TaskStatus!
|
|
267
|
+
assignee: User
|
|
268
|
+
project: Project!
|
|
269
|
+
createdAt: DateTime!
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
input CreateTaskInput {
|
|
273
|
+
title: String!
|
|
274
|
+
projectId: ID!
|
|
275
|
+
assigneeId: ID
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
type TaskPayload {
|
|
279
|
+
task: Task
|
|
280
|
+
errors: [UserError!]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
type UserError {
|
|
284
|
+
field: String
|
|
285
|
+
message: String!
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### GraphQL Best Practices
|
|
290
|
+
|
|
291
|
+
| Practice | Example |
|
|
292
|
+
|----------|---------|
|
|
293
|
+
| Nullable by default | `assignee: User` (nullable) |
|
|
294
|
+
| Non-null when guaranteed | `id: ID!`, `createdAt: DateTime!` |
|
|
295
|
+
| Input types for mutations | `input CreateTaskInput` |
|
|
296
|
+
| Payload types with errors | `TaskPayload { task, errors }` |
|
|
297
|
+
| Connection pattern for lists | `TaskConnection { edges, pageInfo }` |
|
|
298
|
+
| Use enums | `enum TaskStatus { TODO, IN_PROGRESS, DONE }` |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## gRPC Design
|
|
303
|
+
|
|
304
|
+
### Proto File Structure
|
|
305
|
+
|
|
306
|
+
```protobuf
|
|
307
|
+
syntax = "proto3";
|
|
308
|
+
|
|
309
|
+
package tasks.v1;
|
|
310
|
+
|
|
311
|
+
option go_package = "github.com/org/project/gen/tasks/v1";
|
|
312
|
+
|
|
313
|
+
service TaskService {
|
|
314
|
+
rpc GetTask(GetTaskRequest) returns (Task);
|
|
315
|
+
rpc ListTasks(ListTasksRequest) returns (ListTasksResponse);
|
|
316
|
+
rpc CreateTask(CreateTaskRequest) returns (Task);
|
|
317
|
+
rpc UpdateTask(UpdateTaskRequest) returns (Task);
|
|
318
|
+
rpc DeleteTask(DeleteTaskRequest) returns (google.protobuf.Empty);
|
|
319
|
+
|
|
320
|
+
// Streaming
|
|
321
|
+
rpc WatchTasks(WatchTasksRequest) returns (stream Task);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
message Task {
|
|
325
|
+
string id = 1;
|
|
326
|
+
string title = 2;
|
|
327
|
+
TaskStatus status = 3;
|
|
328
|
+
optional string assignee_id = 4;
|
|
329
|
+
google.protobuf.Timestamp created_at = 5;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
enum TaskStatus {
|
|
333
|
+
TASK_STATUS_UNSPECIFIED = 0;
|
|
334
|
+
TASK_STATUS_TODO = 1;
|
|
335
|
+
TASK_STATUS_IN_PROGRESS = 2;
|
|
336
|
+
TASK_STATUS_DONE = 3;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
message ListTasksRequest {
|
|
340
|
+
int32 page_size = 1;
|
|
341
|
+
string page_token = 2;
|
|
342
|
+
string filter = 3; // CEL expression
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
message ListTasksResponse {
|
|
346
|
+
repeated Task tasks = 1;
|
|
347
|
+
string next_page_token = 2;
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### gRPC Best Practices
|
|
352
|
+
|
|
353
|
+
| Practice | Why |
|
|
354
|
+
|----------|-----|
|
|
355
|
+
| Prefix enums with type name | Avoid conflicts: `TASK_STATUS_TODO` |
|
|
356
|
+
| Use `UNSPECIFIED = 0` | Default value detection |
|
|
357
|
+
| Use `optional` for nullable | Distinguish null vs default |
|
|
358
|
+
| Package versioning | `package tasks.v1` |
|
|
359
|
+
| Pagination with tokens | Stateless, efficient |
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## OpenAPI Specification
|
|
364
|
+
|
|
365
|
+
### Minimal Example
|
|
366
|
+
|
|
367
|
+
```yaml
|
|
368
|
+
openapi: 3.1.0
|
|
369
|
+
info:
|
|
370
|
+
title: Tasks API
|
|
371
|
+
version: 1.0.0
|
|
372
|
+
|
|
373
|
+
servers:
|
|
374
|
+
- url: https://api.example.com/v1
|
|
375
|
+
|
|
376
|
+
paths:
|
|
377
|
+
/tasks:
|
|
378
|
+
get:
|
|
379
|
+
summary: List tasks
|
|
380
|
+
operationId: listTasks
|
|
381
|
+
tags: [Tasks]
|
|
382
|
+
parameters:
|
|
383
|
+
- name: status
|
|
384
|
+
in: query
|
|
385
|
+
schema:
|
|
386
|
+
$ref: '#/components/schemas/TaskStatus'
|
|
387
|
+
- name: limit
|
|
388
|
+
in: query
|
|
389
|
+
schema:
|
|
390
|
+
type: integer
|
|
391
|
+
default: 20
|
|
392
|
+
maximum: 100
|
|
393
|
+
responses:
|
|
394
|
+
'200':
|
|
395
|
+
description: Success
|
|
396
|
+
content:
|
|
397
|
+
application/json:
|
|
398
|
+
schema:
|
|
399
|
+
$ref: '#/components/schemas/TaskList'
|
|
400
|
+
post:
|
|
401
|
+
summary: Create task
|
|
402
|
+
operationId: createTask
|
|
403
|
+
tags: [Tasks]
|
|
404
|
+
requestBody:
|
|
405
|
+
required: true
|
|
406
|
+
content:
|
|
407
|
+
application/json:
|
|
408
|
+
schema:
|
|
409
|
+
$ref: '#/components/schemas/CreateTaskRequest'
|
|
410
|
+
responses:
|
|
411
|
+
'201':
|
|
412
|
+
description: Created
|
|
413
|
+
content:
|
|
414
|
+
application/json:
|
|
415
|
+
schema:
|
|
416
|
+
$ref: '#/components/schemas/Task'
|
|
417
|
+
'422':
|
|
418
|
+
$ref: '#/components/responses/ValidationError'
|
|
419
|
+
|
|
420
|
+
components:
|
|
421
|
+
schemas:
|
|
422
|
+
Task:
|
|
423
|
+
type: object
|
|
424
|
+
required: [id, title, status, createdAt]
|
|
425
|
+
properties:
|
|
426
|
+
id:
|
|
427
|
+
type: string
|
|
428
|
+
format: uuid
|
|
429
|
+
title:
|
|
430
|
+
type: string
|
|
431
|
+
maxLength: 255
|
|
432
|
+
status:
|
|
433
|
+
$ref: '#/components/schemas/TaskStatus'
|
|
434
|
+
createdAt:
|
|
435
|
+
type: string
|
|
436
|
+
format: date-time
|
|
437
|
+
|
|
438
|
+
TaskStatus:
|
|
439
|
+
type: string
|
|
440
|
+
enum: [todo, in_progress, done]
|
|
441
|
+
|
|
442
|
+
CreateTaskRequest:
|
|
443
|
+
type: object
|
|
444
|
+
required: [title]
|
|
445
|
+
properties:
|
|
446
|
+
title:
|
|
447
|
+
type: string
|
|
448
|
+
minLength: 1
|
|
449
|
+
maxLength: 255
|
|
450
|
+
assigneeId:
|
|
451
|
+
type: string
|
|
452
|
+
format: uuid
|
|
453
|
+
|
|
454
|
+
responses:
|
|
455
|
+
ValidationError:
|
|
456
|
+
description: Validation failed
|
|
457
|
+
content:
|
|
458
|
+
application/json:
|
|
459
|
+
schema:
|
|
460
|
+
$ref: '#/components/schemas/Error'
|
|
461
|
+
|
|
462
|
+
securitySchemes:
|
|
463
|
+
bearerAuth:
|
|
464
|
+
type: http
|
|
465
|
+
scheme: bearer
|
|
466
|
+
bearerFormat: JWT
|
|
467
|
+
|
|
468
|
+
security:
|
|
469
|
+
- bearerAuth: []
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Rate Limiting
|
|
475
|
+
|
|
476
|
+
### Headers
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
X-RateLimit-Limit: 1000
|
|
480
|
+
X-RateLimit-Remaining: 999
|
|
481
|
+
X-RateLimit-Reset: 1640000000
|
|
482
|
+
Retry-After: 60
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Response (429)
|
|
486
|
+
|
|
487
|
+
```json
|
|
488
|
+
{
|
|
489
|
+
"error": {
|
|
490
|
+
"code": "RATE_LIMITED",
|
|
491
|
+
"message": "Too many requests",
|
|
492
|
+
"retry_after": 60
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## Validation Checklist
|
|
500
|
+
|
|
501
|
+
Before completing API design:
|
|
502
|
+
|
|
503
|
+
- [ ] URLs follow RESTful conventions
|
|
504
|
+
- [ ] HTTP methods used correctly
|
|
505
|
+
- [ ] Status codes are appropriate
|
|
506
|
+
- [ ] Error responses are consistent
|
|
507
|
+
- [ ] Pagination implemented (cursor preferred)
|
|
508
|
+
- [ ] Versioning strategy defined
|
|
509
|
+
- [ ] Authentication documented
|
|
510
|
+
- [ ] Rate limiting defined
|
|
511
|
+
- [ ] OpenAPI spec complete
|
|
512
|
+
- [ ] Examples for all endpoints
|
|
513
|
+
- [ ] Breaking changes identified
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Output
|
|
518
|
+
|
|
519
|
+
- OpenAPI: `docs/architecture/{module}/api/{resource}.yaml`
|
|
520
|
+
- GraphQL: `docs/architecture/{module}/api/schema.graphql`
|
|
521
|
+
- gRPC: `proto/{service}/v1/{service}.proto`
|
|
522
|
+
|
|
523
|
+
## Related Skills
|
|
524
|
+
|
|
525
|
+
- `architecture-design` — API is part of architecture
|
|
526
|
+
- `unit-writing` — API specs in api/ folder
|
|
527
|
+
- `adr-writing` — Document API decisions
|