Date: 2026-07-10
Accepted
A fresh install seeds an admin@local administrator (F-01b) so the operator has a usable identity, but it seeds no roles. RBAC0 (ADR-0006) attaches every grant to a Role, and access resolves as user → user_roles → role → RoleResourceGrant → resource. So on a brand-new instance the operator cannot grant access to anything until they first create a role, then assign users to it. That is a cold-start papercut precisely at the moment a new operator is trying to see the product work.
Operators reach for a "group that contains everyone" — the shape Google Workspace (all-users@), Microsoft 365 ("Everyone"), and Slack (@channel) all ship. In Islandr's vocabulary there are no groups; the grouping primitive is the Role. So "Everyone" is a seeded default role, not a new entity.
The quick-start value only materialises under one condition: new users must belong to "Everyone" automatically. A pre-created but empty role that the admin still has to populate by hand is barely better than "create a role yourself" — the operator adds every user twice (once to Everyone, once to their real role) and every future user is silently outside it. The decision therefore hinges on auto-membership, not on the mere existence of a default role.
A sibling idea — a default "admins" access-role — is explicitly out of scope: application-level admin vs. end-user is already the fixed system-role enum ADMIN/END_USER (F-19). A second "admins" access role would duplicate that axis and invite confusion between "may reach the admin console" and "has an ACL grant". If a concrete grant-bundle for admins is ever needed, it is a normal role, created on demand — nothing special.
Seed one default role, Everyone, carrying an autoAll flag that makes every user an implicit member — present and future — without any user_roles rows.
Concretely:
auto_all BOOLEAN NOT NULL DEFAULT 0 to the roles table (Flyway migration). Only the seeded Everyone role has it set; ordinary roles never do (no UI to toggle it in v1).RoleBootstrap idempotently creates the Everyone role (auto_all = 1) on first startup (unconditionally — unlike the ENV-gated admin@local seed). It is created with zero grants — inert until the admin deliberately grants something to it.roles(user_roles) ∪ roles(auto_all = 1):
MyAccessResource — the portal "what can I reach?" query unions the auto-all roles.RuleBuilder — the firewall recompute adds every auto-all role's grants to every user-linked peer. Site/gateway peers have no userId and are unaffected (Everyone models user access, not routing).AclMatrixResource — the matrix shows Everyone like any role, but the UI labels its membership as "alle Nutzer (auch künftige)" rather than a member count.Everyone is a protected role: it cannot be deleted or renamed, and its auto_all flag cannot be cleared via the API — otherwise the contract "a grant on Everyone reaches all users" silently breaks. Grants on it are freely editable.admin@local is a user, it is automatically covered by Everyone; the operator can grant a resource to Everyone and immediately reach it from their own peer, with no role plumbing.Baseline: A — seeded Everyone role with auto_all auto-membership (the decision).
| Criterion (weight) | A: auto_all role (baseline) | B: plain pre-created role (manual membership) | C: no default role (status quo) | D: "applies to all" flag on the grant (no role) |
|---|---|---|---|---|
| Quick-start value on a fresh install (4) | 0 | -1 | -1 | 0 |
| Covers future users automatically (4) | 0 | -1 | -1 | 0 |
| Fits the existing RBAC0 model, no new concept (3) | 0 | 0 | 0 | -1 |
| Least-privilege safety (harder to over-grant) (3) | 0 | +1 | +1 | 0 |
| Implementation cost (2) | 0 | +1 | +1 | -1 |
| Audit clarity ("who reaches X?") (2) | 0 | 0 | 0 | -1 |
| Weighted total | 0 | −1 | −1 | −7 |
Honest reading:
A ties B and C at the weighted total because its safety cost is real (see R-130) and is the price for the quick-start gain. The tie is broken deliberately in favour of the operator experience, with the safety cost mitigated rather than denied — the same shape as the ADR-0006 ⓐ-all-ports decision (R-054).
Positive
Everyone → every user (including admin@local) reaches it. No role plumbing for the first win.Everyone is an ordinary row in roles with one extra boolean; the RBAC0 story from ADR-0006 is intact.Risks created
auto_all role grants to all users, present and future. A careless grant on Everyone (especially ⓐ-all-ports, compounding R-054) silently widens access to every current user and every user created afterwards — a least-privilege footgun. Mitigation: (1) Everyone is seeded empty (inert until a grant is added deliberately); (2) the ACL matrix labels the column "alle Nutzer (auch künftige)" and warns on any grant added to an auto_all role; (3) every grant change on Everyone is audited like any grant; (4) auto-membership is a fixed property of exactly one seeded role — there is no UI to mark arbitrary roles auto_all, so the blast radius cannot spread.Everyone could be deleted, renamed, or have auto_all cleared, the "reaches all users" contract would break silently and existing grants would change meaning. Mitigation: the role is protected server-side — delete/rename/flag-clear on it return HTTP 409; grants on it stay editable.Accepted trade-offs
user_roles row". Accepted for the quick-start payoff; contained to exactly one seeded role.Everyone. A future dynamic-group feature (rule-based membership) is a separate, larger design, not opened here.ADMIN/END_USER system-role enum (F-19) already carries that axis.Everyone role to docs/prd.md (BR + F-ID) and a Gherkin acceptance scenario ("grant to Everyone → new user reaches it").