# PERMISSIONS.md Permission reference for `autonomous.contact`. This document was built by crawling the codebase for: - default permission assignment in [public/api/users/index.ts](public/api/users/index.ts) - server-side permission checks in [public/api/](public/api) - frontend permission gates in [public/tabs/](public/tabs) and related UI files ## Sources of truth Current default permission sets are defined in [public/api/users/index.ts](public/api/users/index.ts#L14-L58). - `DEFAULT_USER_PERMISSIONS` are assigned to normal users during signup. - `DEFAULT_SUPERUSER_PERMISSIONS` are assigned to the first/bootstrap user. ## How permissions work There are two layers of access control in this codebase: 1. **Global permission strings** stored on the user record. 2. **Object-level ACLs** stored inside resources, especially channel `permissions.read`, `permissions.write`, `permissions.events.read`, and `permissions.events.write`. Important consequence: a user may have a global permission and still be blocked by a channel-level ACL. ## Generic permission families These are not stored as standalone permissions, but the server checks for these prefixes: - `events.create.*` via [public/api/events/index.ts](public/api/events/index.ts#L188) and [utils/prechecks.ts](utils/prechecks.ts#L47-L48) - `events.write.*` via [public/api/events/:event_id/index.ts](public/api/events/:event_id/index.ts#L34-L35), [public/api/events/:event_id/index.ts](public/api/events/:event_id/index.ts#L117-L118), and [utils/prechecks.ts](utils/prechecks.ts#L50-L51) ## Permissions bible | Permission | Default user | Bootstrap superuser | Purpose | Where checked | Notes | | --- | --- | --- | --- | --- | --- | | `channels.read` | yes | yes | Allows listing channels. | [public/api/channels/index.ts](public/api/channels/index.ts#L12) | Channel detail reads also require channel ACL membership; this permission gates the channel list endpoint only. | | `channels.create` | no | yes | Allows creating channels. | [public/api/channels/index.ts](public/api/channels/index.ts#L31), [public/tabs/chat/channel_sidebar.html](public/tabs/chat/channel_sidebar.html#L189) | Fully wired. | | `channels.delete` | no | yes | Intended to allow channel deletion. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L51) | **No direct server-side check found.** Channel deletion currently uses `channel.permissions.write` membership instead of this string. See [public/api/channels/:channel_id/index.ts](public/api/channels/:channel_id/index.ts#L98-L100). | | `channels.write` | no | yes | Intended to allow channel updates. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L52) | **No direct server-side check found.** Channel updates currently use `channel.permissions.write` membership instead of this string. See [public/api/channels/:channel_id/index.ts](public/api/channels/:channel_id/index.ts#L45-L47). | | `events.create.blurb` | yes | yes | Allows creating `blurb` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48), [public/tabs/blurbs/new_blurb.html](public/tabs/blurbs/new_blurb.html#L28) | Matches server behavior. | | `events.create.chat` | yes | yes | Allows creating `chat` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48) | **UI mismatch:** chat composer is gated by `events.write.chat`, not `events.create.chat`. See [public/tabs/chat/chat.html](public/tabs/chat/chat.html#L151). | | `events.create.essay` | yes | yes | Allows creating `essay` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48), [public/tabs/essays/new_essay.html](public/tabs/essays/new_essay.html#L25) | Matches server behavior. | | `events.create.post` | yes | yes | Allows creating `post` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48), [public/tabs/forum/new_post.html](public/tabs/forum/new_post.html#L9) | Matches server behavior. | | `events.create.presence` | yes | yes | Intended to allow creating `presence` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48) | No dedicated UI or route-specific feature found beyond generic event creation. | | `events.read.blurb` | yes | yes | Intended to allow viewing blurbs. | [public/tabs/blurbs/blurbs.html](public/tabs/blurbs/blurbs.html#L150) | **Frontend-only gate found.** No matching server-side event-read check by permission string was found. | | `events.read.chat` | yes | yes | Intended to allow viewing chat. | [public/tabs/chat/chat.html](public/tabs/chat/chat.html#L23) | **Frontend-only gate found.** Server reads rely on authentication and channel ACLs, not this string. | | `events.read.essay` | yes | yes | Intended to allow viewing essays. | [public/tabs/essays/essays.html](public/tabs/essays/essays.html#L126) | **Frontend-only gate found.** | | `events.read.post` | yes | yes | Intended to allow viewing posts. | [public/tabs/forum/forum.html](public/tabs/forum/forum.html#L181) | **Frontend-only gate found.** | | `events.read.presence` | yes | yes | Intended to allow viewing presence events. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L27) | **No active check found** beyond the default assignment. | | `events.write.blurb` | yes | yes | Allows updating/deleting `blurb` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | Used by generic event update/delete endpoints. | | `events.write.chat` | yes | yes | Allows updating/deleting `chat` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51), [public/tabs/chat/chat.html](public/tabs/chat/chat.html#L151) | Also used by the chat composer UI, which appears to be stricter/different than server-side create rules. | | `events.write.essay` | yes | yes | Allows updating/deleting `essay` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | No dedicated UI gate found. | | `events.write.post` | yes | yes | Allows updating/deleting `post` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | No dedicated UI gate found. | | `events.write.presence` | yes | yes | Intended to allow updating/deleting `presence` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | No dedicated UI or route-specific usage found beyond generic event mutation logic. | | `files.write.own` | yes | yes | Allows uploads only inside the current user's home path under `/files/users//...`. | [public/_pre.ts](public/_pre.ts#L12-L20) | Fully wired. | | `files.write.all` | no | yes | Allows uploads anywhere under `/files/...`. | [public/_pre.ts](public/_pre.ts#L13-L20), [tests/11_file_uploads.test.ts](tests/11_file_uploads.test.ts#L165) | Fully wired. | | `invites.create` | yes | yes | Allows creating invite codes. | [public/api/users/:user_id/invites/index.ts](public/api/users/:user_id/invites/index.ts#L73) | Fully wired. | | `invites.read.own` | yes | yes | Allows reading invites for the path user when it is self. | [public/api/users/:user_id/invites/index.ts](public/api/users/:user_id/invites/index.ts#L17-L20) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | | `invites.read.all` | no | yes | Allows reading invites across users. | [public/api/users/:user_id/invites/index.ts](public/api/users/:user_id/invites/index.ts#L18-L20) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | | `self.read` | yes | yes | Allows reading the current authenticated user's own profile. | [public/api/users/me/index.ts](public/api/users/me/index.ts#L8), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L13-L17) | Fully wired. | | `self.write` | yes | yes | Allows updating/deleting the current user's own profile. | [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L44-L48), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L109-L113) | Fully wired. | | `signups.read.own` | yes | yes | Allows reading signups for the path user when it is self. | [public/api/users/:user_id/signups/index.ts](public/api/users/:user_id/signups/index.ts#L13-L16) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | | `signups.read.all` | no | yes | Allows reading signups across users. | [public/api/users/:user_id/signups/index.ts](public/api/users/:user_id/signups/index.ts#L14-L16) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | | `users.read` | yes | yes | Allows reading/searching other users. | [public/api/users/index.ts](public/api/users/index.ts#L67), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L14-L17) | Fully wired. | | `users.write` | no | yes | Allows updating/deleting other users and editing permissions. | [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L45), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L81), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L110) | Fully wired. | | `watches.create.own` | yes | yes | Allows creating watches for self. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L80-L83) | Fully wired. | | `watches.create.all` | no | no | Allows creating watches for other users. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L81-L83) | **Referenced but not granted by either default permission set.** Must be assigned manually if needed. | | `watches.read.own` | yes | yes | Allows reading watches for self. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L15-L18) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | | `watches.read.all` | no | yes | Allows reading watches across users. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L16-L18) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | | `watches.write.own` | yes | yes | Intended to allow updating/deleting own watches. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L44) | **No direct permission check found.** Watch update/delete currently use ownership only. See [public/api/users/:user_id/watches/:watch_id/index.ts](public/api/users/:user_id/watches/:watch_id/index.ts#L20-L22) and [public/api/users/:user_id/watches/:watch_id/index.ts](public/api/users/:user_id/watches/:watch_id/index.ts#L73-L75). | | `watches.write.all` | no | yes | Intended to allow updating/deleting others' watches. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L58) | **No direct permission check found.** Watch update/delete currently use ownership only. | ## Summary: default permissions vs actual code ### Normal-user defaults that are clearly used These are present in `DEFAULT_USER_PERMISSIONS` and have matching checks in code: - `channels.read` - `events.create.blurb` - `events.create.chat` - `events.create.essay` - `events.create.post` - `events.create.presence` - `events.write.blurb` - `events.write.chat` - `events.write.essay` - `events.write.post` - `events.write.presence` - `files.write.own` - `invites.create` - `invites.read.own` - `self.read` - `self.write` - `signups.read.own` - `users.read` - `watches.create.own` - `watches.read.own` ### Defaults that are only partially matched or frontend-only - `events.read.blurb` - `events.read.chat` - `events.read.essay` - `events.read.post` - `events.read.presence` - `watches.write.own` ### Bootstrap/superuser defaults that are present but not fully wired as permission strings - `channels.delete` - `channels.write` - `watches.write.all` ### Referenced in code but not granted by default - `watches.create.all` ## Biggest mismatches to know about 1. **Channel update/delete do not use `channels.write` or `channels.delete`.** They use per-channel ACL membership instead. See [public/api/channels/:channel_id/index.ts](public/api/channels/:channel_id/index.ts). 2. **Watch update/delete do not use `watches.write.own` or `watches.write.all`.** They use ownership checks only. See [public/api/users/:user_id/watches/:watch_id/index.ts](public/api/users/:user_id/watches/:watch_id/index.ts). 3. **`events.read.*` permissions are mostly UI gates, not server-enforced authorization.** The event read endpoints do not generally check these strings. 4. **Chat creation UI uses `events.write.chat`, but the server requires `events.create.chat` for POST.** This is the clearest create-vs-write mismatch in the current code. 5. **`watches.create.all` exists in code but is missing from both default sets.** ## Recommendation If the goal is to make permissions predictable, the cleanest next step would be to choose one of these approaches: 1. remove unused permission strings from defaults, or 2. add explicit checks so every documented permission is actually authoritative The most important cleanup targets are: - `channels.write` - `channels.delete` - `watches.write.own` - `watches.write.all` - the `events.read.*` family - the chat UI mismatch between `events.create.chat` and `events.write.chat`