Files
NextChair/.env.example
T
Stefan Lazic 9e39908ea7 Post Phase 8 - Fixes 1
Delivered:

Super Administrator — env-var provisioned, no StaffProfile at all (structural exclusion from Team/barber-picker/appointments/staff-totals, not a filter). hasPermission short-circuit + new getActingBusinessContext() helper retrofitted across 16 owner pages so it can actually manage the business.
Media Manager — one upload/library/external-URL modal + field picker, backing every image field app-wide. Local-disk storage + Docker volume, SVG rejected, size-capped.
Welcome backgrounds — desktop/mobile images with CSS breakpoint swap.
Business Branding settings — logo/cover/welcome/favicon/icon/colours all editable post-install; cover image finally rendered (was dead config).
Service descriptions — now surfaced on Home and in the booking flow.
Loyalty card — live preview, ColorPicker/MediaPicker/IconPicker, flip removed for a static premium-styled card, Loyalty added to bottom nav. Fixed a real pre-existing bug where the card's configured colour/image/icon were stored but never actually rendered.
Home Screen Redesign — hero gallery + sticky Services/Portfolio/Reviews/Details tabs, backed by a new unified gallery model/service (no hero/portfolio duplication). Details tab surfaces social links and a map that were never shown before.
Google Reviews — real sync pipeline (24h cron, CRON_SECRET-gated, mirrors the existing notification cron exactly), DB-only customer reads, owner hide/unhide + policy management page.
Architecture cleanup — SettingsPageShell extracted from 6 duplicated page wrappers; fixed a second pre-existing bug where branding image fields could never actually be cleared once set.
Verification: 418 tests passing (236 unit + 182 integration, all against a real MySQL database), full typecheck/lint clean across src, and a real Docker build+run cycle — which caught and fixed a genuine bug (scripts/ wasn't copied into the production image, so Super Admin sync would have crashed on every real deployment).
2026-08-04 17:10:30 +01:00

87 lines
3.9 KiB
Bash

# Database (MySQL 8.0 — migrated from PostgreSQL in Phase 7, see
# docs/phase-7-summary.md; the production host only supports MySQL).
DATABASE_URL="mysql://user:password@localhost:3306/nextchair"
# Optional: cap the connection pool (see src/lib/db/prisma.ts). Lower this
# for a hosting provider with a small max-connections limit.
DATABASE_CONNECTION_LIMIT="5"
# Auth.js (NextAuth v5). Generate with: npx auth secret
AUTH_SECRET="replace-me-with-a-32-byte-random-string"
# Google OAuth — https://console.cloud.google.com/apis/credentials
AUTH_GOOGLE_ID=""
AUTH_GOOGLE_SECRET=""
# Base URL of the app (used for callback URLs, email links, etc.)
NEXT_PUBLIC_APP_URL="http://localhost:3000"
# Media Manager (Phase 9) — max upload size in bytes. Defaults to
# 5,000,000 (5MB) if unset. See src/lib/media/media-storage.ts.
MEDIA_MAX_UPLOAD_BYTES="5000000"
# Google Reviews (Phase 9) — from https://console.cloud.google.com/apis/credentials,
# needs the Places API enabled. Leave unset to keep review sync disabled
# (Home shows clearly-labelled demo reviews instead). See
# src/services/reviews/review-sync.service.ts and /owner/settings/reviews.
GOOGLE_PLACES_API_KEY=""
# Email (Phase 7) — see src/services/notifications/providers.
# "console" logs would-be emails to the server console instead of sending
# (safe default — never send real email from an unconfigured environment).
# "brevo" sends for real over Brevo's SMTP relay via nodemailer (see
# brevo-email-provider.ts for why SMTP rather than Brevo's REST API).
EMAIL_PROVIDER="console"
EMAIL_SMTP_HOST="smtp-relay.brevo.com"
EMAIL_SMTP_PORT="587"
EMAIL_SMTP_USERNAME=""
EMAIL_SMTP_PASSWORD=""
EMAIL_FROM_ADDRESS=""
# EMAIL_FROM_NAME is optional and is only used when no business name can
# be resolved. Normal business emails use the installed business name
# automatically (see docs/phase-8-email-sender-summary.md) — you do not
# need to set or keep this in sync with Business Settings.
EMAIL_FROM_NAME=""
# Web Push (Phase 7) — generate with: npx web-push generate-vapid-keys
# NEXT_PUBLIC_VAPID_PUBLIC_KEY must be the same value as VAPID_PUBLIC_KEY —
# it's duplicated because the browser needs it for pushManager.subscribe.
# PUSH_PROVIDER="web-push" to actually send; defaults to "console" (logs only).
PUSH_PROVIDER="console"
VAPID_PUBLIC_KEY=""
NEXT_PUBLIC_VAPID_PUBLIC_KEY=""
VAPID_PRIVATE_KEY=""
VAPID_SUBJECT="mailto:owner@example.com"
# Background notification processing (Phase 7) — shared secret an external
# scheduler presents as `Authorization: Bearer <value>` to
# /api/cron/process-notifications. Generate with: openssl rand -hex 32
CRON_SECRET=""
# First-run installation wizard (Phase 8) — required before /install will
# create the first business/administrator. Generate with:
# openssl rand -hex 32
INSTALLATION_TOKEN=""
# Super Administrator (Phase 9) — platform-level account with every Owner
# permission, provisioned from these env vars rather than the installation
# wizard (see scripts/ensure-super-admin.ts, run on every container start).
# Has no StaffProfile by design: never appears in Team, the customer-facing
# barber picker, or staff totals, and can never receive an appointment. All
# four optional — leave SUPER_ADMIN_EMAIL unset to skip provisioning one
# entirely. Re-run to rotate the password (re-hashed every run).
SUPER_ADMIN_EMAIL=""
SUPER_ADMIN_PASSWORD=""
SUPER_ADMIN_FIRST_NAME=""
SUPER_ADMIN_LAST_NAME=""
# Staff Google Calendar sync (Phase 8) — separate OAuth client from
# AUTH_GOOGLE_ID/SECRET above (different scopes; see
# src/services/calendar/google-calendar.provider.ts). Leave unset to keep
# calendar sync disabled — Settings shows a "not configured" state rather
# than crashing.
GOOGLE_CALENDAR_CLIENT_ID=""
GOOGLE_CALENDAR_CLIENT_SECRET=""
GOOGLE_CALENDAR_REDIRECT_URI="http://localhost:3000/api/staff/calendar/google/callback"
# Encrypts stored refresh tokens at rest. Generate with: openssl rand -hex 32
CALENDAR_TOKEN_ENCRYPTION_KEY=""