@odvi/create-dtt-framework 0.1.3 → 0.1.6

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 (111) hide show
  1. package/dist/commands/create.d.ts.map +1 -1
  2. package/dist/commands/create.js +16 -13
  3. package/dist/commands/create.js.map +1 -1
  4. package/package.json +3 -2
  5. package/template/.env.example +106 -0
  6. package/template/components.json +22 -0
  7. package/template/docs/framework/01-overview.md +289 -0
  8. package/template/docs/framework/02-techstack.md +503 -0
  9. package/template/docs/framework/api-layer.md +681 -0
  10. package/template/docs/framework/clerk-authentication.md +649 -0
  11. package/template/docs/framework/cli-installation.md +564 -0
  12. package/template/docs/framework/deployment/ci-cd.md +907 -0
  13. package/template/docs/framework/deployment/digitalocean.md +991 -0
  14. package/template/docs/framework/deployment/domain-setup.md +972 -0
  15. package/template/docs/framework/deployment/environment-variables.md +862 -0
  16. package/template/docs/framework/deployment/monitoring.md +927 -0
  17. package/template/docs/framework/deployment/production-checklist.md +649 -0
  18. package/template/docs/framework/deployment/vercel.md +791 -0
  19. package/template/docs/framework/environment-variables.md +646 -0
  20. package/template/docs/framework/health-check-system.md +583 -0
  21. package/template/docs/framework/implementation.md +559 -0
  22. package/template/docs/framework/snowflake-integration.md +594 -0
  23. package/template/docs/framework/state-management.md +615 -0
  24. package/template/docs/framework/supabase-integration.md +582 -0
  25. package/template/docs/framework/testing-guide.md +544 -0
  26. package/template/docs/framework/what-did-i-miss.md +526 -0
  27. package/template/drizzle.config.ts +11 -0
  28. package/template/next.config.js +21 -0
  29. package/template/postcss.config.js +5 -0
  30. package/template/prettier.config.js +4 -0
  31. package/template/public/favicon.ico +0 -0
  32. package/template/src/app/(auth)/layout.tsx +4 -0
  33. package/template/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +10 -0
  34. package/template/src/app/(auth)/sign-up/[[...sign-up]]/page.tsx +10 -0
  35. package/template/src/app/(dashboard)/dashboard/page.tsx +8 -0
  36. package/template/src/app/(dashboard)/health/page.tsx +16 -0
  37. package/template/src/app/(dashboard)/layout.tsx +17 -0
  38. package/template/src/app/api/[[...route]]/route.ts +11 -0
  39. package/template/src/app/api/debug-files/route.ts +33 -0
  40. package/template/src/app/api/webhooks/clerk/route.ts +112 -0
  41. package/template/src/app/layout.tsx +28 -0
  42. package/template/src/app/page.tsx +12 -0
  43. package/template/src/app/providers.tsx +20 -0
  44. package/template/src/components/layouts/navbar.tsx +14 -0
  45. package/template/src/components/shared/loading-spinner.tsx +6 -0
  46. package/template/src/components/ui/badge.tsx +46 -0
  47. package/template/src/components/ui/button.tsx +62 -0
  48. package/template/src/components/ui/card.tsx +92 -0
  49. package/template/src/components/ui/collapsible.tsx +33 -0
  50. package/template/src/components/ui/scroll-area.tsx +58 -0
  51. package/template/src/components/ui/sheet.tsx +139 -0
  52. package/template/src/config/__tests__/env.test.ts +164 -0
  53. package/template/src/config/__tests__/site.test.ts +46 -0
  54. package/template/src/config/env.ts +36 -0
  55. package/template/src/config/site.ts +10 -0
  56. package/template/src/env.js +44 -0
  57. package/template/src/features/__tests__/health-check-config.test.ts +142 -0
  58. package/template/src/features/__tests__/health-check-types.test.ts +201 -0
  59. package/template/src/features/documentation/components/doc-sidebar.tsx +109 -0
  60. package/template/src/features/documentation/components/doc-viewer.tsx +70 -0
  61. package/template/src/features/documentation/index.tsx +92 -0
  62. package/template/src/features/documentation/utils/doc-loader.ts +177 -0
  63. package/template/src/features/health-check/components/health-dashboard.tsx +374 -0
  64. package/template/src/features/health-check/config.ts +71 -0
  65. package/template/src/features/health-check/index.ts +4 -0
  66. package/template/src/features/health-check/stores/health-store.ts +14 -0
  67. package/template/src/features/health-check/types.ts +18 -0
  68. package/template/src/hooks/__tests__/use-debounce.test.tsx +28 -0
  69. package/template/src/hooks/queries/use-health-checks.ts +16 -0
  70. package/template/src/hooks/utils/use-debounce.ts +20 -0
  71. package/template/src/lib/__tests__/utils.test.ts +52 -0
  72. package/template/src/lib/__tests__/validators.test.ts +114 -0
  73. package/template/src/lib/nextbank/client.ts +67 -0
  74. package/template/src/lib/snowflake/client.ts +102 -0
  75. package/template/src/lib/supabase/admin.ts +7 -0
  76. package/template/src/lib/supabase/client.ts +7 -0
  77. package/template/src/lib/supabase/server.ts +23 -0
  78. package/template/src/lib/utils.ts +6 -0
  79. package/template/src/lib/validators.ts +9 -0
  80. package/template/src/middleware.ts +22 -0
  81. package/template/src/server/api/index.ts +22 -0
  82. package/template/src/server/api/middleware/auth.ts +19 -0
  83. package/template/src/server/api/middleware/logger.ts +4 -0
  84. package/template/src/server/api/routes/health/clerk.ts +214 -0
  85. package/template/src/server/api/routes/health/database.ts +141 -0
  86. package/template/src/server/api/routes/health/edge-functions.ts +107 -0
  87. package/template/src/server/api/routes/health/framework.ts +48 -0
  88. package/template/src/server/api/routes/health/index.ts +102 -0
  89. package/template/src/server/api/routes/health/nextbank.ts +46 -0
  90. package/template/src/server/api/routes/health/snowflake.ts +83 -0
  91. package/template/src/server/api/routes/health/storage.ts +177 -0
  92. package/template/src/server/api/routes/users.ts +79 -0
  93. package/template/src/server/db/index.ts +17 -0
  94. package/template/src/server/db/queries/users.ts +8 -0
  95. package/template/src/server/db/schema/__tests__/health-checks.test.ts +31 -0
  96. package/template/src/server/db/schema/__tests__/users.test.ts +46 -0
  97. package/template/src/server/db/schema/health-checks.ts +11 -0
  98. package/template/src/server/db/schema/index.ts +2 -0
  99. package/template/src/server/db/schema/users.ts +16 -0
  100. package/template/src/server/db/schema.ts +1 -0
  101. package/template/src/stores/__tests__/ui-store.test.ts +87 -0
  102. package/template/src/stores/ui-store.ts +14 -0
  103. package/template/src/styles/globals.css +129 -0
  104. package/template/src/test/mocks/clerk.ts +35 -0
  105. package/template/src/test/mocks/snowflake.ts +28 -0
  106. package/template/src/test/mocks/supabase.ts +37 -0
  107. package/template/src/test/setup.ts +69 -0
  108. package/template/src/test/utils/test-helpers.ts +158 -0
  109. package/template/src/types/index.ts +14 -0
  110. package/template/tsconfig.json +43 -0
  111. package/template/vitest.config.ts +44 -0
