@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,972 @@
|
|
|
1
|
+
# DTT Framework - Domain Setup Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide provides comprehensive instructions for configuring custom domains for your DTT Framework deployment, including DNS settings, SSL/TLS certificates, and various domain configurations for both Vercel and DigitalOcean.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Domain Configuration for Vercel](#domain-configuration-for-vercel)
|
|
12
|
+
2. [Domain Configuration for DigitalOcean](#domain-configuration-for-digitalocean)
|
|
13
|
+
3. [DNS Settings](#dns-settings)
|
|
14
|
+
4. [SSL/TLS Certificate Setup](#ssltls-certificate-setup)
|
|
15
|
+
5. [Custom Domain Verification](#custom-domain-verification)
|
|
16
|
+
6. [Subdomain Configuration](#subdomain-configuration)
|
|
17
|
+
7. [Redirects](#redirects)
|
|
18
|
+
8. [CDN Configuration](#cdn-configuration)
|
|
19
|
+
9. [Troubleshooting Domain Issues](#troubleshooting-domain-issues)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Domain Configuration for Vercel
|
|
24
|
+
|
|
25
|
+
### Step 1: Add Domain to Vercel
|
|
26
|
+
|
|
27
|
+
1. Go to [Vercel Dashboard](https://vercel.com/dashboard)
|
|
28
|
+
2. Select your project
|
|
29
|
+
3. Go to **Settings** → **Domains**
|
|
30
|
+
4. Click **"Add"**
|
|
31
|
+
5. Enter your domain name (e.g., `your-app.com`)
|
|
32
|
+
6. Click **"Add"**
|
|
33
|
+
|
|
34
|
+
### Step 2: Choose Domain Type
|
|
35
|
+
|
|
36
|
+
Vercel offers two domain types:
|
|
37
|
+
|
|
38
|
+
| Type | Description | Cost |
|
|
39
|
+
|------|-------------|------|
|
|
40
|
+
| **Production Domain** | Main domain for production | Free |
|
|
41
|
+
| **Preview Domain** | For preview deployments | Free |
|
|
42
|
+
| **Wildcard Domain** | For all subdomains | Paid |
|
|
43
|
+
|
|
44
|
+
### Step 3: Configure DNS Records
|
|
45
|
+
|
|
46
|
+
Vercel will display the required DNS records:
|
|
47
|
+
|
|
48
|
+
#### A Record
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Type: A
|
|
52
|
+
Name: @
|
|
53
|
+
Value: 76.76.21.21
|
|
54
|
+
TTL: 300
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### CNAME Record
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Type: CNAME
|
|
61
|
+
Name: www
|
|
62
|
+
Value: cname.vercel-dns.com
|
|
63
|
+
TTL: 300
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Step 4: Update DNS Records
|
|
67
|
+
|
|
68
|
+
Go to your domain registrar (GoDaddy, Namecheap, Cloudflare, etc.) and add the DNS records:
|
|
69
|
+
|
|
70
|
+
#### Example for Cloudflare
|
|
71
|
+
|
|
72
|
+
1. Go to **DNS** → **Records**
|
|
73
|
+
2. Add A record:
|
|
74
|
+
- **Type**: A
|
|
75
|
+
- **Name**: `@`
|
|
76
|
+
- **IPv4 address**: `76.76.21.21`
|
|
77
|
+
- **Proxy status**: Proxied (orange cloud) or DNS only (gray cloud)
|
|
78
|
+
3. Add CNAME record:
|
|
79
|
+
- **Type**: CNAME
|
|
80
|
+
- **Name**: `www`
|
|
81
|
+
- **Target**: `cname.vercel-dns.com`
|
|
82
|
+
- **Proxy status**: Proxied or DNS only
|
|
83
|
+
|
|
84
|
+
#### Example for GoDaddy
|
|
85
|
+
|
|
86
|
+
1. Go to **DNS Management**
|
|
87
|
+
2. Add A record:
|
|
88
|
+
- **Type**: A
|
|
89
|
+
- **Name**: `@`
|
|
90
|
+
- **Value**: `76.76.21.21`
|
|
91
|
+
- **TTL**: 1 Hour
|
|
92
|
+
3. Add CNAME record:
|
|
93
|
+
- **Type**: CNAME
|
|
94
|
+
- **Name**: `www`
|
|
95
|
+
- **Value**: `cname.vercel-dns.com`
|
|
96
|
+
- **TTL**: 1 Hour
|
|
97
|
+
|
|
98
|
+
### Step 5: Verify DNS Propagation
|
|
99
|
+
|
|
100
|
+
Wait for DNS propagation (can take up to 24 hours):
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Check DNS propagation
|
|
104
|
+
dig your-app.com
|
|
105
|
+
|
|
106
|
+
# Or use online tools:
|
|
107
|
+
# https://dnschecker.org/
|
|
108
|
+
# https://whatsmydns.net/
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Step 6: Update Environment Variables
|
|
112
|
+
|
|
113
|
+
Update your `NEXT_PUBLIC_APP_URL` in Vercel:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Via Vercel Dashboard
|
|
117
|
+
# Settings → Environment Variables → Edit
|
|
118
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com
|
|
119
|
+
|
|
120
|
+
# Via CLI
|
|
121
|
+
vercel env add NEXT_PUBLIC_APP_URL production
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Step 7: Redeploy Application
|
|
125
|
+
|
|
126
|
+
Redeploy to apply changes:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Via CLI
|
|
130
|
+
vercel --prod
|
|
131
|
+
|
|
132
|
+
# Or via Dashboard
|
|
133
|
+
# Deployments → Redeploy
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Step 8: Verify Domain
|
|
137
|
+
|
|
138
|
+
1. Go to **Settings** → **Domains**
|
|
139
|
+
2. Wait for the domain status to show **"Valid Configuration"**
|
|
140
|
+
3. Visit your domain: `https://your-app.com`
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Domain Configuration for DigitalOcean
|
|
145
|
+
|
|
146
|
+
### For App Platform
|
|
147
|
+
|
|
148
|
+
#### Step 1: Add Domain to App Platform
|
|
149
|
+
|
|
150
|
+
1. Go to [DigitalOcean App Platform](https://cloud.digitalocean.com/apps)
|
|
151
|
+
2. Select your app
|
|
152
|
+
3. Go to **Settings** → **Domains**
|
|
153
|
+
4. Click **"Add Domain"**
|
|
154
|
+
5. Enter your domain name (e.g., `your-app.com`)
|
|
155
|
+
6. Click **"Add Domain"**
|
|
156
|
+
|
|
157
|
+
#### Step 2: Configure DNS Records
|
|
158
|
+
|
|
159
|
+
DigitalOcean will display the required DNS records:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
Type: CNAME
|
|
163
|
+
Name: @
|
|
164
|
+
Value: your-app.ondigitalocean.app
|
|
165
|
+
TTL: 300
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Step 3: Update DNS Records
|
|
169
|
+
|
|
170
|
+
Add the CNAME record to your domain registrar.
|
|
171
|
+
|
|
172
|
+
#### Step 4: Configure SSL
|
|
173
|
+
|
|
174
|
+
DigitalOcean App Platform automatically provisions SSL certificates via Let's Encrypt.
|
|
175
|
+
|
|
176
|
+
#### Step 5: Update Environment Variables
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# In App Platform settings
|
|
180
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### For Droplets
|
|
184
|
+
|
|
185
|
+
#### Step 1: Point Domain to Droplet IP
|
|
186
|
+
|
|
187
|
+
Add an A record pointing to your Droplet's IP address:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
Type: A
|
|
191
|
+
Name: @
|
|
192
|
+
Value: your-droplet-ip
|
|
193
|
+
TTL: 300
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Step 2: Configure Nginx Server Block
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Edit Nginx configuration
|
|
200
|
+
nano /etc/nginx/sites-available/dtt-framework
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Update the server name:
|
|
204
|
+
|
|
205
|
+
```nginx
|
|
206
|
+
server {
|
|
207
|
+
listen 80;
|
|
208
|
+
server_name your-app.com www.your-app.com;
|
|
209
|
+
|
|
210
|
+
location / {
|
|
211
|
+
proxy_pass http://localhost:3000;
|
|
212
|
+
# ... rest of configuration
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Step 3: Test and Reload Nginx
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Test configuration
|
|
221
|
+
nginx -t
|
|
222
|
+
|
|
223
|
+
# Reload Nginx
|
|
224
|
+
systemctl reload nginx
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### Step 4: Configure SSL with Let's Encrypt
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Obtain SSL certificate
|
|
231
|
+
certbot --nginx -d your-app.com -d www.your-app.com
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### Step 5: Update Environment Variables
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Edit .env file
|
|
238
|
+
nano /var/www/dtt-framework/.env
|
|
239
|
+
|
|
240
|
+
# Update APP_URL
|
|
241
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com
|
|
242
|
+
|
|
243
|
+
# Restart application
|
|
244
|
+
pm2 restart dtt-framework
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## DNS Settings
|
|
250
|
+
|
|
251
|
+
### Understanding DNS Record Types
|
|
252
|
+
|
|
253
|
+
| Record Type | Purpose | Example |
|
|
254
|
+
|-------------|---------|---------|
|
|
255
|
+
| **A** | Maps domain to IPv4 address | `your-app.com → 76.76.21.21` |
|
|
256
|
+
| **AAAA** | Maps domain to IPv6 address | `your-app.com → 2606:4700::1` |
|
|
257
|
+
| **CNAME** | Maps domain to another domain | `www.your-app.com → your-app.com` |
|
|
258
|
+
| **MX** | Mail exchange server | `@ → mail.your-app.com` |
|
|
259
|
+
| **TXT** | Text records for verification | `@ → v=spf1 include:_spf.google.com ~all` |
|
|
260
|
+
| **SRV** | Service records | `_sip._tcp.your-app.com` |
|
|
261
|
+
|
|
262
|
+
### Common DNS Configurations
|
|
263
|
+
|
|
264
|
+
#### Root Domain (A Record)
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
Type: A
|
|
268
|
+
Name: @
|
|
269
|
+
Value: 76.76.21.21
|
|
270
|
+
TTL: 300
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### WWW Subdomain (CNAME)
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
Type: CNAME
|
|
277
|
+
Name: www
|
|
278
|
+
Value: cname.vercel-dns.com
|
|
279
|
+
TTL: 300
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### API Subdomain (CNAME)
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
Type: CNAME
|
|
286
|
+
Name: api
|
|
287
|
+
Value: cname.vercel-dns.com
|
|
288
|
+
TTL: 300
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### Wildcard Subdomain (CNAME)
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
Type: CNAME
|
|
295
|
+
Name: *
|
|
296
|
+
Value: cname.vercel-dns.com
|
|
297
|
+
TTL: 300
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### DNS TTL (Time to Live)
|
|
301
|
+
|
|
302
|
+
| TTL Value | Use Case |
|
|
303
|
+
|-----------|----------|
|
|
304
|
+
| **300 (5 minutes)** | Development/testing |
|
|
305
|
+
| **3600 (1 hour)** | Production standard |
|
|
306
|
+
| **86400 (1 day)** | Rarely changed records |
|
|
307
|
+
|
|
308
|
+
### DNS Propagation
|
|
309
|
+
|
|
310
|
+
DNS changes can take anywhere from a few minutes to 48 hours to propagate globally.
|
|
311
|
+
|
|
312
|
+
#### Check Propagation Status
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
# Check from different locations
|
|
316
|
+
dig your-app.com
|
|
317
|
+
|
|
318
|
+
# Or use online tools
|
|
319
|
+
# https://dnschecker.org/
|
|
320
|
+
# https://whatsmydns.net/
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## SSL/TLS Certificate Setup
|
|
326
|
+
|
|
327
|
+
### Vercel SSL
|
|
328
|
+
|
|
329
|
+
Vercel automatically provisions SSL certificates for all domains:
|
|
330
|
+
|
|
331
|
+
- **Automatic**: No configuration needed
|
|
332
|
+
- **Free**: Let's Encrypt certificates
|
|
333
|
+
- **Auto-renewal**: Certificates renew automatically
|
|
334
|
+
|
|
335
|
+
#### Check SSL Status
|
|
336
|
+
|
|
337
|
+
1. Go to **Settings** → **Domains**
|
|
338
|
+
2. Check the SSL certificate status
|
|
339
|
+
3. Should show **"Valid Certificate"**
|
|
340
|
+
|
|
341
|
+
### DigitalOcean App Platform SSL
|
|
342
|
+
|
|
343
|
+
DigitalOcean App Platform also provides automatic SSL:
|
|
344
|
+
|
|
345
|
+
- **Automatic**: Provisioned via Let's Encrypt
|
|
346
|
+
- **Free**: No additional cost
|
|
347
|
+
- **Auto-renewal**: Automatic renewal
|
|
348
|
+
|
|
349
|
+
### DigitalOcean Droplet SSL with Let's Encrypt
|
|
350
|
+
|
|
351
|
+
#### Install Certbot
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
# Install Certbot
|
|
355
|
+
apt install -y certbot python3-certbot-nginx
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### Obtain SSL Certificate
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
# For single domain
|
|
362
|
+
certbot --nginx -d your-app.com
|
|
363
|
+
|
|
364
|
+
# For multiple domains
|
|
365
|
+
certbot --nginx -d your-app.com -d www.your-app.com
|
|
366
|
+
|
|
367
|
+
# For wildcard (requires DNS challenge)
|
|
368
|
+
certbot certonly --manual --preferred-challenges dns -d "*.your-app.com"
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### SSL Configuration
|
|
372
|
+
|
|
373
|
+
Certbot automatically configures Nginx with SSL:
|
|
374
|
+
|
|
375
|
+
```nginx
|
|
376
|
+
server {
|
|
377
|
+
listen 443 ssl;
|
|
378
|
+
server_name your-app.com www.your-app.com;
|
|
379
|
+
|
|
380
|
+
ssl_certificate /etc/letsencrypt/live/your-app.com/fullchain.pem;
|
|
381
|
+
ssl_certificate_key /etc/letsencrypt/live/your-app.com/privkey.pem;
|
|
382
|
+
|
|
383
|
+
# SSL configuration
|
|
384
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
385
|
+
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
386
|
+
ssl_prefer_server_ciphers on;
|
|
387
|
+
|
|
388
|
+
# ... rest of configuration
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
# HTTP to HTTPS redirect
|
|
392
|
+
server {
|
|
393
|
+
listen 80;
|
|
394
|
+
server_name your-app.com www.your-app.com;
|
|
395
|
+
return 301 https://$server_name$request_uri;
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### Test SSL Configuration
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# Test SSL certificate
|
|
403
|
+
certbot certificates
|
|
404
|
+
|
|
405
|
+
# Test SSL configuration
|
|
406
|
+
openssl s_client -connect your-app.com:443
|
|
407
|
+
|
|
408
|
+
# Or use online tools
|
|
409
|
+
# https://www.ssllabs.com/ssltest/
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
#### Auto-Renewal
|
|
413
|
+
|
|
414
|
+
Certbot sets up automatic renewal by default:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
# Test renewal
|
|
418
|
+
certbot renew --dry-run
|
|
419
|
+
|
|
420
|
+
# Check renewal timer
|
|
421
|
+
systemctl list-timers | grep certbot
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### SSL Best Practices
|
|
425
|
+
|
|
426
|
+
1. **Use HTTPS Only**: Redirect all HTTP traffic to HTTPS
|
|
427
|
+
2. **Strong Ciphers**: Use strong SSL/TLS ciphers
|
|
428
|
+
3. **HSTS**: Enable HTTP Strict Transport Security
|
|
429
|
+
4. **Certificate Monitoring**: Monitor certificate expiration
|
|
430
|
+
5. **Regular Updates**: Keep SSL libraries updated
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Custom Domain Verification
|
|
435
|
+
|
|
436
|
+
### Why Verification is Needed
|
|
437
|
+
|
|
438
|
+
Domain verification ensures:
|
|
439
|
+
- You own the domain
|
|
440
|
+
- Prevents unauthorized domain usage
|
|
441
|
+
- Required for SSL certificates
|
|
442
|
+
|
|
443
|
+
### Verification Methods
|
|
444
|
+
|
|
445
|
+
#### Method 1: DNS TXT Record
|
|
446
|
+
|
|
447
|
+
Add a TXT record to your DNS:
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
Type: TXT
|
|
451
|
+
Name: @
|
|
452
|
+
Value: vercel-domain-verification=your-verification-code
|
|
453
|
+
TTL: 300
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### Method 2: HTML File Upload
|
|
457
|
+
|
|
458
|
+
Upload a verification file:
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
# Create verification file
|
|
462
|
+
echo "verification-code" > .well-known/vercel-domain-verification
|
|
463
|
+
|
|
464
|
+
# Upload to your server
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### Method 3: Meta Tag
|
|
468
|
+
|
|
469
|
+
Add meta tag to your HTML:
|
|
470
|
+
|
|
471
|
+
```html
|
|
472
|
+
<meta name="vercel-domain-verification" content="your-verification-code">
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Verify Domain Ownership
|
|
476
|
+
|
|
477
|
+
#### Via Vercel Dashboard
|
|
478
|
+
|
|
479
|
+
1. Go to **Settings** → **Domains**
|
|
480
|
+
2. Click **"Verify"** next to your domain
|
|
481
|
+
3. Follow the verification instructions
|
|
482
|
+
4. Wait for verification to complete
|
|
483
|
+
|
|
484
|
+
#### Via CLI
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
# Verify domain
|
|
488
|
+
vercel domains verify your-app.com
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Verification Status
|
|
492
|
+
|
|
493
|
+
| Status | Description | Action Required |
|
|
494
|
+
|--------|-------------|-----------------|
|
|
495
|
+
| **Pending** | Verification in progress | Wait for DNS propagation |
|
|
496
|
+
| **Verified** | Domain verified | No action needed |
|
|
497
|
+
| **Failed** | Verification failed | Check DNS records |
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Subdomain Configuration
|
|
502
|
+
|
|
503
|
+
### Common Subdomain Patterns
|
|
504
|
+
|
|
505
|
+
| Subdomain | Purpose | Example |
|
|
506
|
+
|-----------|---------|---------|
|
|
507
|
+
| **www** | Main website | `www.your-app.com` |
|
|
508
|
+
| **api** | API endpoints | `api.your-app.com` |
|
|
509
|
+
| **app** | Application | `app.your-app.com` |
|
|
510
|
+
| **admin** | Admin panel | `admin.your-app.com` |
|
|
511
|
+
| **staging** | Staging environment | `staging.your-app.com` |
|
|
512
|
+
| **dev** | Development environment | `dev.your-app.com` |
|
|
513
|
+
|
|
514
|
+
### Configuring Subdomains in Vercel
|
|
515
|
+
|
|
516
|
+
#### Add Subdomain
|
|
517
|
+
|
|
518
|
+
1. Go to **Settings** → **Domains**
|
|
519
|
+
2. Click **"Add"**
|
|
520
|
+
3. Enter subdomain (e.g., `api.your-app.com`)
|
|
521
|
+
4. Click **"Add"**
|
|
522
|
+
|
|
523
|
+
#### Configure DNS Records
|
|
524
|
+
|
|
525
|
+
```
|
|
526
|
+
Type: CNAME
|
|
527
|
+
Name: api
|
|
528
|
+
Value: cname.vercel-dns.com
|
|
529
|
+
TTL: 300
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Configuring Subdomains in DigitalOcean
|
|
533
|
+
|
|
534
|
+
#### For App Platform
|
|
535
|
+
|
|
536
|
+
Add each subdomain in **Settings** → **Domains**.
|
|
537
|
+
|
|
538
|
+
#### For Droplets
|
|
539
|
+
|
|
540
|
+
Add CNAME records to your DNS:
|
|
541
|
+
|
|
542
|
+
```
|
|
543
|
+
Type: CNAME
|
|
544
|
+
Name: api
|
|
545
|
+
Value: your-app.com
|
|
546
|
+
TTL: 300
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
Configure Nginx server block:
|
|
550
|
+
|
|
551
|
+
```nginx
|
|
552
|
+
server {
|
|
553
|
+
listen 80;
|
|
554
|
+
server_name api.your-app.com;
|
|
555
|
+
|
|
556
|
+
location / {
|
|
557
|
+
proxy_pass http://localhost:3000;
|
|
558
|
+
# ... rest of configuration
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Wildcard Subdomains
|
|
564
|
+
|
|
565
|
+
Configure a wildcard subdomain for all subdomains:
|
|
566
|
+
|
|
567
|
+
```
|
|
568
|
+
Type: CNAME
|
|
569
|
+
Name: *
|
|
570
|
+
Value: cname.vercel-dns.com
|
|
571
|
+
TTL: 300
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Redirects
|
|
577
|
+
|
|
578
|
+
### WWW to Non-WWW Redirect
|
|
579
|
+
|
|
580
|
+
#### In Vercel
|
|
581
|
+
|
|
582
|
+
Add redirect configuration to `vercel.json`:
|
|
583
|
+
|
|
584
|
+
```json
|
|
585
|
+
{
|
|
586
|
+
"redirects": [
|
|
587
|
+
{
|
|
588
|
+
"source": "/:path*",
|
|
589
|
+
"has": [
|
|
590
|
+
{
|
|
591
|
+
"type": "host",
|
|
592
|
+
"value": "www.your-app.com"
|
|
593
|
+
}
|
|
594
|
+
],
|
|
595
|
+
"destination": "https://your-app.com/:path*",
|
|
596
|
+
"permanent": true
|
|
597
|
+
}
|
|
598
|
+
]
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
#### In Nginx
|
|
603
|
+
|
|
604
|
+
```nginx
|
|
605
|
+
server {
|
|
606
|
+
listen 80;
|
|
607
|
+
server_name www.your-app.com;
|
|
608
|
+
return 301 https://your-app.com$request_uri;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
server {
|
|
612
|
+
listen 443 ssl;
|
|
613
|
+
server_name www.your-app.com;
|
|
614
|
+
return 301 https://your-app.com$request_uri;
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### HTTP to HTTPS Redirect
|
|
619
|
+
|
|
620
|
+
#### In Vercel
|
|
621
|
+
|
|
622
|
+
Vercel automatically redirects HTTP to HTTPS for custom domains.
|
|
623
|
+
|
|
624
|
+
#### In Nginx
|
|
625
|
+
|
|
626
|
+
```nginx
|
|
627
|
+
server {
|
|
628
|
+
listen 80;
|
|
629
|
+
server_name your-app.com www.your-app.com;
|
|
630
|
+
return 301 https://$server_name$request_uri;
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Custom Path Redirects
|
|
635
|
+
|
|
636
|
+
#### In Vercel
|
|
637
|
+
|
|
638
|
+
```json
|
|
639
|
+
{
|
|
640
|
+
"redirects": [
|
|
641
|
+
{
|
|
642
|
+
"source": "/old-path",
|
|
643
|
+
"destination": "/new-path",
|
|
644
|
+
"permanent": true
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
"source": "/blog/:slug",
|
|
648
|
+
"destination": "/articles/:slug",
|
|
649
|
+
"permanent": true
|
|
650
|
+
}
|
|
651
|
+
]
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### In Nginx
|
|
656
|
+
|
|
657
|
+
```nginx
|
|
658
|
+
server {
|
|
659
|
+
# ... other configuration
|
|
660
|
+
|
|
661
|
+
location /old-path {
|
|
662
|
+
return 301 /new-path;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
rewrite ^/blog/(.*)$ /articles/$1 permanent;
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Domain Migration Redirects
|
|
670
|
+
|
|
671
|
+
When migrating domains, set up redirects:
|
|
672
|
+
|
|
673
|
+
```nginx
|
|
674
|
+
server {
|
|
675
|
+
listen 80;
|
|
676
|
+
server_name old-domain.com www.old-domain.com;
|
|
677
|
+
return 301 https://new-domain.com$request_uri;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
server {
|
|
681
|
+
listen 443 ssl;
|
|
682
|
+
server_name old-domain.com www.old-domain.com;
|
|
683
|
+
return 301 https://new-domain.com$request_uri;
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## CDN Configuration
|
|
690
|
+
|
|
691
|
+
### Vercel Edge Network
|
|
692
|
+
|
|
693
|
+
Vercel automatically uses its global Edge Network for CDN:
|
|
694
|
+
|
|
695
|
+
- **Global**: 100+ edge locations worldwide
|
|
696
|
+
- **Automatic**: No configuration needed
|
|
697
|
+
- **Smart Caching**: Intelligent cache invalidation
|
|
698
|
+
|
|
699
|
+
### Cloudflare CDN
|
|
700
|
+
|
|
701
|
+
#### Step 1: Add Domain to Cloudflare
|
|
702
|
+
|
|
703
|
+
1. Sign up at [cloudflare.com](https://cloudflare.com)
|
|
704
|
+
2. Add your domain
|
|
705
|
+
3. Scan existing DNS records
|
|
706
|
+
4. Change nameservers to Cloudflare
|
|
707
|
+
|
|
708
|
+
#### Step 2: Configure DNS Records
|
|
709
|
+
|
|
710
|
+
Update DNS records in Cloudflare:
|
|
711
|
+
|
|
712
|
+
```
|
|
713
|
+
Type: CNAME
|
|
714
|
+
Name: www
|
|
715
|
+
Value: cname.vercel-dns.com
|
|
716
|
+
Proxy status: Proxied (orange cloud)
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
#### Step 3: Configure SSL
|
|
720
|
+
|
|
721
|
+
In Cloudflare SSL/TLS settings:
|
|
722
|
+
|
|
723
|
+
- **SSL Mode**: Full (strict)
|
|
724
|
+
- **Always Use HTTPS**: On
|
|
725
|
+
- **Automatic HTTPS Rewrites**: On
|
|
726
|
+
|
|
727
|
+
#### Step 4: Configure Caching
|
|
728
|
+
|
|
729
|
+
In Cloudflare Caching settings:
|
|
730
|
+
|
|
731
|
+
- **Caching Level**: Standard
|
|
732
|
+
- **Browser Cache TTL**: Respect Existing Headers
|
|
733
|
+
- **Always Online**: On
|
|
734
|
+
|
|
735
|
+
### DigitalOcean CDN (Spaces)
|
|
736
|
+
|
|
737
|
+
For static assets, use DigitalOcean Spaces CDN:
|
|
738
|
+
|
|
739
|
+
```bash
|
|
740
|
+
# Create a Space
|
|
741
|
+
# Enable CDN
|
|
742
|
+
# Configure custom CDN endpoint
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## Troubleshooting Domain Issues
|
|
748
|
+
|
|
749
|
+
### Issue: Domain Not Resolving
|
|
750
|
+
|
|
751
|
+
**Symptoms:**
|
|
752
|
+
- Domain returns "server not found"
|
|
753
|
+
- DNS lookup fails
|
|
754
|
+
|
|
755
|
+
**Solutions:**
|
|
756
|
+
|
|
757
|
+
```bash
|
|
758
|
+
# Check DNS propagation
|
|
759
|
+
dig your-app.com
|
|
760
|
+
|
|
761
|
+
# Check from multiple locations
|
|
762
|
+
# https://dnschecker.org/
|
|
763
|
+
|
|
764
|
+
# Verify DNS records at registrar
|
|
765
|
+
# Ensure records are correct
|
|
766
|
+
|
|
767
|
+
# Wait for propagation (up to 48 hours)
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### Issue: SSL Certificate Not Issued
|
|
771
|
+
|
|
772
|
+
**Symptoms:**
|
|
773
|
+
- HTTPS not working
|
|
774
|
+
- Certificate errors in browser
|
|
775
|
+
|
|
776
|
+
**Solutions:**
|
|
777
|
+
|
|
778
|
+
```bash
|
|
779
|
+
# Check DNS records
|
|
780
|
+
dig your-app.com
|
|
781
|
+
|
|
782
|
+
# Verify domain is pointing correctly
|
|
783
|
+
# Ensure A/CNAME records are correct
|
|
784
|
+
|
|
785
|
+
# Check SSL status in dashboard
|
|
786
|
+
# Vercel: Settings → Domains
|
|
787
|
+
# DigitalOcean: Settings → Domains
|
|
788
|
+
|
|
789
|
+
# Manually trigger certificate issuance
|
|
790
|
+
# Vercel: Click "Issue Certificate"
|
|
791
|
+
# DigitalOcean: Automatic, check logs
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### Issue: Mixed Content Errors
|
|
795
|
+
|
|
796
|
+
**Symptoms:**
|
|
797
|
+
- Browser shows "mixed content" warnings
|
|
798
|
+
- Some resources load over HTTP
|
|
799
|
+
|
|
800
|
+
**Solutions:**
|
|
801
|
+
|
|
802
|
+
```javascript
|
|
803
|
+
// Ensure all resources use HTTPS
|
|
804
|
+
// Update image URLs
|
|
805
|
+
// Update API endpoints
|
|
806
|
+
// Update CDN URLs
|
|
807
|
+
|
|
808
|
+
// Use relative URLs
|
|
809
|
+
<img src="/images/logo.png" />
|
|
810
|
+
|
|
811
|
+
// Or use protocol-relative URLs
|
|
812
|
+
<img src="//cdn.example.com/image.png" />
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
### Issue: Redirect Loops
|
|
816
|
+
|
|
817
|
+
**Symptoms:**
|
|
818
|
+
- Browser shows "too many redirects"
|
|
819
|
+
- Page won't load
|
|
820
|
+
|
|
821
|
+
**Solutions:**
|
|
822
|
+
|
|
823
|
+
```bash
|
|
824
|
+
# Check redirect configurations
|
|
825
|
+
# Ensure no conflicting redirects
|
|
826
|
+
|
|
827
|
+
# Check Nginx configuration
|
|
828
|
+
nginx -t
|
|
829
|
+
|
|
830
|
+
# Check Vercel redirects
|
|
831
|
+
# Review vercel.json
|
|
832
|
+
|
|
833
|
+
# Clear browser cache
|
|
834
|
+
# Test in incognito mode
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Issue: Subdomain Not Working
|
|
838
|
+
|
|
839
|
+
**Symptoms:**
|
|
840
|
+
- Subdomain returns error
|
|
841
|
+
- Subdomain doesn't resolve
|
|
842
|
+
|
|
843
|
+
**Solutions:**
|
|
844
|
+
|
|
845
|
+
```bash
|
|
846
|
+
# Check DNS records
|
|
847
|
+
dig api.your-app.com
|
|
848
|
+
|
|
849
|
+
# Verify CNAME record
|
|
850
|
+
# Ensure it points to correct target
|
|
851
|
+
|
|
852
|
+
# Check server configuration
|
|
853
|
+
# Ensure server block includes subdomain
|
|
854
|
+
|
|
855
|
+
# Restart services
|
|
856
|
+
systemctl reload nginx
|
|
857
|
+
pm2 restart dtt-framework
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### Issue: DNS Propagation Delay
|
|
861
|
+
|
|
862
|
+
**Symptoms:**
|
|
863
|
+
- Domain works on some devices but not others
|
|
864
|
+
- Inconsistent behavior
|
|
865
|
+
|
|
866
|
+
**Solutions:**
|
|
867
|
+
|
|
868
|
+
```bash
|
|
869
|
+
# Check propagation status
|
|
870
|
+
# https://dnschecker.org/
|
|
871
|
+
# https://whatsmydns.net/
|
|
872
|
+
|
|
873
|
+
# Clear DNS cache
|
|
874
|
+
# Windows: ipconfig /flushdns
|
|
875
|
+
# Mac: sudo dscacheutil -flushcache
|
|
876
|
+
# Linux: sudo systemd-resolve --flush-caches
|
|
877
|
+
|
|
878
|
+
# Wait for full propagation (up to 48 hours)
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### Issue: HSTS Configuration Issues
|
|
882
|
+
|
|
883
|
+
**Symptoms:**
|
|
884
|
+
- Can't access HTTP version
|
|
885
|
+
- Browser forces HTTPS
|
|
886
|
+
|
|
887
|
+
**Solutions:**
|
|
888
|
+
|
|
889
|
+
```bash
|
|
890
|
+
# Clear HSTS settings in browser
|
|
891
|
+
# Chrome: chrome://net-internals/#hsts
|
|
892
|
+
|
|
893
|
+
# Check HSTS configuration
|
|
894
|
+
# Ensure correct headers
|
|
895
|
+
|
|
896
|
+
# Temporarily disable HSTS for testing
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
## Best Practices
|
|
902
|
+
|
|
903
|
+
### 1. Use HTTPS Everywhere
|
|
904
|
+
|
|
905
|
+
```nginx
|
|
906
|
+
# Always redirect HTTP to HTTPS
|
|
907
|
+
server {
|
|
908
|
+
listen 80;
|
|
909
|
+
return 301 https://$server_name$request_uri;
|
|
910
|
+
}
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
### 2. Implement HSTS
|
|
914
|
+
|
|
915
|
+
```nginx
|
|
916
|
+
# Add HSTS header
|
|
917
|
+
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
### 3. Monitor SSL Certificates
|
|
921
|
+
|
|
922
|
+
```bash
|
|
923
|
+
# Set up certificate monitoring
|
|
924
|
+
# Use tools like:
|
|
925
|
+
# - SSL Mate
|
|
926
|
+
# - UptimeRobot
|
|
927
|
+
# - Pingdom
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
### 4. Use DNSSEC
|
|
931
|
+
|
|
932
|
+
Enable DNSSEC for additional security:
|
|
933
|
+
|
|
934
|
+
1. Go to your domain registrar
|
|
935
|
+
2. Enable DNSSEC
|
|
936
|
+
3. Follow the setup instructions
|
|
937
|
+
|
|
938
|
+
### 5. Implement CAA Records
|
|
939
|
+
|
|
940
|
+
Add CAA records to specify certificate authorities:
|
|
941
|
+
|
|
942
|
+
```
|
|
943
|
+
Type: CAA
|
|
944
|
+
Name: @
|
|
945
|
+
Value: 0 issue "letsencrypt.org"
|
|
946
|
+
TTL: 300
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### 6. Regular DNS Audits
|
|
950
|
+
|
|
951
|
+
Regularly audit your DNS configuration:
|
|
952
|
+
|
|
953
|
+
```bash
|
|
954
|
+
# Check all DNS records
|
|
955
|
+
dig your-app.com ANY
|
|
956
|
+
|
|
957
|
+
# Check DNS propagation
|
|
958
|
+
# https://dnschecker.org/
|
|
959
|
+
|
|
960
|
+
# Check DNS security
|
|
961
|
+
# https://securitytrails.com/
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
---
|
|
965
|
+
|
|
966
|
+
## Related Documentation
|
|
967
|
+
|
|
968
|
+
- [Vercel Deployment](./vercel.md) - Vercel deployment guide
|
|
969
|
+
- [DigitalOcean Deployment](./digitalocean.md) - DigitalOcean deployment guide
|
|
970
|
+
- [Environment Variables](./environment-variables.md) - Complete variable reference
|
|
971
|
+
- [Production Checklist](./production-checklist.md) - Pre-deployment checklist
|
|
972
|
+
- [Monitoring](./monitoring.md) - Monitoring and alerting setup
|