# Supabase/PostgreSQL SaaS 题库后端配置(服务端/worker 使用,前端不读取此文件) # 复制此文件为 .env 并填写实际值。 # 生产上线前运行: # npm run readiness:production # npm run readiness:production:db # 运行环境。生产必须是 production;本地开发可用 development。 NODE_ENV=development # API 服务端口 PORT=8787 # Supabase/PostgreSQL 重构 API DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres DEFAULT_TENANT_SLUG=master # 生产必须只写真实 HTTPS 域名,不能包含 * CORS_ORIGIN=http://127.0.0.1:5173,http://localhost:5173 MAX_JSON_BODY_BYTES=1048576 MAX_IMPORT_JSON_BODY_BYTES=10485760 # 认证迁移期配置:生产环境必须替换为高强度随机值,并配置 Supabase Auth JWT AUTH_SMS_PROVIDER=mock AUTH_CODE_PEPPER=replace_with_a_long_random_secret AUTH_SESSION_SECRET=replace_with_another_long_random_secret # 生产推荐使用 Supabase Auth JWKS: # AUTH_JWT_ISSUER=https://.supabase.co/auth/v1 # AUTH_JWT_JWKS_URL=https://.supabase.co/auth/v1/.well-known/jwks.json # 自托管或旧项目兼容才使用强随机 AUTH_JWT_SECRET;配置 JWKS 时必须同时配置 issuer。 AUTH_JWT_ISSUER= AUTH_JWT_AUDIENCE=authenticated AUTH_JWT_SECRET=development-jwt-secret-change-me AUTH_JWT_JWKS_URL= AUTH_CODE_TTL_SECONDS=300 AUTH_SMS_COOLDOWN_SECONDS=60 AUTH_SESSION_TTL_SECONDS=604800 # 远程 Auth/JWKS 验收脚本配置。只在预生产/生产验收命令行临时设置真实 access token, # 不要把真实 token 写入仓库、前端 runtime-config 或长期 .env。 # AUTH_SMOKE_API_BASE_URL=https://api.example.com # AUTH_SMOKE_TENANT_ID= # AUTH_SMOKE_STUDENT_ACCESS_TOKEN= # AUTH_SMOKE_TENANT_ADMIN_ACCESS_TOKEN= # AUTH_SMOKE_PLATFORM_ADMIN_ACCESS_TOKEN= # AUTH_SMOKE_WRONG_TENANT_ID= # AUTH_SMOKE_REQUIRE_ADMIN_TOKENS=true # 安全目标默认关闭迁移期身份头。仅本地兼容旧测试/旧前端时可临时设为 true。 ALLOW_LEGACY_AUTH_HEADERS=false ALLOW_PLATFORM_ADMIN_KEY=false # 迁移期平台管理 API Key。生产环境必须使用平台管理员 JWT/服务端会话,不能开启 ALLOW_PLATFORM_ADMIN_KEY。 PLATFORM_ADMIN_API_KEY=replace_with_platform_admin_key # Worker 配置:CRM webhook、支付补偿、导入复检等后台任务使用 WORKER_CRM_BATCH_SIZE=20 WORKER_CRM_POLL_INTERVAL_MS=10000 WORKER_CRM_MAX_ATTEMPTS=5 WORKER_CRM_BACKOFF_SECONDS=5,30,120,600,1800 WORKER_CRM_REQUEST_TIMEOUT_MS=10000 # 仅本地 fake webhook 测试允许 http://127.0.0.1;生产建议 false WORKER_CRM_ALLOW_INSECURE_LOCALHOST=false # Worker 配置:支付/退款补偿 WORKER_COMMERCE_BATCH_SIZE=20 WORKER_COMMERCE_MIN_AGE_SECONDS=300 WORKER_COMMERCE_REQUEST_TIMEOUT_MS=10000 # Worker 配置:平台 SaaS 订阅自动开票和逾期催缴。 # 自动开票只处理有明确 expires_at 且未开过非 void 订阅账单的订阅。 WORKER_PLATFORM_BILLING_BATCH_SIZE=50 WORKER_PLATFORM_BILLING_DAYS_AHEAD=45 WORKER_PLATFORM_BILLING_DUE_DAYS=15 WORKER_PLATFORM_BILLING_ID=platform-billing-1 # 平台 SaaS 用量超额自动开票默认处理上一个自然月,也可用 YYYY-MM 补跑指定月份。 WORKER_PLATFORM_USAGE_OVERAGE_BATCH_SIZE=100 WORKER_PLATFORM_USAGE_OVERAGE_MONTH= WORKER_PLATFORM_USAGE_OVERAGE_DUE_DAYS=15 WORKER_PLATFORM_USAGE_OVERAGE_ID=platform-usage-overage-1 # 逾期催缴只标记 overdue、写 tenant_invoice_reminders 和审计,不自动停用租户。 WORKER_PLATFORM_DUNNING_BATCH_SIZE=100 WORKER_PLATFORM_DUNNING_ID=platform-dunning-1 # 逾期催缴外部通知会消费 tenant_invoice_reminders,并发送到 generic/钉钉/飞书/企微 webhook。 WORKER_PLATFORM_DUNNING_NOTIFICATION_BATCH_SIZE=50 WORKER_PLATFORM_DUNNING_NOTIFICATION_MAX_ATTEMPTS=5 WORKER_PLATFORM_DUNNING_NOTIFICATION_BACKOFF_SECONDS=10,60,300,900,1800 WORKER_PLATFORM_DUNNING_NOTIFICATION_REQUEST_TIMEOUT_MS=10000 # 仅本地 fake webhook 测试允许 http://127.0.0.1;生产必须 false WORKER_PLATFORM_DUNNING_NOTIFICATION_ALLOW_INSECURE_LOCALHOST=false # Worker 配置:平台审计告警生成和外部通知。 WORKER_PLATFORM_AUDIT_ALERT_BATCH_SIZE=200 WORKER_PLATFORM_AUDIT_ALERT_LOOKBACK_DAYS=14 WORKER_PLATFORM_AUDIT_ALERT_ID=platform-audit-alerts-1 WORKER_PLATFORM_AUDIT_NOTIFICATION_BATCH_SIZE=50 WORKER_PLATFORM_AUDIT_NOTIFICATION_MAX_ATTEMPTS=5 WORKER_PLATFORM_AUDIT_NOTIFICATION_BACKOFF_SECONDS=10,60,300,900,1800 WORKER_PLATFORM_AUDIT_NOTIFICATION_REQUEST_TIMEOUT_MS=10000 # 仅本地 fake webhook 测试允许 http://127.0.0.1;生产必须 false WORKER_PLATFORM_AUDIT_NOTIFICATION_ALLOW_INSECURE_LOCALHOST=false # Worker 配置:内容资源复检。异常托管对象会被标记 failed 并从 active 退回 draft。 WORKER_ASSET_BATCH_SIZE=50 WORKER_ASSET_MIN_AGE_SECONDS=300 WORKER_ASSET_RECHECK_INTERVAL_SECONDS=86400 WORKER_ASSET_REQUEST_TIMEOUT_MS=10000 # 内容资源安全扫描。生产必须使用 metadata_rules,http,HTTP scanner 必须是 HTTPS 且 fail-open=false。 WORKER_ASSET_SECURITY_SCANNER=metadata_rules WORKER_ASSET_SECURITY_SCAN_HTTP_ENDPOINT= WORKER_ASSET_SECURITY_SCAN_HTTP_TOKEN= WORKER_ASSET_SECURITY_SCAN_HTTP_TIMEOUT_MS=10000 WORKER_ASSET_SECURITY_SCAN_FAIL_OPEN=false # Worker 配置:大批量内容导入 WORKER_IMPORT_BATCH_SIZE=5 WORKER_IMPORT_ID=imports-1 WORKER_IMPORT_BACKOFF_SECONDS=30,120,600,1800 # Worker 配置:公共题库自动同步。冲突会保留租户自改题目并等待后台处理。 WORKER_PUBLIC_BANK_SYNC_BATCH_SIZE=5 WORKER_PUBLIC_BANK_SYNC_COPY_LIMIT=1000 WORKER_PUBLIC_BANK_SYNC_ID=public-banks-1 WORKER_PUBLIC_BANK_SYNC_CLAIM_STALE_SECONDS=900 # Worker 配置:题库 PDF/Word 导出。生产建议使用真实对象存储 provider;local_dev 只用于本地开发。 WORKER_EXPORT_BATCH_SIZE=5 WORKER_EXPORT_ID=exports-1 WORKER_EXPORT_BACKOFF_SECONDS=30,120,600,1800 EXPORT_LOCAL_STORAGE_ROOT=.local-storage # Windows 本地可填 C:\Windows\Fonts\NotoSansSC-VF.ttf;Linux 生产建议安装 Noto Sans CJK 并配置路径。 EXPORT_PDF_FONT_PATH= # 对象存储配置:API 和 assets worker 共用 STORAGE_DEFAULT_PROVIDER=local_dev STORAGE_DEFAULT_BUCKET=tenant-assets STORAGE_PUBLIC_BASE_URL= STORAGE_MAX_UPLOAD_BYTES=524288000 STORAGE_ALLOWED_MIME_PREFIXES=image/,video/,audio/ STORAGE_ALLOWED_MIME_TYPES=application/pdf,application/json,application/zip,application/x-zip-compressed,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/octet-stream,text/plain,text/markdown,text/csv STORAGE_REQUIRE_TENANT_PREFIX=true ALIYUN_OSS_REGION= ALIYUN_OSS_ENDPOINT= ALIYUN_OSS_ACCESS_KEY_ID= ALIYUN_OSS_ACCESS_KEY_SECRET= ALIYUN_OSS_STS_TOKEN= ALIYUN_OSS_INTERNAL=false TENCENT_COS_REGION= TENCENT_COS_APP_ID= TENCENT_COS_SECRET_ID= TENCENT_COS_SECRET_KEY= TENCENT_COS_SECURITY_TOKEN= SUPABASE_STORAGE_URL= SUPABASE_STORAGE_SERVICE_KEY= # 国内短信/OAuth/支付的租户级密钥不建议放在 .env。 # 正式使用时请通过租户后台写入 app_private.tenant_secrets,并只在 config_public 暴露非敏感配置。