Routes and redirects: where the base URL leads and how roles are routed. The login mechanics (tokens, hashing, password change) live in authentication — this page is only the map.
/admin and /chat — are one React app.
The admin zone is a separate lazy chunk. Shared layer: auth / tokens,
design system, i18n. The gate is a client-side redirect in the router.
/login?returnTo=<route>
→
return to origin
?returnTo takes
priority, if the role is allowed there.
?returnTo is accepted only as a
local path (starts with a single /,
but not // or /\, no scheme or host) —
otherwise it is ignored and the redirect goes to the role's home.
Open-redirect protection: an external ?returnTo would
send the user to a phishing clone after
login.
must_change_password
→
/change-password
→
on by role
must_change_password set (a temporary password was
issued) → forced redirect to /change-password, with
sign-out blocked until a permanent password is set. The redirect is
client-side; the real boundary is held by the server — a direct API
call bypassing the screen is rejected — the mechanics are in the
data model.
Once the flag is cleared →
routing by role (Q3 above). The feature —
Forced password change.
/admin/*
/admin/*
→
403 Forbidden
→
/chat
/admin/* — Owner / Admin only.
A Member on an admin route → redirect to their own /chat:
when the role's home is known, we avoid a dead end. The shared
403 “Access denied”
screen is for other forbidden deep-links where there is no obvious
redirect.