RegularUpkeep uses Supabase Row Level Security (RLS) to enforce multi-tenant data isolation at the database level. This ensures that users can only access data they are authorized to see, regardless of how the application code behaves.
| Role | Description | Access Level |
|---|---|---|
customer |
Homeowner/property investor | Own properties, bookings, payments |
tenant |
Resident of a property | Limited; submit issues, view within spend threshold |
provider |
Service company owner/dispatcher | Own services, bookings, team management |
handyman |
Field technician | Assigned jobs, availability, earnings |
admin |
Platform operations/support | Full system access |
territory_manager |
Regional operator | Properties/providers within territory |
franchisee |
Territory franchise owner | Territory management and revenue |
Returns TRUE if the current user has the admin role.
SELECT is_admin(); -- Returns booleanReturns the role of the currently authenticated user.
SELECT current_user_role(); -- Returns user_role enumChecks if the current user can access a specific property. Returns TRUE if:
- User is an admin
- User is a member of the property
- User is a territory manager/franchisee for the property's territory
- User is a provider with a booking at the property
- User is a handyman assigned to a booking at the property
SELECT can_access_property('uuid-here'); -- Returns booleanChecks if the current user manages a specific territory.
SELECT in_territory('uuid-here'); -- Returns booleanChecks if the current user is on a provider's team (owner or staff).
SELECT is_provider_team_member('uuid-here'); -- Returns boolean| Operation | Who Can Access |
|---|---|
| SELECT | Property members, territory managers, admin, providers/handymen with bookings |
| INSERT | Customers, admins, territory managers, franchisees |
| UPDATE | Property owners/managers, admin |
| DELETE | Property owners, admin |
| Operation | Who Can Access |
|---|---|
| SELECT | Anyone who can access the property |
| INSERT | Property owners/managers with can_manage_members, admin, or first member |
| UPDATE | Property owners/managers with can_manage_members, admin |
| DELETE | Property owners, admin |
| Operation | Who Can Access |
|---|---|
| SELECT | Everyone (active territories only) |
| INSERT | Admin only |
| UPDATE | Franchisee (own territory), admin |
| DELETE | Admin only |
| Operation | Who Can Access |
|---|---|
| SELECT | Team members, admin |
| INSERT | Provider owner, team admins, admin |
| UPDATE | Provider owner, team admins, admin |
| DELETE | Provider owner, admin |
Properties are the central entity in RegularUpkeep. All service-related data (bookings, quotes, maintenance, documents) links back to a property.
| Role | Permissions |
|---|---|
owner |
Full control: manage members, approve quotes, view history, delete property |
manager |
Manage members, approve quotes, view history |
tenant |
Request service (within threshold), view limited history |
Tenants have an optional spend_threshold_cents field. If a service quote exceeds this amount, the property owner must approve before the booking can proceed.
-- Example: Tenant can approve up to $500
UPDATE property_members
SET spend_threshold_cents = 50000
WHERE user_id = 'tenant-uuid' AND member_role = 'tenant';Providers can have multiple team members with different roles:
| Team Role | Capabilities |
|---|---|
owner |
Full control, manage team, access all data |
admin |
Manage team, access all data |
dispatcher |
Assign jobs, manage schedule |
tech |
View assigned jobs, update status |
Territories define geographic regions for franchising:
- Boundaries defined by counties, ZIP codes, or polygon geometry
- Franchisee owns the territory and manages local operations
- Territory managers oversee provider recruitment and performance
- Properties auto-assigned to territories based on location
- Never bypass RLS: Always use the Supabase client with user authentication
- Test with different roles: Verify policies work for all user types
- Use helper functions:
can_access_property()is the canonical access check - Property-first design: New features should link to properties when appropriate
- Always enable RLS:
ALTER TABLE new_table ENABLE ROW LEVEL SECURITY; - Create explicit policies for SELECT, INSERT, UPDATE, DELETE
- Consider property access: Use
can_access_property()when relevant - Document policies in this file
- Test migrations on a development database first
- Include rollback statements where possible
- Update this security document when adding new policies
- Verify RLS is enabled on all new tables
The following tables maintain audit information:
booking_status_history- All booking status changes*.updated_attriggers - Automatic timestamp on all updates
- API key authentication for service accounts
- Role switching for admin impersonation
- Detailed permission matrix per feature
- Audit logging for sensitive operations