# 02 — Roles & Permission Matrix

Navi uses **permission-based authorization**, not role-name checks. A role is a named bag of permissions. A user may hold multiple roles. A partner user belongs to one or more `Business` records via `UserMembership`, with scoped permissions per business.

## Naming convention

`<resource>.<action>.<scope>` — e.g. `booking.read.own`, `booking.read.partner`, `booking.read.all`.

Scopes:

- `own` — rows the user owns (`userId === currentUserId`)
- `assigned` — rows belonging to a business the user is a member of (`businessId IN currentUser.memberships`)
- `partner` — alias for `assigned`, used for read paths
- `all` — global (super-admin or audit roles)
- `support` — restricted update path (e.g. `booking.update.support` cannot refund)

## Resources

`profile`, `user`, `role`, `permission`, `business`, `membership`, `destination`, `category`, `listing`, `room`, `booking`, `order`, `payment`, `refund`, `payout`, `saved`, `trip`, `review`, `ticket`, `audit`, `content`, `report`, `settings`, `integration`, `feature_flag`.

## Roles → permissions (MVP)

### Guest
`destination.read.public`, `listing.read.public`, `category.read.public`, `content.read.public`.

### Registered User
Inherits Guest, plus:
`profile.*.own`, `user.delete.own`, `saved.*.own`, `booking.create`, `booking.read.own`, `order.create`, `order.read.own`, `payment.create.own`, `review.create.own`, `review.update.own`, `trip.*.own`, `ticket.create`, `ticket.read.own`.

### Premium User
Inherits Registered, plus:
`booking.priority`, `trip.advanced`, `support.priority`.

### Hotel Partner / Activity Partner / Restaurant Partner / Taxi Partner / Pharmacy Partner / Grocery Partner / SIM Provider
All scoped to assigned businesses:
`business.read.assigned`, `business.update.assigned`, `listing.*.assigned`, `room.*.assigned` (hotel only), `booking.read.assigned`, `booking.update.assigned`, `order.read.assigned`, `order.update.assigned`, `payout.read.assigned`, `analytics.read.assigned`, `membership.read.assigned`, `membership.invite.assigned`.

### Support Agent
`user.read.all`, `booking.read.all`, `booking.update.support`, `order.read.all`, `order.update.support`, `ticket.*.all`, `audit.read.support`. **No** payment refund.

### Operations Manager
Inherits Support, plus:
`destination.*`, `category.*`, `listing.read.all`, `business.read.all`, `feature_flag.read`.

### Content Manager
`content.*`, `destination.*`, `category.*`, `media.*`, `listing.update.content`.

### Finance Manager
`payment.read.all`, `refund.create`, `refund.approve`, `payout.*`, `report.read.financial`, `audit.read.financial`.

### Admin
Most things, including `role.read.all`, `permission.read.all`, `feature_flag.update`, but cannot delete the SuperAdmin role or grant `*`.

### Super Admin
`*` (full).

## Multi-role and multi-business behavior

- A user's effective permissions = union of permissions from all assigned roles ∪ membership-scoped permissions.
- For `assigned` scope, the API enforces a `businessId` filter automatically using a Prisma middleware that reads `RequestContext.memberships`.
- A user holding both `Registered` and `HotelPartner` (e.g. a partner who also books trips as a tourist) gets both. Partner data and personal data are visually separated in the UI.

## Enforcement points

1. **API gateway:** every route declares required permissions via `@RequirePermissions(...)` and a `RbacGuard` checks them against the resolved user.
2. **Prisma middleware:** scopes queries to the user's owned/assigned rows automatically.
3. **Dashboard:** route gates use the same permission strings; client never trusts itself, every render still re-validates server-side on data fetch.
4. **Mobile:** clients see only own data because the API filters by `userId`.

## Audit triggers

Login, logout, password change, role change, permission change, profile update, booking create/cancel, order create/cancel, payment status change, refund request/approve, payout, partner approve/reject, content publish/unpublish, role assignment, membership change, feature-flag change, admin login.

## Documented assumptions

1. Permissions are stored as strings in the DB (`Permission.code`) for portability and quick check via in-memory set.
2. Granting `*` is forbidden except to the seeded SuperAdmin role.
3. Partner accounts cannot self-elevate; OperationsManager+ approves partner onboarding.
