@prmichaelsen/acp-visualizer 0.1.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 (180) hide show
  1. package/README.md +68 -0
  2. package/agent/commands/acp.clarification-address.md +417 -0
  3. package/agent/commands/acp.clarification-capture.md +386 -0
  4. package/agent/commands/acp.clarification-create.md +437 -0
  5. package/agent/commands/acp.clarifications-research.md +326 -0
  6. package/agent/commands/acp.command-create.md +432 -0
  7. package/agent/commands/acp.design-create.md +286 -0
  8. package/agent/commands/acp.design-reference.md +355 -0
  9. package/agent/commands/acp.handoff.md +270 -0
  10. package/agent/commands/acp.index.md +423 -0
  11. package/agent/commands/acp.init.md +546 -0
  12. package/agent/commands/acp.package-create.md +895 -0
  13. package/agent/commands/acp.package-info.md +212 -0
  14. package/agent/commands/acp.package-install.md +539 -0
  15. package/agent/commands/acp.package-list.md +280 -0
  16. package/agent/commands/acp.package-publish.md +541 -0
  17. package/agent/commands/acp.package-remove.md +293 -0
  18. package/agent/commands/acp.package-search.md +307 -0
  19. package/agent/commands/acp.package-update.md +361 -0
  20. package/agent/commands/acp.package-validate.md +540 -0
  21. package/agent/commands/acp.pattern-create.md +386 -0
  22. package/agent/commands/acp.plan.md +587 -0
  23. package/agent/commands/acp.proceed.md +882 -0
  24. package/agent/commands/acp.project-create.md +675 -0
  25. package/agent/commands/acp.project-info.md +312 -0
  26. package/agent/commands/acp.project-list.md +226 -0
  27. package/agent/commands/acp.project-remove.md +379 -0
  28. package/agent/commands/acp.project-set.md +227 -0
  29. package/agent/commands/acp.project-update.md +307 -0
  30. package/agent/commands/acp.projects-restore.md +228 -0
  31. package/agent/commands/acp.projects-sync.md +347 -0
  32. package/agent/commands/acp.report.md +407 -0
  33. package/agent/commands/acp.resume.md +239 -0
  34. package/agent/commands/acp.sessions.md +301 -0
  35. package/agent/commands/acp.status.md +293 -0
  36. package/agent/commands/acp.sync.md +364 -0
  37. package/agent/commands/acp.task-create.md +500 -0
  38. package/agent/commands/acp.update.md +302 -0
  39. package/agent/commands/acp.validate.md +466 -0
  40. package/agent/commands/acp.version-check-for-updates.md +276 -0
  41. package/agent/commands/acp.version-check.md +191 -0
  42. package/agent/commands/acp.version-update.md +289 -0
  43. package/agent/commands/command.template.md +339 -0
  44. package/agent/commands/git.commit.md +526 -0
  45. package/agent/commands/git.init.md +514 -0
  46. package/agent/commands/tanstack-cloudflare.deploy.md +272 -0
  47. package/agent/commands/tanstack-cloudflare.tail.md +275 -0
  48. package/agent/design/.gitkeep +0 -0
  49. package/agent/design/design.template.md +154 -0
  50. package/agent/design/local.dashboard-layout-routing.md +288 -0
  51. package/agent/design/local.data-model-yaml-parsing.md +310 -0
  52. package/agent/design/local.search-filtering.md +331 -0
  53. package/agent/design/local.server-api-auto-refresh.md +235 -0
  54. package/agent/design/local.table-tree-views.md +299 -0
  55. package/agent/design/local.visualizer-requirements.md +349 -0
  56. package/agent/design/requirements.template.md +387 -0
  57. package/agent/index/.gitkeep +0 -0
  58. package/agent/index/acp.core.yaml +137 -0
  59. package/agent/index/local.main.template.yaml +37 -0
  60. package/agent/manifest.template.yaml +13 -0
  61. package/agent/manifest.yaml +302 -0
  62. package/agent/milestones/.gitkeep +0 -0
  63. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +67 -0
  64. package/agent/milestones/milestone-1-{title}.template.md +206 -0
  65. package/agent/milestones/milestone-2-dashboard-views-interaction.md +79 -0
  66. package/agent/package.template.yaml +86 -0
  67. package/agent/patterns/.gitkeep +0 -0
  68. package/agent/patterns/bootstrap.template.md +1237 -0
  69. package/agent/patterns/pattern.template.md +382 -0
  70. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +332 -0
  71. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +416 -0
  72. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +401 -0
  73. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +387 -0
  74. package/agent/patterns/tanstack-cloudflare.card-and-list.md +271 -0
  75. package/agent/patterns/tanstack-cloudflare.chat-engine.md +353 -0
  76. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +346 -0
  77. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +516 -0
  78. package/agent/patterns/tanstack-cloudflare.email-service.md +431 -0
  79. package/agent/patterns/tanstack-cloudflare.expander.md +98 -0
  80. package/agent/patterns/tanstack-cloudflare.fcm-push.md +115 -0
  81. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +441 -0
  82. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +348 -0
  83. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +550 -0
  84. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +369 -0
  85. package/agent/patterns/tanstack-cloudflare.form-controls.md +145 -0
  86. package/agent/patterns/tanstack-cloudflare.global-search-context.md +93 -0
  87. package/agent/patterns/tanstack-cloudflare.image-carousel.md +126 -0
  88. package/agent/patterns/tanstack-cloudflare.library-services.md +553 -0
  89. package/agent/patterns/tanstack-cloudflare.lightbox.md +169 -0
  90. package/agent/patterns/tanstack-cloudflare.markdown-content.md +115 -0
  91. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +98 -0
  92. package/agent/patterns/tanstack-cloudflare.modal.md +156 -0
  93. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +461 -0
  94. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +151 -0
  95. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +90 -0
  96. package/agent/patterns/tanstack-cloudflare.og-metadata.md +296 -0
  97. package/agent/patterns/tanstack-cloudflare.pagination.md +442 -0
  98. package/agent/patterns/tanstack-cloudflare.pill-input.md +220 -0
  99. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +401 -0
  100. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +323 -0
  101. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +338 -0
  102. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +375 -0
  103. package/agent/patterns/tanstack-cloudflare.slide-over.md +129 -0
  104. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +571 -0
  105. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +508 -0
  106. package/agent/patterns/tanstack-cloudflare.toast-system.md +142 -0
  107. package/agent/patterns/tanstack-cloudflare.unified-header.md +280 -0
  108. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +628 -0
  109. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +237 -0
  110. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +358 -0
  111. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +336 -0
  112. package/agent/progress.template.yaml +161 -0
  113. package/agent/progress.yaml +145 -0
  114. package/agent/schemas/package.schema.yaml +276 -0
  115. package/agent/scripts/acp.common.sh +1781 -0
  116. package/agent/scripts/acp.install.sh +333 -0
  117. package/agent/scripts/acp.package-create.sh +924 -0
  118. package/agent/scripts/acp.package-info.sh +288 -0
  119. package/agent/scripts/acp.package-install.sh +893 -0
  120. package/agent/scripts/acp.package-list.sh +311 -0
  121. package/agent/scripts/acp.package-publish.sh +420 -0
  122. package/agent/scripts/acp.package-remove.sh +348 -0
  123. package/agent/scripts/acp.package-search.sh +156 -0
  124. package/agent/scripts/acp.package-update.sh +517 -0
  125. package/agent/scripts/acp.package-validate.sh +1018 -0
  126. package/agent/scripts/acp.uninstall.sh +85 -0
  127. package/agent/scripts/acp.version-check-for-updates.sh +98 -0
  128. package/agent/scripts/acp.version-check.sh +47 -0
  129. package/agent/scripts/acp.version-update.sh +176 -0
  130. package/agent/scripts/acp.yaml-parser.sh +985 -0
  131. package/agent/scripts/acp.yaml-validate.sh +205 -0
  132. package/agent/tasks/.gitkeep +0 -0
  133. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +210 -0
  134. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +294 -0
  135. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +193 -0
  136. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +262 -0
  137. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +156 -0
  138. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +178 -0
  139. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +141 -0
  140. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +153 -0
  141. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +174 -0
  142. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +233 -0
  143. package/agent/tasks/task-1-{title}.template.md +244 -0
  144. package/bin/visualize.mjs +84 -0
  145. package/package.json +48 -0
  146. package/src/components/ExtraFieldsBadge.tsx +15 -0
  147. package/src/components/FilterBar.tsx +33 -0
  148. package/src/components/Header.tsx +23 -0
  149. package/src/components/MilestoneTable.tsx +167 -0
  150. package/src/components/MilestoneTree.tsx +84 -0
  151. package/src/components/ProgressBar.tsx +20 -0
  152. package/src/components/SearchInput.tsx +22 -0
  153. package/src/components/Sidebar.tsx +54 -0
  154. package/src/components/StatusBadge.tsx +23 -0
  155. package/src/components/StatusDot.tsx +12 -0
  156. package/src/components/TaskList.tsx +36 -0
  157. package/src/components/ViewToggle.tsx +31 -0
  158. package/src/lib/config.ts +8 -0
  159. package/src/lib/file-watcher.ts +43 -0
  160. package/src/lib/search.ts +48 -0
  161. package/src/lib/types.ts +73 -0
  162. package/src/lib/useAutoRefresh.ts +31 -0
  163. package/src/lib/useCollapse.ts +31 -0
  164. package/src/lib/useFilteredData.ts +55 -0
  165. package/src/lib/yaml-loader-real.spec.ts +47 -0
  166. package/src/lib/yaml-loader.spec.ts +201 -0
  167. package/src/lib/yaml-loader.ts +265 -0
  168. package/src/routeTree.gen.ts +140 -0
  169. package/src/router.tsx +10 -0
  170. package/src/routes/__root.tsx +75 -0
  171. package/src/routes/api/watch.ts +29 -0
  172. package/src/routes/index.tsx +115 -0
  173. package/src/routes/milestones.tsx +50 -0
  174. package/src/routes/search.tsx +84 -0
  175. package/src/routes/tasks.tsx +63 -0
  176. package/src/services/progress-database.service.ts +46 -0
  177. package/src/styles.css +25 -0
  178. package/tsconfig.json +24 -0
  179. package/vite.config.ts +16 -0
  180. package/vitest.config.ts +27 -0
