- Proxy-Sperre für /sign-up, INVITE_REQUIRED, set-invite/consume-invite, invites-Router, Admin-Invite-Seite und -Prozeduren, Startcodes in pets.create entfernt — Registrierung ist offen - /join?code=… leitet auf /r/<code> um, /invite auf /einladen; alte geteilte Links laufen nicht ins Leere - InviteCode-Tabelle bleibt nur als Historie (Kontolöschung räumt sie weiter auf) - Datenschutzerklärung 4b (Empfehlungsprogramm, Herkunftsangabe, pf_ref-Cookie) und Nutzungsbedingungen 3b (Programmbedingungen, Bestandsschutz, Missbrauch) - CLAUDE.md: Abschnitt "Referral program" statt "Invite system" Build, Typecheck und alle Tests grün. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
5.8 KiB
Bash
91 lines
5.8 KiB
Bash
# ============================================================
|
|
# OnlyPets — Environment Variables
|
|
# Copy this file to .env.local and fill in your values.
|
|
# NEVER commit .env.local to version control.
|
|
# ============================================================
|
|
|
|
# ── Supabase ─────────────────────────────────────────────────
|
|
# Supabase Dashboard -> Project Settings -> Database -> Connection string
|
|
# DATABASE_URL: POOLED connection (port 6543, pgbouncer) — used by Prisma at runtime
|
|
# DIRECT_URL: DIRECT connection (port 5432) — used by Prisma for migrations
|
|
DATABASE_URL="postgresql://postgres.xxxxxxxxxxxx:password@aws-0-eu-central-1.pooler.supabase.com:6543/postgres?pgbouncer=true"
|
|
DIRECT_URL="postgresql://postgres.xxxxxxxxxxxx:password@aws-0-eu-central-1.pooler.supabase.com:5432/postgres"
|
|
|
|
# Supabase Dashboard -> Project Settings -> API
|
|
# NEXT_PUBLIC_SUPABASE_URL: Project URL (e.g. https://xxxx.supabase.co)
|
|
# !! This is NOT the database URL — it is the Supabase REST/Storage base URL !!
|
|
# Used for: avatar CDN links, signed upload URLs, Storage client.
|
|
# Baked into the client bundle at build time (NEXT_PUBLIC_ prefix).
|
|
# SUPABASE_SERVICE_ROLE_KEY: service_role key (secret! — server-only, never expose to client)
|
|
NEXT_PUBLIC_SUPABASE_URL="https://xxxxxxxxxxxxxxxxxxxx.supabase.co"
|
|
SUPABASE_SERVICE_ROLE_KEY="eyJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
|
|
# ── Clerk (Authentication) ───────────────────────────────────
|
|
# Clerk Dashboard -> API Keys
|
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_xxxxxxxxxxxxxxxxxxxx"
|
|
CLERK_SECRET_KEY="sk_test_xxxxxxxxxxxxxxxxxxxx"
|
|
|
|
# ── Stripe (Sponsoring, Gitea #22) ──────────────────────────
|
|
# Stripe Dashboard → Developers → API keys
|
|
STRIPE_SECRET_KEY="sk_test_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
# Stripe Dashboard → Developers → Webhooks → Add endpoint → copy Signing Secret
|
|
# Endpoint must point at https://<your-domain>/api/webhooks/stripe
|
|
# Subscribe to: checkout.session.completed, invoice.paid,
|
|
# customer.subscription.updated, customer.subscription.deleted
|
|
STRIPE_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
|
|
# ── Mux (Video) ──────────────────────────────────────────────
|
|
# Mux Dashboard → Settings → Access Tokens → Create Token (Mux Video)
|
|
MUX_TOKEN_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
|
MUX_TOKEN_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
# Mux Dashboard → Webhooks → Add endpoint → copy Signing Secret
|
|
# Endpoint must point at https://<your-domain>/api/webhooks/mux
|
|
MUX_WEBHOOK_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
# Your public app URL — currently informational only. Mux's cors_origin
|
|
# (videos.ts) is intentionally "*" for now; restrict it to this value if
|
|
# you lock down direct-upload origins later.
|
|
NEXT_PUBLIC_APP_URL="http://localhost:3000"
|
|
|
|
# ── Cron ──────────────────────────────────────────────────────
|
|
# Bearer token required by /api/cron/trim-feeds and /api/cron/anniversaries.
|
|
# vercel.json's crons array is inert on this self-hosted deployment — an
|
|
# external trigger (e.g. a NAS-side crontab) must call these routes with
|
|
# this token in the Authorization header.
|
|
CRON_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
|
|
# ── Admin Panel ───────────────────────────────────────────────
|
|
# NEVER use NEXT_PUBLIC_ prefix — these MUST stay server-only!
|
|
# ADMIN_SECRET: random UUID path segment (/p/[secret]/) — generate with:
|
|
# node -e "console.log(require('crypto').randomUUID())"
|
|
ADMIN_SECRET="your-random-uuid-here"
|
|
# ADMIN_OWNER_ID: Your Clerk user ID (Clerk dashboard). Bootstraps the super-admin.
|
|
ADMIN_OWNER_ID="user_xxxxxxxxxxxxxxxxxxxx"
|
|
|
|
# ── Redis ─────────────────────────────────────────────────────
|
|
# Self-hosted: use the Docker Redis service (docker-compose sets this automatically).
|
|
# Local dev: run `docker run -d -p 6379:6379 redis:7-alpine` or install Redis locally.
|
|
REDIS_URL="redis://localhost:6379"
|
|
|
|
# ── Error Monitoring (Sentry) ───────────────────────────────────
|
|
# Sentry Dashboard -> Settings -> Projects -> <project> -> Client Keys (DSN)
|
|
# Same DSN value in both — server-side (src/instrumentation.ts) and
|
|
# client-side (src/instrumentation-client.ts) report to the same project.
|
|
# Leave unset to run with Sentry fully inert (no build-time requirement).
|
|
SENTRY_DSN="https://xxxxxxxxxxxxxxxxxxxx@o0.ingest.sentry.io/0"
|
|
NEXT_PUBLIC_SENTRY_DSN="https://xxxxxxxxxxxxxxxxxxxx@o0.ingest.sentry.io/0"
|
|
# Optional — only needed to upload source maps for readable stack traces.
|
|
# Sentry Dashboard -> Settings -> Auth Tokens (needs project:releases scope).
|
|
SENTRY_ORG="your-sentry-org"
|
|
SENTRY_PROJECT="your-sentry-project"
|
|
SENTRY_AUTH_TOKEN=""
|
|
|
|
# ── SMTP (Team mailbox) ──────────────────────────────────────────
|
|
# Use a mailbox hosted by an established provider (e.g. your domain host's
|
|
# mail hosting) — NOT a self-hosted relay from a home/dynamic IP, which gets
|
|
# spam-flagged by most receiving servers regardless of DKIM/SPF.
|
|
SMTP_HOST="smtp.example.com"
|
|
SMTP_PORT="465"
|
|
SMTP_USER="team@example.com"
|
|
SMTP_PASSWORD=""
|
|
MAIL_FROM="team@example.com"
|