Background
PR #259 added per-user server access — you can give a single user access to a specific server and optionally restrict them to one or more databases. That covers the simple case really well.
But during the review a good point came up: for teams working on multiple client environments it makes more sense to group servers and volumes under an Organization and manage access at that level, rather than wiring up every user individually. At the same time, the single-user-to-single-database path should still work without having to spin up a full org for it.
This issue is to plan that out and get everyone's input before writing code.
Proposed model
Two access paths, both supported
Org path — for teams
Create an org → assign servers/volumes to it → add users as members. Everyone in the org gets access to those resources automatically.
Direct path — for individuals
Assign a user directly to a server (with optional DB restriction) using the existing UserServerAccess mechanism. No org needed.
Data model sketch
organizations
id, name, slug, created_by
organization_members (pivot)
organization_id, user_id, role: owner | admin | member | viewer
database_servers → + organization_id (nullable)
volumes → + organization_id (nullable)
user_server_accesses (already exists from PR #259)
user_id, database_server_id, allowed_databases[], can_restore
organization_id being nullable keeps the direct-access path intact — a server with no org is only reachable by app admins and users with an explicit grant.
Permission resolution
- App
Admin → full access, no restrictions
- Org
member/viewer → sees servers and volumes belonging to their active org, scoped to their allowed_databases if set
- User with a direct
UserServerAccess grant (no org) → sees only those specific servers/databases
Org switcher
Session-based selector in the nav (same approach as the theme switcher) — keeps routing simple and doesn't require touching every URL.
Suggested build order
Since this touches a lot of models and policies, splitting it into two PRs makes sense:
PR 1 — Organizations
- Migrations:
organizations, organization_members, organization_id on servers + volumes
- Auto-migration: existing servers/volumes stay accessible (nullable FK, no breaking change)
- CRUD: manage orgs and members (admin only)
- Nav org-switcher
- Policies updated to respect org membership
PR 2 — Fine-grained access (builds on PR 1)
Open questions
-
Org member roles — does viewer = read-only (no backup/restore triggers) and member = full actions make sense? Or should that be configurable per org?
-
Org-level DB restriction vs per-member restriction — should an org be able to say "everyone in this org only sees databases X and Y on server Z"? Or is per-member restriction (via UserServerAccess) enough?
-
Personal org or truly optional? — always giving every user a personal org (GitHub-style) simplifies the "always have an active org" assumption but adds noise for solo installs. Truly optional is cleaner for simple setups.
-
Existing installs — for people already running the app, what's the migration story? Auto-create a default org and move everything into it, or leave organization_id null and let admins organise things manually?
Happy to start building once there's some alignment on the questions above. Curious what others think about the org roles and whether an org-level DB restriction is worth the extra complexity.
Background
PR #259 added per-user server access — you can give a single user access to a specific server and optionally restrict them to one or more databases. That covers the simple case really well.
But during the review a good point came up: for teams working on multiple client environments it makes more sense to group servers and volumes under an Organization and manage access at that level, rather than wiring up every user individually. At the same time, the single-user-to-single-database path should still work without having to spin up a full org for it.
This issue is to plan that out and get everyone's input before writing code.
Proposed model
Two access paths, both supported
Org path — for teams
Create an org → assign servers/volumes to it → add users as members. Everyone in the org gets access to those resources automatically.
Direct path — for individuals
Assign a user directly to a server (with optional DB restriction) using the existing
UserServerAccessmechanism. No org needed.Data model sketch
organization_idbeing nullable keeps the direct-access path intact — a server with no org is only reachable by app admins and users with an explicit grant.Permission resolution
Admin→ full access, no restrictionsmember/viewer→ sees servers and volumes belonging to their active org, scoped to theirallowed_databasesif setUserServerAccessgrant (no org) → sees only those specific servers/databasesOrg switcher
Session-based selector in the nav (same approach as the theme switcher) — keeps routing simple and doesn't require touching every URL.
Suggested build order
Since this touches a lot of models and policies, splitting it into two PRs makes sense:
PR 1 — Organizations
organizations,organization_members,organization_idon servers + volumesPR 2 — Fine-grained access (builds on PR 1)
UserServerAccessrows)Open questions
Org member roles — does
viewer= read-only (no backup/restore triggers) andmember= full actions make sense? Or should that be configurable per org?Org-level DB restriction vs per-member restriction — should an org be able to say "everyone in this org only sees databases X and Y on server Z"? Or is per-member restriction (via
UserServerAccess) enough?Personal org or truly optional? — always giving every user a personal org (GitHub-style) simplifies the "always have an active org" assumption but adds noise for solo installs. Truly optional is cleaner for simple setups.
Existing installs — for people already running the app, what's the migration story? Auto-create a default org and move everything into it, or leave
organization_idnull and let admins organise things manually?Happy to start building once there's some alignment on the questions above. Curious what others think about the org roles and whether an org-level DB restriction is worth the extra complexity.