@@ -0,0 +1,583 @@
1
+ # DTT Framework - Health Check System
2
+
3
+ ## Overview
4
+
5
+ The Health Check System provides comprehensive monitoring of all integrated services. It verifies that each service is properly configured and functioning correctly, providing real-time visibility into the system's health.
6
+
7
+ ### Purpose
8
+
9
+ - **Service Verification**: Ensure all services are properly connected
10
+ - **Performance Monitoring**: Track response times for each service
11
+ - **Error Detection**: Identify and report service issues
12
+ - **Dashboard UI**: Visual representation of system health
13
+ - **Troubleshooting**: Quick diagnosis of integration issues
14
+
15
+ ---
16
+
17
+ ## Health Check Architecture
18
+
19
+ ### System Architecture
20
+
21
+ ```
22
+ ┌─────────────────────────────────────────────────────────────────┐
23
+ │ Health Check Dashboard │
24
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
25
+ │ │ Service │ │ Service │ │ Service │ │
26
+ │ │ Status │ │ Status │ │ Status │ │
27
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
28
+ └─────────────────────────────────────────────────────────────────┘
29
+
30
+
31
+ ┌─────────────────────────────────────────────────────────────────┐
32
+ │ TanStack Query Hook │
33
+ │ useHealthChecks() │
34
+ └─────────────────────────────────────────────────────────────────┘
35
+
36
+
37
+ ┌─────────────────────────────────────────────────────────────────┐
38
+ │ Hono API Routes │
39
+ │ /api/health/all │
40
+ └─────────────────────────────────────────────────────────────────┘
41
+
42
+ ┌─────────────────────┼─────────────────────┐
43
+ ▼ ▼ ▼
44
+ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
45
+ │ Service │ │ Service │ │ Service │
46
+ │ Health │ │ Health │ │ Health │
47
+ │ Check │ │ Check │ │ Check │
48
+ └──────────────┘ └──────────────┘ └──────────────┘
49
+ ```
50
+
51
+ ### Component Structure
52
+
53
+ ```
54
+ src/features/health-check/
55
+ ├── components/
56
+ │ └── health-dashboard.tsx # Dashboard UI component
57
+ ├── config.ts # Service configuration
58
+ ├── types.ts # TypeScript types
59
+ └── index.ts # Feature exports
60
+
61
+ src/hooks/queries/
62
+ └── use-health-checks.ts # TanStack Query hook
63
+
64
+ src/server/api/routes/health/
65
+ ├── index.ts # Health route aggregation
66
+ ├── clerk.ts # Clerk health checks
67
+ ├── database.ts # Database health checks
68
+ ├── storage.ts # Storage health checks
69
+ ├── edge-functions.ts # Edge function checks
70
+ ├── snowflake.ts # Snowflake health checks
71
+ └── nextbank.ts # NextBank health checks
72
+ ```
73
+
74
+ ---
75
+
76
+ ## All Available Endpoints
77
+
78
+ ### Health Check Endpoints
79
+
80
+ | Service | Endpoint | Method | Description |
81
+ |----------|----------|--------|-------------|
82
+ | **Clerk** | `/api/health/clerk/user` | GET | Get current user |
83
+ | **Clerk** | `/api/health/clerk/org` | GET | Get organization membership |
84
+ | **Clerk** | `/api/health/clerk/members` | GET | List organization members |
85
+ | **Database** | `/api/health/database/write` | POST | Write test row to database |
86
+ | **Database** | `/api/health/database/read` | GET | Read test row from database |
87
+ | **Database** | `/api/health/database/delete` | DELETE | Delete test row from database |
88
+ | **Storage** | `/api/health/storage/upload` | POST | Upload test file to storage |
89
+ | **Storage** | `/api/health/storage/download` | GET | Generate signed URL for test file |
90
+ | **Storage** | `/api/health/storage/delete` | DELETE | Delete test file from storage |
91
+ | **Edge Functions** | `/api/health/edge/ping` | GET | Ping edge function (placeholder) |
92
+ | **Edge Functions** | `/api/health/edge/auth` | GET | Test auth header passthrough (placeholder) |
93
+ | **Snowflake** | `/api/health/snowflake/connect` | GET | Test Snowflake connection |
94
+ | **Snowflake** | `/api/health/snowflake/query` | GET | Execute test query |
95
+ | **NextBank** | `/api/health/nextbank/ping` | GET | Ping NextBank API |
96
+ | **NextBank** | `/api/health/nextbank/auth` | GET | Test NextBank authentication |
97
+ | **All** | `/api/health/all` | GET | Run all health checks |
98
+
99
+ ---
100
+
101
+ ## Dashboard Usage
102
+
103
+ ### Accessing the Dashboard
104
+
105
+ Navigate to `/health` in your application:
106
+
107
+ ```
108
+ http://localhost:3000/health
109
+ ```
110
+
111
+ ### Dashboard Components
112
+
113
+ **Overall Status Card**
114
+
115
+ Shows the overall system status:
116
+ - **Status Badge**: `HEALTHY`, `UNHEALTHY`, `PARTIAL`, or `PENDING`
117
+ - **Response Time**: Total time to run all checks
118
+ - **"Run All" Button**: Execute all health checks with counter showing total number of checks
119
+ - **Last Updated**: Timestamp of last check
120
+
121
+ **Service Cards**
122
+
123
+ Each service has its own card:
124
+ - **Service Name**: Display name of the service
125
+ - **Status Badge**: Service-level status
126
+ - **Check Count**: Number of checks for this service
127
+ - **Individual Check Buttons**: Each check has a dedicated "Run Check" button
128
+ - **Check Results**: Results display below each button
129
+
130
+ **Individual Check Buttons**
131
+
132
+ Each health check has its own button:
133
+ - **"Run Check" Button**: Execute individual health check
134
+ - **Loading State**: Spinner shows while check is in progress
135
+ - **Disabled State**: Button is disabled during execution
136
+
137
+ **Check Results Display**
138
+
139
+ Results appear below each check button:
140
+ - **Status Badge**: Individual check status with color coding
141
+ - **Response Time**: Time taken for the check (in milliseconds)
142
+ - **Error Message**: Detailed error if check failed
143
+ - **HTTP Status Code**: HTTP response status
144
+ - **Timestamp**: When the check was executed
145
+
146
+ ### Status Types
147
+
148
+ | Status | Description | Color |
149
+ |---------|-------------|--------|
150
+ | **healthy** | Service is functioning correctly | Green |
151
+ | **unhealthy** | Service is not functioning | Red |
152
+ | **error** | Check failed with an error | Red |
153
+ | **pending** | Check is in progress | Yellow |
154
+ | **unconfigured** | Service is not configured | Gray |
155
+
156
+ ### Using the Dashboard Hook
157
+
158
+ Located at [`src/hooks/queries/use-health-checks.ts`](../../src/hooks/queries/use-health-checks.ts):
159
+
160
+ ```typescript
161
+ 'use client'
162
+
163
+ import { useQuery } from '@tanstack/react-query'
164
+
165
+ export function useHealthChecks() {
166
+ return useQuery({
167
+ queryKey: ['health-checks'],
168
+ queryFn: async () => {
169
+ const response = await fetch('/api/health/all')
170
+ if (!response.ok) throw new Error('Failed to fetch health checks')
171
+ return response.json()
172
+ },
173
+ })
174
+ }
175
+ ```
176
+
177
+ **Usage:**
178
+
179
+ ```typescript
180
+ import { useHealthChecks } from '@/hooks/queries/use-health-checks'
181
+
182
+ function MyComponent() {
183
+ const { data, isLoading, error, refetch } = useHealthChecks()
184
+
185
+ if (isLoading) return <div>Loading...</div>
186
+ if (error) return <div>Error: {error.message}</div>
187
+
188
+ return (
189
+ <div>
190
+ <h1>Status: {data?.status}</h1>
191
+ <button onClick={() => refetch()}>Refresh</button>
192
+ </div>
193
+ )
194
+ }
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Adding New Health Checks
200
+
201
+ ### Step 1: Define Service Configuration
202
+
203
+ Add to [`src/features/health-check/config.ts`](../../src/features/health-check/config.ts):
204
+
205
+ ```typescript
206
+ export const SERVICES = [
207
+ // ... existing services
208
+ {
209
+ name: 'Your Service',
210
+ icon: 'icon-name',
211
+ checks: [
212
+ { name: 'Check Name', endpoint: '/your-service/check' },
213
+ ],
214
+ },
215
+ ] as const
216
+ ```
217
+
218
+ ### Step 2: Create Health Check Routes
219
+
220
+ Create [`src/server/api/routes/health/your-service.ts`](../../src/server/api/routes/health/your-service.ts):
221
+
222
+ ```typescript
223
+ import { Hono } from 'hono'
224
+
225
+ export const yourServiceHealthRoutes = new Hono()
226
+
227
+ yourServiceHealthRoutes.get('/check', async (c) => {
228
+ const start = performance.now()
229
+
230
+ try {
231
+ // Perform your health check logic
232
+ const result = await checkYourService()
233
+
234
+ return c.json({
235
+ status: 'healthy',
236
+ responseTimeMs: Math.round(performance.now() - start),
237
+ message: 'Successfully checked service',
238
+ data: result,
239
+ })
240
+ } catch (error) {
241
+ return c.json(
242
+ {
243
+ status: 'error',
244
+ responseTimeMs: Math.round(performance.now() - start),
245
+ error: error instanceof Error ? error.message : 'Check failed',
246
+ },
247
+ 500
248
+ )
249
+ }
250
+ })
251
+ ```
252
+
253
+ ### Step 3: Register Routes
254
+
255
+ Add to [`src/server/api/routes/health/index.ts`](../../src/server/api/routes/health/index.ts):
256
+
257
+ ```typescript
258
+ import { yourServiceHealthRoutes } from './your-service'
259
+
260
+ export const healthRoutes = new Hono()
261
+
262
+ // ... existing routes
263
+ healthRoutes.route('/your-service', yourServiceHealthRoutes)
264
+ ```
265
+
266
+ ### Step 4: Add to Aggregated Check
267
+
268
+ Update the `/all` endpoint in [`src/server/api/routes/health/index.ts`](../../src/server/api/routes/health/index.ts):
269
+
270
+ ```typescript
271
+ healthRoutes.get('/all', async (c) => {
272
+ const start = performance.now()
273
+ const baseUrl = new URL(c.req.url).origin
274
+
275
+ const checks = [
276
+ // ... existing checks
277
+ { name: 'Your Service Check', url: `${baseUrl}/api/health/your-service/check` },
278
+ ]
279
+
280
+ // ... rest of the implementation
281
+ })
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Response Format Specification
287
+
288
+ ### Standard Response Format
289
+
290
+ All health check endpoints follow this response format:
291
+
292
+ ```typescript
293
+ interface HealthCheckResponse {
294
+ status: 'healthy' | 'error' | 'unconfigured' | 'pending'
295
+ responseTimeMs: number
296
+ message: string
297
+ data?: any
298
+ error?: string
299
+ }
300
+ ```
301
+
302
+ ### Successful Response
303
+
304
+ ```json
305
+ {
306
+ "status": "healthy",
307
+ "responseTimeMs": 45,
308
+ "message": "Successfully retrieved current user",
309
+ "data": {
310
+ "userId": "user_abc123",
311
+ "hasOrg": true
312
+ }
313
+ }
314
+ ```
315
+
316
+ ### Error Response
317
+
318
+ ```json
319
+ {
320
+ "status": "error",
321
+ "responseTimeMs": 123,
322
+ "error": "Connection failed"
323
+ }
324
+ ```
325
+
326
+ ### Unconfigured Response
327
+
328
+ ```json
329
+ {
330
+ "status": "unconfigured",
331
+ "responseTimeMs": 5,
332
+ "message": "Service not configured"
333
+ }
334
+ ```
335
+
336
+ ### Aggregated Response
337
+
338
+ The `/api/health/all` endpoint returns:
339
+
340
+ ```typescript
341
+ interface AggregatedHealthResponse {
342
+ status: 'healthy' | 'unhealthy' | 'partial'
343
+ responseTimeMs: number
344
+ timestamp: string
345
+ services: {
346
+ clerk: CheckResult[]
347
+ database: CheckResult[]
348
+ storage: CheckResult[]
349
+ edge: CheckResult[]
350
+ snowflake: CheckResult[]
351
+ nextbank: CheckResult[]
352
+ }
353
+ checks: CheckResult[]
354
+ }
355
+ ```
356
+
357
+ ```json
358
+ {
359
+ "status": "healthy",
360
+ "responseTimeMs": 1234,
361
+ "timestamp": "2025-12-29T08:00:00.000Z",
362
+ "services": {
363
+ "clerk": [
364
+ {
365
+ "name": "Clerk User",
366
+ "status": "healthy",
367
+ "responseTimeMs": 45,
368
+ "httpStatus": 200
369
+ }
370
+ ],
371
+ "database": [
372
+ {
373
+ "name": "Database Write",
374
+ "status": "healthy",
375
+ "responseTimeMs": 123,
376
+ "httpStatus": 200
377
+ }
378
+ ]
379
+ },
380
+ "checks": [
381
+ {
382
+ "name": "Clerk User",
383
+ "status": "healthy",
384
+ "responseTimeMs": 45,
385
+ "httpStatus": 200
386
+ }
387
+ ]
388
+ }
389
+ ```
390
+
391
+ ---
392
+
393
+ ## Health Check Types
394
+
395
+ Located at [`src/features/health-check/types.ts`](../../src/features/health-check/types.ts):
396
+
397
+ ```typescript
398
+ export type HealthStatus = 'healthy' | 'unhealthy' | 'error' | 'pending' | 'unconfigured'
399
+
400
+ export interface ServiceCheck {
401
+ name: string
402
+ endpoint: string
403
+ status: HealthStatus
404
+ responseTimeMs?: number
405
+ error?: string
406
+ }
407
+
408
+ export interface ServiceHealth {
409
+ name: string
410
+ icon: string
411
+ status: HealthStatus
412
+ responseTimeMs: number
413
+ checks: ServiceCheck[]
414
+ }
415
+ ```
416
+
417
+ ---
418
+
419
+ ## Service Configuration
420
+
421
+ Located at [`src/features/health-check/config.ts`](../../src/features/health-check/config.ts):
422
+
423
+ ```typescript
424
+ export const SERVICES = [
425
+ {
426
+ name: 'Clerk Authentication',
427
+ icon: 'key',
428
+ checks: [
429
+ { name: 'Get Current User', endpoint: '/clerk/user' },
430
+ { name: 'Get Org Membership', endpoint: '/clerk/org' },
431
+ { name: 'List Org Members', endpoint: '/clerk/members' },
432
+ ],
433
+ },
434
+ {
435
+ name: 'Supabase Database',
436
+ icon: 'database',
437
+ checks: [
438
+ { name: 'Write Test Row', endpoint: '/database/write' },
439
+ { name: 'Read Test Row', endpoint: '/database/read' },
440
+ { name: 'Delete Test Row', endpoint: '/database/delete' },
441
+ ],
442
+ },
443
+ {
444
+ name: 'Supabase Storage',
445
+ icon: 'folder',
446
+ checks: [
447
+ { name: 'Upload Test File', endpoint: '/storage/upload' },
448
+ { name: 'Download Test File', endpoint: '/storage/download' },
449
+ { name: 'Delete Test File', endpoint: '/storage/delete' },
450
+ ],
451
+ },
452
+ {
453
+ name: 'Supabase Edge Functions',
454
+ icon: 'zap',
455
+ checks: [
456
+ { name: 'Ping Edge Function', endpoint: '/edge/ping' },
457
+ { name: 'Test Auth Header', endpoint: '/edge/auth' },
458
+ ],
459
+ },
460
+ {
461
+ name: 'Snowflake',
462
+ icon: 'snowflake',
463
+ checks: [
464
+ { name: 'Test Connection', endpoint: '/snowflake/connect' },
465
+ { name: 'Execute Query', endpoint: '/snowflake/query' },
466
+ ],
467
+ },
468
+ {
469
+ name: 'NextBank',
470
+ icon: 'building',
471
+ checks: [
472
+ { name: 'Ping API', endpoint: '/nextbank/ping' },
473
+ { name: 'Test Authentication', endpoint: '/nextbank/auth' },
474
+ ],
475
+ },
476
+ ] as const
477
+ ```
478
+
479
+ ---
480
+
481
+ ## Best Practices
482
+
483
+ ### 1. Keep Checks Fast
484
+
485
+ Health checks should be quick and lightweight:
486
+
487
+ ```typescript
488
+ // ✅ Good - Fast check
489
+ const result = await db.select().from(table).limit(1)
490
+
491
+ // ❌ Bad - Slow check
492
+ const result = await db.select().from(table) // No limit
493
+ ```
494
+
495
+ ### 2. Use Meaningful Messages
496
+
497
+ Provide clear, actionable error messages:
498
+
499
+ ```typescript
500
+ // ✅ Good - Clear message
501
+ return c.json({
502
+ status: 'error',
503
+ error: 'Failed to connect to database: connection timeout',
504
+ })
505
+
506
+ // ❌ Bad - Vague message
507
+ return c.json({
508
+ status: 'error',
509
+ error: 'Error',
510
+ })
511
+ ```
512
+
513
+ ### 3. Handle Unconfigured Services
514
+
515
+ Gracefully handle services that aren't configured:
516
+
517
+ ```typescript
518
+ if (!env.SERVICE_API_KEY) {
519
+ return c.json({
520
+ status: 'unconfigured',
521
+ message: 'Service not configured',
522
+ })
523
+ }
524
+ ```
525
+
526
+ ### 4. Measure Response Time
527
+
528
+ Always track response time for performance monitoring:
529
+
530
+ ```typescript
531
+ const start = performance.now()
532
+
533
+ try {
534
+ // Perform check
535
+ const result = await performCheck()
536
+
537
+ return c.json({
538
+ status: 'healthy',
539
+ responseTimeMs: Math.round(performance.now() - start),
540
+ })
541
+ } catch (error) {
542
+ return c.json({
543
+ status: 'error',
544
+ responseTimeMs: Math.round(performance.now() - start),
545
+ error: error.message,
546
+ })
547
+ }
548
+ ```
549
+
550
+ ---
551
+
552
+ ## Troubleshooting
553
+
554
+ ### Common Issues
555
+
556
+ **Issue: Health check shows "unconfigured"**
557
+
558
+ - Verify environment variables are set
559
+ - Check if service credentials are correct
560
+ - Ensure service is enabled in configuration
561
+
562
+ **Issue: Health check shows "error"**
563
+
564
+ - Check service logs for detailed error messages
565
+ - Verify network connectivity to the service
566
+ - Check if service is running and accessible
567
+ - For Supabase Database: Ensure migrations are applied (`pnpm db:push` or `pnpm db:migrate`) so `health_check_tests` table exists
568
+
569
+ **Issue: Health check is slow**
570
+
571
+ - Optimize the check query or operation
572
+ - Check if service is experiencing high load
573
+ - Consider caching results for frequently checked services
574
+
575
+ ---
576
+
577
+ ## Related Documentation
578
+
579
+ - [API Layer](./api-layer.md) - API route implementation
580
+ - [Clerk Authentication](./clerk-authentication.md) - Clerk health checks
581
+ - [Supabase Integration](./supabase-integration.md) - Database and storage checks
582
+ - [Snowflake Integration](./snowflake-integration.md) - Snowflake health checks
583
+ - [State Management](./state-management.md) - Data fetching with TanStack Query