-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnetlify.toml
More file actions
357 lines (307 loc) · 13.6 KB
/
netlify.toml
File metadata and controls
357 lines (307 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# ============================================
# Netlify Configuration - JudgeFinder Platform
# ============================================
# Production deployment configuration for Netlify
# Domain: judgefinder.io
# See: https://docs.netlify.com/configure-builds/file-based-configuration/
# ============================================
[build]
# Build command - use build:netlify which skips env validation for Netlify
# CRITICAL: Unset NODE_ENV before build to prevent Next.js 15 "Html should not be imported" error
# Next.js sets NODE_ENV automatically during build; setting it manually causes Pages Router conflicts
command = "npm run build:netlify"
# NOTE: Do NOT set 'publish' when using @netlify/plugin-nextjs
# The plugin automatically manages the output directory for Next.js SSR
# publish = ".next" # Commented out - managed by Next.js plugin
# NOTE: Do NOT set 'functions' when using @netlify/plugin-nextjs for API routes
# The plugin automatically handles Next.js API routes as serverless functions
# functions = "netlify/functions" # Only for standalone Netlify functions (scheduled tasks)
# Ignore builds for documentation changes only
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ':(exclude)docs/' ':(exclude)*.md'"
[build.environment]
# Node.js and Build Configuration
NODE_VERSION = "20" # Match package.json requirement (^20 || ^22)
# Legacy peer dependencies flag for compatibility
NPM_FLAGS = "--legacy-peer-deps"
# NOTE: Do NOT set NODE_ENV - Next.js sets it automatically during build
# Setting NODE_ENV manually causes "Html should not be imported outside of pages/_document" error
# Build Performance
# Increase memory for Next.js build (default: 1024)
NODE_OPTIONS = "--max-old-space-size=4096"
# Next.js Build Optimizations
# Reduce parallelism to prevent timeouts and memory issues
# This limits concurrent page generation during build
NEXT_PRIVATE_WORKER_THREADS = "1"
# IMPORTANT: Set these in Netlify UI (Site settings > Environment variables)
# ENCRYPTION_KEY - Required for secure data encryption in production
# CRON_SECRET - Required for cron job authentication (Authorization header)
# STRIPE_PRICE_MONTHLY - Stripe price ID for $500/month universal access
# STRIPE_PRICE_YEARLY - Stripe price ID for $5,000/year universal access
# STRIPE_PRICE_ADSPACE - (deprecated) Legacy price ID, use STRIPE_PRICE_MONTHLY
# Public Environment Variables (safe for client-side, NEXT_PUBLIC_ prefix)
# IMPORTANT: Set NEXT_PUBLIC_APP_URL and NEXT_PUBLIC_SITE_URL in Netlify UI to avoid secrets scanner
NEXT_PUBLIC_APP_NAME = "Judge Finder"
# NEXT_PUBLIC_APP_URL - Set in Netlify UI (do not hardcode URLs)
# NEXT_PUBLIC_SITE_URL - Set in Netlify UI (do not hardcode URLs)
NEXT_PUBLIC_CLERK_SIGN_IN_URL = "/sign-in"
NEXT_PUBLIC_CLERK_SIGN_UP_URL = "/sign-up"
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL = "/dashboard"
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL = "/welcome"
# Build Optimizations
NEXT_TELEMETRY_DISABLED = "1"
# ============================================
# ENVIRONMENT VARIABLE CONFIGURATION STRATEGY
# ============================================
# AWS Lambda has a 4KB limit for ALL environment variables combined.
# With 60+ env vars, we must carefully scope them to avoid deployment failures.
#
# SOLUTION: Configure variable scopes in Netlify Dashboard:
# Site Settings → Environment Variables → Edit scopes
#
# BUILD-ONLY Variables (DO NOT inject into Lambda):
# ─────────────────────────────────────────────────
# These should have scope: ✅ Builds, ❌ Functions
#
# Stripe Price IDs (public product catalog identifiers):
# - STRIPE_PRICE_PROFESSIONAL_MONTHLY, STRIPE_PRICE_PROFESSIONAL_ANNUAL
# - STRIPE_PRICE_ENTERPRISE_MONTHLY, STRIPE_PRICE_ENTERPRISE_ANNUAL
# - STRIPE_PRICE_STATE_JUDGE_MONTHLY, STRIPE_PRICE_STATE_JUDGE_ANNUAL
# - STRIPE_PRICE_FEDERAL_JUDGE_MONTHLY, STRIPE_PRICE_FEDERAL_JUDGE_ANNUAL
# - STRIPE_PRICE_COURT_ADVERTISING_MONTHLY, STRIPE_PRICE_COURT_ADVERTISING_ANNUAL
#
# Build Optimization:
# - NODE_OPTIONS, NEXT_PRIVATE_WORKER_THREADS, NEXT_TELEMETRY_DISABLED
# - NPM_FLAGS, ANALYZE
#
# SEO & Verification:
# - NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION, NEXT_PUBLIC_BING_SITE_VERIFICATION
#
# Build-time Tokens:
# - SENTRY_AUTH_TOKEN, SENTRY_RELEASE
#
# Feature Flags:
# - ENABLE_BETA_FEATURES, ENABLE_CRYPTO_PAYMENTS, NEXT_PUBLIC_ENABLE_ADS
#
# API Fine-tuning (compile-time config):
# - COURTLISTENER_REQUEST_DELAY_MS, COURTLISTENER_REQUEST_TIMEOUT_MS, etc.
# - UNICOURT_REQUEST_DELAY_MS, UNICOURT_REQUEST_TIMEOUT_MS, etc.
#
# FUNCTION-REQUIRED Variables (needed at runtime):
# ─────────────────────────────────────────────────
# These should have scope: ✅ Builds, ✅ Functions
#
# Core Infrastructure:
# - NEXT_PUBLIC_SITE_URL, URL, DATABASE_URL
# - NEXT_PUBLIC_SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY
# - SUPABASE_JWT_SECRET, NEXT_PUBLIC_SUPABASE_ANON_KEY
#
# Authentication & Security:
# - CLERK_SECRET_KEY, CLERK_WEBHOOK_SECRET
# - ENCRYPTION_KEY, SYNC_API_KEY, CRON_SECRET, ADMIN_API_KEY
# - TURNSTILE_SECRET_KEY
#
# Payment Processing:
# - STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
#
# External APIs:
# - OPENAI_API_KEY, GOOGLE_AI_API_KEY
# - COURTLISTENER_API_KEY, UNICOURT_CLIENT_SECRET, UNICOURT_BEARER_TOKEN
# - SENDGRID_API_KEY
#
# Cache & Monitoring:
# - UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN
# - SENTRY_DSN, NEXT_PUBLIC_SENTRY_DSN
#
# See netlify-env-var-configuration.md for full documentation
#
# ============================================
# SECRETS SCANNING CONFIGURATION
# ============================================
# Configured in Netlify UI to avoid Lambda 4KB limit
# Setting these in UI prevents injection into Lambda functions
# Exclude docs/examples from scanner (they contain example values, not real secrets)
SECRETS_SCAN_OMIT_PATHS = "docs/**,scripts/**,monitoring/**,public/**,.env.example,.env.production.example,lib/config/example-usage.ts,*.md,screenshots/**,supabase/migrations/**"
# ============================================
# Context-Specific Configurations
# ============================================
# Production Context
[context.production]
command = "npm run build:netlify"
[context.production.environment]
# NOTE: Do NOT set NODE_ENV - Next.js sets it automatically during build
# Production-specific optimizations
NEXT_TELEMETRY_DISABLED = "1"
# Secrets scanning configuration is in Netlify UI (not here)
# SECRETS_SCAN_OMIT_KEYS and SECRETS_SCAN_OMIT_PATHS configured in dashboard
# NEXT_PUBLIC_SITE_URL - Set in Netlify UI (do not hardcode URLs)
# Deploy Preview Context (PR previews)
[context.deploy-preview]
command = "npm run build:netlify"
[context.deploy-preview.environment]
# NOTE: Do NOT set NODE_ENV - Next.js sets it automatically during build
# Branch Deploy Context
[context.branch-deploy]
command = "npm run build:netlify"
[context.branch-deploy.environment]
# NOTE: Do NOT set NODE_ENV - Next.js sets it automatically during build
# Redirect rules for SEO
[[redirects]]
from = "/sitemap_index.xml"
to = "/sitemap.xml"
status = 301
[[redirects]]
from = "/sitemap-index.xml"
to = "/sitemap.xml"
status = 301
# Headers for security and SEO
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
Referrer-Policy = "strict-origin-when-cross-origin"
Permissions-Policy = "geolocation=(), microphone=(), camera=(), payment=(), usb=()"
[[headers]]
for = "/_next/static/css/*"
[headers.values]
Content-Type = "text/css; charset=utf-8"
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/sitemap.xml"
[headers.values]
Content-Type = "application/xml; charset=utf-8"
Cache-Control = "public, max-age=3600, s-maxage=3600"
[[headers]]
for = "/robots.txt"
[headers.values]
Content-Type = "text/plain; charset=utf-8"
Cache-Control = "public, max-age=86400, s-maxage=86400"
# Dynamic routes - no HTML caching to prevent serving stale page data
# These routes use SSR and must fetch fresh data based on URL parameters
[[headers]]
for = "/judges"
[headers.values]
Cache-Control = "public, max-age=0, must-revalidate, s-maxage=0"
X-Robots-Tag = "index, follow"
# API routes with query parameters - ensure proper cache key variation
# Critical for pagination: CDN must include query params in cache key
[[headers]]
for = "/api/judges/list"
[headers.values]
# Netlify-specific: Include query parameters in CDN cache key
# This ensures /api/judges/list?page=1 and ?page=2 are cached separately
Netlify-Vary = "query"
X-Robots-Tag = "noindex, nofollow"
# ============================================
# Serverless Functions Configuration
# ============================================
[functions]
# Function bundler and optimization
node_bundler = "esbuild"
external_node_modules = ["@supabase/supabase-js", "@google/generative-ai", "sharp"]
# Memory allocation is controlled by Netlify plan tier (not configurable in netlify.toml)
# Pro plan: 1024 MB default, Business/Enterprise: up to 3008 MB
# For memory control, upgrade plan or use background functions for heavy operations
# Function timeouts: Configure per-function or via @netlify/plugin-nextjs
# Next.js API routes with maxDuration export are automatically configured by the plugin
# Standard functions: max 26 seconds, Background functions: up to 15 minutes
# Long-running sync functions (background mode)
# These routes have maxDuration = 300 (5 minutes) in code
# The @netlify/plugin-nextjs plugin automatically respects the maxDuration export from route handlers
# No additional configuration needed in netlify.toml for Next.js API routes
# Cron Jobs (scheduled background functions)
[functions."api/cron/daily-sync/route"]
schedule = "0 2 * * *" # Daily at 2:00 AM UTC
node_bundler = "esbuild"
[functions."api/cron/weekly-sync/route"]
schedule = "0 3 * * 0" # Weekly on Sunday at 3:00 AM UTC
node_bundler = "esbuild"
[functions."api/cron/cleanup-checkouts/route"]
schedule = "0 4 * * *" # Daily at 4:00 AM UTC (cleanup expired checkouts)
node_bundler = "esbuild"
# Daily data ingestion cron jobs (staggered to prevent API rate limit conflicts)
# Cron format: minute hour day-of-month month day-of-week
[functions."api/cron/unicourt-daily/route"]
schedule = "0 2 * * *" # Daily at 2:00 AM UTC - UniCourt daily ingestion
node_bundler = "esbuild"
[functions."api/cron/unicourt-weekly/route"]
schedule = "0 4 * * 0" # Weekly on Sunday at 4:00 AM UTC - UniCourt comprehensive sync (CA, TX, NY)
node_bundler = "esbuild"
[functions."api/cron/courtlistener-daily/route"]
schedule = "0 3 * * *" # Daily at 3:00 AM UTC - CourtListener daily ingestion (staggered 1 hour after UniCourt)
node_bundler = "esbuild"
# Analytics materialized views refresh
[functions."api/cron/refresh-analytics-views/route"]
schedule = "0 4 * * *" # Daily at 4:00 AM UTC - Refresh analytics materialized views after data ingestion
node_bundler = "esbuild"
# Cache warming function (runs every 6 hours)
[functions."cache-warmer"]
schedule = "0 */6 * * *"
node_bundler = "esbuild"
# Legacy scheduled function (kept for compatibility)
[functions."submit-sitemap"]
schedule = "@weekly"
# ============================================
# Post-Processing & Optimization
# ============================================
[build.processing]
skip_processing = false
[build.processing.css]
bundle = true
minify = true
[build.processing.js]
bundle = true
minify = true
[build.processing.html]
pretty_urls = true
[build.processing.images]
compress = true
# ============================================
# Plugin Configuration
# ============================================
[[plugins]]
package = "@netlify/plugin-nextjs"
# CDN Cache Purge Plugin
# Automatically purges CDN cache after successful deployment
# TEMPORARILY DISABLED - Netlify build cache issue
# [[plugins]]
# package = "./netlify/plugins/cdn-purge"
#
# [plugins.inputs]
# # Patterns to purge from CDN cache
# purgePatterns = [
# "/_next/static/**",
# "/api/**",
# "/**/*.html",
# "/sitemap.xml",
# "/robots.txt",
# "/judges/**",
# "/courts/**"
# ]
# ============================================
# Edge Functions & Middleware
# ============================================
# Next.js middleware is automatically handled by @netlify/plugin-nextjs
# Custom edge functions can be added to netlify/edge-functions/
# ============================================
# Environment Context Overrides
# ============================================
# Staging/Preview Environment (if using branch deploys)
[context.staging]
command = "npm run build:netlify"
[context.staging.environment]
# NOTE: Do NOT set NODE_ENV - Next.js sets it automatically during build
NEXT_PUBLIC_APP_NAME = "Judge Finder (Staging)"
# ============================================
# Split Testing (A/B Testing)
# ============================================
# Uncomment to enable A/B testing between branches
# [[context.production.split]]
# id = "feature-test"
# branches = ["main", "feature-branch"]
# weight = [90, 10] # 90% main, 10% feature-branch
# ============================================
# Build Performance & Caching
# ============================================
# Next.js cache is automatically managed by @netlify/plugin-nextjs
# Additional caching can be configured here if needed