red64-cli 0.1.0 → 0.2.0

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.
Files changed (103) hide show
  1. package/dist/cli/parseArgs.d.ts.map +1 -1
  2. package/dist/cli/parseArgs.js +5 -0
  3. package/dist/cli/parseArgs.js.map +1 -1
  4. package/dist/components/init/CompleteStep.d.ts.map +1 -1
  5. package/dist/components/init/CompleteStep.js +2 -2
  6. package/dist/components/init/CompleteStep.js.map +1 -1
  7. package/dist/components/init/TestCheckStep.d.ts +16 -0
  8. package/dist/components/init/TestCheckStep.d.ts.map +1 -0
  9. package/dist/components/init/TestCheckStep.js +120 -0
  10. package/dist/components/init/TestCheckStep.js.map +1 -0
  11. package/dist/components/init/index.d.ts +1 -0
  12. package/dist/components/init/index.d.ts.map +1 -1
  13. package/dist/components/init/index.js +1 -0
  14. package/dist/components/init/index.js.map +1 -1
  15. package/dist/components/init/types.d.ts +9 -0
  16. package/dist/components/init/types.d.ts.map +1 -1
  17. package/dist/components/screens/InitScreen.d.ts.map +1 -1
  18. package/dist/components/screens/InitScreen.js +69 -6
  19. package/dist/components/screens/InitScreen.js.map +1 -1
  20. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  21. package/dist/components/screens/StartScreen.js +89 -3
  22. package/dist/components/screens/StartScreen.js.map +1 -1
  23. package/dist/services/ConfigService.d.ts +1 -0
  24. package/dist/services/ConfigService.d.ts.map +1 -1
  25. package/dist/services/ConfigService.js.map +1 -1
  26. package/dist/services/ProjectDetector.d.ts +28 -0
  27. package/dist/services/ProjectDetector.d.ts.map +1 -0
  28. package/dist/services/ProjectDetector.js +236 -0
  29. package/dist/services/ProjectDetector.js.map +1 -0
  30. package/dist/services/TestRunner.d.ts +46 -0
  31. package/dist/services/TestRunner.d.ts.map +1 -0
  32. package/dist/services/TestRunner.js +85 -0
  33. package/dist/services/TestRunner.js.map +1 -0
  34. package/dist/services/index.d.ts +2 -0
  35. package/dist/services/index.d.ts.map +1 -1
  36. package/dist/services/index.js +2 -0
  37. package/dist/services/index.js.map +1 -1
  38. package/dist/types/index.d.ts +1 -0
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/index.js.map +1 -1
  41. package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
  42. package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
  43. package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
  44. package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
  45. package/framework/stacks/generic/feedback.md +80 -0
  46. package/framework/stacks/nextjs/accessibility.md +437 -0
  47. package/framework/stacks/nextjs/api.md +431 -0
  48. package/framework/stacks/nextjs/coding-style.md +282 -0
  49. package/framework/stacks/nextjs/commenting.md +226 -0
  50. package/framework/stacks/nextjs/components.md +411 -0
  51. package/framework/stacks/nextjs/conventions.md +333 -0
  52. package/framework/stacks/nextjs/css.md +310 -0
  53. package/framework/stacks/nextjs/error-handling.md +442 -0
  54. package/framework/stacks/nextjs/feedback.md +124 -0
  55. package/framework/stacks/nextjs/migrations.md +332 -0
  56. package/framework/stacks/nextjs/models.md +362 -0
  57. package/framework/stacks/nextjs/queries.md +410 -0
  58. package/framework/stacks/nextjs/responsive.md +338 -0
  59. package/framework/stacks/nextjs/tech-stack.md +177 -0
  60. package/framework/stacks/nextjs/test-writing.md +475 -0
  61. package/framework/stacks/nextjs/validation.md +467 -0
  62. package/framework/stacks/python/api.md +468 -0
  63. package/framework/stacks/python/authentication.md +342 -0
  64. package/framework/stacks/python/code-quality.md +283 -0
  65. package/framework/stacks/python/code-refactoring.md +315 -0
  66. package/framework/stacks/python/coding-style.md +462 -0
  67. package/framework/stacks/python/conventions.md +399 -0
  68. package/framework/stacks/python/error-handling.md +512 -0
  69. package/framework/stacks/python/feedback.md +92 -0
  70. package/framework/stacks/python/implement-ai-llm.md +468 -0
  71. package/framework/stacks/python/migrations.md +388 -0
  72. package/framework/stacks/python/models.md +399 -0
  73. package/framework/stacks/python/python.md +232 -0
  74. package/framework/stacks/python/queries.md +451 -0
  75. package/framework/stacks/python/structure.md +245 -58
  76. package/framework/stacks/python/tech.md +92 -35
  77. package/framework/stacks/python/testing.md +380 -0
  78. package/framework/stacks/python/validation.md +471 -0
  79. package/framework/stacks/rails/authentication.md +176 -0
  80. package/framework/stacks/rails/code-quality.md +287 -0
  81. package/framework/stacks/rails/code-refactoring.md +299 -0
  82. package/framework/stacks/rails/feedback.md +130 -0
  83. package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
  84. package/framework/stacks/rails/rails.md +301 -0
  85. package/framework/stacks/rails/rails8-best-practices.md +498 -0
  86. package/framework/stacks/rails/rails8-css.md +573 -0
  87. package/framework/stacks/rails/structure.md +140 -0
  88. package/framework/stacks/rails/tech.md +108 -0
  89. package/framework/stacks/react/code-quality.md +521 -0
  90. package/framework/stacks/react/components.md +625 -0
  91. package/framework/stacks/react/data-fetching.md +586 -0
  92. package/framework/stacks/react/feedback.md +110 -0
  93. package/framework/stacks/react/forms.md +694 -0
  94. package/framework/stacks/react/performance.md +640 -0
  95. package/framework/stacks/react/product.md +22 -9
  96. package/framework/stacks/react/state-management.md +472 -0
  97. package/framework/stacks/react/structure.md +351 -44
  98. package/framework/stacks/react/tech.md +219 -30
  99. package/framework/stacks/react/testing.md +690 -0
  100. package/package.json +1 -1
  101. package/framework/stacks/node/product.md +0 -27
  102. package/framework/stacks/node/structure.md +0 -82
  103. package/framework/stacks/node/tech.md +0 -63
