@odvi/create-dtt-framework 0.1.2 → 0.1.5

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 (114) 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/dist/utils/template.d.ts.map +1 -1
  5. package/dist/utils/template.js +5 -0
  6. package/dist/utils/template.js.map +1 -1
  7. package/package.json +3 -2
  8. package/template/.env.example +103 -0
  9. package/template/components.json +22 -0
  10. package/template/docs/framework/01-overview.md +289 -0
  11. package/template/docs/framework/02-techstack.md +503 -0
  12. package/template/docs/framework/api-layer.md +681 -0
  13. package/template/docs/framework/clerk-authentication.md +649 -0
  14. package/template/docs/framework/cli-installation.md +564 -0
  15. package/template/docs/framework/deployment/ci-cd.md +907 -0
  16. package/template/docs/framework/deployment/digitalocean.md +991 -0
  17. package/template/docs/framework/deployment/domain-setup.md +972 -0
  18. package/template/docs/framework/deployment/environment-variables.md +863 -0
  19. package/template/docs/framework/deployment/monitoring.md +927 -0
  20. package/template/docs/framework/deployment/production-checklist.md +649 -0
  21. package/template/docs/framework/deployment/vercel.md +791 -0
  22. package/template/docs/framework/environment-variables.md +658 -0
  23. package/template/docs/framework/health-check-system.md +582 -0
  24. package/template/docs/framework/implementation.md +559 -0
  25. package/template/docs/framework/snowflake-integration.md +591 -0
  26. package/template/docs/framework/state-management.md +615 -0
  27. package/template/docs/framework/supabase-integration.md +581 -0
  28. package/template/docs/framework/testing-guide.md +544 -0
  29. package/template/docs/framework/what-did-i-miss.md +526 -0
  30. package/template/drizzle.config.ts +12 -0
  31. package/template/next.config.js +21 -0
  32. package/template/postcss.config.js +5 -0
  33. package/template/prettier.config.js +4 -0
  34. package/template/public/favicon.ico +0 -0
  35. package/template/src/app/(auth)/layout.tsx +4 -0
  36. package/template/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +10 -0
  37. package/template/src/app/(auth)/sign-up/[[...sign-up]]/page.tsx +10 -0
  38. package/template/src/app/(dashboard)/dashboard/page.tsx +8 -0
  39. package/template/src/app/(dashboard)/health/page.tsx +16 -0
  40. package/template/src/app/(dashboard)/layout.tsx +17 -0
  41. package/template/src/app/api/[[...route]]/route.ts +11 -0
  42. package/template/src/app/api/debug-files/route.ts +33 -0
  43. package/template/src/app/api/webhooks/clerk/route.ts +112 -0
  44. package/template/src/app/layout.tsx +28 -0
  45. package/template/src/app/page.tsx +12 -0
  46. package/template/src/app/providers.tsx +20 -0
  47. package/template/src/components/layouts/navbar.tsx +14 -0
  48. package/template/src/components/shared/loading-spinner.tsx +6 -0
  49. package/template/src/components/ui/badge.tsx +46 -0
  50. package/template/src/components/ui/button.tsx +62 -0
  51. package/template/src/components/ui/card.tsx +92 -0
  52. package/template/src/components/ui/collapsible.tsx +33 -0
  53. package/template/src/components/ui/scroll-area.tsx +58 -0
  54. package/template/src/components/ui/sheet.tsx +139 -0
  55. package/template/src/config/__tests__/env.test.ts +166 -0
  56. package/template/src/config/__tests__/site.test.ts +46 -0
  57. package/template/src/config/env.ts +36 -0
  58. package/template/src/config/site.ts +10 -0
  59. package/template/src/env.js +44 -0
  60. package/template/src/features/__tests__/health-check-config.test.ts +142 -0
  61. package/template/src/features/__tests__/health-check-types.test.ts +201 -0
  62. package/template/src/features/documentation/components/doc-sidebar.tsx +109 -0
  63. package/template/src/features/documentation/components/doc-viewer.tsx +70 -0
  64. package/template/src/features/documentation/index.tsx +92 -0
  65. package/template/src/features/documentation/utils/doc-loader.ts +177 -0
  66. package/template/src/features/health-check/components/health-dashboard.tsx +363 -0
  67. package/template/src/features/health-check/config.ts +72 -0
  68. package/template/src/features/health-check/index.ts +4 -0
  69. package/template/src/features/health-check/stores/health-store.ts +14 -0
  70. package/template/src/features/health-check/types.ts +18 -0
  71. package/template/src/hooks/__tests__/use-debounce.test.tsx +28 -0
  72. package/template/src/hooks/queries/use-health-checks.ts +16 -0
  73. package/template/src/hooks/utils/use-debounce.ts +20 -0
  74. package/template/src/lib/__tests__/utils.test.ts +52 -0
  75. package/template/src/lib/__tests__/validators.test.ts +114 -0
  76. package/template/src/lib/nextbank/client.ts +37 -0
  77. package/template/src/lib/snowflake/client.ts +53 -0
  78. package/template/src/lib/supabase/admin.ts +7 -0
  79. package/template/src/lib/supabase/client.ts +7 -0
  80. package/template/src/lib/supabase/server.ts +23 -0
  81. package/template/src/lib/utils.ts +6 -0
  82. package/template/src/lib/validators.ts +9 -0
  83. package/template/src/middleware.ts +22 -0
  84. package/template/src/server/api/index.ts +22 -0
  85. package/template/src/server/api/middleware/auth.ts +19 -0
  86. package/template/src/server/api/middleware/logger.ts +4 -0
  87. package/template/src/server/api/routes/health/clerk.ts +214 -0
  88. package/template/src/server/api/routes/health/database.ts +117 -0
  89. package/template/src/server/api/routes/health/edge-functions.ts +75 -0
  90. package/template/src/server/api/routes/health/framework.ts +45 -0
  91. package/template/src/server/api/routes/health/index.ts +102 -0
  92. package/template/src/server/api/routes/health/nextbank.ts +67 -0
  93. package/template/src/server/api/routes/health/snowflake.ts +83 -0
  94. package/template/src/server/api/routes/health/storage.ts +163 -0
  95. package/template/src/server/api/routes/users.ts +95 -0
  96. package/template/src/server/db/index.ts +17 -0
  97. package/template/src/server/db/queries/users.ts +8 -0
  98. package/template/src/server/db/schema/__tests__/health-checks.test.ts +31 -0
  99. package/template/src/server/db/schema/__tests__/users.test.ts +46 -0
  100. package/template/src/server/db/schema/health-checks.ts +11 -0
  101. package/template/src/server/db/schema/index.ts +2 -0
  102. package/template/src/server/db/schema/users.ts +16 -0
  103. package/template/src/server/db/schema.ts +26 -0
  104. package/template/src/stores/__tests__/ui-store.test.ts +87 -0
  105. package/template/src/stores/ui-store.ts +14 -0
  106. package/template/src/styles/globals.css +129 -0
  107. package/template/src/test/mocks/clerk.ts +35 -0
  108. package/template/src/test/mocks/snowflake.ts +28 -0
  109. package/template/src/test/mocks/supabase.ts +37 -0
  110. package/template/src/test/setup.ts +69 -0
  111. package/template/src/test/utils/test-helpers.ts +158 -0
  112. package/template/src/types/index.ts +14 -0
  113. package/template/tsconfig.json +43 -0
  114. package/template/vitest.config.ts +44 -0
