vibes-plug 1.0.0 → 2.11.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 (183) hide show
  1. package/.claude/rules/vibes-plug-core.md +32 -0
  2. package/.cursor/rules/vibes-plug-core.mdc +51 -0
  3. package/.cursorrules +42 -0
  4. package/AGENTS.md +96 -0
  5. package/BLUEPRINT.md +309 -125
  6. package/CHANGELOG.md +183 -1
  7. package/CLAUDE.md +70 -0
  8. package/LICENSE +1 -1
  9. package/README.md +641 -263
  10. package/index.js +19 -0
  11. package/package.json +61 -25
  12. package/plugin.json +24 -7
  13. package/scripts/generate_swarm_gif.py +295 -0
  14. package/scripts/install.js +201 -0
  15. package/skills/accessibility-testing-expert/SKILL.md +116 -0
  16. package/skills/ai-cost-token-optimizer/SKILL.md +82 -0
  17. package/skills/ai-evals-benchmark-expert/SKILL.md +188 -0
  18. package/skills/ai-llm-integration-expert/SKILL.md +147 -122
  19. package/skills/ai-media-generation-expert/SKILL.md +172 -0
  20. package/skills/ai-prompt-engineering-expert/SKILL.md +84 -0
  21. package/skills/angular-expert/SKILL.md +148 -0
  22. package/skills/api-design-expert/SKILL.md +316 -309
  23. package/skills/api-gateway-proxy-expert/SKILL.md +81 -0
  24. package/skills/app-analyzer-optimizer/SKILL.md +195 -188
  25. package/skills/apple-ecosystem-expert/SKILL.md +145 -0
  26. package/skills/{asisten_ramah → asisten-ramah}/SKILL.md +7 -1
  27. package/skills/astro-framework-expert/SKILL.md +200 -0
  28. package/skills/async-queue-temporal-expert/SKILL.md +240 -0
  29. package/skills/authentication-identity-expert/SKILL.md +279 -45
  30. package/skills/auto-doc-updater/SKILL.md +219 -203
  31. package/skills/autonomous-chaos-monkey/SKILL.md +63 -0
  32. package/skills/autonomous-red-teamer/SKILL.md +203 -0
  33. package/skills/autonomous-tdd-debugger/SKILL.md +71 -0
  34. package/skills/background-jobs-queue-expert/SKILL.md +235 -0
  35. package/skills/biome-linter-formatter-expert/SKILL.md +89 -0
  36. package/skills/blockchain-web3-expert/SKILL.md +115 -0
  37. package/skills/bootstrap-to-modern/SKILL.md +93 -86
  38. package/skills/brainstorming/SKILL.md +381 -353
  39. package/skills/browser-automation-expert/SKILL.md +222 -0
  40. package/skills/bun-runtime-expert/SKILL.md +7 -1
  41. package/skills/chatbot-messaging-expert/SKILL.md +114 -0
  42. package/skills/ci-cd-devops-architect/SKILL.md +81 -45
  43. package/skills/cloud-hosting-expert/SKILL.md +249 -243
  44. package/skills/coderabbit/SKILL.md +197 -191
  45. package/skills/compliance-gdpr-privacy-expert/SKILL.md +85 -0
  46. package/skills/cron-scheduler-expert/SKILL.md +304 -0
  47. package/skills/data-pipeline-etl-expert/SKILL.md +84 -0
  48. package/skills/data-telemetry-expert/SKILL.md +218 -212
  49. package/skills/data-visualization-expert/SKILL.md +154 -0
  50. package/skills/database-migration-versioning-expert/SKILL.md +90 -0
  51. package/skills/database-orm-expert/SKILL.md +303 -293
  52. package/skills/dependency-upgrade-migrator/SKILL.md +301 -0
  53. package/skills/design-system-architect/SKILL.md +278 -242
  54. package/skills/desktop-electron-expert/SKILL.md +128 -0
  55. package/skills/documentation-site-expert/SKILL.md +59 -0
  56. package/skills/doku-mcp-server/SKILL.md +257 -0
  57. package/skills/doku-payment-gateway/SKILL.md +233 -0
  58. package/skills/domain-driven-design-expert/SKILL.md +82 -0
  59. package/skills/e2e-testing-expert/SKILL.md +320 -314
  60. package/skills/ecommerce-expert/SKILL.md +87 -0
  61. package/skills/edge-serverless-db-expert/SKILL.md +99 -0
  62. package/skills/email-notification-expert/SKILL.md +368 -0
  63. package/skills/error-resilience-expert/SKILL.md +486 -0
  64. package/skills/event-driven-architect/SKILL.md +86 -80
  65. package/skills/feature-flag-analytics-expert/SKILL.md +66 -0
  66. package/skills/file-upload-media-expert/SKILL.md +437 -0
  67. package/skills/firebase-security-expert/SKILL.md +7 -1
  68. package/skills/form-validation-expert/SKILL.md +407 -0
  69. package/skills/fullstack-expert/SKILL.md +260 -201
  70. package/skills/fullstack-expert/references/api_design_guide.md +466 -466
  71. package/skills/fullstack-expert/references/multi_language_backend.md +528 -528
  72. package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -253
  73. package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -326
  74. package/skills/gemini-agent-booster/SKILL.md +142 -104
  75. package/skills/geospatial-maps-expert/SKILL.md +80 -0
  76. package/skills/global-a11y-i18n-expert/SKILL.md +86 -80
  77. package/skills/glsl-shader-expert/SKILL.md +107 -0
  78. package/skills/go-programming-expert/SKILL.md +300 -294
  79. package/skills/graph-rag-knowledge-expert/SKILL.md +159 -0
  80. package/skills/graphql-apollo-expert/SKILL.md +114 -0
  81. package/skills/headless-cms-expert/SKILL.md +181 -0
  82. package/skills/hig/SKILL.md +193 -187
  83. package/skills/js-backend-expert/SKILL.md +218 -191
  84. package/skills/legacy-code-translator/SKILL.md +71 -0
  85. package/skills/local-slm-edge-ai-expert/SKILL.md +167 -0
  86. package/skills/logging-error-tracking-expert/SKILL.md +344 -0
  87. package/skills/mcp-client-orchestrator/SKILL.md +76 -0
  88. package/skills/mcp-server-architect/SKILL.md +226 -126
  89. package/skills/micro-frontend-architect/SKILL.md +112 -0
  90. package/skills/mobile-expo-expert/SKILL.md +191 -185
  91. package/skills/mobile-push-notification-expert/SKILL.md +71 -0
  92. package/skills/modern-css-native-expert/SKILL.md +189 -0
  93. package/skills/monday-design-aesthetic/SKILL.md +72 -66
  94. package/skills/monorepo-architect/SKILL.md +232 -226
  95. package/skills/mpa-orchestrator/SKILL.md +120 -101
  96. package/skills/multi-agent-orchestration/SKILL.md +173 -153
  97. package/skills/multiple-entry-points/SKILL.md +91 -55
  98. package/skills/mvc-expert/SKILL.md +237 -231
  99. package/skills/n8n-automation-expert/SKILL.md +89 -0
  100. package/skills/nextjs-app-router-expert/SKILL.md +148 -0
  101. package/skills/openapi-swagger-codegen-expert/SKILL.md +67 -0
  102. package/skills/payment-gateway-expert/SKILL.md +129 -45
  103. package/skills/pdf-document-generation-expert/SKILL.md +91 -0
  104. package/skills/performance-web-vitals/SKILL.md +337 -331
  105. package/skills/post-quantum-crypto-migrator/SKILL.md +57 -0
  106. package/skills/prd-architect/SKILL.md +206 -190
  107. package/skills/proactive-background-watcher/SKILL.md +68 -0
  108. package/skills/production-ready-hardener/PRODUCTION_READINESS_REPORT.md +67 -0
  109. package/skills/production-ready-hardener/SKILL.md +461 -468
  110. package/skills/production-ready-hardener/references/production_checklist.md +161 -161
  111. package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +881 -875
  112. package/skills/project-context-mapper/SKILL.md +85 -0
  113. package/skills/pwa-offline-first-expert/SKILL.md +185 -0
  114. package/skills/python-programming-expert/SKILL.md +407 -270
  115. package/skills/rate-limit-abuse-prevention/SKILL.md +377 -0
  116. package/skills/realtime-collaboration-expert/SKILL.md +99 -45
  117. package/skills/rich-text-editor-expert/SKILL.md +177 -0
  118. package/skills/rust-programming-expert/SKILL.md +240 -234
  119. package/skills/saas-billing/SKILL.md +382 -376
  120. package/skills/saas-multi-tenant/SKILL.md +256 -236
  121. package/skills/saas-mvp-launcher/SKILL.md +30 -1
  122. package/skills/saas-transformer/SKILL.md +499 -445
  123. package/skills/saas-transformer/references/billing_integration_guide.md +401 -401
  124. package/skills/saas-transformer/references/feature_gating_patterns.md +137 -137
  125. package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -121
  126. package/skills/saas-transformer/scripts/saas_transformation_scanner.py +39 -29
  127. package/skills/scalability-clean-code/SKILL.md +234 -228
  128. package/skills/search-engine-expert/SKILL.md +89 -0
  129. package/skills/secure-fuzz-testing/SKILL.md +7 -1
  130. package/skills/self-evolving-memory-graph/SKILL.md +91 -0
  131. package/skills/self-healing-cloud-orchestrator/SKILL.md +57 -0
  132. package/skills/senior-frontend/SKILL.md +85 -105
  133. package/skills/seo/SKILL.md +258 -224
  134. package/skills/session-context-loader/SKILL.md +83 -0
  135. package/skills/session-handoff-resume/SKILL.md +163 -157
  136. package/skills/{skill_baru → skill-baru}/SKILL.md +177 -146
  137. package/skills/solidjs-expert/SKILL.md +80 -0
  138. package/skills/spa-orchestrator/SKILL.md +306 -287
  139. package/skills/sse-websocket-streaming-expert/SKILL.md +93 -0
  140. package/skills/state-management-expert/SKILL.md +277 -271
  141. package/skills/supabase-migration/SKILL.md +47 -1
  142. package/skills/supabase-security-expert/SKILL.md +248 -242
  143. package/skills/svelte-sveltekit-expert/SKILL.md +91 -0
  144. package/skills/svg-animation-motion-expert/SKILL.md +115 -0
  145. package/skills/tailwind-expert/SKILL.md +139 -187
  146. package/skills/tanstack-query-expert/SKILL.md +204 -198
  147. package/skills/tauri-expert/SKILL.md +7 -1
  148. package/skills/token-saver/SKILL.md +118 -110
  149. package/skills/typescript-expert/SKILL.md +329 -278
  150. package/skills/ui-components-expert/SKILL.md +166 -63
  151. package/skills/ui-ux-pro-max/SKILL.md +221 -200
  152. package/skills/vector-db-rag-expert/SKILL.md +208 -0
  153. package/skills/vibe-code-gardener/SKILL.md +180 -172
  154. package/skills/visual-qa-vision-agent/SKILL.md +71 -0
  155. package/skills/voice-ai-realtime-agent/SKILL.md +202 -0
  156. package/skills/vue-frontend-expert/SKILL.md +132 -0
  157. package/skills/wasm-edge-computing-expert/SKILL.md +97 -0
  158. package/skills/web-3d-graphics-expert/SKILL.md +137 -0
  159. package/skills/web-game-engine-expert/SKILL.md +102 -0
  160. package/skills/web-scraper/SKILL.md +98 -146
  161. package/skills/website-design-cloner/SKILL.md +180 -0
  162. package/skills/webxr-ar-vr-expert/SKILL.md +123 -0
  163. package/skills/wordpress-headless-expert/SKILL.md +144 -0
  164. package/skills/zero-to-prod-orchestrator/SKILL.md +231 -180
  165. package/skills/zero-trust-secret-vault/SKILL.md +88 -0
  166. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  167. package/CONTRIBUTING.md +0 -199
  168. package/SECURITY.md +0 -21
  169. package/banner.png +0 -0
  170. package/skills/senior-fullstack/SKILL.md +0 -167
  171. package/skills/senior-fullstack/references/architecture_patterns.md +0 -160
  172. package/skills/senior-fullstack/references/development_workflows.md +0 -222
  173. package/skills/senior-fullstack/references/tech_stack_guide.md +0 -190
  174. package/skills/senior-fullstack/scripts/code_quality_analyzer.py +0 -114
  175. package/skills/senior-fullstack/scripts/fullstack_scaffolder.py +0 -114
  176. package/skills/senior-fullstack/scripts/project_scaffolder.py +0 -114
  177. package/skills/seo-aeo-landing-page-writer/SKILL.md +0 -97
  178. package/skills/seo-geo/SKILL.md +0 -188
  179. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
  180. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
  181. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
  182. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
  183. package/skills/ui_ux_expert/SKILL.md +0 -114
