@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.
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +16 -13
- package/dist/commands/create.js.map +1 -1
- package/package.json +3 -2
- package/template/.env.example +106 -0
- package/template/components.json +22 -0
- package/template/docs/framework/01-overview.md +289 -0
- package/template/docs/framework/02-techstack.md +503 -0
- package/template/docs/framework/api-layer.md +681 -0
- package/template/docs/framework/clerk-authentication.md +649 -0
- package/template/docs/framework/cli-installation.md +564 -0
- package/template/docs/framework/deployment/ci-cd.md +907 -0
- package/template/docs/framework/deployment/digitalocean.md +991 -0
- package/template/docs/framework/deployment/domain-setup.md +972 -0
- package/template/docs/framework/deployment/environment-variables.md +862 -0
- package/template/docs/framework/deployment/monitoring.md +927 -0
- package/template/docs/framework/deployment/production-checklist.md +649 -0
- package/template/docs/framework/deployment/vercel.md +791 -0
- package/template/docs/framework/environment-variables.md +646 -0
- package/template/docs/framework/health-check-system.md +583 -0
- package/template/docs/framework/implementation.md +559 -0
- package/template/docs/framework/snowflake-integration.md +594 -0
- package/template/docs/framework/state-management.md +615 -0
- package/template/docs/framework/supabase-integration.md +582 -0
- package/template/docs/framework/testing-guide.md +544 -0
- package/template/docs/framework/what-did-i-miss.md +526 -0
- package/template/drizzle.config.ts +11 -0
- package/template/next.config.js +21 -0
- package/template/postcss.config.js +5 -0
- package/template/prettier.config.js +4 -0
- package/template/public/favicon.ico +0 -0
- package/template/src/app/(auth)/layout.tsx +4 -0
- package/template/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +10 -0
- package/template/src/app/(auth)/sign-up/[[...sign-up]]/page.tsx +10 -0
- package/template/src/app/(dashboard)/dashboard/page.tsx +8 -0
- package/template/src/app/(dashboard)/health/page.tsx +16 -0
- package/template/src/app/(dashboard)/layout.tsx +17 -0
- package/template/src/app/api/[[...route]]/route.ts +11 -0
- package/template/src/app/api/debug-files/route.ts +33 -0
- package/template/src/app/api/webhooks/clerk/route.ts +112 -0
- package/template/src/app/layout.tsx +28 -0
- package/template/src/app/page.tsx +12 -0
- package/template/src/app/providers.tsx +20 -0
- package/template/src/components/layouts/navbar.tsx +14 -0
- package/template/src/components/shared/loading-spinner.tsx +6 -0
- package/template/src/components/ui/badge.tsx +46 -0
- package/template/src/components/ui/button.tsx +62 -0
- package/template/src/components/ui/card.tsx +92 -0
- package/template/src/components/ui/collapsible.tsx +33 -0
- package/template/src/components/ui/scroll-area.tsx +58 -0
- package/template/src/components/ui/sheet.tsx +139 -0
- package/template/src/config/__tests__/env.test.ts +164 -0
- package/template/src/config/__tests__/site.test.ts +46 -0
- package/template/src/config/env.ts +36 -0
- package/template/src/config/site.ts +10 -0
- package/template/src/env.js +44 -0
- package/template/src/features/__tests__/health-check-config.test.ts +142 -0
- package/template/src/features/__tests__/health-check-types.test.ts +201 -0
- package/template/src/features/documentation/components/doc-sidebar.tsx +109 -0
- package/template/src/features/documentation/components/doc-viewer.tsx +70 -0
- package/template/src/features/documentation/index.tsx +92 -0
- package/template/src/features/documentation/utils/doc-loader.ts +177 -0
- package/template/src/features/health-check/components/health-dashboard.tsx +374 -0
- package/template/src/features/health-check/config.ts +71 -0
- package/template/src/features/health-check/index.ts +4 -0
- package/template/src/features/health-check/stores/health-store.ts +14 -0
- package/template/src/features/health-check/types.ts +18 -0
- package/template/src/hooks/__tests__/use-debounce.test.tsx +28 -0
- package/template/src/hooks/queries/use-health-checks.ts +16 -0
- package/template/src/hooks/utils/use-debounce.ts +20 -0
- package/template/src/lib/__tests__/utils.test.ts +52 -0
- package/template/src/lib/__tests__/validators.test.ts +114 -0
- package/template/src/lib/nextbank/client.ts +67 -0
- package/template/src/lib/snowflake/client.ts +102 -0
- package/template/src/lib/supabase/admin.ts +7 -0
- package/template/src/lib/supabase/client.ts +7 -0
- package/template/src/lib/supabase/server.ts +23 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/src/lib/validators.ts +9 -0
- package/template/src/middleware.ts +22 -0
- package/template/src/server/api/index.ts +22 -0
- package/template/src/server/api/middleware/auth.ts +19 -0
- package/template/src/server/api/middleware/logger.ts +4 -0
- package/template/src/server/api/routes/health/clerk.ts +214 -0
- package/template/src/server/api/routes/health/database.ts +141 -0
- package/template/src/server/api/routes/health/edge-functions.ts +107 -0
- package/template/src/server/api/routes/health/framework.ts +48 -0
- package/template/src/server/api/routes/health/index.ts +102 -0
- package/template/src/server/api/routes/health/nextbank.ts +46 -0
- package/template/src/server/api/routes/health/snowflake.ts +83 -0
- package/template/src/server/api/routes/health/storage.ts +177 -0
- package/template/src/server/api/routes/users.ts +79 -0
- package/template/src/server/db/index.ts +17 -0
- package/template/src/server/db/queries/users.ts +8 -0
- package/template/src/server/db/schema/__tests__/health-checks.test.ts +31 -0
- package/template/src/server/db/schema/__tests__/users.test.ts +46 -0
- package/template/src/server/db/schema/health-checks.ts +11 -0
- package/template/src/server/db/schema/index.ts +2 -0
- package/template/src/server/db/schema/users.ts +16 -0
- package/template/src/server/db/schema.ts +1 -0
- package/template/src/stores/__tests__/ui-store.test.ts +87 -0
- package/template/src/stores/ui-store.ts +14 -0
- package/template/src/styles/globals.css +129 -0
- package/template/src/test/mocks/clerk.ts +35 -0
- package/template/src/test/mocks/snowflake.ts +28 -0
- package/template/src/test/mocks/supabase.ts +37 -0
- package/template/src/test/setup.ts +69 -0
- package/template/src/test/utils/test-helpers.ts +158 -0
- package/template/src/types/index.ts +14 -0
- package/template/tsconfig.json +43 -0
- package/template/vitest.config.ts +44 -0
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
# DTT Framework - Deployment Environment Variables
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document provides a comprehensive guide to managing environment variables for deploying the DTT Framework. It covers the complete list of required variables, platform-specific configurations, security best practices, and credential management.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Complete List of Required Environment Variables](#complete-list-of-required-environment-variables)
|
|
12
|
+
2. [Platform-Specific Configuration](#platform-specific-configuration)
|
|
13
|
+
3. [Security Best Practices](#security-best-practices)
|
|
14
|
+
4. [Managing Secrets](#managing-secrets)
|
|
15
|
+
5. [Rotating Credentials](#rotating-credentials)
|
|
16
|
+
6. [Environment Variable Templates](#environment-variable-templates)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Complete List of Required Environment Variables
|
|
21
|
+
|
|
22
|
+
### Application Variables
|
|
23
|
+
|
|
24
|
+
| Variable Name | Type | Required | Description | Example |
|
|
25
|
+
|---------------|------|----------|-------------|---------|
|
|
26
|
+
| `NEXT_PUBLIC_APP_URL` | Public | Yes | Base URL of your application | `https://your-app.com` |
|
|
27
|
+
| `NODE_ENV` | Server | Yes | Node environment | `production` |
|
|
28
|
+
|
|
29
|
+
### Clerk Authentication Variables
|
|
30
|
+
|
|
31
|
+
| Variable Name | Type | Required | Description | Example |
|
|
32
|
+
|---------------|------|----------|-------------|---------|
|
|
33
|
+
| `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` | Public | Yes | Clerk publishable key (client-side) | `pk_live_xxx` |
|
|
34
|
+
| `CLERK_SECRET_KEY` | Server | Yes | Clerk secret key (server-side) | `sk_live_xxx` |
|
|
35
|
+
| `CLERK_WEBHOOK_SECRET` | Server | Yes | Clerk webhook signing secret | `whsec_xxx` |
|
|
36
|
+
| `NEXT_PUBLIC_CLERK_SIGN_IN_URL` | Public | Yes | Sign-in page URL | `/sign-in` |
|
|
37
|
+
| `NEXT_PUBLIC_CLERK_SIGN_UP_URL` | Public | Yes | Sign-up page URL | `/sign-up` |
|
|
38
|
+
| `NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL` | Public | Yes | Redirect URL after sign-in | `/health` |
|
|
39
|
+
| `NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL` | Public | Yes | Redirect URL after sign-up | `/health` |
|
|
40
|
+
|
|
41
|
+
### Supabase Variables
|
|
42
|
+
|
|
43
|
+
| Variable Name | Type | Required | Description | Example |
|
|
44
|
+
|---------------|------|----------|-------------|---------|
|
|
45
|
+
| `NEXT_PUBLIC_SUPABASE_URL` | Public | Yes | Supabase project URL | `https://xxx.supabase.co` |
|
|
46
|
+
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Public | Yes | Supabase anonymous key | `eyJxxx` |
|
|
47
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Server | Yes | Supabase service role key | `eyJxxx` |
|
|
48
|
+
| `DATABASE_URL` | Server | Yes | PostgreSQL connection string | `postgresql://user:pass@host:6543/db` |
|
|
49
|
+
|
|
50
|
+
### Snowflake Variables (Optional)
|
|
51
|
+
|
|
52
|
+
| Variable Name | Type | Required | Description | Example |
|
|
53
|
+
|---------------|------|----------|-------------|---------|
|
|
54
|
+
| `SNOWFLAKE_ACCOUNT` | Server | No | Snowflake account identifier | `xxx.us-east-1` |
|
|
55
|
+
| `SNOWFLAKE_USERNAME` | Server | No | Snowflake username | `myuser` |
|
|
56
|
+
| `SNOWFLAKE_PASSWORD` | Server | No | Snowflake password | `mypassword` |
|
|
57
|
+
| `SNOWFLAKE_WAREHOUSE` | Server | No | Snowflake warehouse name | `COMPUTE_WH` |
|
|
58
|
+
| `SNOWFLAKE_DATABASE` | Server | No | Snowflake database name | `ANALYTICS` |
|
|
59
|
+
| `SNOWFLAKE_SCHEMA` | Server | No | Snowflake schema name | `PUBLIC` |
|
|
60
|
+
| `SNOWFLAKE_ROLE` | Server | No | Snowflake role name | `ANALYST` |
|
|
61
|
+
|
|
62
|
+
### NextBank Variables (Placeholder, Optional)
|
|
63
|
+
|
|
64
|
+
| Variable Name | Type | Required | Description | Example |
|
|
65
|
+
|---------------|------|----------|-------------|---------|
|
|
66
|
+
| `NEXTBANK_API` | Server | No | NextBank API endpoint | `https://api.nextbank.com` |
|
|
67
|
+
| `NEXTBANK_API_USERNAME` | Server | No | NextBank API username | `user` |
|
|
68
|
+
| `NEXTBANK_API_PASSWORD` | Server | No | NextBank API password | `pass` |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Platform-Specific Configuration
|
|
73
|
+
|
|
74
|
+
### Vercel Configuration
|
|
75
|
+
|
|
76
|
+
#### Setting Variables via Dashboard
|
|
77
|
+
|
|
78
|
+
1. Go to **Settings** → **Environment Variables**
|
|
79
|
+
2. Click **"Add New"**
|
|
80
|
+
3. Enter variable name and value
|
|
81
|
+
4. Select environments (Production, Preview, Development)
|
|
82
|
+
5. Click **"Save"**
|
|
83
|
+
|
|
84
|
+
#### Setting Variables via CLI
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Add variable to production
|
|
88
|
+
vercel env add DATABASE_URL production
|
|
89
|
+
|
|
90
|
+
# Add variable to all environments
|
|
91
|
+
vercel env add NEXT_PUBLIC_APP_URL
|
|
92
|
+
|
|
93
|
+
# List all variables
|
|
94
|
+
vercel env ls
|
|
95
|
+
|
|
96
|
+
# Pull variables locally
|
|
97
|
+
vercel env pull .env.production
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Environment-Specific Variables
|
|
101
|
+
|
|
102
|
+
Vercel supports three environments:
|
|
103
|
+
|
|
104
|
+
| Environment | Use Case | Branch |
|
|
105
|
+
|-------------|----------|--------|
|
|
106
|
+
| **Production** | Live application | `main` or `master` |
|
|
107
|
+
| **Preview** | Pull request deployments | Pull request branches |
|
|
108
|
+
| **Development** | Testing environment | `dev` branch |
|
|
109
|
+
|
|
110
|
+
#### Vercel .env.example
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# ============================================
|
|
114
|
+
# DTT Framework - Vercel Environment Variables
|
|
115
|
+
# ============================================
|
|
116
|
+
|
|
117
|
+
# Application
|
|
118
|
+
NEXT_PUBLIC_APP_URL=https://your-app.vercel.app
|
|
119
|
+
NODE_ENV=production
|
|
120
|
+
|
|
121
|
+
# Clerk Authentication
|
|
122
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxx
|
|
123
|
+
CLERK_SECRET_KEY=sk_live_xxx
|
|
124
|
+
CLERK_WEBHOOK_SECRET=whsec_xxx
|
|
125
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
126
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
127
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
|
|
128
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
|
|
129
|
+
|
|
130
|
+
# Supabase
|
|
131
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
|
132
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxx
|
|
133
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJxxx
|
|
134
|
+
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
135
|
+
|
|
136
|
+
# Snowflake (Optional)
|
|
137
|
+
SNOWFLAKE_ACCOUNT=xxx.us-east-1
|
|
138
|
+
SNOWFLAKE_USERNAME=xxx
|
|
139
|
+
SNOWFLAKE_PASSWORD=xxx
|
|
140
|
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
|
141
|
+
SNOWFLAKE_DATABASE=ANALYTICS
|
|
142
|
+
SNOWFLAKE_SCHEMA=PUBLIC
|
|
143
|
+
SNOWFLAKE_ROLE=ANALYST
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### DigitalOcean App Platform Configuration
|
|
147
|
+
|
|
148
|
+
#### Setting Variables via Dashboard
|
|
149
|
+
|
|
150
|
+
1. Go to **App Platform** → **Your App** → **Settings**
|
|
151
|
+
2. Scroll to **Environment Variables**
|
|
152
|
+
3. Click **"Add Variable"**
|
|
153
|
+
4. Enter variable name and value
|
|
154
|
+
5. Click **"Save"**
|
|
155
|
+
|
|
156
|
+
#### Setting Variables via doctl CLI
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Install doctl
|
|
160
|
+
snap install doctl
|
|
161
|
+
|
|
162
|
+
# Authenticate
|
|
163
|
+
doctl auth init
|
|
164
|
+
|
|
165
|
+
# Add variable to app
|
|
166
|
+
doctl apps create-deployment <app-id> --env DATABASE_URL="postgresql://..."
|
|
167
|
+
|
|
168
|
+
# List variables
|
|
169
|
+
doctl apps spec <app-id>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### DigitalOcean App Platform .env.example
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# ============================================
|
|
176
|
+
# DTT Framework - DigitalOcean App Platform
|
|
177
|
+
# ============================================
|
|
178
|
+
|
|
179
|
+
# Application
|
|
180
|
+
NEXT_PUBLIC_APP_URL=https://your-app.ondigitalocean.app
|
|
181
|
+
NODE_ENV=production
|
|
182
|
+
|
|
183
|
+
# Clerk Authentication
|
|
184
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxx
|
|
185
|
+
CLERK_SECRET_KEY=sk_live_xxx
|
|
186
|
+
CLERK_WEBHOOK_SECRET=whsec_xxx
|
|
187
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
188
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
189
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
|
|
190
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
|
|
191
|
+
|
|
192
|
+
# Supabase
|
|
193
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
|
194
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxx
|
|
195
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJxxx
|
|
196
|
+
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
197
|
+
|
|
198
|
+
# Snowflake (Optional)
|
|
199
|
+
SNOWFLAKE_ACCOUNT=xxx.us-east-1
|
|
200
|
+
SNOWFLAKE_USERNAME=xxx
|
|
201
|
+
SNOWFLAKE_PASSWORD=xxx
|
|
202
|
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
|
203
|
+
SNOWFLAKE_DATABASE=ANALYTICS
|
|
204
|
+
SNOWFLAKE_SCHEMA=PUBLIC
|
|
205
|
+
SNOWFLAKE_ROLE=ANALYST
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### DigitalOcean Droplet Configuration
|
|
209
|
+
|
|
210
|
+
#### Setting Variables via File
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# Create .env file
|
|
214
|
+
nano /var/www/dtt-framework/.env
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Add environment variables:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# ============================================
|
|
221
|
+
# DTT Framework - DigitalOcean Droplet
|
|
222
|
+
# ============================================
|
|
223
|
+
|
|
224
|
+
# Application
|
|
225
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com
|
|
226
|
+
NODE_ENV=production
|
|
227
|
+
|
|
228
|
+
# Clerk Authentication
|
|
229
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxx
|
|
230
|
+
CLERK_SECRET_KEY=sk_live_xxx
|
|
231
|
+
CLERK_WEBHOOK_SECRET=whsec_xxx
|
|
232
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
233
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
234
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
|
|
235
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
|
|
236
|
+
|
|
237
|
+
# Supabase
|
|
238
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
|
239
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxx
|
|
240
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJxxx
|
|
241
|
+
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
242
|
+
|
|
243
|
+
# Snowflake (Optional)
|
|
244
|
+
SNOWFLAKE_ACCOUNT=xxx.us-east-1
|
|
245
|
+
SNOWFLAKE_USERNAME=xxx
|
|
246
|
+
SNOWFLAKE_PASSWORD=xxx
|
|
247
|
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
|
248
|
+
SNOWFLAKE_DATABASE=ANALYTICS
|
|
249
|
+
SNOWFLAKE_SCHEMA=PUBLIC
|
|
250
|
+
SNOWFLAKE_ROLE=ANALYST
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Secure the .env File
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Set correct permissions
|
|
257
|
+
chmod 600 /var/www/dtt-framework/.env
|
|
258
|
+
|
|
259
|
+
# Verify permissions
|
|
260
|
+
ls -la /var/www/dtt-framework/.env
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### Restart Application After Changes
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Restart PM2 application
|
|
267
|
+
pm2 restart dtt-framework
|
|
268
|
+
|
|
269
|
+
# Or reload without downtime
|
|
270
|
+
pm2 reload dtt-framework
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### GitHub Actions Configuration
|
|
274
|
+
|
|
275
|
+
#### Setting Variables via GitHub Secrets
|
|
276
|
+
|
|
277
|
+
1. Go to **Repository** → **Settings** → **Secrets and variables** → **Actions**
|
|
278
|
+
2. Click **"New repository secret"**
|
|
279
|
+
3. Enter secret name and value
|
|
280
|
+
4. Click **"Add secret"**
|
|
281
|
+
|
|
282
|
+
#### Using Secrets in Workflow
|
|
283
|
+
|
|
284
|
+
```yaml
|
|
285
|
+
# .github/workflows/deploy.yml
|
|
286
|
+
name: Deploy
|
|
287
|
+
|
|
288
|
+
on:
|
|
289
|
+
push:
|
|
290
|
+
branches: [main]
|
|
291
|
+
|
|
292
|
+
jobs:
|
|
293
|
+
deploy:
|
|
294
|
+
runs-on: ubuntu-latest
|
|
295
|
+
steps:
|
|
296
|
+
- uses: actions/checkout@v4
|
|
297
|
+
|
|
298
|
+
- name: Setup Node.js
|
|
299
|
+
uses: actions/setup-node@v4
|
|
300
|
+
with:
|
|
301
|
+
node-version: '20'
|
|
302
|
+
|
|
303
|
+
- name: Install pnpm
|
|
304
|
+
uses: pnpm/action-setup@v2
|
|
305
|
+
with:
|
|
306
|
+
version: 10
|
|
307
|
+
|
|
308
|
+
- name: Install dependencies
|
|
309
|
+
run: pnpm install
|
|
310
|
+
|
|
311
|
+
- name: Build application
|
|
312
|
+
env:
|
|
313
|
+
NEXT_PUBLIC_APP_URL: ${{ secrets.NEXT_PUBLIC_APP_URL }}
|
|
314
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
|
|
315
|
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
316
|
+
run: pnpm build
|
|
317
|
+
|
|
318
|
+
- name: Deploy to Vercel
|
|
319
|
+
uses: amondnet/vercel-action@v25
|
|
320
|
+
with:
|
|
321
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
322
|
+
vercel-org-id: ${{ secrets.ORG_ID }}
|
|
323
|
+
vercel-project-id: ${{ secrets.PROJECT_ID }}
|
|
324
|
+
vercel-args: '--prod'
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Security Best Practices
|
|
330
|
+
|
|
331
|
+
### 1. Never Commit .env Files
|
|
332
|
+
|
|
333
|
+
Always add `.env` to `.gitignore`:
|
|
334
|
+
|
|
335
|
+
```gitignore
|
|
336
|
+
# Environment variables
|
|
337
|
+
.env
|
|
338
|
+
.env.local
|
|
339
|
+
.env.development.local
|
|
340
|
+
.env.test.local
|
|
341
|
+
.env.production.local
|
|
342
|
+
|
|
343
|
+
# Also ignore secrets files
|
|
344
|
+
*.key
|
|
345
|
+
*.pem
|
|
346
|
+
secrets/
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 2. Use Environment-Specific Files
|
|
350
|
+
|
|
351
|
+
Use different environment files for different stages:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
# Development
|
|
355
|
+
.env.development
|
|
356
|
+
|
|
357
|
+
# Staging
|
|
358
|
+
.env.staging
|
|
359
|
+
|
|
360
|
+
# Production
|
|
361
|
+
.env.production
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Load appropriate file based on environment:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
# In package.json scripts
|
|
368
|
+
"dev": "cp .env.development .env && next dev",
|
|
369
|
+
"build:staging": "cp .env.staging .env && next build",
|
|
370
|
+
"build:production": "cp .env.production .env && next build"
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### 3. Prefix Client Variables
|
|
374
|
+
|
|
375
|
+
Only prefix variables with `NEXT_PUBLIC_` if they need to be exposed to client:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
# ✅ Good - Exposed to client (safe)
|
|
379
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com
|
|
380
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxx
|
|
381
|
+
|
|
382
|
+
# ❌ Bad - Not exposed, but might be needed
|
|
383
|
+
APP_URL=https://your-app.com
|
|
384
|
+
CLERK_PUBLISHABLE_KEY=pk_live_xxx
|
|
385
|
+
|
|
386
|
+
# ✅ Good - Server-side only (secure)
|
|
387
|
+
DATABASE_URL=postgresql://user:pass@host:6543/db
|
|
388
|
+
CLERK_SECRET_KEY=sk_live_xxx
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### 4. Validate Environment Variables
|
|
392
|
+
|
|
393
|
+
The framework uses `@t3-oss/env-nextjs` for validation:
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
// src/config/env.ts
|
|
397
|
+
import { createEnv } from '@t3-oss/env-nextjs'
|
|
398
|
+
import { z } from 'zod'
|
|
399
|
+
|
|
400
|
+
export const env = createEnv({
|
|
401
|
+
server: {
|
|
402
|
+
DATABASE_URL: z.string().url(),
|
|
403
|
+
CLERK_SECRET_KEY: z.string().startsWith('sk_'),
|
|
404
|
+
CLERK_WEBHOOK_SECRET: z.string().startsWith('whsec_'),
|
|
405
|
+
SUPABASE_SERVICE_ROLE_KEY: z.string(),
|
|
406
|
+
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
|
|
407
|
+
},
|
|
408
|
+
client: {
|
|
409
|
+
NEXT_PUBLIC_APP_URL: z.string().url(),
|
|
410
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().startsWith('pk_'),
|
|
411
|
+
NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
|
|
412
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string(),
|
|
413
|
+
},
|
|
414
|
+
runtimeEnv: {
|
|
415
|
+
DATABASE_URL: process.env.DATABASE_URL,
|
|
416
|
+
CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
|
|
417
|
+
CLERK_WEBHOOK_SECRET: process.env.CLERK_WEBHOOK_SECRET,
|
|
418
|
+
SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
|
419
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
420
|
+
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
|
|
421
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
|
|
422
|
+
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
|
423
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
|
424
|
+
},
|
|
425
|
+
})
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
This ensures:
|
|
429
|
+
- All required variables are present
|
|
430
|
+
- Variables are correctly formatted
|
|
431
|
+
- Build fails if variables are missing
|
|
432
|
+
|
|
433
|
+
### 5. Use Secret Management Services
|
|
434
|
+
|
|
435
|
+
For production, consider using secret management:
|
|
436
|
+
|
|
437
|
+
| Service | Platform | Description |
|
|
438
|
+
|---------|----------|-------------|
|
|
439
|
+
| **Vercel Environment Variables** | Vercel | Built-in secret management |
|
|
440
|
+
| **DigitalOcean App Platform** | DigitalOcean | Built-in secret management |
|
|
441
|
+
| **GitHub Secrets** | GitHub Actions | CI/CD secrets |
|
|
442
|
+
| **AWS Secrets Manager** | AWS | Enterprise secret management |
|
|
443
|
+
| **HashiCorp Vault** | Multi-cloud | Advanced secret management |
|
|
444
|
+
| **1Password Secrets Automation** | Multi-cloud | Password manager integration |
|
|
445
|
+
|
|
446
|
+
### 6. Implement Least Privilege
|
|
447
|
+
|
|
448
|
+
Use the minimum required permissions for each key:
|
|
449
|
+
|
|
450
|
+
| Key Type | Permissions | Use Case |
|
|
451
|
+
|----------|-------------|----------|
|
|
452
|
+
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Limited (RLS) | Client-side operations |
|
|
453
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Full access | Server-side operations |
|
|
454
|
+
| `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` | Read-only | Client-side auth |
|
|
455
|
+
| `CLERK_SECRET_KEY` | Full access | Server-side auth |
|
|
456
|
+
|
|
457
|
+
### 7. Rotate Secrets Regularly
|
|
458
|
+
|
|
459
|
+
Establish a secret rotation schedule:
|
|
460
|
+
|
|
461
|
+
| Secret Type | Rotation Frequency |
|
|
462
|
+
|-------------|-------------------|
|
|
463
|
+
| API Keys | Every 90 days |
|
|
464
|
+
| Database Passwords | Every 180 days |
|
|
465
|
+
| Webhook Secrets | When compromised |
|
|
466
|
+
| Service Role Keys | Every 180 days |
|
|
467
|
+
|
|
468
|
+
### 8. Audit Access to Secrets
|
|
469
|
+
|
|
470
|
+
Track who has access to secrets:
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
# Vercel: Check team member access
|
|
474
|
+
# Dashboard → Team → Members
|
|
475
|
+
|
|
476
|
+
# GitHub: Check secret access
|
|
477
|
+
# Settings → Secrets and variables → Actions
|
|
478
|
+
|
|
479
|
+
# DigitalOcean: Check team access
|
|
480
|
+
# Dashboard → Team → Members
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## Managing Secrets
|
|
486
|
+
|
|
487
|
+
### Secret Management Strategies
|
|
488
|
+
|
|
489
|
+
#### 1. Environment Variable Files
|
|
490
|
+
|
|
491
|
+
Use `.env` files for local development:
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
# .env.local (not committed)
|
|
495
|
+
DATABASE_URL=postgresql://user:pass@localhost:5432/db
|
|
496
|
+
CLERK_SECRET_KEY=sk_test_xxx
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### 2. Secret Management Tools
|
|
500
|
+
|
|
501
|
+
Use tools like:
|
|
502
|
+
|
|
503
|
+
- **direnv**: Load environment variables automatically
|
|
504
|
+
- **dotenv**: Load variables from `.env` files
|
|
505
|
+
- **envsubst**: Substitute variables in files
|
|
506
|
+
|
|
507
|
+
#### 3. Encrypted Secrets
|
|
508
|
+
|
|
509
|
+
Use encryption for sensitive secrets:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
# Using OpenSSL
|
|
513
|
+
openssl enc -aes-256-cbc -salt -in secret.txt -out secret.enc
|
|
514
|
+
|
|
515
|
+
# Decrypt
|
|
516
|
+
openssl enc -aes-256-cbc -d -in secret.enc -out secret.txt
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Secret Storage Options
|
|
520
|
+
|
|
521
|
+
#### Option 1: Platform-Native Storage
|
|
522
|
+
|
|
523
|
+
| Platform | Storage Method | Security |
|
|
524
|
+
|----------|---------------|----------|
|
|
525
|
+
| **Vercel** | Environment Variables | Encrypted at rest |
|
|
526
|
+
| **DigitalOcean App Platform** | Environment Variables | Encrypted at rest |
|
|
527
|
+
| **DigitalOcean Droplet** | File system | Manual encryption needed |
|
|
528
|
+
|
|
529
|
+
#### Option 2: Third-Party Secret Managers
|
|
530
|
+
|
|
531
|
+
| Tool | Features | Cost |
|
|
532
|
+
|------|----------|------|
|
|
533
|
+
| **AWS Secrets Manager** | Auto-rotation, audit logs | Paid |
|
|
534
|
+
| **HashiCorp Vault** | Advanced features | Open source + Paid |
|
|
535
|
+
| **1Password** | UI-based, team sharing | Paid |
|
|
536
|
+
| **Infisical** | Open source, syncs to platforms | Free tier available |
|
|
537
|
+
|
|
538
|
+
### Secret Access Control
|
|
539
|
+
|
|
540
|
+
#### Grant Access by Role
|
|
541
|
+
|
|
542
|
+
```yaml
|
|
543
|
+
# Example: Role-based access
|
|
544
|
+
roles:
|
|
545
|
+
- developer:
|
|
546
|
+
secrets: [DATABASE_URL, API_KEY]
|
|
547
|
+
- devops:
|
|
548
|
+
secrets: [DATABASE_URL, API_KEY, CLERK_SECRET_KEY]
|
|
549
|
+
- admin:
|
|
550
|
+
secrets: [ALL_SECRETS]
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
#### Use Temporary Credentials
|
|
554
|
+
|
|
555
|
+
For CI/CD, use temporary credentials:
|
|
556
|
+
|
|
557
|
+
```yaml
|
|
558
|
+
# GitHub Actions example
|
|
559
|
+
jobs:
|
|
560
|
+
deploy:
|
|
561
|
+
steps:
|
|
562
|
+
- name: Get temporary credentials
|
|
563
|
+
id: creds
|
|
564
|
+
run: |
|
|
565
|
+
TOKEN=$(curl -X POST https://api.example.com/creds)
|
|
566
|
+
echo "::add-mask::$TOKEN"
|
|
567
|
+
echo "::set-output name=token::$TOKEN"
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Rotating Credentials
|
|
573
|
+
|
|
574
|
+
### Rotation Strategy
|
|
575
|
+
|
|
576
|
+
#### 1. Plan Rotation
|
|
577
|
+
|
|
578
|
+
Create a rotation plan:
|
|
579
|
+
|
|
580
|
+
| Step | Description | Timeline |
|
|
581
|
+
|------|-------------|----------|
|
|
582
|
+
| **Preparation** | Generate new credentials | Day 1 |
|
|
583
|
+
| **Testing** | Test new credentials in staging | Day 2 |
|
|
584
|
+
| **Deployment** | Deploy new credentials to production | Day 3 |
|
|
585
|
+
| **Verification** | Verify application works | Day 3 |
|
|
586
|
+
| **Cleanup** | Revoke old credentials | Day 7 |
|
|
587
|
+
|
|
588
|
+
#### 2. Rotate Clerk Keys
|
|
589
|
+
|
|
590
|
+
```bash
|
|
591
|
+
# 1. Generate new keys in Clerk Dashboard
|
|
592
|
+
# Dashboard → Your App → API Keys → Rotate
|
|
593
|
+
|
|
594
|
+
# 2. Update environment variables
|
|
595
|
+
vercel env add CLERK_SECRET_KEY production
|
|
596
|
+
|
|
597
|
+
# 3. Redeploy application
|
|
598
|
+
vercel --prod
|
|
599
|
+
|
|
600
|
+
# 4. Verify authentication works
|
|
601
|
+
# Test sign-in/sign-up flows
|
|
602
|
+
|
|
603
|
+
# 5. Revoke old keys (after 7 days)
|
|
604
|
+
# Clerk Dashboard → API Keys → Revoke
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
#### 3. Rotate Supabase Keys
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
# 1. Generate new keys in Supabase Dashboard
|
|
611
|
+
# Dashboard → Settings → API → Rotate
|
|
612
|
+
|
|
613
|
+
# 2. Update environment variables
|
|
614
|
+
vercel env add SUPABASE_SERVICE_ROLE_KEY production
|
|
615
|
+
|
|
616
|
+
# 3. Redeploy application
|
|
617
|
+
vercel --prod
|
|
618
|
+
|
|
619
|
+
# 4. Verify database operations work
|
|
620
|
+
# Test database queries
|
|
621
|
+
|
|
622
|
+
# 5. Revoke old keys (after 7 days)
|
|
623
|
+
# Supabase Dashboard → Settings → API → Revoke
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
#### 4. Rotate Database Password
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
# 1. Generate new password
|
|
630
|
+
# Use a password manager
|
|
631
|
+
|
|
632
|
+
# 2. Update database password
|
|
633
|
+
# Supabase Dashboard → Settings → Database → Password
|
|
634
|
+
|
|
635
|
+
# 3. Update DATABASE_URL
|
|
636
|
+
vercel env add DATABASE_URL production
|
|
637
|
+
|
|
638
|
+
# 4. Redeploy application
|
|
639
|
+
vercel --prod
|
|
640
|
+
|
|
641
|
+
# 5. Verify database connection
|
|
642
|
+
# Test database operations
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### Automated Rotation
|
|
646
|
+
|
|
647
|
+
#### Using Cron Jobs
|
|
648
|
+
|
|
649
|
+
```bash
|
|
650
|
+
# Set up automated rotation check
|
|
651
|
+
# Add to crontab:
|
|
652
|
+
0 0 1 * * /usr/local/bin/check-rotation.sh
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### Using CI/CD
|
|
656
|
+
|
|
657
|
+
```yaml
|
|
658
|
+
# .github/workflows/rotate-secrets.yml
|
|
659
|
+
name: Rotate Secrets
|
|
660
|
+
|
|
661
|
+
on:
|
|
662
|
+
schedule:
|
|
663
|
+
- cron: '0 0 1 * *' # Monthly
|
|
664
|
+
|
|
665
|
+
jobs:
|
|
666
|
+
rotate:
|
|
667
|
+
runs-on: ubuntu-latest
|
|
668
|
+
steps:
|
|
669
|
+
- name: Check secret age
|
|
670
|
+
run: |
|
|
671
|
+
# Check if secrets need rotation
|
|
672
|
+
# Trigger rotation if needed
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## Environment Variable Templates
|
|
678
|
+
|
|
679
|
+
### Development Template (.env.development)
|
|
680
|
+
|
|
681
|
+
```bash
|
|
682
|
+
# ============================================
|
|
683
|
+
# DTT Framework - Development Environment
|
|
684
|
+
# ============================================
|
|
685
|
+
|
|
686
|
+
# Application
|
|
687
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
688
|
+
NODE_ENV=development
|
|
689
|
+
|
|
690
|
+
# Clerk Authentication (Test Mode)
|
|
691
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
|
|
692
|
+
CLERK_SECRET_KEY=sk_test_xxx
|
|
693
|
+
CLERK_WEBHOOK_SECRET=whsec_test_xxx
|
|
694
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
695
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
696
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
|
|
697
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
|
|
698
|
+
|
|
699
|
+
# Supabase (Development Project)
|
|
700
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx-dev.supabase.co
|
|
701
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxx
|
|
702
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJxxx
|
|
703
|
+
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
704
|
+
|
|
705
|
+
# Snowflake (Optional - Test Account)
|
|
706
|
+
SNOWFLAKE_ACCOUNT=xxx.us-east-1
|
|
707
|
+
SNOWFLAKE_USERNAME=xxx
|
|
708
|
+
SNOWFLAKE_PASSWORD=xxx
|
|
709
|
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
|
710
|
+
SNOWFLAKE_DATABASE=ANALYTICS
|
|
711
|
+
SNOWFLAKE_SCHEMA=PUBLIC
|
|
712
|
+
SNOWFLAKE_ROLE=ANALYST
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
### Staging Template (.env.staging)
|
|
716
|
+
|
|
717
|
+
```bash
|
|
718
|
+
# ============================================
|
|
719
|
+
# DTT Framework - Staging Environment
|
|
720
|
+
# ============================================
|
|
721
|
+
|
|
722
|
+
# Application
|
|
723
|
+
NEXT_PUBLIC_APP_URL=https://staging.your-app.com
|
|
724
|
+
NODE_ENV=production
|
|
725
|
+
|
|
726
|
+
# Clerk Authentication (Test Mode)
|
|
727
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
|
|
728
|
+
CLERK_SECRET_KEY=sk_test_xxx
|
|
729
|
+
CLERK_WEBHOOK_SECRET=whsec_test_xxx
|
|
730
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
731
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
732
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
|
|
733
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
|
|
734
|
+
|
|
735
|
+
# Supabase (Staging Project)
|
|
736
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx-staging.supabase.co
|
|
737
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxx
|
|
738
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJxxx
|
|
739
|
+
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
740
|
+
|
|
741
|
+
# Snowflake (Optional - Test Account)
|
|
742
|
+
SNOWFLAKE_ACCOUNT=xxx.us-east-1
|
|
743
|
+
SNOWFLAKE_USERNAME=xxx
|
|
744
|
+
SNOWFLAKE_PASSWORD=xxx
|
|
745
|
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
|
746
|
+
SNOWFLAKE_DATABASE=ANALYTICS
|
|
747
|
+
SNOWFLAKE_SCHEMA=PUBLIC
|
|
748
|
+
SNOWFLAKE_ROLE=ANALYST
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
### Production Template (.env.production)
|
|
752
|
+
|
|
753
|
+
```bash
|
|
754
|
+
# ============================================
|
|
755
|
+
# DTT Framework - Production Environment
|
|
756
|
+
# ============================================
|
|
757
|
+
|
|
758
|
+
# Application
|
|
759
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com
|
|
760
|
+
NODE_ENV=production
|
|
761
|
+
|
|
762
|
+
# Clerk Authentication (Live Mode)
|
|
763
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxx
|
|
764
|
+
CLERK_SECRET_KEY=sk_live_xxx
|
|
765
|
+
CLERK_WEBHOOK_SECRET=whsec_xxx
|
|
766
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
767
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
768
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/health
|
|
769
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/health
|
|
770
|
+
|
|
771
|
+
# Supabase (Production Project)
|
|
772
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
|
773
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxx
|
|
774
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJxxx
|
|
775
|
+
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
776
|
+
|
|
777
|
+
# Snowflake (Optional - Production Account)
|
|
778
|
+
SNOWFLAKE_ACCOUNT=xxx.us-east-1
|
|
779
|
+
SNOWFLAKE_USERNAME=xxx
|
|
780
|
+
SNOWFLAKE_PASSWORD=xxx
|
|
781
|
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
|
782
|
+
SNOWFLAKE_DATABASE=ANALYTICS
|
|
783
|
+
SNOWFLAKE_SCHEMA=PUBLIC
|
|
784
|
+
SNOWFLAKE_ROLE=ANALYST
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## Troubleshooting
|
|
790
|
+
|
|
791
|
+
### Issue: Environment Variables Not Loading
|
|
792
|
+
|
|
793
|
+
**Symptoms:**
|
|
794
|
+
- Application can't access environment variables
|
|
795
|
+
- `undefined` values for environment variables
|
|
796
|
+
|
|
797
|
+
**Solutions:**
|
|
798
|
+
|
|
799
|
+
```bash
|
|
800
|
+
# Verify .env file exists
|
|
801
|
+
ls -la .env
|
|
802
|
+
|
|
803
|
+
# Check file permissions
|
|
804
|
+
chmod 600 .env
|
|
805
|
+
|
|
806
|
+
# Restart application
|
|
807
|
+
pm2 restart dtt-framework
|
|
808
|
+
|
|
809
|
+
# Check for typos in variable names
|
|
810
|
+
# Environment variables are case-sensitive
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### Issue: Build Fails Due to Missing Variables
|
|
814
|
+
|
|
815
|
+
**Symptoms:**
|
|
816
|
+
- Build process fails
|
|
817
|
+
- Error about missing environment variables
|
|
818
|
+
|
|
819
|
+
**Solutions:**
|
|
820
|
+
|
|
821
|
+
```bash
|
|
822
|
+
# Verify all required variables are set
|
|
823
|
+
vercel env ls
|
|
824
|
+
|
|
825
|
+
# Check variable names match exactly
|
|
826
|
+
# NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY (correct)
|
|
827
|
+
# next_public_clerk_publishable_key (incorrect)
|
|
828
|
+
|
|
829
|
+
# For local builds, verify .env file
|
|
830
|
+
cat .env
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Issue: Variables Not Available in Production
|
|
834
|
+
|
|
835
|
+
**Symptoms:**
|
|
836
|
+
- Variables work in development but not production
|
|
837
|
+
- Application fails in production
|
|
838
|
+
|
|
839
|
+
**Solutions:**
|
|
840
|
+
|
|
841
|
+
```bash
|
|
842
|
+
# Verify variables are set for production environment
|
|
843
|
+
vercel env ls --environment=production
|
|
844
|
+
|
|
845
|
+
# Redeploy to apply changes
|
|
846
|
+
vercel --prod
|
|
847
|
+
|
|
848
|
+
# Check deployment logs
|
|
849
|
+
vercel logs
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## Related Documentation
|
|
855
|
+
|
|
856
|
+
- [Vercel Deployment](./vercel.md) - Vercel deployment guide
|
|
857
|
+
- [DigitalOcean Deployment](./digitalocean.md) - DigitalOcean deployment guide
|
|
858
|
+
- [Domain Setup](./domain-setup.md) - Custom domain configuration
|
|
859
|
+
- [CI/CD Setup](./ci-cd.md) - Automated deployments
|
|
860
|
+
- [Production Checklist](./production-checklist.md) - Pre-deployment checklist
|
|
861
|
+
- [Monitoring](./monitoring.md) - Monitoring and alerting setup
|
|
862
|
+
- [Framework Environment Variables](../environment-variables.md) - Complete variable reference
|