9e3e59a804
One person could not work for two businesses, and signup and staff creation told anyone whether an email or phone was registered anywhere on the platform. - User email and phone are now unique per business: indexes on (businessId, email) and (businessId, phoneNumber). Duplicate checks in signup and branch-manager creation are scoped to the business, so they no longer reveal other businesses' users. - Login finds the email in every business and checks the password against each account. One match signs straight in; several return 300 with the businesses to choose from, and the login page shows a picker. A wrong password returns the same 401 as before and reveals nothing; failures count against each candidate account, and a correct password only resets the accounts it opens. - Platform-operator access now also needs a platformAdmin flag on the account. With per-business emails, an email match alone would have let any owner create a staff account with the operator's email and open the cross-tenant console. The flag is only set by the seed and the migration; removing the email from PLATFORM_ADMIN_EMAILS still revokes. - npm run migrate:identity flags today's operators (while each listed email still matches one account) and syncs the User indexes, dropping the old unique email_1 and phoneNumber_1. Checked against a database in the old shape; safe to re-run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
2.0 KiB
Bash
49 lines
2.0 KiB
Bash
# AquaFlow now runs entirely as one Next.js app (frontend + API routes),
|
|
# deployed as a single Vercel project. Every variable below is needed —
|
|
# set them all in Vercel's Project Settings -> Environment Variables.
|
|
|
|
# ---- MongoDB ----
|
|
MONGODB_URI=mongodb+srv://user:password@cluster0.mongodb.net/aquaflow?retryWrites=true&w=majority
|
|
|
|
# ---- Auth / JWT ----
|
|
JWT_ACCESS_SECRET=replace_with_a_long_random_string
|
|
JWT_REFRESH_SECRET=replace_with_a_different_long_random_string
|
|
JWT_ACCESS_TTL=15m
|
|
JWT_REFRESH_TTL=30d
|
|
DELIVERY_MAX_DEVICES=2
|
|
|
|
# ---- Platform operator ----
|
|
# Comma-separated emails with cross-tenant access to /platform. The account
|
|
# must also carry the platformAdmin flag, set only by `npm run seed` or
|
|
# `npm run migrate:identity`. Removing an email here revokes access.
|
|
# Public signup refuses these addresses.
|
|
PLATFORM_ADMIN_EMAILS=
|
|
|
|
# ---- Invite links ----
|
|
# Public base URL used in staff invite links. Optional: defaults to the
|
|
# address the request came in on.
|
|
APP_URL=
|
|
|
|
# ---- M-Pesa (optional, off for the pilot) ----
|
|
# M-Pesa STK Push is out of scope for the pilot. While this is false every
|
|
# /api/mpesa route returns 404 and the Daraja variables below are ignored.
|
|
# If you turn it on in production, DARAJA_CALLBACK_IP_ALLOWLIST is required.
|
|
FEATURE_MPESA=false
|
|
|
|
# ---- Safaricom Daraja (only read when FEATURE_MPESA=true) ----
|
|
DARAJA_ENV=sandbox
|
|
DARAJA_CONSUMER_KEY=xxxxxxxxxxxxxxxx
|
|
DARAJA_CONSUMER_SECRET=xxxxxxxxxxxxxxxx
|
|
DARAJA_SHORTCODE=174379
|
|
DARAJA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
|
|
DARAJA_TRANSACTION_TYPE=CustomerPayBillOnline
|
|
# Must be this deployment's own public URL + /api/mpesa/callback, set
|
|
# AFTER your first deploy once you know the real domain, e.g.
|
|
# https://your-app.vercel.app/api/mpesa/callback
|
|
DARAJA_CALLBACK_URL=https://your-app.vercel.app/api/mpesa/callback
|
|
DARAJA_CALLBACK_IP_ALLOWLIST=
|
|
|
|
# ---- Seed / bootstrap ----
|
|
SEED_SUPER_ADMIN_EMAIL=admin@aquaflow.local
|
|
SEED_SUPER_ADMIN_PASSWORD=change_me_immediately
|