Orgs: let any user create an organization and become its admin
Organization writes were superadmin-only, so standing up a tenant needed an out-of-band superadmin. Creating one is now self-service, and an admin manages the org they belong to. - POST /api/orgs is open to any authenticated user. A creator who isn't a superadmin must have no organization yet (a single-valued membership relation means a second one would abandon the first), and is promoted to the new org's admin and first member in the same request. If that promotion fails the org is rolled back, so it is never left stranded with nobody able to administer it. Superadmins still create tenants without joining them. - PATCH/DELETE are manager-gated and scope an admin to their own org. An admin deletes theirs only as its sole member: they are detached and demoted to a plain user before the record goes, so the org is empty when it is removed. Other members still block deletion with a 409. - /api/me now carries organization + organizationName, which the clients need to tell "no org yet" from "org you administer". The panel, Web App (new OrgManager.vue in Settings) and Phone App (new _OrganizationSection) all mirror the server's gates rather than re-deciding them. The Phone App cached its role at login and gates the Users tab on it, so AuthService.adoptRole refreshes that from the profile instead of making a freshly promoted admin sign in again. Covered by orgs_test.go, which drives the real handler + middleware chain against a stand-in PocketBase: promotion, the already-a-member refusal, superadmin staying unattached, the rollback, own-org scoping, the detach-and-demote, and the blocking-member 409. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
358ee68f94
commit
cd16d4383f
+17
-1
@@ -76,6 +76,22 @@ their own account. An organization cannot be deleted while it still has members.
|
||||
membership. A superadmin spans all organizations; an admin is scoped by the
|
||||
server to their own. Users may have no organization at all.
|
||||
|
||||
Creating one is self-service: any user who does not already belong to an
|
||||
organization may `POST /api/orgs`, and becomes that organization's **admin** and
|
||||
first member in the same request (if the promotion fails the new organization is
|
||||
rolled back, so it is never left with nobody able to administer it). A user who
|
||||
already belongs to one is refused — membership is a single relation, so creating
|
||||
a second would mean silently abandoning the first.
|
||||
|
||||
A superadmin is the exception: they create organizations without joining them,
|
||||
since they already span every tenant.
|
||||
|
||||
From there an admin manages **their own** organization — rename it, or delete it
|
||||
once they are its only member. Deleting it detaches and demotes them back to a
|
||||
plain `user` before the record is removed, so the organization is empty when it
|
||||
goes. A superadmin may rename or delete any organization, but still only once it
|
||||
has no members at all.
|
||||
|
||||
### Per-user car ownership + sharing
|
||||
|
||||
Cars are not a global list. `cars.owner` marks ownership and `car_shares` grants
|
||||
@@ -139,7 +155,7 @@ POST /api/me/verify/request
|
||||
GET /api/me/export POST /api/me/import
|
||||
POST /api/me/delete POST /api/me/delete/cancel
|
||||
|
||||
# users + organizations (admin or superadmin; org writes are superadmin-only)
|
||||
# users + organizations (admin or superadmin; POST /api/orgs is open to any user)
|
||||
GET /api/users POST /api/users
|
||||
PATCH /api/users/{id} DELETE /api/users/{id}
|
||||
GET /api/orgs POST /api/orgs
|
||||
|
||||
Reference in New Issue
Block a user