@@ -0,0 +1,649 @@
1
+ # DTT Framework - Clerk Authentication
2
+
3
+ ## Overview
4
+
5
+ The DTT Framework uses [Clerk](https://clerk.com/) as the authentication and user management solution. Clerk provides a complete authentication system with built-in UI components, organization management, and webhook support for synchronizing user data with your local database.
6
+
7
+ ### Why Clerk?
8
+
9
+ - **Complete Auth Solution**: Sign-in, sign-up, password reset, email verification, MFA
10
+ - **Built-in Components**: Pre-built, customizable auth UI components
11
+ - **Organization Support**: Multi-tenant architecture out of the box
12
+ - **Webhooks**: Real-time user data synchronization
13
+ - **Type Safety**: Full TypeScript support
14
+ - **Security**: SOC 2 Type II compliant, GDPR ready
15
+
16
+ ---
17
+
18
+ ## Clerk Integration Setup
19
+
20
+ ### 1. Create a Clerk Account
21
+
22
+ 1. Go to [clerk.com](https://clerk.com/) and sign up
23
+ 2. Create a new application
24
+ 3. Note down your API keys from the dashboard
25
+
26
+ ### 2. Install Clerk Dependencies
27
+
28
+ ```bash
29
+ pnpm add @clerk/nextjs
30
+ ```
31
+
32
+ ### 3. Configure Environment Variables
33
+
34
+ Add the following to your [`.env`](../environment-variables.md) file:
35
+
36
+ ```bash
37
+ # Clerk
38
+ NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
39
+ CLERK_SECRET_KEY=sk_test_xxx
40
+ CLERK_WEBHOOK_SECRET=whsec_xxx
41
+ NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
42
+ NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
43
+ NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
44
+ NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
45
+ ```
46
+
47
+ **Where to find these keys:**
48
+
49
+ - **Publishable Key**: Clerk Dashboard → Your App → API Keys → Publishable Key
50
+ - **Secret Key**: Clerk Dashboard → Your App → API Keys → Secret Key
51
+ - **Webhook Secret**: Clerk Dashboard → Your App → Webhooks → Add Endpoint → Copy Secret
52
+
53
+ ### 4. Configure Environment Validation
54
+
55
+ Update [`src/config/env.ts`](../../src/config/env.ts) to validate Clerk environment variables:
56
+
57
+ ```typescript
58
+ import { createEnv } from '@t3-oss/env-nextjs'
59
+ import { z } from 'zod'
60
+
61
+ export const env = createEnv({
62
+ server: {
63
+ // ... other variables
64
+ CLERK_SECRET_KEY: z.string().startsWith('sk_'),
65
+ CLERK_WEBHOOK_SECRET: z.string().optional(),
66
+ },
67
+ client: {
68
+ NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().startsWith('pk_'),
69
+ NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.string().default('/sign-in'),
70
+ NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.string().default('/sign-up'),
71
+ NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: z.string().default('/health'),
72
+ NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL: z.string().default('/health'),
73
+ },
74
+ runtimeEnv: {
75
+ CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
76
+ CLERK_WEBHOOK_SECRET: process.env.CLERK_WEBHOOK_SECRET,
77
+ NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
78
+ NEXT_PUBLIC_CLERK_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL,
79
+ NEXT_PUBLIC_CLERK_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL,
80
+ NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL,
81
+ NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL,
82
+ },
83
+ })
84
+ ```
85
+
86
+ ---
87
+
88
+ ## User Authentication Flow
89
+
90
+ ### Authentication Flow Diagram
91
+
92
+ ```
93
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
94
+ │ User │────▶│ Clerk UI │────▶│ Clerk API │────▶│ Session │
95
+ │ Browser │ │ Components │ │ Server │ │ Created │
96
+ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
97
+ │ │
98
+ │ ▼
99
+ │ ┌─────────────┐
100
+ │ │ Clerk │
101
+ │ │ Webhook │
102
+ │ └─────────────┘
103
+ │ │
104
+ ▼ ▼
105
+ ┌─────────────┐ ┌─────────────┐
106
+ │ Redirect │ │ Local DB │
107
+ │ to App │ │ Updated │
108
+ └─────────────┘ └─────────────┘
109
+ ```
110
+
111
+ ### Sign-In Flow
112
+
113
+ 1. User navigates to `/sign-in`
114
+ 2. Clerk `<SignIn />` component renders
115
+ 3. User enters credentials
116
+ 4. Clerk validates credentials
117
+ 5. Clerk creates session and stores tokens
118
+ 6. User is redirected to `NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL`
119
+
120
+ ### Sign-Up Flow
121
+
122
+ 1. User navigates to `/sign-up`
123
+ 2. Clerk `<SignUp />` component renders
124
+ 3. User enters registration details
125
+ 4. Clerk validates and creates user account
126
+ 5. Clerk triggers `user.created` webhook
127
+ 6. Webhook handler creates user in local database
128
+ 7. User is redirected to `NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL`
129
+
130
+ ---
131
+
132
+ ## Organization Management
133
+
134
+ ### Clerk Organizations
135
+
136
+ Clerk provides built-in organization management for multi-tenant applications. Organizations allow you to group users and manage permissions at the organization level.
137
+
138
+ ### Organization Features
139
+
140
+ - **Multi-Tenancy**: Separate data per organization
141
+ - **Organization Roles**: Admin, Member, etc.
142
+ - **Organization Memberships**: Users can belong to multiple organizations
143
+ - **Organization Webhooks**: Sync organization membership changes
144
+
145
+ ### Organization Schema
146
+
147
+ The local database schema includes organization tracking:
148
+
149
+ ```typescript
150
+ // src/server/db/schema/users.ts
151
+ export const users = pgTable('users', {
152
+ id: text('id').primaryKey(), // Clerk user ID
153
+ email: varchar('email', { length: 255 }).notNull().unique(),
154
+ firstName: varchar('first_name', { length: 255 }),
155
+ lastName: varchar('last_name', { length: 255 }),
156
+ imageUrl: text('image_url'),
157
+ clerkOrgId: text('clerk_org_id'), // Clerk organization ID
158
+ createdAt: timestamp('created_at').defaultNow().notNull(),
159
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
160
+ })
161
+ ```
162
+
163
+ ### Accessing Organization Data
164
+
165
+ **Server-Side:**
166
+
167
+ ```typescript
168
+ import { getAuth } from '@clerk/nextjs/server'
169
+
170
+ export async function getServerData() {
171
+ const auth = getAuth()
172
+
173
+ return {
174
+ userId: auth.userId,
175
+ orgId: auth.orgId,
176
+ orgRole: auth.orgRole,
177
+ }
178
+ }
179
+ ```
180
+
181
+ **Client-Side:**
182
+
183
+ ```typescript
184
+ import { useAuth } from '@clerk/nextjs'
185
+
186
+ export function MyComponent() {
187
+ const { orgId, orgRole } = useAuth()
188
+
189
+ return <div>Organization: {orgId}, Role: {orgRole}</div>
190
+ }
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Webhook Synchronization
196
+
197
+ ### Webhook Setup
198
+
199
+ 1. Go to Clerk Dashboard → Your App → Webhooks
200
+ 2. Add a new endpoint: `https://your-domain.com/api/webhooks/clerk`
201
+ 3. Select events to listen for:
202
+ - `user.created`
203
+ - `user.updated`
204
+ - `user.deleted`
205
+ - `organizationMembership.created`
206
+ - `organizationMembership.updated`
207
+ 4. Copy the webhook secret to your `.env` file
208
+
209
+ ### Webhook Handler
210
+
211
+ The webhook handler is located at [`src/app/api/webhooks/clerk/route.ts`](../../src/app/api/webhooks/clerk/route.ts):
212
+
213
+ ```typescript
214
+ import type { WebhookEvent } from '@clerk/nextjs/server'
215
+ import { headers } from 'next/headers'
216
+ import { Webhook } from 'svix'
217
+ import { env } from '@/config/env'
218
+ import { db } from '@/server/db'
219
+ import { users } from '@/server/db/schema/users'
220
+ import { eq } from 'drizzle-orm'
221
+
222
+ export async function POST(req: Request) {
223
+ try {
224
+ // Get headers
225
+ const headerPayload = await headers()
226
+ const svix_id = headerPayload.get('svix-id')
227
+ const svix_timestamp = headerPayload.get('svix-timestamp')
228
+ const svix_signature = headerPayload.get('svix-signature')
229
+
230
+ // Verify headers
231
+ if (!svix_id || !svix_timestamp || !svix_signature) {
232
+ return new Response('Error: Missing Svix headers', { status: 400 })
233
+ }
234
+
235
+ // Get the body
236
+ const payload = await req.json()
237
+ const body = JSON.stringify(payload)
238
+
239
+ // Verify webhook signature
240
+ const wh = new Webhook(env.CLERK_WEBHOOK_SECRET ?? '')
241
+ let event: WebhookEvent
242
+
243
+ try {
244
+ event = wh.verify(body, {
245
+ 'svix-id': svix_id,
246
+ 'svix-timestamp': svix_timestamp,
247
+ 'svix-signature': svix_signature,
248
+ }) as WebhookEvent
249
+ } catch (err) {
250
+ console.error('Error verifying webhook:', err)
251
+ return new Response('Error: Invalid signature', { status: 400 })
252
+ }
253
+
254
+ // Handle events
255
+ const eventType = event.type
256
+
257
+ if (eventType === 'user.created') {
258
+ const { id, email_addresses, first_name, last_name, image_url } = event.data
259
+
260
+ await db.insert(users).values({
261
+ id,
262
+ email: email_addresses[0]?.email_address ?? '',
263
+ firstName: first_name ?? null,
264
+ lastName: last_name ?? null,
265
+ imageUrl: image_url ?? null,
266
+ })
267
+
268
+ console.log(`User created: ${id}`)
269
+ }
270
+
271
+ if (eventType === 'user.updated') {
272
+ const { id, email_addresses, first_name, last_name, image_url } = event.data
273
+
274
+ if (id) {
275
+ await db
276
+ .update(users)
277
+ .set({
278
+ email: email_addresses?.[0]?.email_address,
279
+ firstName: first_name,
280
+ lastName: last_name,
281
+ imageUrl: image_url,
282
+ updatedAt: new Date(),
283
+ })
284
+ .where(eq(users.id, id))
285
+
286
+ console.log(`User updated: ${id}`)
287
+ }
288
+ }
289
+
290
+ if (eventType === 'user.deleted') {
291
+ const { id } = event.data
292
+
293
+ if (id) {
294
+ await db.delete(users).where(eq(users.id, id))
295
+
296
+ console.log(`User deleted: ${id}`)
297
+ }
298
+ }
299
+
300
+ if (eventType === 'organizationMembership.created' ||
301
+ eventType === 'organizationMembership.updated') {
302
+ const data = event.data as any
303
+ const userId = data.public_user_data
304
+ const orgId = data.organization
305
+
306
+ if (userId) {
307
+ await db
308
+ .update(users)
309
+ .set({
310
+ clerkOrgId: orgId,
311
+ updatedAt: new Date(),
312
+ })
313
+ .where(eq(users.id, userId))
314
+
315
+ console.log(`Organization membership updated for user: ${userId}, org: ${orgId}`)
316
+ }
317
+ }
318
+
319
+ return new Response(JSON.stringify({ received: true }), { status: 200 })
320
+ } catch (error) {
321
+ console.error('Error processing webhook:', error)
322
+ return new Response('Error: Webhook processing failed', { status: 500 })
323
+ }
324
+ }
325
+ ```
326
+
327
+ ### Supported Webhook Events
328
+
329
+ | Event | Description | Handler Action |
330
+ |-------|-------------|-----------------|
331
+ | `user.created` | New user registered | Insert user into local database |
332
+ | `user.updated` | User profile updated | Update user in local database |
333
+ | `user.deleted` | User account deleted | Delete user from local database |
334
+ | `organizationMembership.created` | User joined organization | Update user's organization ID |
335
+ | `organizationMembership.updated` | Organization membership changed | Update user's organization ID |
336
+
337
+ ---
338
+
339
+ ## Protected Routes Configuration
340
+
341
+ ### Middleware Setup
342
+
343
+ The middleware is located at [`src/middleware.ts`](../../src/middleware.ts):
344
+
345
+ ```typescript
346
+ import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
347
+
348
+ const isPublicRoute = createRouteMatcher([
349
+ '/sign-in(.*)',
350
+ '/sign-up(.*)',
351
+ '/api/webhooks(.*)',
352
+ '/api/ping',
353
+ ])
354
+
355
+ export default clerkMiddleware(async (auth, request) => {
356
+ if (!isPublicRoute(request)) {
357
+ await auth.protect()
358
+ }
359
+ })
360
+
361
+ export const config = {
362
+ matcher: [
363
+ '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
364
+ '/(api|trpc)(.*)',
365
+ ],
366
+ }
367
+ ```
368
+
369
+ ### Public Routes
370
+
371
+ The following routes are public (no authentication required):
372
+
373
+ - `/sign-in` - Sign-in page
374
+ - `/sign-up` - Sign-up page
375
+ - `/api/webhooks/*` - Webhook endpoints
376
+ - `/api/ping` - Health check ping endpoint
377
+
378
+ ### Protected Routes
379
+
380
+ All other routes require authentication. If a user tries to access a protected route without being authenticated, they will be redirected to the sign-in page.
381
+
382
+ ### Adding Public Routes
383
+
384
+ To add a new public route, add it to the `isPublicRoute` matcher:
385
+
386
+ ```typescript
387
+ const isPublicRoute = createRouteMatcher([
388
+ '/sign-in(.*)',
389
+ '/sign-up(.*)',
390
+ '/api/webhooks(.*)',
391
+ '/api/ping',
392
+ '/your-new-public-route(.*)', // Add new public route here
393
+ ])
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Clerk Components Usage
399
+
400
+ ### Sign-In Component
401
+
402
+ Located at [`src/app/(auth)/sign-in/[[...sign-in]]/page.tsx`](../../src/app/(auth)/sign-in/[[...sign-in]]/page.tsx):
403
+
404
+ ```typescript
405
+ import { SignIn } from '@clerk/nextjs'
406
+
407
+ export default function SignInPage() {
408
+ return (
409
+ <div className="flex min-h-screen items-center justify-center">
410
+ <SignIn />
411
+ </div>
412
+ )
413
+ }
414
+ ```
415
+
416
+ ### Sign-Up Component
417
+
418
+ Located at [`src/app/(auth)/sign-up/[[...sign-up]]/page.tsx`](../../src/app/(auth)/sign-up/[[...sign-up]]/page.tsx):
419
+
420
+ ```typescript
421
+ import { SignUp } from '@clerk/nextjs'
422
+
423
+ export default function SignUpPage() {
424
+ return (
425
+ <div className="flex min-h-screen items-center justify-center">
426
+ <SignUp />
427
+ </div>
428
+ )
429
+ }
430
+ ```
431
+
432
+ ### User Button Component
433
+
434
+ Used in the dashboard layout to show user menu:
435
+
436
+ ```typescript
437
+ import { UserButton } from '@clerk/nextjs'
438
+
439
+ export function Navbar() {
440
+ return (
441
+ <header className="border-b">
442
+ <div className="container flex h-14 items-center justify-between">
443
+ <Link href="/health" className="font-semibold">DTT Framework</Link>
444
+ <UserButton afterSignOutUrl="/sign-in" />
445
+ </div>
446
+ </header>
447
+ )
448
+ }
449
+ ```
450
+
451
+ ### SignedIn and SignedOut Components
452
+
453
+ Conditionally render content based on authentication status:
454
+
455
+ ```typescript
456
+ import { SignedIn, SignedOut } from '@clerk/nextjs'
457
+
458
+ export function MyComponent() {
459
+ return (
460
+ <div>
461
+ <SignedIn>
462
+ <p>You are signed in!</p>
463
+ </SignedIn>
464
+ <SignedOut>
465
+ <p>You are signed out!</p>
466
+ </SignedOut>
467
+ </div>
468
+ )
469
+ }
470
+ ```
471
+
472
+ ### Using Clerk Hooks
473
+
474
+ **useAuth Hook:**
475
+
476
+ ```typescript
477
+ import { useAuth } from '@clerk/nextjs'
478
+
479
+ export function MyComponent() {
480
+ const { userId, isLoaded, isSignedIn } = useAuth()
481
+
482
+ if (!isLoaded) {
483
+ return <div>Loading...</div>
484
+ }
485
+
486
+ if (!isSignedIn) {
487
+ return <div>Not signed in</div>
488
+ }
489
+
490
+ return <div>User ID: {userId}</div>
491
+ }
492
+ ```
493
+
494
+ **useUser Hook:**
495
+
496
+ ```typescript
497
+ import { useUser } from '@clerk/nextjs'
498
+
499
+ export function UserProfile() {
500
+ const { user, isLoaded } = useUser()
501
+
502
+ if (!isLoaded) {
503
+ return <div>Loading...</div>
504
+ }
505
+
506
+ return (
507
+ <div>
508
+ <p>Name: {user?.fullName}</p>
509
+ <p>Email: {user?.primaryEmailAddress?.emailAddress}</p>
510
+ </div>
511
+ )
512
+ }
513
+ ```
514
+
515
+ ---
516
+
517
+ ## Server-Side Authentication
518
+
519
+ ### Getting Auth Context
520
+
521
+ ```typescript
522
+ import { getAuth } from '@clerk/nextjs/server'
523
+ import { NextRequest } from 'next/server'
524
+
525
+ export async function GET(request: NextRequest) {
526
+ const auth = getAuth(request)
527
+
528
+ if (!auth.userId) {
529
+ return new Response('Unauthorized', { status: 401 })
530
+ }
531
+
532
+ return Response.json({ userId: auth.userId })
533
+ }
534
+ ```
535
+
536
+ ### In API Routes (Hono)
537
+
538
+ ```typescript
539
+ import { getAuth } from '@clerk/nextjs/server'
540
+ import type { NextRequest } from 'next/server'
541
+
542
+ export const myRoute = new Hono()
543
+
544
+ myRoute.get('/protected', async (c) => {
545
+ const auth = getAuth(c.req.raw as NextRequest)
546
+
547
+ if (!auth.userId) {
548
+ return c.json({ error: 'Unauthorized' }, 401)
549
+ }
550
+
551
+ return c.json({ userId: auth.userId })
552
+ })
553
+ ```
554
+
555
+ ### In Server Components
556
+
557
+ ```typescript
558
+ import { getAuth } from '@clerk/nextjs/server'
559
+
560
+ export default async function ServerComponent() {
561
+ const auth = getAuth()
562
+
563
+ if (!auth.userId) {
564
+ redirect('/sign-in')
565
+ }
566
+
567
+ return <div>Welcome, {auth.userId}</div>
568
+ }
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Clerk Health Checks
574
+
575
+ The framework includes health check endpoints for verifying Clerk integration:
576
+
577
+ ### Health Check Endpoints
578
+
579
+ | Endpoint | Method | Description |
580
+ |----------|--------|-------------|
581
+ | `/api/health/clerk/user` | GET | Get current user |
582
+ | `/api/health/clerk/org` | GET | Get organization membership |
583
+ | `/api/health/clerk/members` | GET | List organization members |
584
+
585
+ ### Example Response
586
+
587
+ ```json
588
+ {
589
+ "status": "healthy",
590
+ "responseTimeMs": 45,
591
+ "message": "Successfully retrieved current user",
592
+ "data": {
593
+ "userId": "user_abc123",
594
+ "hasOrg": true
595
+ }
596
+ }
597
+ ```
598
+
599
+ ---
600
+
601
+ ## Security Considerations
602
+
603
+ ### Best Practices
604
+
605
+ 1. **Never expose secret keys**: Only use `NEXT_PUBLIC_` prefixed keys in client code
606
+ 2. **Verify webhook signatures**: Always verify webhook signatures to prevent spoofing
607
+ 3. **Use environment variables**: Store all sensitive data in environment variables
608
+ 4. **Enable MFA**: Require multi-factor authentication for sensitive operations
609
+ 5. **Monitor webhook failures**: Set up alerts for failed webhook deliveries
610
+
611
+ ### Session Management
612
+
613
+ - Clerk handles session management automatically
614
+ - Sessions are stored in secure HTTP-only cookies
615
+ - Session tokens are automatically refreshed
616
+ - Sessions can be revoked from the Clerk dashboard
617
+
618
+ ---
619
+
620
+ ## Troubleshooting
621
+
622
+ ### Common Issues
623
+
624
+ **Issue: Webhook signature verification fails**
625
+
626
+ - Verify the `CLERK_WEBHOOK_SECRET` is correct
627
+ - Check that the webhook endpoint URL is correct
628
+ - Ensure the webhook is enabled in Clerk dashboard
629
+
630
+ **Issue: User not redirected after sign-in**
631
+
632
+ - Check `NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL` environment variable
633
+ - Verify middleware configuration
634
+ - Check browser console for errors
635
+
636
+ **Issue: Organization ID not syncing**
637
+
638
+ - Verify organization webhooks are enabled
639
+ - Check webhook logs in Clerk dashboard
640
+ - Ensure `organizationMembership.created` event is selected
641
+
642
+ ---
643
+
644
+ ## Related Documentation
645
+
646
+ - [Environment Variables](./environment-variables.md) - Clerk environment variables
647
+ - [API Layer](./api-layer.md) - API authentication middleware
648
+ - [Health Check System](./health-check-system.md) - Health check endpoints
649
+ - [Supabase Integration](./supabase-integration.md) - Database schema for users