fix(config): require a real API base, ship the env template, show the real team

Three configuration defects and one screen of invented people.

API base. The client defaulted to https://platform.loyaly.ai when
LOYALY_API_BASE was unset, and that host serves THIS console, not the
Behavision API - verified live: it answers /api/auth/me with the console's
own 404 HTML and a login POST with the console's own BFF envelope. So an
unset variable in production made the BFF call its own origin, which fails
looking like a broken login form rather than a misconfiguration. There is
now no remote fallback: development defaults to 127.0.0.1:8088 and
production throws, naming the variable, the way tokenStore already refuses
to run without AUTH_SECRET. A wrong host that appears to work is worse than
a startup failure that says what is missing.

The template. .env.example documented that same wrong host, and .gitignore's
`.env*` matched the template itself, so it was never committed - a fresh
clone got no template at all, for an app that cannot start in production
without AUTH_SECRET. Added `!.env.example` after the ignore rule; .env.local
and every other .env* stay ignored. The template carries placeholders only,
no values.

Team. /settings/team listed five invented people - aravind@nearle.in,
Vikram Seth, Priya Sharma - with store names no endpoint supplies and roles
that do not exist upstream, behind four controls that mutated local state
and were lost on refresh. A merchant could not tell any of it from the real
thing. It now reads GET /api/team, which the platform already serves and
scopes by session, and renders what actually comes back: name, email, role,
whether the account is still active, and last sign-in (or "Never", which is
a fact worth seeing).

The route used to map each row through toAuthUser, which reads client_name -
a field GET /api/team does not send - so organisation was undefined on every
row while active, last_login_at and created_at were discarded. ApiTeamMember
now describes that payload properly and ApiUser is left to authentication.

The screen is READ-ONLY on purpose. Accounts are born from invitations, and
that flow already exists in the platform's own web app: a manager mints a
code, the holder redeems it and chooses their own password. A second way to
create a login does not belong here, least of all on the screen that lists
them. Role changes and deactivation are supported upstream by
PATCH /api/team/{id} and are deliberately not wired: deactivating revokes
every session that person holds immediately, so it wants a confirmation step
and 409 last_owner handling, neither of which belongs in a change whose
purpose is removing invented data.

types.ts also gains the Sales/Floor/Customer interfaces. They are inert here
- nothing imports them yet - and land with this commit so the screens that
consume them arrive as one reviewable change.

Verified against the live local platform: two tenants, correct member lists
for each, and no cross-tenant leakage.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161AMotQ8FxGPZ9gFGb5wiK
This commit is contained in:
2026-09-17 12:05:41 +05:30
parent 697b0d9ef2
commit 759f3b79fd
8 changed files with 353 additions and 291 deletions

5
.gitignore vendored
View File

@@ -33,6 +33,11 @@ yarn-error.log*
# env files (can opt-in for committing if needed)
.env*
# ...except the template, which carries no secret and is the only record of
# which variables the app needs. `.env*` was swallowing it too, so a fresh
# clone got no guidance at all — while AUTH_SECRET and LOYALY_API_BASE are both
# mandatory in production and the app refuses to start without them.
!.env.example
# vercel
.vercel