Files
scan-receipts/.env.example
Timo 84b9987c49 Add full application: receipt scanning, auth, billing, and account deletion
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>
2026-08-19 20:59:04 +02:00

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