01Traveler ↔ platformHardened sign-in, isolated data
Sessions use server-generated random tokens and passwords hashed with scrypt — never stored in the clear. In production, authentication rides on signed JWTs with Postgres row-level security, so every table access is checked server-side, row by row.
02Merchant ↔ platformDeny-by-default merchant access
The merchant console is role-based — owner, manager, viewer, admin — and denies by default. Merchants are scoped strictly to their own resources: anything that isn't yours doesn't error, it simply doesn't exist. Admin routes reject non-admin credentials. Both behaviors are covered by tests.
03Merchant ↔ travelerTravelers stay anonymous to merchants
No API returns a traveler's identity or location to a merchant — matching happens entirely on our side, and merchants receive aggregate analytics only. In the database this is structural, not policy: no rule grants merchants access to traveler tables at all.
04PaymentsNo card numbers, no float math
Raw card data never touches our systems — payment is tokenized through Apple Pay and our payment provider. Money is handled as integer cents, never floating point. Orders carry idempotency keys so a retried request can't double-charge, and order state can only move through whitelisted transitions.