@@ -0,0 +1,468 @@
1
+ # API Design Standards
2
+
3
+ RESTful API conventions for FastAPI applications with consistent patterns for routing, responses, and documentation.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Resource-oriented**: URLs represent resources, HTTP methods represent actions
10
+ - **Consistent responses**: Every endpoint follows the same response envelope
11
+ - **Self-documenting**: OpenAPI spec generated from code, not maintained separately
12
+ - **Dependency injection**: Auth, DB, and shared logic injected via FastAPI dependencies
13
+
14
+ ---
15
+
16
+ ## RESTful Conventions
17
+
18
+ ### URL Structure
19
+
20
+ ```
21
+ /api/v1/{resource} # Collection
22
+ /api/v1/{resource}/{id} # Single resource
23
+ /api/v1/{resource}/{id}/{sub} # Nested resource (max 2 levels)
24
+ ```
25
+
26
+ ### HTTP Methods
27
+
28
+ | Method | URL | Action | Status Code |
29
+ |---|---|---|---|
30
+ | `GET` | `/users` | List users | 200 |
31
+ | `GET` | `/users/42` | Get single user | 200 |
32
+ | `POST` | `/users` | Create user | 201 |
33
+ | `PUT` | `/users/42` | Full replace | 200 |
34
+ | `PATCH` | `/users/42` | Partial update | 200 |
35
+ | `DELETE` | `/users/42` | Delete user | 204 |
36
+
37
+ ### Naming Rules
38
+
39
+ - Plural nouns for resources: `/users`, `/posts`, `/comments`
40
+ - Lowercase with hyphens for multi-word: `/user-profiles`, `/api-keys`
41
+ - No verbs in URLs (use HTTP methods instead)
42
+ - No trailing slashes
43
+
44
+ ```python
45
+ # GOOD
46
+ GET /api/v1/users
47
+ POST /api/v1/users
48
+ GET /api/v1/users/42/posts
49
+
50
+ # BAD
51
+ GET /api/v1/getUsers
52
+ POST /api/v1/createUser
53
+ GET /api/v1/user/42/getAllPosts
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Router Organization
59
+
60
+ ### Feature-Based Routers
61
+
62
+ ```python
63
+ # app/api/__init__.py
64
+ from fastapi import APIRouter
65
+ from app.api import users, posts, auth, health
66
+
67
+ api_router = APIRouter(prefix="/api/v1")
68
+ api_router.include_router(auth.router, prefix="/auth", tags=["Authentication"])
69
+ api_router.include_router(users.router, prefix="/users", tags=["Users"])
70
+ api_router.include_router(posts.router, prefix="/posts", tags=["Posts"])
71
+ api_router.include_router(health.router, prefix="/health", tags=["Health"])
72
+ ```
73
+
74
+ ### Single Resource Router
75
+
76
+ ```python
77
+ # app/api/users.py
78
+ from fastapi import APIRouter, Depends, status
79
+ from app.dependencies import get_db, get_current_user
80
+
81
+ router = APIRouter()
82
+
83
+
84
+ @router.get("", response_model=PaginatedResponse[UserResponse])
85
+ async def list_users(
86
+ page: int = Query(default=1, ge=1),
87
+ per_page: int = Query(default=20, ge=1, le=100),
88
+ db: AsyncSession = Depends(get_db),
89
+ current_user: User = Depends(get_current_user),
90
+ ):
91
+ ...
92
+
93
+
94
+ @router.get("/{user_id}", response_model=UserResponse)
95
+ async def get_user(
96
+ user_id: int = Path(ge=1),
97
+ db: AsyncSession = Depends(get_db),
98
+ ):
99
+ ...
100
+
101
+
102
+ @router.post("", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
103
+ async def create_user(
104
+ data: CreateUserRequest,
105
+ db: AsyncSession = Depends(get_db),
106
+ ):
107
+ ...
108
+
109
+
110
+ @router.patch("/{user_id}", response_model=UserResponse)
111
+ async def update_user(
112
+ user_id: int = Path(ge=1),
113
+ data: UpdateUserRequest,
114
+ db: AsyncSession = Depends(get_db),
115
+ current_user: User = Depends(get_current_user),
116
+ ):
117
+ ...
118
+
119
+
120
+ @router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
121
+ async def delete_user(
122
+ user_id: int = Path(ge=1),
123
+ db: AsyncSession = Depends(get_db),
124
+ current_user: User = Depends(get_current_user),
125
+ ):
126
+ ...
127
+ ```
128
+
129
+ ---
130
+
131
+ ## API Versioning
132
+
133
+ ### URL Path Versioning (Recommended)
134
+
135
+ ```python
136
+ # app/main.py
137
+ from app.api import api_router # /api/v1/...
138
+
139
+ app = FastAPI(title="My API", version="1.0.0")
140
+ app.include_router(api_router)
141
+
142
+ # When v2 is needed:
143
+ # from app.api_v2 import api_router_v2 # /api/v2/...
144
+ # app.include_router(api_router_v2)
145
+ ```
146
+
147
+ ### Versioning Strategy
148
+
149
+ | Approach | Pros | Cons |
150
+ |---|---|---|
151
+ | URL path (`/api/v1/`) | Explicit, easy to route | URL changes on version bump |
152
+ | Header (`Accept-Version: 1`) | Clean URLs | Harder to test, less discoverable |
153
+ | Query param (`?version=1`) | Simple | Clutters query string |
154
+
155
+ **Decision**: Use URL path versioning. It is explicit and works with every HTTP client and caching layer.
156
+
157
+ ---
158
+
159
+ ## Pagination
160
+
161
+ ### Cursor-Based (Default for Lists)
162
+
163
+ ```python
164
+ from pydantic import BaseModel
165
+
166
+
167
+ class PaginatedResponse(BaseModel, Generic[T]):
168
+ items: list[T]
169
+ has_next: bool
170
+ next_cursor: str | None = None
171
+
172
+
173
+ @router.get("/posts", response_model=PaginatedResponse[PostResponse])
174
+ async def list_posts(
175
+ cursor: str | None = Query(default=None, description="Pagination cursor"),
176
+ limit: int = Query(default=20, ge=1, le=100),
177
+ db: AsyncSession = Depends(get_db),
178
+ ):
179
+ posts, has_next, next_cursor = await post_service.list_posts(
180
+ cursor=cursor, limit=limit,
181
+ )
182
+ return PaginatedResponse(
183
+ items=[PostResponse.model_validate(p) for p in posts],
184
+ has_next=has_next,
185
+ next_cursor=next_cursor,
186
+ )
187
+ ```
188
+
189
+ ### Offset-Based (Simple Admin UIs)
190
+
191
+ ```python
192
+ class PagedResponse(BaseModel, Generic[T]):
193
+ items: list[T]
194
+ total: int
195
+ page: int
196
+ per_page: int
197
+ total_pages: int
198
+
199
+
200
+ @router.get("/admin/users", response_model=PagedResponse[UserResponse])
201
+ async def list_users_admin(
202
+ page: int = Query(default=1, ge=1),
203
+ per_page: int = Query(default=20, ge=1, le=100),
204
+ db: AsyncSession = Depends(get_db),
205
+ ):
206
+ users, total = await user_service.list_users_paged(page=page, per_page=per_page)
207
+ return PagedResponse(
208
+ items=[UserResponse.model_validate(u) for u in users],
209
+ total=total,
210
+ page=page,
211
+ per_page=per_page,
212
+ total_pages=(total + per_page - 1) // per_page,
213
+ )
214
+ ```
215
+
216
+ ### When to Use Each
217
+
218
+ | Type | Use Case |
219
+ |---|---|
220
+ | Cursor-based | Public APIs, infinite scroll, real-time data |
221
+ | Offset-based | Admin panels, dashboards, static lists |
222
+
223
+ ---
224
+
225
+ ## Filtering and Sorting
226
+
227
+ ### Query Parameter Patterns
228
+
229
+ ```python
230
+ @router.get("/posts", response_model=PaginatedResponse[PostResponse])
231
+ async def list_posts(
232
+ status: str | None = Query(default=None, pattern="^(draft|published|archived)$"),
233
+ author_id: int | None = Query(default=None, ge=1),
234
+ search: str | None = Query(default=None, min_length=1, max_length=200),
235
+ sort: str = Query(default="-created_at", pattern="^-?(created_at|title|updated_at)$"),
236
+ cursor: str | None = Query(default=None),
237
+ limit: int = Query(default=20, ge=1, le=100),
238
+ db: AsyncSession = Depends(get_db),
239
+ ):
240
+ ...
241
+ ```
242
+
243
+ ### Sort Convention
244
+
245
+ - Prefix with `-` for descending: `-created_at`
246
+ - No prefix for ascending: `title`
247
+ - Validate against allowed fields to prevent SQL injection
248
+
249
+ ---
250
+
251
+ ## HTTP Status Codes
252
+
253
+ ### Standard Responses
254
+
255
+ | Code | Meaning | When to Use |
256
+ |---|---|---|
257
+ | `200` | OK | Successful GET, PUT, PATCH |
258
+ | `201` | Created | Successful POST that creates a resource |
259
+ | `204` | No Content | Successful DELETE |
260
+ | `400` | Bad Request | Malformed request syntax |
261
+ | `401` | Unauthorized | Missing or invalid authentication |
262
+ | `403` | Forbidden | Authenticated but insufficient permissions |
263
+ | `404` | Not Found | Resource does not exist |
264
+ | `409` | Conflict | Duplicate resource, state conflict |
265
+ | `422` | Unprocessable Entity | Validation errors (Pydantic default) |
266
+ | `429` | Too Many Requests | Rate limit exceeded |
267
+ | `500` | Internal Server Error | Unhandled server error |
268
+ | `502` | Bad Gateway | External service failure |
269
+
270
+ ---
271
+
272
+ ## Response Envelope
273
+
274
+ ### Success Response
275
+
276
+ ```json
277
+ {
278
+ "id": 42,
279
+ "email": "user@example.com",
280
+ "name": "Jane Doe",
281
+ "created_at": "2024-01-15T10:30:00Z"
282
+ }
283
+ ```
284
+
285
+ For single resources, return the object directly (no wrapping). FastAPI + Pydantic handles serialization.
286
+
287
+ ### Collection Response
288
+
289
+ ```json
290
+ {
291
+ "items": [...],
292
+ "has_next": true,
293
+ "next_cursor": "eyJpZCI6IDQyfQ=="
294
+ }
295
+ ```
296
+
297
+ ### Error Response
298
+
299
+ ```json
300
+ {
301
+ "error": {
302
+ "code": "NOT_FOUND",
303
+ "message": "User not found: 42",
304
+ "details": {"resource": "User", "identifier": "42"}
305
+ }
306
+ }
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Rate Limiting
312
+
313
+ ### Per-Endpoint Limits
314
+
315
+ ```python
316
+ from slowapi import Limiter
317
+ from slowapi.util import get_remote_address
318
+
319
+ limiter = Limiter(key_func=get_remote_address)
320
+
321
+ @router.post("/auth/login")
322
+ @limiter.limit("5/minute")
323
+ async def login(request: Request, data: LoginRequest):
324
+ ...
325
+
326
+ @router.get("/search")
327
+ @limiter.limit("30/minute")
328
+ async def search(request: Request, q: str = Query(...)):
329
+ ...
330
+ ```
331
+
332
+ ### Rate Limit Headers
333
+
334
+ Include in responses so clients can self-regulate:
335
+
336
+ ```
337
+ X-RateLimit-Limit: 30
338
+ X-RateLimit-Remaining: 28
339
+ X-RateLimit-Reset: 1705312800
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Dependency Injection
345
+
346
+ ### Common Dependencies
347
+
348
+ ```python
349
+ # app/dependencies.py
350
+ from collections.abc import AsyncIterator
351
+ from fastapi import Depends
352
+ from sqlalchemy.ext.asyncio import AsyncSession
353
+
354
+
355
+ async def get_db() -> AsyncIterator[AsyncSession]:
356
+ async with async_session() as session:
357
+ yield session
358
+
359
+
360
+ async def get_current_user(
361
+ token: str = Depends(oauth2_scheme),
362
+ db: AsyncSession = Depends(get_db),
363
+ ) -> User:
364
+ ...
365
+
366
+
367
+ def require_role(*roles: str):
368
+ async def dependency(user: User = Depends(get_current_user)) -> User:
369
+ if user.role not in roles:
370
+ raise HTTPException(status_code=403)
371
+ return user
372
+ return dependency
373
+ ```
374
+
375
+ ### Service Injection Pattern
376
+
377
+ ```python
378
+ async def get_user_service(db: AsyncSession = Depends(get_db)) -> UserService:
379
+ return UserService(repo=UserRepo(db))
380
+
381
+
382
+ @router.post("", status_code=201)
383
+ async def create_user(
384
+ data: CreateUserRequest,
385
+ service: UserService = Depends(get_user_service),
386
+ ) -> UserResponse:
387
+ user = await service.create_user(data)
388
+ return UserResponse.model_validate(user)
389
+ ```
390
+
391
+ ---
392
+
393
+ ## OpenAPI Documentation
394
+
395
+ ### Customize FastAPI Docs
396
+
397
+ ```python
398
+ app = FastAPI(
399
+ title="My API",
400
+ version="1.0.0",
401
+ description="API for managing users and content",
402
+ docs_url="/docs", # Swagger UI
403
+ redoc_url="/redoc", # ReDoc
404
+ openapi_url="/openapi.json",
405
+ )
406
+ ```
407
+
408
+ ### Document Endpoint Responses
409
+
410
+ ```python
411
+ @router.get(
412
+ "/{user_id}",
413
+ response_model=UserResponse,
414
+ summary="Get user by ID",
415
+ description="Retrieve a single user by their unique identifier.",
416
+ responses={
417
+ 404: {"model": ErrorResponse, "description": "User not found"},
418
+ 401: {"model": ErrorResponse, "description": "Not authenticated"},
419
+ },
420
+ )
421
+ async def get_user(user_id: int = Path(ge=1)) -> UserResponse:
422
+ ...
423
+ ```
424
+
425
+ ---
426
+
427
+ ## Health Check
428
+
429
+ ```python
430
+ # app/api/health.py
431
+ from fastapi import APIRouter
432
+
433
+ router = APIRouter()
434
+
435
+
436
+ @router.get("")
437
+ async def health():
438
+ return {"status": "ok"}
439
+
440
+
441
+ @router.get("/ready")
442
+ async def readiness(db: AsyncSession = Depends(get_db)):
443
+ try:
444
+ await db.execute(text("SELECT 1"))
445
+ return {"status": "ready", "database": "connected"}
446
+ except Exception:
447
+ return JSONResponse(
448
+ status_code=503,
449
+ content={"status": "not_ready", "database": "disconnected"},
450
+ )
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Anti-Patterns
456
+
457
+ | Anti-Pattern | Problem | Correct Approach |
458
+ |---|---|---|
459
+ | Verbs in URLs | Not RESTful | Use HTTP methods |
460
+ | Inconsistent status codes | Confusing for clients | Follow the table above |
461
+ | No pagination | Unbounded responses | Always paginate collections |
462
+ | Business logic in routes | Hard to test | Inject services via dependencies |
463
+ | No API versioning | Breaking changes break clients | Version from day one |
464
+ | Returning `dict` | No validation, no docs | Use Pydantic response models |
465
+
466
+ ---
467
+
468
+ _APIs are contracts. Be consistent, be explicit, and let the framework generate documentation from your code._