create-tigra 3.0.0 → 3.0.3

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 (44) hide show
  1. package/package.json +1 -1
  2. package/template/client/.env.example +19 -0
  3. package/template/client/Dockerfile +3 -3
  4. package/template/client/next.config.ts +7 -42
  5. package/template/client/package-lock.json +1896 -146
  6. package/template/client/package.json +2 -0
  7. package/template/client/src/app/layout.tsx +10 -3
  8. package/template/client/src/app/providers.tsx +15 -2
  9. package/template/client/src/instrumentation-client.ts +30 -0
  10. package/template/client/src/instrumentation.ts +38 -0
  11. package/template/client/src/lib/env.ts +13 -2
  12. package/template/client/src/middleware.ts +105 -18
  13. package/template/server/.env.example +269 -236
  14. package/template/server/.env.example.production +236 -208
  15. package/template/server/Dockerfile +7 -5
  16. package/template/server/docker-compose.yml +17 -0
  17. package/template/server/package-lock.json +2136 -86
  18. package/template/server/package.json +6 -0
  19. package/template/server/src/app.ts +335 -303
  20. package/template/server/src/config/env.ts +171 -143
  21. package/template/server/src/config/rate-limit.config.ts +6 -0
  22. package/template/server/src/libs/__tests__/auth-path.test.ts +24 -0
  23. package/template/server/src/libs/__tests__/client-ip.test.ts +121 -0
  24. package/template/server/src/libs/__tests__/ip-block.test.ts +62 -0
  25. package/template/server/src/libs/__tests__/url-safety.test.ts +80 -0
  26. package/template/server/src/libs/auth-path.ts +14 -0
  27. package/template/server/src/libs/client-ip.ts +77 -0
  28. package/template/server/src/libs/ip-block.ts +220 -212
  29. package/template/server/src/libs/logger.ts +15 -0
  30. package/template/server/src/libs/observability/sentry.ts +42 -0
  31. package/template/server/src/libs/query-counter.ts +59 -0
  32. package/template/server/src/libs/requestLogger.ts +8 -2
  33. package/template/server/src/libs/storage/file-storage.service.ts +144 -16
  34. package/template/server/src/libs/url-safety.ts +121 -0
  35. package/template/server/src/modules/admin/__tests__/admin.integration.test.ts +128 -0
  36. package/template/server/src/modules/auth/__tests__/auth.integration.test.ts +138 -0
  37. package/template/server/src/modules/auth/auth.controller.ts +128 -127
  38. package/template/server/src/modules/files/__tests__/files.integration.test.ts +157 -0
  39. package/template/server/src/modules/files/files.controller.ts +180 -0
  40. package/template/server/src/modules/files/files.routes.ts +46 -0
  41. package/template/server/src/server.ts +6 -0
  42. package/template/server/src/test/integration.setup.ts +170 -0
  43. package/template/server/vitest.config.ts +10 -1
  44. package/template/server/vitest.integration.config.ts +50 -0