@@ -0,0 +1,401 @@
1
+ # API Route Handlers Pattern
2
+
3
+ **Category**: Architecture
4
+ **Applicable To**: TanStack Start + Cloudflare Workers applications with REST API endpoints
5
+ **Status**: Stable
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ TanStack Start provides file-based API routing where each file in `src/routes/api/` becomes an HTTP endpoint. This pattern documents the standard approach for creating authenticated, type-safe API routes that delegate to service layers and return proper JSON responses with consistent error handling.
12
+
13
+ API routes use `createFileRoute` with the `server.handlers` configuration to define HTTP method handlers (GET, POST, PATCH, DELETE) that run exclusively on the server. Each handler follows a consistent structure: authenticate, validate, delegate to service, return response.
14
+
15
+ ---
16
+
17
+ ## When to Use This Pattern
18
+
19
+ ✅ **Use this pattern when:**
20
+ - Building REST API endpoints consumed by client-side services
21
+ - Need server-side authentication enforcement
22
+ - Creating CRUD operations for domain entities
23
+ - Building endpoints consumed by external clients or webhooks
24
+ - Need consistent error handling and response formats
25
+
26
+ ❌ **Don't use this pattern when:**
27
+ - Building real-time features (use Durable Objects WebSocket instead)
28
+ - Server functions (`createServerFn`) are sufficient for the use case
29
+ - The endpoint is purely for SSR data preloading (use `beforeLoad` instead)
30
+
31
+ ---
32
+
33
+ ## Core Principles
34
+
35
+ 1. **Auth First**: Every handler starts with authentication check
36
+ 2. **Service Delegation**: Handlers delegate to database services, never access DB directly
37
+ 3. **Consistent Responses**: All responses use `new Response(JSON.stringify(...))` with proper headers
38
+ 4. **Error Boundaries**: Every handler wrapped in try/catch with consistent error response format
39
+ 5. **File-Based Routing**: Route path derived from file location in `src/routes/api/`
40
+ 6. **HTTP Method Handlers**: Use `server.handlers` with explicit GET/POST/PATCH/DELETE
41
+
42
+ ---
43
+
44
+ ## Implementation
45
+
46
+ ### Structure
47
+
48
+ ```
49
+ src/routes/api/
50
+ ├── conversations/
51
+ │ ├── index.tsx # GET /api/conversations (list)
52
+ │ ├── create.tsx # POST /api/conversations/create
53
+ │ └── $id/
54
+ │ ├── index.tsx # GET/PATCH/DELETE /api/conversations/:id
55
+ │ └── messages.tsx # GET /api/conversations/:id/messages
56
+ ├── groups/
57
+ │ ├── index.tsx # GET /api/groups
58
+ │ ├── create.tsx # POST /api/groups/create
59
+ │ └── $id/
60
+ │ ├── index.tsx # GET/PATCH/DELETE /api/groups/:id
61
+ │ └── members/
62
+ │ └── $userId.tsx # POST/DELETE /api/groups/:id/members/:userId
63
+ ├── auth/
64
+ │ ├── session.tsx # POST /api/auth/session (create session)
65
+ │ └── logout.tsx # POST /api/auth/logout
66
+ └── storage/
67
+ └── upload.tsx # POST /api/storage/upload
68
+ ```
69
+
70
+ ### Code Example
71
+
72
+ #### Standard GET Handler (List)
73
+
74
+ ```typescript
75
+ // src/routes/api/groups/index.tsx
76
+ import { createFileRoute } from '@tanstack/react-router'
77
+ import { getAuthSession } from '@/lib/auth/server-fn'
78
+ import { GroupConversationDatabaseService } from '@/services/group-conversation-database.service'
79
+ import { initFirebaseAdmin } from '@/lib/firebase-admin'
80
+
81
+ export const Route = createFileRoute('/api/groups/')({
82
+ server: {
83
+ handlers: {
84
+ GET: async () => {
85
+ initFirebaseAdmin()
86
+
87
+ try {
88
+ // 1. Authenticate
89
+ const user = await getAuthSession()
90
+ if (!user) {
91
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), {
92
+ status: 401,
93
+ headers: { 'Content-Type': 'application/json' },
94
+ })
95
+ }
96
+
97
+ // 2. Delegate to service
98
+ const groups = await GroupConversationDatabaseService.listGroupConversations(user.uid)
99
+
100
+ // 3. Return success response
101
+ return new Response(JSON.stringify({ groups }), {
102
+ status: 200,
103
+ headers: { 'Content-Type': 'application/json' },
104
+ })
105
+ } catch (error) {
106
+ // 4. Handle errors consistently
107
+ console.error('[API] Error listing groups:', error)
108
+ return new Response(JSON.stringify({
109
+ error: 'Internal server error',
110
+ message: error instanceof Error ? error.message : 'Unknown error',
111
+ }), {
112
+ status: 500,
113
+ headers: { 'Content-Type': 'application/json' },
114
+ })
115
+ }
116
+ },
117
+ },
118
+ },
119
+ })
120
+ ```
121
+
122
+ #### Standard POST Handler (Create)
123
+
124
+ ```typescript
125
+ // src/routes/api/groups/create.tsx
126
+ import { createFileRoute } from '@tanstack/react-router'
127
+ import { getAuthSession } from '@/lib/auth/server-fn'
128
+ import { GroupConversationDatabaseService } from '@/services/group-conversation-database.service'
129
+ import { CreateGroupSchema } from '@/schemas/group-conversation'
130
+
131
+ export const Route = createFileRoute('/api/groups/create')({
132
+ server: {
133
+ handlers: {
134
+ POST: async ({ request }) => {
135
+ initFirebaseAdmin()
136
+
137
+ try {
138
+ const user = await getAuthSession()
139
+ if (!user) {
140
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), {
141
+ status: 401,
142
+ headers: { 'Content-Type': 'application/json' },
143
+ })
144
+ }
145
+
146
+ // Parse and validate body
147
+ const body = await request.json()
148
+ const parsed = CreateGroupSchema.safeParse(body)
149
+
150
+ if (!parsed.success) {
151
+ return new Response(JSON.stringify({
152
+ error: 'Validation error',
153
+ details: parsed.error.issues,
154
+ }), {
155
+ status: 400,
156
+ headers: { 'Content-Type': 'application/json' },
157
+ })
158
+ }
159
+
160
+ // Delegate to service
161
+ const group = await GroupConversationDatabaseService.createGroupConversation(
162
+ user.uid,
163
+ parsed.data
164
+ )
165
+
166
+ return new Response(JSON.stringify({ group }), {
167
+ status: 201,
168
+ headers: { 'Content-Type': 'application/json' },
169
+ })
170
+ } catch (error) {
171
+ console.error('[API] Error creating group:', error)
172
+ return new Response(JSON.stringify({
173
+ error: 'Internal server error',
174
+ message: error instanceof Error ? error.message : 'Unknown error',
175
+ }), {
176
+ status: 500,
177
+ headers: { 'Content-Type': 'application/json' },
178
+ })
179
+ }
180
+ },
181
+ },
182
+ },
183
+ })
184
+ ```
185
+
186
+ #### Dynamic Route Parameters
187
+
188
+ ```typescript
189
+ // src/routes/api/groups/$id/index.tsx
190
+ import { createFileRoute } from '@tanstack/react-router'
191
+
192
+ export const Route = createFileRoute('/api/groups/$id/')({
193
+ server: {
194
+ handlers: {
195
+ GET: async ({ params }) => {
196
+ const { id } = params // Group ID from URL
197
+
198
+ const user = await getAuthSession()
199
+ if (!user) {
200
+ return new Response(JSON.stringify({ error: 'Unauthorized' }), {
201
+ status: 401,
202
+ headers: { 'Content-Type': 'application/json' },
203
+ })
204
+ }
205
+
206
+ const group = await GroupConversationDatabaseService.getGroupConversation(user.uid, id)
207
+
208
+ if (!group) {
209
+ return new Response(JSON.stringify({ error: 'Not found' }), {
210
+ status: 404,
211
+ headers: { 'Content-Type': 'application/json' },
212
+ })
213
+ }
214
+
215
+ return new Response(JSON.stringify({ group }), {
216
+ status: 200,
217
+ headers: { 'Content-Type': 'application/json' },
218
+ })
219
+ },
220
+
221
+ PATCH: async ({ params, request }) => {
222
+ const { id } = params
223
+ // ... update logic
224
+ },
225
+
226
+ DELETE: async ({ params }) => {
227
+ const { id } = params
228
+ // ... delete logic
229
+ },
230
+ },
231
+ },
232
+ })
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Response Format Convention
238
+
239
+ ### Success Responses
240
+
241
+ ```typescript
242
+ // List operations: wrap in plural key
243
+ return Response.json({ groups }) // 200
244
+ return Response.json({ conversations }) // 200
245
+
246
+ // Single entity operations
247
+ return Response.json({ group }) // 200 (get/update)
248
+ return Response.json({ group }) // 201 (create)
249
+
250
+ // Delete operations
251
+ return Response.json({ success: true }) // 200
252
+ ```
253
+
254
+ ### Error Responses
255
+
256
+ ```typescript
257
+ // Authentication
258
+ return Response.json({ error: 'Unauthorized' }, { status: 401 })
259
+
260
+ // Validation
261
+ return Response.json({
262
+ error: 'Validation error',
263
+ details: zodError.issues
264
+ }, { status: 400 })
265
+
266
+ // Not found
267
+ return Response.json({ error: 'Not found' }, { status: 404 })
268
+
269
+ // Forbidden
270
+ return Response.json({ error: 'Forbidden' }, { status: 403 })
271
+
272
+ // Rate limited
273
+ return Response.json({
274
+ error: 'Too many requests',
275
+ retryAfter: 60
276
+ }, { status: 429 })
277
+
278
+ // Server error
279
+ return Response.json({
280
+ error: 'Internal server error',
281
+ message: error.message
282
+ }, { status: 500 })
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Benefits
288
+
289
+ ### 1. File-Based Discovery
290
+ API routes are discoverable by browsing `src/routes/api/`. The file path IS the URL path.
291
+
292
+ ### 2. Consistent Auth Pattern
293
+ Every handler starts with the same auth check, making security audits straightforward.
294
+
295
+ ### 3. Type-Safe Parameters
296
+ Dynamic route parameters (`$id`) are typed and extracted from `params`.
297
+
298
+ ### 4. Server-Only Execution
299
+ Handlers in `server.handlers` never run on the client, preventing accidental secret exposure.
300
+
301
+ ---
302
+
303
+ ## Trade-offs
304
+
305
+ ### 1. Verbose Response Construction
306
+ **Downside**: `new Response(JSON.stringify(...))` is verbose compared to frameworks with built-in helpers.
307
+ **Mitigation**: Create helper functions like `jsonResponse(data, status)` if desired.
308
+
309
+ ### 2. No Built-In Middleware
310
+ **Downside**: No middleware system for cross-cutting concerns (auth, logging, rate limiting).
311
+ **Mitigation**: Extract auth/validation into reusable functions called at the start of each handler.
312
+
313
+ ---
314
+
315
+ ## Anti-Patterns
316
+
317
+ ### ❌ Anti-Pattern 1: Direct Database Access in Route
318
+
319
+ ```typescript
320
+ // ❌ BAD: Direct Firestore call in route handler
321
+ GET: async () => {
322
+ const docs = await queryDocuments('groups', {}) // Direct DB access!
323
+ return Response.json({ groups: docs })
324
+ }
325
+
326
+ // ✅ GOOD: Delegate to service
327
+ GET: async () => {
328
+ const groups = await GroupDatabaseService.listGroups(user.uid)
329
+ return Response.json({ groups })
330
+ }
331
+ ```
332
+
333
+ ### ❌ Anti-Pattern 2: Missing Error Handler
334
+
335
+ ```typescript
336
+ // ❌ BAD: No try/catch — unhandled errors crash the worker
337
+ GET: async () => {
338
+ const user = await getAuthSession()
339
+ const groups = await service.listGroups(user.uid) // Could throw!
340
+ return Response.json({ groups })
341
+ }
342
+
343
+ // ✅ GOOD: Wrapped in try/catch
344
+ GET: async () => {
345
+ try {
346
+ const user = await getAuthSession()
347
+ const groups = await service.listGroups(user.uid)
348
+ return Response.json({ groups })
349
+ } catch (error) {
350
+ return Response.json({ error: 'Internal server error' }, { status: 500 })
351
+ }
352
+ }
353
+ ```
354
+
355
+ ### ❌ Anti-Pattern 3: Skipping Auth Check
356
+
357
+ ```typescript
358
+ // ❌ BAD: No authentication — anyone can access
359
+ GET: async () => {
360
+ const groups = await service.listGroups('some-user-id')
361
+ return Response.json({ groups })
362
+ }
363
+
364
+ // ✅ GOOD: Always authenticate first
365
+ GET: async () => {
366
+ const user = await getAuthSession()
367
+ if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 })
368
+ const groups = await service.listGroups(user.uid)
369
+ return Response.json({ groups })
370
+ }
371
+ ```
372
+
373
+ ---
374
+
375
+ ## Related Patterns
376
+
377
+ - **[Library Services Pattern](./tanstack-cloudflare.library-services.md)**: API routes delegate to database services
378
+ - **[Auth Session Management](./tanstack-cloudflare.auth-session-management.md)**: `getAuthSession()` used in every handler
379
+ - **[Zod Schema Validation](./tanstack-cloudflare.zod-schema-validation.md)**: Request body validation with Zod
380
+ - **[Rate Limiting](./tanstack-cloudflare.rate-limiting.md)**: Rate limit API endpoints
381
+
382
+ ---
383
+
384
+ ## Checklist for Implementation
385
+
386
+ - [ ] Route file uses `createFileRoute` with `server.handlers`
387
+ - [ ] Every handler starts with `getAuthSession()` check
388
+ - [ ] Request body validated with Zod `safeParse` for POST/PATCH
389
+ - [ ] All responses include `Content-Type: application/json` header
390
+ - [ ] Error responses use consistent `{ error, message? }` format
391
+ - [ ] Every handler wrapped in try/catch
392
+ - [ ] Dynamic route parameters accessed via `params`
393
+ - [ ] Database operations delegated to service layer
394
+ - [ ] Firebase Admin SDK initialized at handler start
395
+
396
+ ---
397
+
398
+ **Status**: Stable - Standard pattern for TanStack Start API endpoints
399
+ **Recommendation**: Use for all REST API endpoints in TanStack Start applications
400
+ **Last Updated**: 2026-02-28
401
+ **Contributors**: Patrick Michaelsen