@torus-engineering/tas-kit 1.10.0 → 1.12.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 (162) hide show
  1. package/.tas/README.md +70 -70
  2. package/{.claude → .tas/_platform/claude-code}/settings.json +0 -12
  3. package/{.claude → .tas/_platform}/hooks/code-quality.js +1 -1
  4. package/{.claude → .tas/_platform}/hooks/session-end.js +20 -25
  5. package/.tas/commands/ado-create.md +28 -0
  6. package/.tas/commands/ado-delete.md +22 -0
  7. package/.tas/commands/ado-get.md +20 -0
  8. package/.tas/commands/ado-status.md +18 -0
  9. package/.tas/commands/ado-update.md +27 -0
  10. package/.tas/commands/tas-adr.md +33 -0
  11. package/.tas/commands/tas-apitest-plan.md +173 -0
  12. package/.tas/commands/tas-apitest.md +143 -0
  13. package/.tas/commands/tas-brainstorm.md +19 -0
  14. package/.tas/commands/tas-bug.md +113 -0
  15. package/.tas/commands/tas-design.md +37 -0
  16. package/.tas/commands/tas-dev.md +125 -0
  17. package/{.claude → .tas}/commands/tas-e2e-mobile.md +155 -155
  18. package/{.claude → .tas}/commands/tas-e2e-web.md +163 -163
  19. package/.tas/commands/tas-e2e.md +102 -0
  20. package/.tas/commands/tas-epic.md +35 -0
  21. package/.tas/commands/tas-feature.md +47 -0
  22. package/.tas/commands/tas-fix.md +51 -0
  23. package/.tas/commands/tas-functest-mobile.md +144 -0
  24. package/{.claude → .tas}/commands/tas-functest-web.md +192 -192
  25. package/.tas/commands/tas-functest.md +76 -0
  26. package/.tas/commands/tas-init.md +17 -0
  27. package/.tas/commands/tas-plan.md +198 -0
  28. package/.tas/commands/tas-prd.md +37 -0
  29. package/.tas/commands/tas-review.md +113 -0
  30. package/.tas/commands/tas-sad.md +43 -0
  31. package/.tas/commands/tas-security.md +87 -0
  32. package/.tas/commands/tas-spec.md +50 -0
  33. package/.tas/commands/tas-status.md +16 -0
  34. package/.tas/commands/tas-story.md +91 -0
  35. package/.tas/platforms.json +5 -0
  36. package/.tas/project-status-example.yaml +17 -17
  37. package/.tas/rules/ado-integration.md +65 -0
  38. package/{.claude/skills/api-design/SKILL.md → .tas/rules/common/api-design.md} +517 -530
  39. package/{.claude → .tas}/rules/common/code-review.md +30 -6
  40. package/.tas/rules/common/post-implementation-review.md +51 -0
  41. package/{.claude → .tas}/rules/common/project-status.md +80 -80
  42. package/.tas/rules/common/stack-detection.md +29 -0
  43. package/.tas/rules/common/story-done.md +30 -0
  44. package/.tas/rules/common/tdd.md +89 -0
  45. package/{.claude → .tas}/rules/common/testing.md +3 -8
  46. package/.tas/rules/common/token-logging.md +36 -0
  47. package/{.claude → .tas}/rules/csharp/api-testing.md +20 -20
  48. package/{.claude → .tas}/rules/csharp/coding-style.md +0 -2
  49. package/{.claude → .tas}/rules/csharp/security.md +10 -0
  50. package/{.claude → .tas}/rules/python/coding-style.md +0 -2
  51. package/{.claude → .tas}/rules/typescript/coding-style.md +0 -2
  52. package/.tas/rules/typescript/patterns.md +142 -0
  53. package/.tas/rules/typescript/security.md +88 -0
  54. package/{.claude → .tas}/rules/typescript/testing.md +0 -4
  55. package/{.claude → .tas}/rules/web/coding-style.md +0 -2
  56. package/.tas/tas-example.yaml +10 -11
  57. package/.tas/templates/ADR.md +47 -47
  58. package/.tas/templates/AGENTS.md +37 -0
  59. package/.tas/templates/API-Test-Spec.md +3 -3
  60. package/.tas/templates/Bug.md +67 -67
  61. package/.tas/templates/Design-Spec.md +36 -36
  62. package/.tas/templates/E2E-Execution-Report.md +1 -1
  63. package/.tas/templates/Epic.md +46 -46
  64. package/.tas/templates/Feature.md +10 -10
  65. package/.tas/templates/Func-Test-Spec.md +3 -3
  66. package/.tas/templates/SAD.md +106 -106
  67. package/.tas/templates/Security-Report.md +27 -27
  68. package/.tas/templates/Story.md +9 -9
  69. package/.tas/tools/tas-ado-readme.md +68 -68
  70. package/.tas/tools/tas-ado.py +621 -621
  71. package/README.md +78 -78
  72. package/bin/cli.js +91 -73
  73. package/lib/adapters/antigravity.js +137 -0
  74. package/lib/adapters/claude-code.js +35 -0
  75. package/lib/adapters/codex.js +163 -0
  76. package/lib/adapters/cursor.js +80 -0
  77. package/lib/adapters/index.js +20 -0
  78. package/lib/adapters/utils.js +81 -0
  79. package/lib/deleted-files.json +99 -0
  80. package/lib/install.js +403 -327
  81. package/package.json +4 -3
  82. package/.claude/agents/code-reviewer.md +0 -41
  83. package/.claude/agents/e2e-runner.md +0 -61
  84. package/.claude/agents/planner.md +0 -82
  85. package/.claude/agents/tdd-guide.md +0 -84
  86. package/.claude/commands/ado-create.md +0 -27
  87. package/.claude/commands/ado-delete.md +0 -21
  88. package/.claude/commands/ado-get.md +0 -20
  89. package/.claude/commands/ado-status.md +0 -18
  90. package/.claude/commands/ado-update.md +0 -26
  91. package/.claude/commands/tas-adr.md +0 -33
  92. package/.claude/commands/tas-apitest-plan.md +0 -173
  93. package/.claude/commands/tas-apitest.md +0 -143
  94. package/.claude/commands/tas-brainstorm.md +0 -19
  95. package/.claude/commands/tas-bug.md +0 -113
  96. package/.claude/commands/tas-design.md +0 -37
  97. package/.claude/commands/tas-dev.md +0 -128
  98. package/.claude/commands/tas-e2e.md +0 -102
  99. package/.claude/commands/tas-epic.md +0 -35
  100. package/.claude/commands/tas-feature.md +0 -47
  101. package/.claude/commands/tas-fix.md +0 -51
  102. package/.claude/commands/tas-functest-mobile.md +0 -144
  103. package/.claude/commands/tas-functest.md +0 -76
  104. package/.claude/commands/tas-init.md +0 -17
  105. package/.claude/commands/tas-plan.md +0 -200
  106. package/.claude/commands/tas-prd.md +0 -37
  107. package/.claude/commands/tas-review.md +0 -111
  108. package/.claude/commands/tas-sad.md +0 -43
  109. package/.claude/commands/tas-security.md +0 -87
  110. package/.claude/commands/tas-spec.md +0 -50
  111. package/.claude/commands/tas-status.md +0 -16
  112. package/.claude/commands/tas-story.md +0 -91
  113. package/.claude/commands/tas-verify.md +0 -51
  114. package/.claude/rules/common/post-review-agent.md +0 -49
  115. package/.claude/rules/common/stack-detection.md +0 -29
  116. package/.claude/rules/common/token-logging.md +0 -27
  117. package/.claude/rules/typescript/patterns.md +0 -62
  118. package/.claude/rules/typescript/security.md +0 -28
  119. package/.claude/settings.local.json +0 -38
  120. package/.claude/skills/ado-integration/SKILL.md +0 -75
  121. package/.claude/skills/ai-regression-testing/SKILL.md +0 -364
  122. package/.claude/skills/architecture-decision-records/SKILL.md +0 -184
  123. package/.claude/skills/benchmark/SKILL.md +0 -98
  124. package/.claude/skills/browser-qa/SKILL.md +0 -92
  125. package/.claude/skills/canary-watch/SKILL.md +0 -104
  126. package/.claude/skills/js-backend-patterns/SKILL.md +0 -603
  127. package/.claude/skills/tas-conventions/SKILL.md +0 -65
  128. package/.claude/skills/tas-implementation-complete/SKILL.md +0 -99
  129. package/.claude/skills/tas-tdd/SKILL.md +0 -123
  130. package/.claude/skills/token-logger/SKILL.md +0 -19
  131. package/.tas/checklists/code-review.md +0 -29
  132. package/.tas/checklists/security.md +0 -21
  133. package/.tas/checklists/story-done.md +0 -23
  134. package/CLAUDE-Example.md +0 -61
  135. /package/{.claude → .tas}/agents/architect.md +0 -0
  136. /package/{.claude → .tas}/agents/aws-reviewer.md +0 -0
  137. /package/{.claude → .tas}/agents/build-resolver.md +0 -0
  138. /package/{.claude → .tas}/agents/code-explorer.md +0 -0
  139. /package/{.claude → .tas}/agents/csharp-reviewer.md +0 -0
  140. /package/{.claude → .tas}/agents/database-reviewer.md +0 -0
  141. /package/{.claude → .tas}/agents/doc-updater.md +0 -0
  142. /package/{.claude → .tas}/agents/python-reviewer.md +0 -0
  143. /package/{.claude → .tas}/agents/security-reviewer.md +0 -0
  144. /package/{.claude → .tas}/agents/typescript-reviewer.md +0 -0
  145. /package/{.claude → .tas}/rules/.gitkeep +0 -0
  146. /package/{.claude → .tas}/rules/common/hooks.md +0 -0
  147. /package/{.claude → .tas}/rules/common/patterns.md +0 -0
  148. /package/{.claude → .tas}/rules/common/security.md +0 -0
  149. /package/{.claude → .tas}/rules/csharp/hooks.md +0 -0
  150. /package/{.claude → .tas}/rules/csharp/patterns.md +0 -0
  151. /package/{.claude → .tas}/rules/csharp/testing.md +0 -0
  152. /package/{.claude → .tas}/rules/python/hooks.md +0 -0
  153. /package/{.claude → .tas}/rules/python/patterns.md +0 -0
  154. /package/{.claude → .tas}/rules/python/security.md +0 -0
  155. /package/{.claude → .tas}/rules/python/testing.md +0 -0
  156. /package/{.claude → .tas}/rules/typescript/hooks.md +0 -0
  157. /package/{.claude → .tas}/rules/web/design-quality.md +0 -0
  158. /package/{.claude → .tas}/rules/web/hooks.md +0 -0
  159. /package/{.claude → .tas}/rules/web/patterns.md +0 -0
  160. /package/{.claude → .tas}/rules/web/performance.md +0 -0
  161. /package/{.claude → .tas}/rules/web/security.md +0 -0
  162. /package/{.claude → .tas}/rules/web/testing.md +0 -0
