Files
baya-monorepo/archive/build-chain/working-context/backend/handoff/after-backend-phase-2.md
T
2026-08-02 18:48:32 +03:30

3.5 KiB

After backend-phase-2 — auth is live over REST

The marketplace has its front door: phone-OTP login, revocable sessions with refresh-token rotation + stolen-token detection, /me, and public role selection — all over REST, wrapping the pre-existing JWE/TOTP/RBAC engine (nothing was rebuilt). Contract: dev/contracts/domains/identity-auth.md; machine schema: dev/contracts/openapi/swagger.v1.json (refreshed — 22 paths).

What the frontend (f1-b2) can now build

  • Login flow: POST api/v1/auth/request_otpPOST api/v1/auth/verify_otp (camelCase bodies; exact snake_case paths per the contract — note request_otp, not otp/request).
  • Session handling: store the token pair; POST api/v1/auth/refresh rotates it (never reuse an old refresh token — replay = 401 + logout-everywhere); POST api/v1/auth/logout (send {}).
  • AuthContext roles + role router: GET api/v1/me returns masked phone, roles[], profile-completion flags (false until b3) and nurseVerificationStatus (not_started until b6). Fresh users have roles: [] → route to POST api/v1/me/select_role (customer/nurse, both allowed, 403 for anything else). Refresh tokens after role selection — role claims are baked into the access token.
  • Errors: 400 invalid phone/code (safe, non-enumerating message), 401 with the standard envelope (also written by the auth stack itself), 403 admin self-assign, 429 over the OTP/auth per-IP limits. The envelope is unchanged (camelCase body, snake_case URLs).

What's mocked

  • SMS delivery (ISmsSender🟡). The OTP code is written to the server log instead of a SIM. Local testing: call request_otp, read the code from the API console log, verify_otp with it.

Rules baked into the API (don't fight them client-side)

  • Phone is the only public credential; email is optional and never a login key.
  • One resend per auth_otp_resend_seconds (response says otpSent: false + wait time).
  • After auth_otp_max_attempts wrong codes, verification refuses until a fresh OTP is requested.
  • Logout rotates the security stamp: all devices' access tokens die; they recover via refresh.

Schema / migration

Migration 20260701222425_IdentitySessionsAndUserExtensions applied to the dev DB on top of b1's baseline: usr.Users gains Gender, NationalId (enc, NULL until b6 KYC), NationalIdVerifiedAt, ShahkarVerifiedAt (auto-reset on phone change), PhoneHash (UNIQUE), PhoneVerifiedAt, IsActive, DeletedAt (+ soft-delete filter); new usr.UserSessions; usr.UserRoles gains GrantedById/GrantedAt/RevokedAt (revoked grants filtered out globally). PhoneNumber/Email/NationalId are now encrypted at rest — never query them by equality; use PhoneHash. Roles seeded: customer, nurse, admin, support, finance, moderation, super_admin. Config keys added: auth_otp_resend_seconds (120), auth_otp_max_attempts (5), auth_session_ttl_days (30).

Follow-ups later phases must close

  • b3: profiles/patients/addresses/bank accounts; gender + names become settable; the /me profile-completion flags start reading real tables.
  • b6: Shahkar + KYC set NationalId/ShahkarVerifiedAt; nurseVerificationStatus becomes real.
  • Legacy UserRefreshTokens still backs the gRPC path only; retire it when gRPC moves to sessions (or gRPC is dropped).
  • ISmsSender → real gateway (see mocks-registry row).