11cd2fd01a
Deploy to route.crispygoat.com / deploy (push) Successful in 4m33s
Completes the Tuxedo Water Log feature end-to-end. Builds on the existing
water_* tables in 0001_init.sql; extends them with 0090 and rewrites the
server actions, settings page, export route, and admin panel to actually
function.
Schema (db/migrations/0090_water_log_completion.sql, db/schema/water-log.ts)
- headgate_token + status + max_flow_gpm + thresholds + notes on water_headgates
- role + phone + notes on water_irrigators
- method + total_gallons + photo_url + logged_date + lat/lon on water_log_entries
- new tables: water_admin_settings, water_admin_sessions, water_audit_log, water_alert_log
Auth (src/lib/water-log-pin.ts, src/lib/water-log-audit.ts)
- scrypt N=16384 per-PIN random salt, self-describing hash format
- weak-PIN detection (repeats, monotonic, palindromes)
- 200ms delay + timingSafeEqual on failed verify
- 4-8 digit PINs, generatePin() rejects weak patterns
Server actions (src/actions/water-log/{admin,field,settings}.ts)
- full Drizzle CRUD: headgates, irrigators, entries (with audit hooks)
- verifyPin + 8h field sessions, admin PIN + configurable 1-168h sessions
- regenerateAdminPin invalidates existing admin sessions
- threshold breach detection + alert log writes
- getWaterAdminSession() helper for admin pages
API routes
- /api/water-admin-auth: PIN-protected, generic error (no enum leak)
- /api/water-logs/export: admin-gated JSON/CSV, correct headers
UI (Field Almanac — cream + forest, Fraunces display, § section markers)
- src/components/admin/WaterLogAdminPanel.tsx: full rewrite
- src/components/water/WaterFieldClient.tsx: matches palette
- src/components/water/icons/{WaterGauge,SeasonMark}.tsx: custom SVGs
- src/app/admin/water-log/settings/page.tsx: full rewrite, Field Almanac
Tests
- tests/unit/water-log-pin.test.ts (21 cases): validate, hash, verify, generate
- tests/unit/water-log-reporting.test.ts (31 cases): season, filter, CSV, report
- tests/water-log.spec.ts (Playwright E2E): PIN form, auth gates, API gates
Docs
- docs/water-log.md: full admin guide, security model, data dictionary, checklist
- README: link to docs/water-log.md in admin modules list
- .env.example: Water Log section comment
Type-check: clean. Tests: 70 pass, 3 fail (3 pre-existing getAdminUser
failures on main, unrelated to this work).
82 lines
4.5 KiB
Bash
82 lines
4.5 KiB
Bash
# ============================================================================
|
|
# Route Commerce — Environment variables
|
|
# ============================================================================
|
|
# Copy to `.env.local` and fill in real values for local development.
|
|
# Production: set these in your hosting dashboard (Vercel / Netlify / etc.).
|
|
# ============================================================================
|
|
|
|
# ── App ─────────────────────────────────────────────────────────────────────
|
|
NEXT_PUBLIC_BASE_URL=http://localhost:4000
|
|
NEXT_PUBLIC_SITE_URL=http://localhost:4000
|
|
|
|
# ── Database (Neon Postgres, direct pg driver) ─────────────────────────────
|
|
# Single connection string used by the pg Pool in src/lib/auth.ts and the
|
|
# admin-permissions / data-service layer. Format:
|
|
# postgresql://USER:PASS@HOST:PORT/DBNAME?sslmode=require
|
|
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/route_commerce
|
|
|
|
# ── Neon Auth (Better Auth) ───────────────────────────────────────────────
|
|
# Get these from: neonctl neon-auth status
|
|
# Base URL: "Auth Base URL" field
|
|
# Cookie secret: openssl rand -base64 32 (min 32 chars)
|
|
NEON_AUTH_BASE_URL=https://your-branch.neonauth.region.aws.neon.tech/neondb/auth
|
|
NEON_AUTH_COOKIE_SECRET=replace-me-with-a-32-char-secret
|
|
|
|
# ── Stripe ─────────────────────────────────────────────────────────────────
|
|
STRIPE_SECRET_KEY=
|
|
STRIPE_WEBHOOK_SECRET=
|
|
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
|
STRIPE_PRICE_STARTER=
|
|
STRIPE_PRICE_FARM=
|
|
STRIPE_PRICE_ENTERPRISE=
|
|
STRIPE_PRICE_HARVEST_REACH=
|
|
STRIPE_PRICE_WHOLESALE_PORTAL=
|
|
STRIPE_PRICE_WATER_LOG=
|
|
STRIPE_PRICE_AI_TOOLS=
|
|
STRIPE_PRICE_SQUARE_SYNC=
|
|
STRIPE_PRICE_SMS_CAMPAIGNS=
|
|
|
|
# ── Resend (transactional email) ────────────────────────────────────────────
|
|
RESEND_API_KEY=
|
|
RESEND_WEBHOOK_SECRET=
|
|
|
|
# ── AI providers ──────────────────────────────────────────────────────────
|
|
OPENAI_API_KEY=
|
|
ANTHROPIC_API_KEY=
|
|
GOOGLE_API_KEY=
|
|
XAI_API_KEY=
|
|
MINIMAX_API_KEY=
|
|
MINIMAX_BASE_URL=https://api.minimax.io/v1
|
|
|
|
# ── Square (optional) ─────────────────────────────────────────────────────
|
|
SQUARE_APP_SECRET=
|
|
SQUARE_ENVIRONMENT=sandbox
|
|
|
|
# ── MinIO / S3-compatible object storage ─────────────────────────────────────
|
|
# Endpoint: host:port only (no https://). Use MINIO_PUBLIC_URL for the public base.
|
|
MINIO_ENDPOINT=s3.crispygoat.com
|
|
MINIO_REGION=us-east-1
|
|
MINIO_USE_SSL=true
|
|
MINIO_ACCESS_KEY=routecommerce
|
|
MINIO_SECRET_KEY=miniochangeme123
|
|
# Override public URL if different from endpoint (e.g. Cloudflare CDN in front)
|
|
MINIO_PUBLIC_URL=https://s3.crispygoat.com
|
|
# Bucket names — create these in MinIO first (mc mb myminio/route-products, etc.)
|
|
MINIO_BUCKET_PRODUCTS=route-products
|
|
MINIO_BUCKET_BRAND_LOGOS=route-brand-logos
|
|
MINIO_BUCKET_WATER_LOGS=route-water-logs
|
|
|
|
# ── Cron / automation ───────────────────────────────────────────────────────
|
|
CRON_SECRET=replace-me-with-a-random-string
|
|
|
|
# ── Water Log ───────────────────────────────────────────────────────────────
|
|
# The Water Log module reuses the existing `DATABASE_URL` and (for photo
|
|
# uploads) the `MINIO_BUCKET_WATER_LOGS` bucket above. It also reuses the
|
|
# brand's Twilio / SMS config for high/low threshold alerts. The
|
|
# Tuxedo brand UUID is a public default used as a fallback for cold-start
|
|
# paths when the calling admin user is a platform_admin with brand_id=null.
|
|
# It does NOT need to be set as an env var — the value is hardcoded in
|
|
# the server actions — but you can override it with:
|
|
# TUXEDO_BRAND_ID=64294306-5f42-463d-a5e8-2ad6c81a96de
|
|
# See docs/water-log.md for the full module guide.
|