Brings the working codebase (Next.js app, auth system, Stripe billing, Docker/deploy config, tests, docs) into version control on top of the placeholder initial commit, and adds account self-deletion (Danger Zone in Settings, password + typed-email confirmation, cascading DB cleanup, Stripe cancellation) per GDPR right-to-erasure. Excludes local build caches, node_modules, and internal agent scratch files; .gitignore hardened to keep those out going forward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
134 lines
6.3 KiB
Plaintext
134 lines
6.3 KiB
Plaintext
# ==============================================
|
|
# OpenRouter / DeepSeek AI Vision Keys
|
|
# ==============================================
|
|
# OpenRouter API Key for GPT-5.6 Luna ($0.10 / $0.60 per 1M)
|
|
OPENROUTER_API_KEY=your_openrouter_api_key_here
|
|
OPENROUTER_MODEL=openai/gpt-5.6-luna
|
|
|
|
# DeepSeek Direct API
|
|
DEEPSEEK_API_KEY=your_deepseek_api_key_here
|
|
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
|
|
|
# Fallback Vision Provider (OpenAI GPT-4o-mini / Gemini Flash)
|
|
OPENAI_API_KEY=your_openai_api_key_here
|
|
GEMINI_API_KEY=your_gemini_api_key_here
|
|
|
|
# ==============================================
|
|
# Database (PostgreSQL - Neon / Supabase)
|
|
# ==============================================
|
|
# Local-First IndexedDB is active by default. Optional PostgreSQL for production:
|
|
DATABASE_URL=postgresql://user:password@localhost:5432/receipt_scanner
|
|
|
|
# Least-privilege runtime role (recommended for production).
|
|
# Provision it with scripts/db-permissions.sql — via `node
|
|
# scripts/apply-db-permissions.mjs`, or automatically on a fresh volume through
|
|
# the docker-compose init mount — then point the app's RUNTIME connection at
|
|
# it. The role (receipt_app) has CONNECT + schema USAGE + table/sequence DML
|
|
# only: no superuser, no CREATEDB/CREATEROLE, no DDL. Migrations and schema
|
|
# init still require the OWNER DATABASE_URL above (they run DDL), so run those
|
|
# with the owner URL and the app with the restricted URL.
|
|
# APP_DATABASE_URL=postgresql://receipt_app:receipt_app_secure_password@localhost:5432/receipt_scanner
|
|
# APP_DATABASE_PASSWORD=receipt_app_secure_password
|
|
|
|
# ==============================================
|
|
# Storage (Cloudflare R2 / S3 - Optional)
|
|
# ==============================================
|
|
R2_ACCOUNT_ID=your_cloudflare_account_id
|
|
R2_ACCESS_KEY_ID=your_r2_access_key
|
|
R2_SECRET_ACCESS_KEY=your_r2_secret_key
|
|
R2_BUCKET_NAME=receipt-images
|
|
R2_PUBLIC_URL=https://your-bucket-url.com
|
|
|
|
# ==============================================
|
|
# Payments & Webhooks (Stripe)
|
|
# ==============================================
|
|
STRIPE_SECRET_KEY=sk_test_...
|
|
STRIPE_PUBLISHABLE_KEY=pk_test_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
STRIPE_WEEKLY_PRICE_ID=price_...
|
|
STRIPE_ANNUAL_PRICE_ID=price_...
|
|
STRIPE_LIFETIME_PRICE_ID=price_...
|
|
# Prices are decided server-side from src/lib/billing/pricing.ts. When a Price
|
|
# ID above is set, Checkout uses it; otherwise the catalog amount is charged.
|
|
# The webhook cross-checks the paid amount against that same catalog, so a
|
|
# Price ID must never diverge from the catalog amount for its plan.
|
|
|
|
# ==============================================
|
|
# Authentication — Google Sign-In (optional)
|
|
# ==============================================
|
|
# Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client ID
|
|
# (type "Web application"). Authorised redirect URI must be exactly:
|
|
# <NEXT_PUBLIC_APP_URL>/api/auth/google/callback
|
|
# The Google button only renders when both values are present.
|
|
GOOGLE_CLIENT_ID=your_client_id.apps.googleusercontent.com
|
|
GOOGLE_CLIENT_SECRET=your_client_secret
|
|
|
|
# ==============================================
|
|
# Authentication — SMTP for confirmation links
|
|
# ==============================================
|
|
# Required in production: signup fails loudly without it, because an account
|
|
# that can never be confirmed must not be created. In development, missing SMTP
|
|
# makes the confirmation link appear in the server log and in the UI instead.
|
|
SMTP_HOST=smtp.example.com
|
|
SMTP_PORT=587
|
|
SMTP_USER=no-reply@yourdomain.com
|
|
SMTP_PASSWORD=your_smtp_password
|
|
# true for implicit TLS on port 465; false for STARTTLS on 587.
|
|
SMTP_SECURE=false
|
|
MAIL_FROM=ScanReceipts <no-reply@yourdomain.com>
|
|
|
|
# ==============================================
|
|
# Discord Sales Notification Bot
|
|
# ==============================================
|
|
DISCORD_SALES_WEBHOOK_URL=https://discord.com/api/webhooks/...
|
|
|
|
# ==============================================
|
|
# App Settings
|
|
# ==============================================
|
|
# Inlined into the client bundle at build time and baked into the Docker image.
|
|
# Pass it as --build-arg NEXT_PUBLIC_APP_URL (docker-compose forwards it via
|
|
# build.args) so sitemap/robots/canonicals are built against the real domain.
|
|
# PRODUCTION MUST BE AN https:// URL: the app is HTTPS-only (HSTS via
|
|
# Strict-Transport-Security), and an http:// value would make browsers refuse
|
|
# the upgrade promise baked into every response. http://localhost:3000 is fine
|
|
# for local development only.
|
|
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
|
|
# ==============================================
|
|
# Cookie domain — share the session across subdomains
|
|
# ==============================================
|
|
# When the dashboard is served on app.<domain> and the admin on admin.<domain>
|
|
# (both rewritten by src/middleware.ts), the session, guest, CSRF and OAuth
|
|
# cookies must be scoped to the parent domain so one login works everywhere.
|
|
# Leave EMPTY in local development (localhost cookies stay host-only).
|
|
# Example for production:
|
|
# COOKIE_DOMAIN=.scan-receipts.app
|
|
|
|
# ==============================================
|
|
# CORS — cross-origin API access
|
|
# ==============================================
|
|
# Comma-separated allowlist of origins (scheme://host[:port]) allowed to call
|
|
# the API with credentials. The app's own origin (NEXT_PUBLIC_APP_URL) is
|
|
# always allowed and must NOT be repeated here. Never use "*": the app sends
|
|
# cookies (guest sessions, admin subdomain) and a wildcard would be rejected by
|
|
# browsers and is a CSRF risk. Include the admin subdomain origin
|
|
# (e.g. https://admin.example.com) if it should call the API cross-origin.
|
|
# Leave empty for same-origin-only access.
|
|
CORS_ORIGINS=
|
|
|
|
# ==============================================
|
|
# Umami Analytics (self-hosted, optional)
|
|
# ==============================================
|
|
# Inlined into the client bundle at build time (see Dockerfile ARG/ENV) and
|
|
# also read by next.config.ts to widen the CSP to the script's origin. The
|
|
# tracking script only renders when BOTH values are set (src/app/(app)/layout.tsx
|
|
# and src/app/(marketing)/[locale]/layout.tsx). Leave empty to disable.
|
|
# NEXT_PUBLIC_UMAMI_SRC=https://analytics.yourdomain.com/script.js
|
|
# NEXT_PUBLIC_UMAMI_ID=your-website-id
|
|
|
|
# ==============================================
|
|
# Admin Dashboard Access
|
|
# ==============================================
|
|
# Comma-separated list of email addresses with admin access
|
|
ADMIN_EMAILS=admin@example.com
|