# Authorization policy. Format: p, subject(role), object(path-pattern), action(method-regex), effect # # DECISION: this app intentionally runs with a SINGLE hardcoded admin (the user # whose email matches ADMIN_EMAIL in .env, via guard::is_admin / admin_seeder). # Everyone else is `customer` (logged in) or `anonymous` (not). There is no # stored `role` column yet. This is a deliberate choice for current scale, not a # limitation of the wiring — see src/shared/rbac.rs for the upgrade path. # # Deny everyone except admins under the admin subtree. `keyMatch` treats the # trailing `*` as "anything after /admin/", so /admin/dashboard, /admin/orders/5 # etc. are all covered; the bare /admin entry point stays open so it can redirect # to /login. Admins match no deny rule and so are allowed through. # # To grow this: give users a real role, emit it as the subject in # src/shared/rbac.rs, then add `p` lines (allow/deny) and `g, , ` # mappings here. p, customer, /admin/*, .*, deny p, anonymous, /admin/*, .*, deny # Admin-only endpoints that live outside the /admin/* subtree: the admin JSON # API and the image upload. Public image serving (/images/{filename}) is GET and # not matched here, so it stays open. p, customer, /api/admin/*, .*, deny p, anonymous, /api/admin/*, .*, deny p, customer, /images/upload, .*, deny p, anonymous, /images/upload, .*, deny