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.