@@ -1,236 +1,269 @@
1
- # ===================================================================
2
- # APPLICATION CONFIGURATION
3
- # ===================================================================
4
- #
5
- # COOLIFY DEPLOYMENT NOTE:
6
- # When adding environment variables in Coolify, do NOT check
7
- # "Available at Buildtime" for any variable unless explicitly noted.
8
- # The server Dockerfile handles build-time config internally.
9
- # All variables below are RUNTIME-ONLY unless marked otherwise.
10
- #
11
- # ===================================================================
12
-
13
- # Environment: development | production | test
14
- # COOLIFY: Do NOT check "Available at Buildtime" — the Dockerfile
15
- # sets NODE_ENV=development during build to ensure devDependencies install.
16
- NODE_ENV=development
17
-
18
- # Server port (default: 8000)
19
- PORT=8000
20
-
21
- # Server host (0.0.0.0 = listen on all interfaces)
22
- HOST=0.0.0.0
23
-
24
- # ===================================================================
25
- # SERVER TIMEOUTS
26
- # ===================================================================
27
-
28
- # Fastify request timeout in milliseconds (default: 30000 = 30s)
29
- # Long-running routes (LLM calls, big exports) may need 180000+ (180s).
30
- # IMPORTANT: the reverse proxy (Nginx/Coolify) timeout must be raised to
31
- # match, or the proxy cuts the connection before the server does.
32
- REQUEST_TIMEOUT_MS=30000
33
-
34
- # Fastify connection timeout in milliseconds (default: 60000 = 60s)
35
- CONNECTION_TIMEOUT_MS=60000
36
-
37
- # ===================================================================
38
- # DATABASE CONFIGURATION (MySQL 8.0+)
39
- # ===================================================================
40
-
41
- # Database connection string
42
- # Format: mysql://username:password@host:port/database
43
- # COOLIFY: Runtime only. Do NOT check "Available at Buildtime".
44
- DATABASE_URL="mysql://root:rootpassword@localhost:{{MYSQL_PORT}}/{{DATABASE_NAME}}"
45
-
46
- # Connection pool settings (for high-traffic production)
47
- # Min connections: 2-5 for low traffic, 5-10 for medium, 10-20 for high
48
- # Max connections: 10 for dev, 20-50 for production (10K-100K users/day)
49
- DATABASE_POOL_MIN=2
50
- DATABASE_POOL_MAX=10
51
-
52
- # ===================================================================
53
- # REDIS CONFIGURATION
54
- # ===================================================================
55
-
56
- # Redis connection URL
57
- # Format: redis://[:password@]host:port[/database]
58
- # COOLIFY: Runtime only. Do NOT check "Available at Buildtime".
59
- REDIS_URL="redis://localhost:{{REDIS_PORT}}"
60
-
61
- # Max retry attempts for failed Redis operations
62
- REDIS_MAX_RETRIES=3
63
-
64
- # Connection timeout in milliseconds
65
- REDIS_CONNECT_TIMEOUT=10000
66
-
67
- # ===================================================================
68
- # RATE LIMITING
69
- # ===================================================================
70
-
71
- # Master switch to enable/disable rate limiting (default: true)
72
- # Set to false in development to disable all rate limits
73
- RATE_LIMIT_ENABLED=true
74
-
75
- # Multiply all rate limit max values by this factor (default: 1)
76
- # Set to 10 in development for 10x headroom, or 0.5 for tighter limits
77
- RATE_LIMIT_MULTIPLIER=1
78
-
79
- # Optional: Override specific critical route limits (uses defaults if not set)
80
- # RATE_LIMIT_AUTH_LOGIN_MAX=10
81
- # RATE_LIMIT_AUTH_REGISTER_MAX=5
82
-
83
- # ===================================================================
84
- # IP AUTO-BLOCK
85
- # ===================================================================
86
- #
87
- # An IP that exceeds rate limits IP_AUTO_BLOCK_THRESHOLD times within
88
- # IP_AUTO_BLOCK_WINDOW_SECONDS is blocked for IP_AUTO_BLOCK_DURATION_SECONDS.
89
- # The threshold targets SUSTAINED abuse keep it high enough that a
90
- # retry-looping legitimate client or a NAT'd office sharing one IP cannot
91
- # self-ban. See src/config/rate-limit.config.ts for the interaction notes.
92
-
93
- # Rate-limit violations before an IP is auto-blocked (default: 20)
94
- IP_AUTO_BLOCK_THRESHOLD=20
95
-
96
- # Sliding window for counting violations, in seconds (default: 300 = 5 min)
97
- IP_AUTO_BLOCK_WINDOW_SECONDS=300
98
-
99
- # How long an auto-blocked IP stays blocked, in seconds (default: 3600 = 1 hour)
100
- IP_AUTO_BLOCK_DURATION_SECONDS=3600
101
-
102
- # ===================================================================
103
- # ACCOUNT ACTIVATION
104
- # ===================================================================
105
-
106
- # When true (default), new users are created as inactive and must
107
- # verify their account before they can log in.
108
- # When false, users are active immediately after registration.
109
- # NOTE: When this variable is not provided, users are NOT activated
110
- # by default — you must explicitly set it to false to skip verification.
111
- REQUIRE_USER_VERIFICATION=true
112
-
113
- # ===================================================================
114
- # FILE UPLOAD
115
- # ===================================================================
116
-
117
- # Maximum file upload size in MB (default: 10)
118
- MAX_FILE_SIZE_MB=10
119
-
120
- # COOLIFY PERSISTENT STORAGE (required for uploads to survive redeployments):
121
- # Go to your service in Coolify Storages Add Volume Mount:
122
- # Name: uploads (or <project-name>-uploads)
123
- # Source Path: (leave empty — Coolify manages the Docker volume)
124
- # Destination Path: /app/uploads
125
- # Without this, all uploaded files are lost on every redeployment.
126
-
127
- # ===================================================================
128
- # DOCKER PORTS — LOCAL DEVELOPMENT ONLY
129
- # ===================================================================
130
- #
131
- # These ports are used by docker-compose to expose MySQL, Redis, and
132
- # their admin UIs on your local machine. They are NOT needed in
133
- # production — production connects via DATABASE_URL and REDIS_URL
134
- # (typically over a private network), not through exposed ports.
135
- #
136
- # Change these if they conflict with other services on your machine.
137
-
138
- MYSQL_PORT={{MYSQL_PORT}}
139
- PHPMYADMIN_PORT={{PHPMYADMIN_PORT}}
140
- REDIS_PORT={{REDIS_PORT}}
141
- REDIS_COMMANDER_PORT={{REDIS_COMMANDER_PORT}}
142
-
143
- # ===================================================================
144
- # JWT AUTHENTICATION
145
- # ===================================================================
146
-
147
- # JWT secret key (MUST be at least 32 characters)
148
- # CRITICAL: Generate a strong random secret for production!
149
- # Example: openssl rand -base64 48
150
- # COOLIFY: Runtime only. Do NOT check "Available at Buildtime" — this is a secret!
151
- JWT_SECRET="{{JWT_SECRET}}"
152
-
153
- # Access token expiry (short-lived)
154
- # Format: 1s, 1m, 1h, 1d (default: 15m)
155
- JWT_ACCESS_EXPIRY="15m"
156
-
157
- # Refresh token expiry (long-lived)
158
- # Format: 1s, 1m, 1h, 1d (default: 7d)
159
- JWT_REFRESH_EXPIRY="7d"
160
-
161
- # Cookie signing secret (separate from JWT for defense-in-depth)
162
- # Optional: defaults to JWT_SECRET if not set
163
- # For production: generate a separate secret: openssl rand -base64 48
164
- # COOLIFY: Runtime only. Do NOT check "Available at Buildtime" — this is a secret!
165
- # COOKIE_SECRET="change-this-to-a-different-secret-at-least-32-chars"
166
-
167
- # Cookie domain for cross-origin deployments
168
- # REQUIRED when client and API are on different subdomains:
169
- # Client: https://app.example.com | API: https://api.example.com
170
- # → Set COOKIE_DOMAIN=".example.com" (note the leading dot)
171
- # NOT needed when client and API share the same hostname (local dev, same-origin prod)
172
- # Without this, cookies are scoped to the API hostname only and the browser
173
- # will silently reject them on cross-origin requests (login appears to do nothing).
174
- # COOKIE_DOMAIN=".example.com"
175
-
176
- # ===================================================================
177
- # CORS (Cross-Origin Resource Sharing)
178
- # ===================================================================
179
-
180
- # Allowed origins for CORS
181
- # Development: Optional (allows all origins for easier local dev)
182
- # Production: REQUIRED (must be your frontend URL for security)
183
- # Multiple origins: Separate with commas
184
- # Examples:
185
- # Single origin: CORS_ORIGIN="https://myapp.com"
186
- # Multiple origins: CORS_ORIGIN="https://myapp.com,https://app.myapp.com"
187
- # Local dev: CORS_ORIGIN="http://localhost:3001"
188
- # CORS_ORIGIN="http://localhost:3001"
189
-
190
- # ===================================================================
191
- # EMAIL (Resend)
192
- # ===================================================================
193
-
194
- # Resend API key for transactional emails (password reset, verification, etc.)
195
- # Get your API key from: https://resend.com/api-keys
196
- # COOLIFY: Runtime only. Do NOT check "Available at Buildtime" this is a secret!
197
- RESEND_API_KEY="re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
198
-
199
- # Sender email address
200
- # Development: Use Resend's test address (onboarding@resend.dev) — delivers to your Resend dashboard
201
- # Production: Use a verified domain email (e.g., noreply@yourdomain.com)
202
- RESEND_FROM_EMAIL="onboarding@resend.dev"
203
-
204
- # Frontend URL used to build links in emails (e.g., password reset links)
205
- # Must match the URL where your Next.js client is running
206
- CLIENT_URL="http://localhost:3000"
207
-
208
- # ===================================================================
209
- # LOGGING
210
- # ===================================================================
211
-
212
- # Log level: fatal | error | warn | info | debug | trace
213
- # Production: info or warn (reduces noise)
214
- # Development: debug (verbose logging)
215
- # Staging: info
216
- LOG_LEVEL=info
217
-
218
- # ===================================================================
219
- # DATABASE SEEDING (npm run prisma:seed — dev/test only)
220
- # ===================================================================
221
-
222
- # Passwords for the seeded demo accounts (admin@example.com / user@example.com).
223
- # Optional in development — well-known dev defaults (Admin123! / User123!) are
224
- # used when unset. The seed script REFUSES to run when NODE_ENV=production.
225
- # SEED_ADMIN_PASSWORD="choose-a-dev-admin-password"
226
- # SEED_USER_PASSWORD="choose-a-dev-user-password"
227
-
228
- # ===================================================================
229
- # ERROR TRACKING (Optional)
230
- # ===================================================================
231
-
232
- # Sentry DSN for error tracking and monitoring
233
- # Get your DSN from: https://sentry.io/settings/projects/
234
- # Leave empty to disable Sentry
235
- # Example: SENTRY_DSN="https://examplePublicKey@o0.ingest.sentry.io/0"
236
- # SENTRY_DSN=""
1
+ # ===================================================================
2
+ # APPLICATION CONFIGURATION
3
+ # ===================================================================
4
+ #
5
+ # COOLIFY DEPLOYMENT NOTE:
6
+ # When adding environment variables in Coolify, do NOT check
7
+ # "Available at Buildtime" for any variable unless explicitly noted.
8
+ # The server Dockerfile handles build-time config internally.
9
+ # All variables below are RUNTIME-ONLY unless marked otherwise.
10
+ #
11
+ # ===================================================================
12
+
13
+ # Environment: development | production | test
14
+ # COOLIFY: Do NOT check "Available at Buildtime" — the Dockerfile
15
+ # sets NODE_ENV=development during build to ensure devDependencies install.
16
+ NODE_ENV=development
17
+
18
+ # Server port (default: 8000)
19
+ PORT=8000
20
+
21
+ # Server host (0.0.0.0 = listen on all interfaces)
22
+ HOST=0.0.0.0
23
+
24
+ # ===================================================================
25
+ # SERVER TIMEOUTS
26
+ # ===================================================================
27
+
28
+ # Fastify request timeout in milliseconds (default: 30000 = 30s)
29
+ # Long-running routes (LLM calls, big exports) may need 180000+ (180s).
30
+ # IMPORTANT: the reverse proxy (Nginx/Coolify) timeout must be raised to
31
+ # match, or the proxy cuts the connection before the server does.
32
+ REQUEST_TIMEOUT_MS=30000
33
+
34
+ # Fastify connection timeout in milliseconds (default: 60000 = 60s)
35
+ CONNECTION_TIMEOUT_MS=60000
36
+
37
+ # ===================================================================
38
+ # DATABASE CONFIGURATION (MySQL 8.0+)
39
+ # ===================================================================
40
+
41
+ # Database connection string
42
+ # Format: mysql://username:password@host:port/database
43
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime".
44
+ DATABASE_URL="mysql://root:rootpassword@localhost:{{MYSQL_PORT}}/{{DATABASE_NAME}}"
45
+
46
+ # Connection pool settings (for high-traffic production)
47
+ # Min connections: 2-5 for low traffic, 5-10 for medium, 10-20 for high
48
+ # Max connections: 10 for dev, 20-50 for production (10K-100K users/day)
49
+ DATABASE_POOL_MIN=2
50
+ DATABASE_POOL_MAX=10
51
+
52
+ # ===================================================================
53
+ # REDIS CONFIGURATION
54
+ # ===================================================================
55
+
56
+ # Redis connection URL
57
+ # Format: redis://[:password@]host:port[/database]
58
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime".
59
+ REDIS_URL="redis://localhost:{{REDIS_PORT}}"
60
+
61
+ # Max retry attempts for failed Redis operations
62
+ REDIS_MAX_RETRIES=3
63
+
64
+ # Connection timeout in milliseconds
65
+ REDIS_CONNECT_TIMEOUT=10000
66
+
67
+ # ===================================================================
68
+ # RATE LIMITING
69
+ # ===================================================================
70
+
71
+ # Master switch to enable/disable rate limiting (default: true)
72
+ # Set to false in development to disable all rate limits
73
+ RATE_LIMIT_ENABLED=true
74
+
75
+ # Multiply all rate limit max values by this factor (default: 1)
76
+ # Set to 10 in development for 10x headroom, or 0.5 for tighter limits
77
+ RATE_LIMIT_MULTIPLIER=1
78
+
79
+ # Optional: Override specific critical route limits (uses defaults if not set)
80
+ # RATE_LIMIT_AUTH_LOGIN_MAX=10
81
+ # RATE_LIMIT_AUTH_REGISTER_MAX=5
82
+
83
+ # Trust Cloudflare's CF-Connecting-IP header for the real client IP (default: false)
84
+ # Used ONLY for rate-limiting and IP auto-block decisions. Behind Cloudflare,
85
+ # request.ip is a CF edge IP — without this, all users behind one edge collapse
86
+ # onto a single IP and can rate-limit or auto-ban each other.
87
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime".
88
+ # SECURITY: the header is client-spoofable. Set true ONLY when the origin
89
+ # accepts traffic exclusively via Cloudflare (direct origin access is blocked).
90
+ # Note: the left-most X-Forwarded-For entry is now trusted as the client IP
91
+ # regardless of this flag (covers grey-cloud / DNS-only), so the origin must be
92
+ # proxy-locked (firewall direct access) in production either way.
93
+ TRUST_CLOUDFLARE=false
94
+
95
+ # ===================================================================
96
+ # IP AUTO-BLOCK
97
+ # ===================================================================
98
+ #
99
+ # An IP that exceeds rate limits IP_AUTO_BLOCK_THRESHOLD times within
100
+ # IP_AUTO_BLOCK_WINDOW_SECONDS is blocked for IP_AUTO_BLOCK_DURATION_SECONDS.
101
+ # The threshold targets SUSTAINED abuse — keep it high enough that a
102
+ # retry-looping legitimate client or a NAT'd office sharing one IP cannot
103
+ # self-ban. See src/config/rate-limit.config.ts for the interaction notes.
104
+
105
+ # Rate-limit violations before an IP is auto-blocked (default: 20)
106
+ IP_AUTO_BLOCK_THRESHOLD=20
107
+
108
+ # Sliding window for counting violations, in seconds (default: 300 = 5 min)
109
+ IP_AUTO_BLOCK_WINDOW_SECONDS=300
110
+
111
+ # How long an auto-blocked IP stays blocked, in seconds (default: 3600 = 1 hour)
112
+ IP_AUTO_BLOCK_DURATION_SECONDS=3600
113
+
114
+ # ===================================================================
115
+ # ACCOUNT ACTIVATION
116
+ # ===================================================================
117
+
118
+ # When true (default), new users are created as inactive and must
119
+ # verify their account before they can log in.
120
+ # When false, users are active immediately after registration.
121
+ # NOTE: When this variable is not provided, users are NOT activated
122
+ # by default — you must explicitly set it to false to skip verification.
123
+ REQUIRE_USER_VERIFICATION=true
124
+
125
+ # ===================================================================
126
+ # FILE UPLOAD
127
+ # ===================================================================
128
+
129
+ # Maximum file upload size in MB (default: 10)
130
+ MAX_FILE_SIZE_MB=10
131
+
132
+ # Two-tier upload storage. BOTH optional leave unset to use the defaults
133
+ # (<cwd>/uploads/public and <cwd>/uploads/private).
134
+ # PUBLIC tier: served as static files at /uploads/ viewable by ANYONE,
135
+ # including unauthenticated users (e.g. avatars). @fastify/static
136
+ # is scoped to ONLY this dir so it can never serve a private file.
137
+ # PRIVATE tier: lives OUTSIDE the static root; served ONLY through the
138
+ # auth-gated, owner-scoped route GET /api/v1/files/:filename.
139
+ # Both must live UNDER the Coolify uploads volume (/app/uploads/...) so files
140
+ # survive redeploys — see COOLIFY PERSISTENT STORAGE below.
141
+ # UPLOAD_PUBLIC_DIR=/app/uploads/public
142
+ # UPLOAD_PRIVATE_DIR=/app/uploads/private
143
+
144
+ # COOLIFY PERSISTENT STORAGE (required for uploads to survive redeployments):
145
+ # Go to your service in Coolify → Storages → Add Volume Mount:
146
+ # Name: uploads (or <project-name>-uploads)
147
+ # Source Path: (leave empty Coolify manages the Docker volume)
148
+ # Destination Path: /app/uploads
149
+ # Without this, all uploaded files are lost on every redeployment.
150
+
151
+ # ===================================================================
152
+ # DOCKER PORTS — LOCAL DEVELOPMENT ONLY
153
+ # ===================================================================
154
+ #
155
+ # These ports are used by docker-compose to expose MySQL, Redis, and
156
+ # their admin UIs on your local machine. They are NOT needed in
157
+ # production production connects via DATABASE_URL and REDIS_URL
158
+ # (typically over a private network), not through exposed ports.
159
+ #
160
+ # Change these if they conflict with other services on your machine.
161
+
162
+ MYSQL_PORT={{MYSQL_PORT}}
163
+ PHPMYADMIN_PORT={{PHPMYADMIN_PORT}}
164
+ REDIS_PORT={{REDIS_PORT}}
165
+ REDIS_COMMANDER_PORT={{REDIS_COMMANDER_PORT}}
166
+
167
+ # ===================================================================
168
+ # JWT AUTHENTICATION
169
+ # ===================================================================
170
+
171
+ # JWT secret key (MUST be at least 32 characters)
172
+ # CRITICAL: Generate a strong random secret for production!
173
+ # Example: openssl rand -base64 48
174
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime" — this is a secret!
175
+ JWT_SECRET="{{JWT_SECRET}}"
176
+
177
+ # Access token expiry (short-lived)
178
+ # Format: 1s, 1m, 1h, 1d (default: 15m)
179
+ JWT_ACCESS_EXPIRY="15m"
180
+
181
+ # Refresh token expiry (long-lived)
182
+ # Format: 1s, 1m, 1h, 1d (default: 7d)
183
+ JWT_REFRESH_EXPIRY="7d"
184
+
185
+ # Cookie signing secret (separate from JWT for defense-in-depth)
186
+ # Optional: defaults to JWT_SECRET if not set
187
+ # For production: generate a separate secret: openssl rand -base64 48
188
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime" — this is a secret!
189
+ # COOKIE_SECRET="change-this-to-a-different-secret-at-least-32-chars"
190
+
191
+ # Cookie domain for cross-origin deployments
192
+ # REQUIRED when client and API are on different subdomains:
193
+ # Client: https://app.example.com | API: https://api.example.com
194
+ # Set COOKIE_DOMAIN=".example.com" (note the leading dot)
195
+ # NOT needed when client and API share the same hostname (local dev, same-origin prod)
196
+ # Without this, cookies are scoped to the API hostname only and the browser
197
+ # will silently reject them on cross-origin requests (login appears to do nothing).
198
+ # COOKIE_DOMAIN=".example.com"
199
+
200
+ # ===================================================================
201
+ # CORS (Cross-Origin Resource Sharing)
202
+ # ===================================================================
203
+
204
+ # Allowed origins for CORS
205
+ # Development: Optional (allows all origins for easier local dev)
206
+ # Production: REQUIRED (must be your frontend URL for security)
207
+ # Multiple origins: Separate with commas
208
+ # Examples:
209
+ # Single origin: CORS_ORIGIN="https://myapp.com"
210
+ # Multiple origins: CORS_ORIGIN="https://myapp.com,https://app.myapp.com"
211
+ # Local dev: CORS_ORIGIN="http://localhost:3001"
212
+ # CORS_ORIGIN="http://localhost:3001"
213
+
214
+ # ===================================================================
215
+ # EMAIL (Resend)
216
+ # ===================================================================
217
+
218
+ # Resend API key for transactional emails (password reset, verification, etc.)
219
+ # Get your API key from: https://resend.com/api-keys
220
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime" — this is a secret!
221
+ RESEND_API_KEY="re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
222
+
223
+ # Sender email address
224
+ # Development: Use Resend's test address (onboarding@resend.dev) delivers to your Resend dashboard
225
+ # Production: Use a verified domain email (e.g., noreply@yourdomain.com)
226
+ RESEND_FROM_EMAIL="onboarding@resend.dev"
227
+
228
+ # Frontend URL used to build links in emails (e.g., password reset links)
229
+ # Must match the URL where your Next.js client is running
230
+ CLIENT_URL="http://localhost:3000"
231
+
232
+ # ===================================================================
233
+ # LOGGING
234
+ # ===================================================================
235
+
236
+ # Log level: fatal | error | warn | info | debug | trace
237
+ # Production: info or warn (reduces noise)
238
+ # Development: debug (verbose logging)
239
+ # Staging: info
240
+ LOG_LEVEL=info
241
+
242
+ # ===================================================================
243
+ # DATABASE SEEDING (npm run prisma:seed — dev/test only)
244
+ # ===================================================================
245
+
246
+ # Passwords for the seeded demo accounts (admin@example.com / user@example.com).
247
+ # Optional in development — well-known dev defaults (Admin123! / User123!) are
248
+ # used when unset. The seed script REFUSES to run when NODE_ENV=production.
249
+ # SEED_ADMIN_PASSWORD="choose-a-dev-admin-password"
250
+ # SEED_USER_PASSWORD="choose-a-dev-user-password"
251
+
252
+ # ===================================================================
253
+ # ERROR TRACKING (Optional)
254
+ # ===================================================================
255
+
256
+ # Sentry DSN for error tracking and monitoring
257
+ # Get your DSN from: https://sentry.io/settings/projects/
258
+ # Leave empty to disable Sentry — with no DSN, init is a no-op (fully inert).
259
+ # COOLIFY: Runtime only. Do NOT check "Available at Buildtime".
260
+ # Example: SENTRY_DSN="https://examplePublicKey@o0.ingest.sentry.io/0"
261
+ # SENTRY_DSN=""
262
+
263
+ # Fraction of transactions sampled for performance tracing (0.0–1.0, default 0.1).
264
+ # Only takes effect when SENTRY_DSN is set.
265
+ # SENTRY_TRACES_SAMPLE_RATE=0.1
266
+
267
+ # Environment tag attached to Sentry events (e.g. production, staging).
268
+ # Defaults to NODE_ENV when unset.
269
+ # SENTRY_ENVIRONMENT=""