@@ -1,466 +1,466 @@
1
- # API Design Guide
2
-
3
- ## Overview
4
- This reference documents production-grade API design patterns covering REST, GraphQL, gRPC, and WebSocket APIs with concrete implementation examples.
5
-
6
- ---
7
-
8
- ## 1. RESTful API Design (OpenAPI 3.1)
9
-
10
- ### Spec-First Design
11
-
12
- Always define the API contract before implementing. Use OpenAPI 3.1 for REST APIs.
13
-
14
- ```yaml
15
- # openapi.yaml
16
- openapi: 3.1.0
17
- info:
18
- title: Product Catalog API
19
- version: 2.0.0
20
- description: Product management and catalog service
21
-
22
- servers:
23
- - url: https://api.example.com/v2
24
- description: Production
25
- - url: https://staging-api.example.com/v2
26
- description: Staging
27
-
28
- paths:
29
- /products:
30
- get:
31
- operationId: listProducts
32
- summary: List products with filtering and pagination
33
- tags: [Products]
34
- parameters:
35
- - name: cursor
36
- in: query
37
- schema:
38
- type: string
39
- description: Cursor for pagination (base64 encoded)
40
- - name: limit
41
- in: query
42
- schema:
43
- type: integer
44
- minimum: 1
45
- maximum: 100
46
- default: 20
47
- - name: category
48
- in: query
49
- schema:
50
- type: string
51
- - name: fields
52
- in: query
53
- schema:
54
- type: string
55
- description: Comma-separated list of fields to include
56
- responses:
57
- '200':
58
- description: Paginated list of products
59
- content:
60
- application/json:
61
- schema:
62
- $ref: '#/components/schemas/ProductListResponse'
63
- '429':
64
- description: Rate limit exceeded
65
- headers:
66
- Retry-After:
67
- schema:
68
- type: integer
69
- description: Seconds to wait before retrying
70
-
71
- post:
72
- operationId: createProduct
73
- summary: Create a new product
74
- tags: [Products]
75
- parameters:
76
- - name: Idempotency-Key
77
- in: header
78
- required: true
79
- schema:
80
- type: string
81
- format: uuid
82
- description: Unique key to ensure idempotent creation
83
- requestBody:
84
- required: true
85
- content:
86
- application/json:
87
- schema:
88
- $ref: '#/components/schemas/CreateProductRequest'
89
- responses:
90
- '201':
91
- description: Product created successfully
92
- '409':
93
- description: Product already exists (idempotent replay)
94
-
95
- components:
96
- schemas:
97
- ProductListResponse:
98
- type: object
99
- properties:
100
- data:
101
- type: array
102
- items:
103
- $ref: '#/components/schemas/Product'
104
- pagination:
105
- $ref: '#/components/schemas/CursorPagination'
106
-
107
- CursorPagination:
108
- type: object
109
- properties:
110
- next_cursor:
111
- type: string
112
- nullable: true
113
- has_more:
114
- type: boolean
115
- total_count:
116
- type: integer
117
- ```
118
-
119
- ### Cursor-Based Pagination (TypeScript)
120
-
121
- ```typescript
122
- // lib/pagination.ts
123
- interface CursorPaginationParams {
124
- cursor?: string;
125
- limit: number;
126
- }
127
-
128
- interface PaginatedResult<T> {
129
- data: T[];
130
- pagination: {
131
- next_cursor: string | null;
132
- has_more: boolean;
133
- };
134
- }
135
-
136
- export async function paginateWithCursor<T extends { id: string; createdAt: Date }>(
137
- query: (params: { cursor?: { id: string; createdAt: Date }; limit: number }) => Promise<T[]>,
138
- params: CursorPaginationParams
139
- ): Promise<PaginatedResult<T>> {
140
- const { cursor, limit } = params;
141
- const decodedCursor = cursor
142
- ? JSON.parse(Buffer.from(cursor, 'base64url').toString())
143
- : undefined;
144
-
145
- // Fetch one extra to determine if there are more results
146
- const items = await query({ cursor: decodedCursor, limit: limit + 1 });
147
- const hasMore = items.length > limit;
148
- const data = hasMore ? items.slice(0, limit) : items;
149
-
150
- const lastItem = data[data.length - 1];
151
- const nextCursor = hasMore && lastItem
152
- ? Buffer.from(JSON.stringify({ id: lastItem.id, createdAt: lastItem.createdAt }))
153
- .toString('base64url')
154
- : null;
155
-
156
- return { data, pagination: { next_cursor: nextCursor, has_more: hasMore } };
157
- }
158
- ```
159
-
160
- ### Idempotency Key Middleware
161
-
162
- ```typescript
163
- // middleware/idempotency.ts
164
- import { Redis } from '@upstash/redis';
165
-
166
- const redis = new Redis({
167
- url: process.env.UPSTASH_REDIS_REST_URL!,
168
- token: process.env.UPSTASH_REDIS_REST_TOKEN!,
169
- });
170
-
171
- export async function withIdempotency<T>(
172
- key: string,
173
- handler: () => Promise<T>,
174
- ttlSeconds: number = 86400
175
- ): Promise<{ result: T; isReplay: boolean }> {
176
- // Check if this key was already processed
177
- const cached = await redis.get<string>(`idempotency:${key}`);
178
- if (cached) {
179
- return { result: JSON.parse(cached) as T, isReplay: true };
180
- }
181
-
182
- // Execute the handler
183
- const result = await handler();
184
-
185
- // Store the result for replay
186
- await redis.set(`idempotency:${key}`, JSON.stringify(result), { ex: ttlSeconds });
187
-
188
- return { result, isReplay: false };
189
- }
190
- ```
191
-
192
- ---
193
-
194
- ## 2. GraphQL API Design
195
-
196
- ### Schema-First with Code Generation
197
-
198
- ```graphql
199
- # schema.graphql
200
- type Query {
201
- product(id: ID!): Product
202
- products(
203
- filter: ProductFilter
204
- pagination: PaginationInput
205
- sort: ProductSort
206
- ): ProductConnection!
207
- }
208
-
209
- type Mutation {
210
- createProduct(input: CreateProductInput!): CreateProductPayload!
211
- updateProduct(id: ID!, input: UpdateProductInput!): UpdateProductPayload!
212
- deleteProduct(id: ID!): DeleteProductPayload!
213
- }
214
-
215
- type Product {
216
- id: ID!
217
- name: String!
218
- description: String
219
- price: Float!
220
- category: Category!
221
- variants: [ProductVariant!]!
222
- reviews(first: Int, after: String): ReviewConnection!
223
- createdAt: DateTime!
224
- updatedAt: DateTime!
225
- }
226
-
227
- # Relay-style connection for cursor pagination
228
- type ProductConnection {
229
- edges: [ProductEdge!]!
230
- pageInfo: PageInfo!
231
- totalCount: Int!
232
- }
233
-
234
- type ProductEdge {
235
- cursor: String!
236
- node: Product!
237
- }
238
-
239
- type PageInfo {
240
- hasNextPage: Boolean!
241
- hasPreviousPage: Boolean!
242
- startCursor: String
243
- endCursor: String
244
- }
245
-
246
- input ProductFilter {
247
- categoryId: ID
248
- minPrice: Float
249
- maxPrice: Float
250
- search: String
251
- }
252
-
253
- input PaginationInput {
254
- first: Int
255
- after: String
256
- last: Int
257
- before: String
258
- }
259
- ```
260
-
261
- ### DataLoader for N+1 Prevention
262
-
263
- ```typescript
264
- // loaders/product-loader.ts
265
- import DataLoader from 'dataloader';
266
- import { db } from '@/lib/db';
267
- import { products } from '@/lib/db/schema';
268
- import { inArray } from 'drizzle-orm';
269
-
270
- export function createProductLoader() {
271
- return new DataLoader<string, typeof products.$inferSelect | null>(
272
- async (ids) => {
273
- const results = await db
274
- .select()
275
- .from(products)
276
- .where(inArray(products.id, [...ids]));
277
-
278
- // Map results back to input order (DataLoader requirement)
279
- const resultMap = new Map(results.map((r) => [r.id, r]));
280
- return ids.map((id) => resultMap.get(id) ?? null);
281
- },
282
- { cache: true, maxBatchSize: 100 }
283
- );
284
- }
285
- ```
286
-
287
- ---
288
-
289
- ## 3. gRPC API Design
290
-
291
- ### Protocol Buffer Definition
292
-
293
- ```protobuf
294
- // proto/product/v1/product.proto
295
- syntax = "proto3";
296
-
297
- package product.v1;
298
-
299
- option go_package = "github.com/example/api/gen/product/v1";
300
-
301
- import "google/protobuf/timestamp.proto";
302
- import "google/protobuf/field_mask.proto";
303
-
304
- service ProductService {
305
- // Unary RPCs
306
- rpc GetProduct(GetProductRequest) returns (GetProductResponse);
307
- rpc CreateProduct(CreateProductRequest) returns (CreateProductResponse);
308
- rpc UpdateProduct(UpdateProductRequest) returns (UpdateProductResponse);
309
- rpc DeleteProduct(DeleteProductRequest) returns (DeleteProductResponse);
310
-
311
- // Server streaming for real-time updates
312
- rpc WatchProductChanges(WatchProductChangesRequest) returns (stream ProductChange);
313
-
314
- // Bulk operations
315
- rpc BatchGetProducts(BatchGetProductsRequest) returns (BatchGetProductsResponse);
316
- }
317
-
318
- message Product {
319
- string id = 1;
320
- string name = 2;
321
- string description = 3;
322
- int64 price_cents = 4; // Use integer cents to avoid floating point issues
323
- string category_id = 5;
324
- ProductStatus status = 6;
325
- google.protobuf.Timestamp created_at = 7;
326
- google.protobuf.Timestamp updated_at = 8;
327
- }
328
-
329
- enum ProductStatus {
330
- PRODUCT_STATUS_UNSPECIFIED = 0;
331
- PRODUCT_STATUS_DRAFT = 1;
332
- PRODUCT_STATUS_ACTIVE = 2;
333
- PRODUCT_STATUS_ARCHIVED = 3;
334
- }
335
-
336
- message UpdateProductRequest {
337
- string id = 1;
338
- Product product = 2;
339
- google.protobuf.FieldMask update_mask = 3; // Partial updates
340
- }
341
-
342
- message GetProductRequest {
343
- string id = 1;
344
- }
345
-
346
- message GetProductResponse {
347
- Product product = 1;
348
- }
349
- ```
350
-
351
- ---
352
-
353
- ## 4. WebSocket & Real-Time APIs
354
-
355
- ### Type-Safe WebSocket with Zod Validation
356
-
357
- ```typescript
358
- // lib/ws/types.ts
359
- import { z } from 'zod';
360
-
361
- // Define all possible client → server messages
362
- export const ClientMessageSchema = z.discriminatedUnion('type', [
363
- z.object({
364
- type: z.literal('subscribe'),
365
- channel: z.string(),
366
- }),
367
- z.object({
368
- type: z.literal('unsubscribe'),
369
- channel: z.string(),
370
- }),
371
- z.object({
372
- type: z.literal('message'),
373
- channel: z.string(),
374
- payload: z.unknown(),
375
- }),
376
- z.object({
377
- type: z.literal('ping'),
378
- }),
379
- ]);
380
-
381
- // Define all possible server → client messages
382
- export type ServerMessage =
383
- | { type: 'subscribed'; channel: string }
384
- | { type: 'unsubscribed'; channel: string }
385
- | { type: 'message'; channel: string; payload: unknown; sender: string }
386
- | { type: 'pong' }
387
- | { type: 'error'; code: string; message: string };
388
- ```
389
-
390
- ---
391
-
392
- ## 5. Error Handling Standards
393
-
394
- ### Structured Error Response (RFC 7807 - Problem Details)
395
-
396
- ```typescript
397
- // lib/errors.ts
398
- interface ProblemDetails {
399
- type: string; // URI identifying the error type
400
- title: string; // Human-readable summary
401
- status: number; // HTTP status code
402
- detail?: string; // Human-readable explanation specific to this occurrence
403
- instance?: string; // URI identifying the specific occurrence
404
- errors?: FieldError[]; // Validation errors
405
- }
406
-
407
- interface FieldError {
408
- field: string;
409
- message: string;
410
- code: string;
411
- }
412
-
413
- export class AppError extends Error {
414
- constructor(
415
- public readonly status: number,
416
- public readonly type: string,
417
- public readonly title: string,
418
- public readonly detail?: string,
419
- public readonly fieldErrors?: FieldError[],
420
- ) {
421
- super(title);
422
- }
423
-
424
- toProblemDetails(): ProblemDetails {
425
- return {
426
- type: `https://api.example.com/errors/${this.type}`,
427
- title: this.title,
428
- status: this.status,
429
- detail: this.detail,
430
- errors: this.fieldErrors,
431
- };
432
- }
433
- }
434
-
435
- // Usage
436
- throw new AppError(
437
- 422,
438
- 'validation-failed',
439
- 'Validation Failed',
440
- 'One or more fields failed validation',
441
- [
442
- { field: 'email', message: 'Invalid email format', code: 'INVALID_FORMAT' },
443
- { field: 'price', message: 'Price must be positive', code: 'INVALID_RANGE' },
444
- ]
445
- );
446
- ```
447
-
448
- ---
449
-
450
- ## Best Practices Summary
451
-
452
- | Practice | Description |
453
- |----------|-------------|
454
- | Spec-first design | Define API contract before implementation |
455
- | Cursor pagination | Use cursor-based pagination for large datasets |
456
- | Idempotency keys | Make all mutations idempotent with unique keys |
457
- | Rate limiting | Protect APIs with token bucket / sliding window |
458
- | Versioning | URL path versioning (`/v1/`) for breaking changes |
459
- | Error format | Use RFC 7807 Problem Details for structured errors |
460
- | Field masking | Allow clients to select specific fields |
461
- | HATEOAS | Include actionable links in responses |
462
-
463
- ---
464
-
465
- ## Conclusion
466
- Good API design is the foundation of a scalable system. Invest in spec-first design, strong typing, and consistent error handling to create APIs that are easy to consume, evolve, and maintain.
1
+ # API Design Guide
2
+
3
+ ## Overview
4
+ This reference documents production-grade API design patterns covering REST, GraphQL, gRPC, and WebSocket APIs with concrete implementation examples.
5
+
6
+ ---
7
+
8
+ ## 1. RESTful API Design (OpenAPI 3.1)
9
+
10
+ ### Spec-First Design
11
+
12
+ Always define the API contract before implementing. Use OpenAPI 3.1 for REST APIs.
13
+
14
+ ```yaml
15
+ # openapi.yaml
16
+ openapi: 3.1.0
17
+ info:
18
+ title: Product Catalog API
19
+ version: 2.0.0
20
+ description: Product management and catalog service
21
+
22
+ servers:
23
+ - url: https://api.example.com/v2
24
+ description: Production
25
+ - url: https://staging-api.example.com/v2
26
+ description: Staging
27
+
28
+ paths:
29
+ /products:
30
+ get:
31
+ operationId: listProducts
32
+ summary: List products with filtering and pagination
33
+ tags: [Products]
34
+ parameters:
35
+ - name: cursor
36
+ in: query
37
+ schema:
38
+ type: string
39
+ description: Cursor for pagination (base64 encoded)
40
+ - name: limit
41
+ in: query
42
+ schema:
43
+ type: integer
44
+ minimum: 1
45
+ maximum: 100
46
+ default: 20
47
+ - name: category
48
+ in: query
49
+ schema:
50
+ type: string
51
+ - name: fields
52
+ in: query
53
+ schema:
54
+ type: string
55
+ description: Comma-separated list of fields to include
56
+ responses:
57
+ '200':
58
+ description: Paginated list of products
59
+ content:
60
+ application/json:
61
+ schema:
62
+ $ref: '#/components/schemas/ProductListResponse'
63
+ '429':
64
+ description: Rate limit exceeded
65
+ headers:
66
+ Retry-After:
67
+ schema:
68
+ type: integer
69
+ description: Seconds to wait before retrying
70
+
71
+ post:
72
+ operationId: createProduct
73
+ summary: Create a new product
74
+ tags: [Products]
75
+ parameters:
76
+ - name: Idempotency-Key
77
+ in: header
78
+ required: true
79
+ schema:
80
+ type: string
81
+ format: uuid
82
+ description: Unique key to ensure idempotent creation
83
+ requestBody:
84
+ required: true
85
+ content:
86
+ application/json:
87
+ schema:
88
+ $ref: '#/components/schemas/CreateProductRequest'
89
+ responses:
90
+ '201':
91
+ description: Product created successfully
92
+ '409':
93
+ description: Product already exists (idempotent replay)
94
+
95
+ components:
96
+ schemas:
97
+ ProductListResponse:
98
+ type: object
99
+ properties:
100
+ data:
101
+ type: array
102
+ items:
103
+ $ref: '#/components/schemas/Product'
104
+ pagination:
105
+ $ref: '#/components/schemas/CursorPagination'
106
+
107
+ CursorPagination:
108
+ type: object
109
+ properties:
110
+ next_cursor:
111
+ type: string
112
+ nullable: true
113
+ has_more:
114
+ type: boolean
115
+ total_count:
116
+ type: integer
117
+ ```
118
+
119
+ ### Cursor-Based Pagination (TypeScript)
120
+
121
+ ```typescript
122
+ // lib/pagination.ts
123
+ interface CursorPaginationParams {
124
+ cursor?: string;
125
+ limit: number;
126
+ }
127
+
128
+ interface PaginatedResult<T> {
129
+ data: T[];
130
+ pagination: {
131
+ next_cursor: string | null;
132
+ has_more: boolean;
133
+ };
134
+ }
135
+
136
+ export async function paginateWithCursor<T extends { id: string; createdAt: Date }>(
137
+ query: (params: { cursor?: { id: string; createdAt: Date }; limit: number }) => Promise<T[]>,
138
+ params: CursorPaginationParams
139
+ ): Promise<PaginatedResult<T>> {
140
+ const { cursor, limit } = params;
141
+ const decodedCursor = cursor
142
+ ? JSON.parse(Buffer.from(cursor, 'base64url').toString())
143
+ : undefined;
144
+
145
+ // Fetch one extra to determine if there are more results
146
+ const items = await query({ cursor: decodedCursor, limit: limit + 1 });
147
+ const hasMore = items.length > limit;
148
+ const data = hasMore ? items.slice(0, limit) : items;
149
+
150
+ const lastItem = data[data.length - 1];
151
+ const nextCursor = hasMore && lastItem
152
+ ? Buffer.from(JSON.stringify({ id: lastItem.id, createdAt: lastItem.createdAt }))
153
+ .toString('base64url')
154
+ : null;
155
+
156
+ return { data, pagination: { next_cursor: nextCursor, has_more: hasMore } };
157
+ }
158
+ ```
159
+
160
+ ### Idempotency Key Middleware
161
+
162
+ ```typescript
163
+ // middleware/idempotency.ts
164
+ import { Redis } from '@upstash/redis';
165
+
166
+ const redis = new Redis({
167
+ url: process.env.UPSTASH_REDIS_REST_URL!,
168
+ token: process.env.UPSTASH_REDIS_REST_TOKEN!,
169
+ });
170
+
171
+ export async function withIdempotency<T>(
172
+ key: string,
173
+ handler: () => Promise<T>,
174
+ ttlSeconds: number = 86400
175
+ ): Promise<{ result: T; isReplay: boolean }> {
176
+ // Check if this key was already processed
177
+ const cached = await redis.get<string>(`idempotency:${key}`);
178
+ if (cached) {
179
+ return { result: JSON.parse(cached) as T, isReplay: true };
180
+ }
181
+
182
+ // Execute the handler
183
+ const result = await handler();
184
+
185
+ // Store the result for replay
186
+ await redis.set(`idempotency:${key}`, JSON.stringify(result), { ex: ttlSeconds });
187
+
188
+ return { result, isReplay: false };
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 2. GraphQL API Design
195
+
196
+ ### Schema-First with Code Generation
197
+
198
+ ```graphql
199
+ # schema.graphql
200
+ type Query {
201
+ product(id: ID!): Product
202
+ products(
203
+ filter: ProductFilter
204
+ pagination: PaginationInput
205
+ sort: ProductSort
206
+ ): ProductConnection!
207
+ }
208
+
209
+ type Mutation {
210
+ createProduct(input: CreateProductInput!): CreateProductPayload!
211
+ updateProduct(id: ID!, input: UpdateProductInput!): UpdateProductPayload!
212
+ deleteProduct(id: ID!): DeleteProductPayload!
213
+ }
214
+
215
+ type Product {
216
+ id: ID!
217
+ name: String!
218
+ description: String
219
+ price: Float!
220
+ category: Category!
221
+ variants: [ProductVariant!]!
222
+ reviews(first: Int, after: String): ReviewConnection!
223
+ createdAt: DateTime!
224
+ updatedAt: DateTime!
225
+ }
226
+
227
+ # Relay-style connection for cursor pagination
228
+ type ProductConnection {
229
+ edges: [ProductEdge!]!
230
+ pageInfo: PageInfo!
231
+ totalCount: Int!
232
+ }
233
+
234
+ type ProductEdge {
235
+ cursor: String!
236
+ node: Product!
237
+ }
238
+
239
+ type PageInfo {
240
+ hasNextPage: Boolean!
241
+ hasPreviousPage: Boolean!
242
+ startCursor: String
243
+ endCursor: String
244
+ }
245
+
246
+ input ProductFilter {
247
+ categoryId: ID
248
+ minPrice: Float
249
+ maxPrice: Float
250
+ search: String
251
+ }
252
+
253
+ input PaginationInput {
254
+ first: Int
255
+ after: String
256
+ last: Int
257
+ before: String
258
+ }
259
+ ```
260
+
261
+ ### DataLoader for N+1 Prevention
262
+
263
+ ```typescript
264
+ // loaders/product-loader.ts
265
+ import DataLoader from 'dataloader';
266
+ import { db } from '@/lib/db';
267
+ import { products } from '@/lib/db/schema';
268
+ import { inArray } from 'drizzle-orm';
269
+
270
+ export function createProductLoader() {
271
+ return new DataLoader<string, typeof products.$inferSelect | null>(
272
+ async (ids) => {
273
+ const results = await db
274
+ .select()
275
+ .from(products)
276
+ .where(inArray(products.id, [...ids]));
277
+
278
+ // Map results back to input order (DataLoader requirement)
279
+ const resultMap = new Map(results.map((r) => [r.id, r]));
280
+ return ids.map((id) => resultMap.get(id) ?? null);
281
+ },
282
+ { cache: true, maxBatchSize: 100 }
283
+ );
284
+ }
285
+ ```
286
+
287
+ ---
288
+
289
+ ## 3. gRPC API Design
290
+
291
+ ### Protocol Buffer Definition
292
+
293
+ ```protobuf
294
+ // proto/product/v1/product.proto
295
+ syntax = "proto3";
296
+
297
+ package product.v1;
298
+
299
+ option go_package = "github.com/example/api/gen/product/v1";
300
+
301
+ import "google/protobuf/timestamp.proto";
302
+ import "google/protobuf/field_mask.proto";
303
+
304
+ service ProductService {
305
+ // Unary RPCs
306
+ rpc GetProduct(GetProductRequest) returns (GetProductResponse);
307
+ rpc CreateProduct(CreateProductRequest) returns (CreateProductResponse);
308
+ rpc UpdateProduct(UpdateProductRequest) returns (UpdateProductResponse);
309
+ rpc DeleteProduct(DeleteProductRequest) returns (DeleteProductResponse);
310
+
311
+ // Server streaming for real-time updates
312
+ rpc WatchProductChanges(WatchProductChangesRequest) returns (stream ProductChange);
313
+
314
+ // Bulk operations
315
+ rpc BatchGetProducts(BatchGetProductsRequest) returns (BatchGetProductsResponse);
316
+ }
317
+
318
+ message Product {
319
+ string id = 1;
320
+ string name = 2;
321
+ string description = 3;
322
+ int64 price_cents = 4; // Use integer cents to avoid floating point issues
323
+ string category_id = 5;
324
+ ProductStatus status = 6;
325
+ google.protobuf.Timestamp created_at = 7;
326
+ google.protobuf.Timestamp updated_at = 8;
327
+ }
328
+
329
+ enum ProductStatus {
330
+ PRODUCT_STATUS_UNSPECIFIED = 0;
331
+ PRODUCT_STATUS_DRAFT = 1;
332
+ PRODUCT_STATUS_ACTIVE = 2;
333
+ PRODUCT_STATUS_ARCHIVED = 3;
334
+ }
335
+
336
+ message UpdateProductRequest {
337
+ string id = 1;
338
+ Product product = 2;
339
+ google.protobuf.FieldMask update_mask = 3; // Partial updates
340
+ }
341
+
342
+ message GetProductRequest {
343
+ string id = 1;
344
+ }
345
+
346
+ message GetProductResponse {
347
+ Product product = 1;
348
+ }
349
+ ```
350
+
351
+ ---
352
+
353
+ ## 4. WebSocket & Real-Time APIs
354
+
355
+ ### Type-Safe WebSocket with Zod Validation
356
+
357
+ ```typescript
358
+ // lib/ws/types.ts
359
+ import { z } from 'zod';
360
+
361
+ // Define all possible client → server messages
362
+ export const ClientMessageSchema = z.discriminatedUnion('type', [
363
+ z.object({
364
+ type: z.literal('subscribe'),
365
+ channel: z.string(),
366
+ }),
367
+ z.object({
368
+ type: z.literal('unsubscribe'),
369
+ channel: z.string(),
370
+ }),
371
+ z.object({
372
+ type: z.literal('message'),
373
+ channel: z.string(),
374
+ payload: z.unknown(),
375
+ }),
376
+ z.object({
377
+ type: z.literal('ping'),
378
+ }),
379
+ ]);
380
+
381
+ // Define all possible server → client messages
382
+ export type ServerMessage =
383
+ | { type: 'subscribed'; channel: string }
384
+ | { type: 'unsubscribed'; channel: string }
385
+ | { type: 'message'; channel: string; payload: unknown; sender: string }
386
+ | { type: 'pong' }
387
+ | { type: 'error'; code: string; message: string };
388
+ ```
389
+
390
+ ---
391
+
392
+ ## 5. Error Handling Standards
393
+
394
+ ### Structured Error Response (RFC 7807 - Problem Details)
395
+
396
+ ```typescript
397
+ // lib/errors.ts
398
+ interface ProblemDetails {
399
+ type: string; // URI identifying the error type
400
+ title: string; // Human-readable summary
401
+ status: number; // HTTP status code
402
+ detail?: string; // Human-readable explanation specific to this occurrence
403
+ instance?: string; // URI identifying the specific occurrence
404
+ errors?: FieldError[]; // Validation errors
405
+ }
406
+
407
+ interface FieldError {
408
+ field: string;
409
+ message: string;
410
+ code: string;
411
+ }
412
+
413
+ export class AppError extends Error {
414
+ constructor(
415
+ public readonly status: number,
416
+ public readonly type: string,
417
+ public readonly title: string,
418
+ public readonly detail?: string,
419
+ public readonly fieldErrors?: FieldError[],
420
+ ) {
421
+ super(title);
422
+ }
423
+
424
+ toProblemDetails(): ProblemDetails {
425
+ return {
426
+ type: `https://api.example.com/errors/${this.type}`,
427
+ title: this.title,
428
+ status: this.status,
429
+ detail: this.detail,
430
+ errors: this.fieldErrors,
431
+ };
432
+ }
433
+ }
434
+
435
+ // Usage
436
+ throw new AppError(
437
+ 422,
438
+ 'validation-failed',
439
+ 'Validation Failed',
440
+ 'One or more fields failed validation',
441
+ [
442
+ { field: 'email', message: 'Invalid email format', code: 'INVALID_FORMAT' },
443
+ { field: 'price', message: 'Price must be positive', code: 'INVALID_RANGE' },
444
+ ]
445
+ );
446
+ ```
447
+
448
+ ---
449
+
450
+ ## Best Practices Summary
451
+
452
+ | Practice | Description |
453
+ |----------|-------------|
454
+ | Spec-first design | Define API contract before implementation |
455
+ | Cursor pagination | Use cursor-based pagination for large datasets |
456
+ | Idempotency keys | Make all mutations idempotent with unique keys |
457
+ | Rate limiting | Protect APIs with token bucket / sliding window |
458
+ | Versioning | URL path versioning (`/v1/`) for breaking changes |
459
+ | Error format | Use RFC 7807 Problem Details for structured errors |
460
+ | Field masking | Allow clients to select specific fields |
461
+ | HATEOAS | Include actionable links in responses |
462
+
463
+ ---
464
+
465
+ ## Conclusion
466
+ Good API design is the foundation of a scalable system. Invest in spec-first design, strong typing, and consistent error handling to create APIs that are easy to consume, evolve, and maintain.