@@ -1,603 +0,0 @@
1
- ---
2
- name: js-backend-patterns
3
- description: |
4
- Auto-invoke when implementing repository, service, or controller layers on Node.js/Express/Next.js,
5
- fixing N+1 query problems, setting up Redis caching, adding auth middleware, or structuring
6
- background job processing. NOT for API contract design (use api-design instead).
7
- Specifically for Node.js/Express/Next.js stacks — not for .NET C# or Python.
8
- origin: ECC
9
- allowed-tools: Read, Grep, Glob
10
- ---
11
-
12
- # Backend Development Patterns
13
-
14
- Backend architecture patterns and best practices for scalable server-side applications.
15
-
16
- ## When to Activate
17
-
18
- - Designing REST or GraphQL API endpoints
19
- - Implementing repository, service, or controller layers
20
- - Optimizing database queries (N+1, indexing, connection pooling)
21
- - Adding caching (Redis, in-memory, HTTP cache headers)
22
- - Setting up background jobs or async processing
23
- - Structuring error handling and validation for APIs
24
- - Building middleware (auth, logging, rate limiting)
25
-
26
- ## API Design Patterns
27
-
28
- ### RESTful API Structure
29
-
30
- ```typescript
31
- // PASS: Resource-based URLs
32
- GET /api/markets # List resources
33
- GET /api/markets/:id # Get single resource
34
- POST /api/markets # Create resource
35
- PUT /api/markets/:id # Replace resource
36
- PATCH /api/markets/:id # Update resource
37
- DELETE /api/markets/:id # Delete resource
38
-
39
- // PASS: Query parameters for filtering, sorting, pagination
40
- GET /api/markets?status=active&sort=volume&limit=20&offset=0
41
- ```
42
-
43
- ### Repository Pattern
44
-
45
- ```typescript
46
- // Abstract data access logic
47
- interface MarketRepository {
48
- findAll(filters?: MarketFilters): Promise<Market[]>
49
- findById(id: string): Promise<Market | null>
50
- create(data: CreateMarketDto): Promise<Market>
51
- update(id: string, data: UpdateMarketDto): Promise<Market>
52
- delete(id: string): Promise<void>
53
- }
54
-
55
- class SupabaseMarketRepository implements MarketRepository {
56
- async findAll(filters?: MarketFilters): Promise<Market[]> {
57
- let query = supabase.from('markets').select('*')
58
-
59
- if (filters?.status) {
60
- query = query.eq('status', filters.status)
61
- }
62
-
63
- if (filters?.limit) {
64
- query = query.limit(filters.limit)
65
- }
66
-
67
- const { data, error } = await query
68
-
69
- if (error) throw new Error(error.message)
70
- return data
71
- }
72
-
73
- // Other methods...
74
- }
75
- ```
76
-
77
- ### Service Layer Pattern
78
-
79
- ```typescript
80
- // Business logic separated from data access
81
- class MarketService {
82
- constructor(private marketRepo: MarketRepository) {}
83
-
84
- async searchMarkets(query: string, limit: number = 10): Promise<Market[]> {
85
- // Business logic
86
- const embedding = await generateEmbedding(query)
87
- const results = await this.vectorSearch(embedding, limit)
88
-
89
- // Fetch full data
90
- const markets = await this.marketRepo.findByIds(results.map(r => r.id))
91
-
92
- // Sort by similarity
93
- return markets.sort((a, b) => {
94
- const scoreA = results.find(r => r.id === a.id)?.score || 0
95
- const scoreB = results.find(r => r.id === b.id)?.score || 0
96
- return scoreA - scoreB
97
- })
98
- }
99
-
100
- private async vectorSearch(embedding: number[], limit: number) {
101
- // Vector search implementation
102
- }
103
- }
104
- ```
105
-
106
- ### Middleware Pattern
107
-
108
- ```typescript
109
- // Request/response processing pipeline
110
- export function withAuth(handler: NextApiHandler): NextApiHandler {
111
- return async (req, res) => {
112
- const token = req.headers.authorization?.replace('Bearer ', '')
113
-
114
- if (!token) {
115
- return res.status(401).json({ error: 'Unauthorized' })
116
- }
117
-
118
- try {
119
- const user = await verifyToken(token)
120
- req.user = user
121
- return handler(req, res)
122
- } catch (error) {
123
- return res.status(401).json({ error: 'Invalid token' })
124
- }
125
- }
126
- }
127
-
128
- // Usage
129
- export default withAuth(async (req, res) => {
130
- // Handler has access to req.user
131
- })
132
- ```
133
-
134
- ## Database Patterns
135
-
136
- ### Query Optimization
137
-
138
- ```typescript
139
- // PASS: GOOD: Select only needed columns
140
- const { data } = await supabase
141
- .from('markets')
142
- .select('id, name, status, volume')
143
- .eq('status', 'active')
144
- .order('volume', { ascending: false })
145
- .limit(10)
146
-
147
- // FAIL: BAD: Select everything
148
- const { data } = await supabase
149
- .from('markets')
150
- .select('*')
151
- ```
152
-
153
- ### N+1 Query Prevention
154
-
155
- ```typescript
156
- // FAIL: BAD: N+1 query problem
157
- const markets = await getMarkets()
158
- for (const market of markets) {
159
- market.creator = await getUser(market.creator_id) // N queries
160
- }
161
-
162
- // PASS: GOOD: Batch fetch
163
- const markets = await getMarkets()
164
- const creatorIds = markets.map(m => m.creator_id)
165
- const creators = await getUsers(creatorIds) // 1 query
166
- const creatorMap = new Map(creators.map(c => [c.id, c]))
167
-
168
- markets.forEach(market => {
169
- market.creator = creatorMap.get(market.creator_id)
170
- })
171
- ```
172
-
173
- ### Transaction Pattern
174
-
175
- ```typescript
176
- async function createMarketWithPosition(
177
- marketData: CreateMarketDto,
178
- positionData: CreatePositionDto
179
- ) {
180
- // Use Supabase transaction
181
- const { data, error } = await supabase.rpc('create_market_with_position', {
182
- market_data: marketData,
183
- position_data: positionData
184
- })
185
-
186
- if (error) throw new Error('Transaction failed')
187
- return data
188
- }
189
-
190
- // SQL function in Supabase
191
- CREATE OR REPLACE FUNCTION create_market_with_position(
192
- market_data jsonb,
193
- position_data jsonb
194
- )
195
- RETURNS jsonb
196
- LANGUAGE plpgsql
197
- AS $$
198
- BEGIN
199
- -- Start transaction automatically
200
- INSERT INTO markets VALUES (market_data);
201
- INSERT INTO positions VALUES (position_data);
202
- RETURN jsonb_build_object('success', true);
203
- EXCEPTION
204
- WHEN OTHERS THEN
205
- -- Rollback happens automatically
206
- RETURN jsonb_build_object('success', false, 'error', SQLERRM);
207
- END;
208
- $$;
209
- ```
210
-
211
- ## Caching Strategies
212
-
213
- ### Redis Caching Layer
214
-
215
- ```typescript
216
- class CachedMarketRepository implements MarketRepository {
217
- constructor(
218
- private baseRepo: MarketRepository,
219
- private redis: RedisClient
220
- ) {}
221
-
222
- async findById(id: string): Promise<Market | null> {
223
- // Check cache first
224
- const cached = await this.redis.get(`market:${id}`)
225
-
226
- if (cached) {
227
- return JSON.parse(cached)
228
- }
229
-
230
- // Cache miss - fetch from database
231
- const market = await this.baseRepo.findById(id)
232
-
233
- if (market) {
234
- // Cache for 5 minutes
235
- await this.redis.setex(`market:${id}`, 300, JSON.stringify(market))
236
- }
237
-
238
- return market
239
- }
240
-
241
- async invalidateCache(id: string): Promise<void> {
242
- await this.redis.del(`market:${id}`)
243
- }
244
- }
245
- ```
246
-
247
- ### Cache-Aside Pattern
248
-
249
- ```typescript
250
- async function getMarketWithCache(id: string): Promise<Market> {
251
- const cacheKey = `market:${id}`
252
-
253
- // Try cache
254
- const cached = await redis.get(cacheKey)
255
- if (cached) return JSON.parse(cached)
256
-
257
- // Cache miss - fetch from DB
258
- const market = await db.markets.findUnique({ where: { id } })
259
-
260
- if (!market) throw new Error('Market not found')
261
-
262
- // Update cache
263
- await redis.setex(cacheKey, 300, JSON.stringify(market))
264
-
265
- return market
266
- }
267
- ```
268
-
269
- ## Error Handling Patterns
270
-
271
- ### Centralized Error Handler
272
-
273
- ```typescript
274
- class ApiError extends Error {
275
- constructor(
276
- public statusCode: number,
277
- public message: string,
278
- public isOperational = true
279
- ) {
280
- super(message)
281
- Object.setPrototypeOf(this, ApiError.prototype)
282
- }
283
- }
284
-
285
- export function errorHandler(error: unknown, req: Request): Response {
286
- if (error instanceof ApiError) {
287
- return NextResponse.json({
288
- success: false,
289
- error: error.message
290
- }, { status: error.statusCode })
291
- }
292
-
293
- if (error instanceof z.ZodError) {
294
- return NextResponse.json({
295
- success: false,
296
- error: 'Validation failed',
297
- details: error.errors
298
- }, { status: 400 })
299
- }
300
-
301
- // Log unexpected errors
302
- console.error('Unexpected error:', error)
303
-
304
- return NextResponse.json({
305
- success: false,
306
- error: 'Internal server error'
307
- }, { status: 500 })
308
- }
309
-
310
- // Usage
311
- export async function GET(request: Request) {
312
- try {
313
- const data = await fetchData()
314
- return NextResponse.json({ success: true, data })
315
- } catch (error) {
316
- return errorHandler(error, request)
317
- }
318
- }
319
- ```
320
-
321
- ### Retry with Exponential Backoff
322
-
323
- ```typescript
324
- async function fetchWithRetry<T>(
325
- fn: () => Promise<T>,
326
- maxRetries = 3
327
- ): Promise<T> {
328
- let lastError: Error
329
-
330
- for (let i = 0; i < maxRetries; i++) {
331
- try {
332
- return await fn()
333
- } catch (error) {
334
- lastError = error as Error
335
-
336
- if (i < maxRetries - 1) {
337
- // Exponential backoff: 1s, 2s, 4s
338
- const delay = Math.pow(2, i) * 1000
339
- await new Promise(resolve => setTimeout(resolve, delay))
340
- }
341
- }
342
- }
343
-
344
- throw lastError!
345
- }
346
-
347
- // Usage
348
- const data = await fetchWithRetry(() => fetchFromAPI())
349
- ```
350
-
351
- ## Authentication & Authorization
352
-
353
- ### JWT Token Validation
354
-
355
- ```typescript
356
- import jwt from 'jsonwebtoken'
357
-
358
- interface JWTPayload {
359
- userId: string
360
- email: string
361
- role: 'admin' | 'user'
362
- }
363
-
364
- export function verifyToken(token: string): JWTPayload {
365
- try {
366
- const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload
367
- return payload
368
- } catch (error) {
369
- throw new ApiError(401, 'Invalid token')
370
- }
371
- }
372
-
373
- export async function requireAuth(request: Request) {
374
- const token = request.headers.get('authorization')?.replace('Bearer ', '')
375
-
376
- if (!token) {
377
- throw new ApiError(401, 'Missing authorization token')
378
- }
379
-
380
- return verifyToken(token)
381
- }
382
-
383
- // Usage in API route
384
- export async function GET(request: Request) {
385
- const user = await requireAuth(request)
386
-
387
- const data = await getDataForUser(user.userId)
388
-
389
- return NextResponse.json({ success: true, data })
390
- }
391
- ```
392
-
393
- ### Role-Based Access Control
394
-
395
- ```typescript
396
- type Permission = 'read' | 'write' | 'delete' | 'admin'
397
-
398
- interface User {
399
- id: string
400
- role: 'admin' | 'moderator' | 'user'
401
- }
402
-
403
- const rolePermissions: Record<User['role'], Permission[]> = {
404
- admin: ['read', 'write', 'delete', 'admin'],
405
- moderator: ['read', 'write', 'delete'],
406
- user: ['read', 'write']
407
- }
408
-
409
- export function hasPermission(user: User, permission: Permission): boolean {
410
- return rolePermissions[user.role].includes(permission)
411
- }
412
-
413
- export function requirePermission(permission: Permission) {
414
- return (handler: (request: Request, user: User) => Promise<Response>) => {
415
- return async (request: Request) => {
416
- const user = await requireAuth(request)
417
-
418
- if (!hasPermission(user, permission)) {
419
- throw new ApiError(403, 'Insufficient permissions')
420
- }
421
-
422
- return handler(request, user)
423
- }
424
- }
425
- }
426
-
427
- // Usage - HOF wraps the handler
428
- export const DELETE = requirePermission('delete')(
429
- async (request: Request, user: User) => {
430
- // Handler receives authenticated user with verified permission
431
- return new Response('Deleted', { status: 200 })
432
- }
433
- )
434
- ```
435
-
436
- ## Rate Limiting
437
-
438
- ### Simple In-Memory Rate Limiter
439
-
440
- ```typescript
441
- class RateLimiter {
442
- private requests = new Map<string, number[]>()
443
-
444
- async checkLimit(
445
- identifier: string,
446
- maxRequests: number,
447
- windowMs: number
448
- ): Promise<boolean> {
449
- const now = Date.now()
450
- const requests = this.requests.get(identifier) || []
451
-
452
- // Remove old requests outside window
453
- const recentRequests = requests.filter(time => now - time < windowMs)
454
-
455
- if (recentRequests.length >= maxRequests) {
456
- return false // Rate limit exceeded
457
- }
458
-
459
- // Add current request
460
- recentRequests.push(now)
461
- this.requests.set(identifier, recentRequests)
462
-
463
- return true
464
- }
465
- }
466
-
467
- const limiter = new RateLimiter()
468
-
469
- export async function GET(request: Request) {
470
- const ip = request.headers.get('x-forwarded-for') || 'unknown'
471
-
472
- const allowed = await limiter.checkLimit(ip, 100, 60000) // 100 req/min
473
-
474
- if (!allowed) {
475
- return NextResponse.json({
476
- error: 'Rate limit exceeded'
477
- }, { status: 429 })
478
- }
479
-
480
- // Continue with request
481
- }
482
- ```
483
-
484
- ## Background Jobs & Queues
485
-
486
- ### Simple Queue Pattern
487
-
488
- ```typescript
489
- class JobQueue<T> {
490
- private queue: T[] = []
491
- private processing = false
492
-
493
- async add(job: T): Promise<void> {
494
- this.queue.push(job)
495
-
496
- if (!this.processing) {
497
- this.process()
498
- }
499
- }
500
-
501
- private async process(): Promise<void> {
502
- this.processing = true
503
-
504
- while (this.queue.length > 0) {
505
- const job = this.queue.shift()!
506
-
507
- try {
508
- await this.execute(job)
509
- } catch (error) {
510
- console.error('Job failed:', error)
511
- }
512
- }
513
-
514
- this.processing = false
515
- }
516
-
517
- private async execute(job: T): Promise<void> {
518
- // Job execution logic
519
- }
520
- }
521
-
522
- // Usage for indexing markets
523
- interface IndexJob {
524
- marketId: string
525
- }
526
-
527
- const indexQueue = new JobQueue<IndexJob>()
528
-
529
- export async function POST(request: Request) {
530
- const { marketId } = await request.json()
531
-
532
- // Add to queue instead of blocking
533
- await indexQueue.add({ marketId })
534
-
535
- return NextResponse.json({ success: true, message: 'Job queued' })
536
- }
537
- ```
538
-
539
- ## Logging & Monitoring
540
-
541
- ### Structured Logging
542
-
543
- ```typescript
544
- interface LogContext {
545
- userId?: string
546
- requestId?: string
547
- method?: string
548
- path?: string
549
- [key: string]: unknown
550
- }
551
-
552
- class Logger {
553
- log(level: 'info' | 'warn' | 'error', message: string, context?: LogContext) {
554
- const entry = {
555
- timestamp: new Date().toISOString(),
556
- level,
557
- message,
558
- ...context
559
- }
560
-
561
- console.log(JSON.stringify(entry))
562
- }
563
-
564
- info(message: string, context?: LogContext) {
565
- this.log('info', message, context)
566
- }
567
-
568
- warn(message: string, context?: LogContext) {
569
- this.log('warn', message, context)
570
- }
571
-
572
- error(message: string, error: Error, context?: LogContext) {
573
- this.log('error', message, {
574
- ...context,
575
- error: error.message,
576
- stack: error.stack
577
- })
578
- }
579
- }
580
-
581
- const logger = new Logger()
582
-
583
- // Usage
584
- export async function GET(request: Request) {
585
- const requestId = crypto.randomUUID()
586
-
587
- logger.info('Fetching markets', {
588
- requestId,
589
- method: 'GET',
590
- path: '/api/markets'
591
- })
592
-
593
- try {
594
- const markets = await fetchMarkets()
595
- return NextResponse.json({ success: true, data: markets })
596
- } catch (error) {
597
- logger.error('Failed to fetch markets', error as Error, { requestId })
598
- return NextResponse.json({ error: 'Internal error' }, { status: 500 })
599
- }
600
- }
601
- ```
602
-
603
- **Remember**: Backend patterns enable scalable, maintainable server-side applications. Choose patterns that fit your complexity level.
@@ -1,65 +0,0 @@
1
- ---
2
- name: tas-conventions
3
- description: |
4
- Coding conventions và naming rules của dự án Torus.
5
- Auto-invoke khi viết code mới, review code, refactor,
6
- hoặc khi user hỏi về coding standards.
7
- allowed-tools: Read, Grep, Glob
8
- ---
9
-
10
- # TAS Conventions
11
-
12
- Khi generate hoặc review code, PHẢI tuân thủ conventions được định nghĩa trong `CLAUDE.md` của project.
13
-
14
- ## When to Use
15
-
16
- - Trước khi generate code mới (check conventions)
17
- - Khi review code của user (verify compliance)
18
- - Khi user hỏi "đặt tên thế nào?", "format như thế nào?"
19
- - KHÔNG invoke khi: đọc file thuần, không liên quan đến code output
20
-
21
- ## Always / Ask / Never
22
-
23
- | | Hành động |
24
- |---|---|
25
- | **Always** | Đọc `CLAUDE.md` trước khi áp dụng convention |
26
- | **Always** | Chỉ ra file:line cụ thể khi phát hiện vi phạm |
27
- | **Ask** | Khi convention trong CLAUDE.md mơ hồ hoặc có conflict |
28
- | **Never** | Hardcode convention (naming, format) mà không đọc CLAUDE.md trước |
29
- | **Never** | Áp dụng convention từ project khác vào project hiện tại |
30
-
31
- ## Checklist
32
-
33
- - Đọc `CLAUDE.md` để lấy naming conventions, branching, commit format, stack rules
34
- - Enforce các conventions đó trong code output
35
- - Nếu code vi phạm conventions, chỉ ra cụ thể: file:line + convention bị vi phạm + cách sửa
36
-
37
- ## Common Conventions (Default — override bằng CLAUDE.md)
38
-
39
- Các conventions mặc định này chỉ áp dụng khi `CLAUDE.md` không định nghĩa khác:
40
-
41
- - Variables/functions: `camelCase`
42
- - Types/Interfaces/Components: `PascalCase`
43
- - Constants: `UPPER_SNAKE_CASE`
44
- - Boolean vars: prefix `is`, `has`, `should`, `can`
45
- - File naming: kebab-case cho files, PascalCase cho components
46
- - Commit format: `<type>: <description>` (feat, fix, refactor, docs, test, chore)
47
-
48
- ## Red Flags
49
-
50
- - Magic numbers trong code (e.g. `if (count > 50)`) → phải dùng named constant
51
- - Deep nesting >4 levels → dùng early return hoặc extract method
52
- - Function >50 lines → extract thành functions nhỏ hơn
53
- - File >800 lines → extract thành modules
54
- - Variable tên 1-2 ký tự (`x`, `t`, `d`) trong production code → đặt tên mô tả
55
- - `any` type trong TypeScript → dùng type cụ thể hoặc generic
56
- - Commented-out code block lớn → xóa nếu không cần, dùng git history thay thế
57
-
58
- ## Verification
59
-
60
- - [ ] CLAUDE.md đã được đọc trước khi review/generate code
61
- - [ ] Naming tuân thủ conventions trong CLAUDE.md
62
- - [ ] Không có magic numbers
63
- - [ ] Không có deep nesting (>4 levels)
64
- - [ ] Functions < 50 lines, files < 800 lines
65
- - [ ] Commit message theo format đã định nghĩa