Team & RBAC

A property owner rarely runs check-ins themselves. They hire a front-desk team, a manager, possibly an accountant. ABc lets the owner add as many staff accounts as they need, each with a scoped role that limits exactly what they can see and do.

Built-in roles

OW

Owner

Full access. Can add/remove staff, change pricing, change payout bank, delete property. Only role allowed to invite other owners.

MG

Manager

Everything an owner can do, except: cannot delete the property, cannot change payout bank, cannot remove the owner. Default role for "second-in-command".

FD

Front-desk

Can view bookings, create manual bookings, capture cash/UPI, check-in/check-out. Cannot edit rates, cannot view payout reports.

FN

Finance

Read-only on bookings; full access to payments, refunds, invoices, GST reports. Cannot modify property data.

RO

Read-only

Everything visible, nothing editable. Great for accountants, auditors, board members.

CU

Custom

Owner mixes-and-matches individual permissions. V1.x feature; MVP ships the 5 presets above.

Permission matrix

Every action in ABc maps to one of ~30 permissions. Here is the abbreviated map across the 5 preset roles:

PermissionOwnerManagerFront-deskFinanceRead-only
property.create
property.edit
property.delete
property.pause
room.create_edit
rate.edit
booking.view
booking.create_manual
booking.checkin_checkout
booking.cancel
booking.price_override± (≤20 %)
payment.capture
payment.refund
payout_bank.edit
channel.connect
team.invite
team.remove
analytics.view
analytics.financials
audit_log.view

Property scope

Beyond role, every team member is scoped to one or more properties. A multi-property owner can hire one manager for "Manali" and another for "Kasol" — they will not see each other's data.

Global staff

Owner-level account, all properties owned. Default when the owner adds someone to "all properties".

Property-scoped staff

Visible only on the assigned property. UI hides everything else; API enforces scope on every read & write.

Team list UI

app.abc.com/team
Team
4 members · 1 pending invite
MemberRolePropertiesStatus
RM
Rohan Mehta · you
rohan@parkviewhotel.in
Owner All (3) Active
SK
Sneha Kapoor
sneha@parkviewhotel.in
Manager Park View · Hillside Active
AP
Anjali Patel
anjali@parkviewhotel.in
Front-desk Park View Active
RK
Ravi Khanna (CA)
ravi.ca@example.com
Finance All (3) Active
?
arjun@example.com
Invited 2 hrs ago
Front-desk Hillside Pending

Invite member · UI

app.abc.com/team · new invite
Invite a team member
They'll receive a one-time link, valid 7 days.
Property scope
Park View × Hillside × + Add property

Custom role · permissions editor

app.abc.com/team/roles/new
New custom role
Pick exactly which actions this role can take.
Summary
6 permissions selected across 5 domains.

Property

Bookings

Payments

Team

Analytics

Activity by member

app.abc.com/team/activity
Activity · last 14 days
Per-member action counts & risky-action flags.
Live
MemberActivity (14 d)TotalLast seenRisky actions
RM
Rohan Mehta
Owner
142 actions Now
SK
Sneha Kapoor
Manager
89 actions 12 m ago 1 price override
AP
Anjali Patel
Front-desk
56 actions 2 h ago
RK
Ravi Khanna
Finance · CA
23 actions Yesterday 2 refunds today

Invite flow

  1. Owner enters email + role + property scope

    Optional: a personalised note.

  2. System sends invite email

    One-time link, valid 7 days. New users get a sign-up page; existing users get a one-click accept.

  3. Invitee accepts

    If new: completes sign-up (name, password, phone OTP). If existing: just confirms.

  4. Membership row created

    user × property × role stored in memberships. User now sees that property in their workspace switcher.

  5. Welcome email + notification to owner

    Owner gets a heads-up that the invite was accepted.

Removing a member

  • Owner clicks "Remove" → confirmation dialog → membership row deleted.
  • Active sessions for that user / property revoked immediately (JWT version bumped).
  • The user's bookings and audit entries stay intact (we never delete history). Their attribution is preserved.
  • If the user has no other memberships, their account remains but they lose access to this workspace.

The DB model

memberships
  • iduuid
  • user_id→ users
  • property_id→ properties · nullable
  • roleenum
  • scopeall | specific
  • invited_byuuid
  • accepted_attimestamp
invitations
  • iduuid
  • emailtext
  • property_id→ properties
  • roleenum
  • token_hashtext
  • expires_attimestamp
  • accepted_attimestamp · nullable

Permission checks in code

middleware
// Express / NestJS-style guard
@RequiresPermission("booking.cancel")
@RequiresProperty()
async cancelBooking(@Param("id") id: string, @User() me: CurrentUser) {
  // Guard already verified:
  //   - user has booking.cancel permission
  //   - user has access to the property the booking belongs to
  return bookings.cancel(id, me);
}
Never trust the client.

Front-end hides buttons by role for UX, but every server endpoint re-checks the permission. A revoked agent loading a stale page should still be denied.