Skip to content

Instantly share code, notes, and snippets.

@ajoslin
Created August 26, 2026 05:24
Show Gist options
  • Select an option

  • Save ajoslin/4ea9cb7ef85b156db800a6cc40794427 to your computer and use it in GitHub Desktop.

Select an option

Save ajoslin/4ea9cb7ef85b156db800a6cc40794427 to your computer and use it in GitHub Desktop.
Boja permission-shaped state and gate manifest

Boja permission-shaped state and gate manifest

Scope: repository state or decisions that admit, deny, hide, narrow, revoke, or expose a user operation or row. Transport-only integrity checks are included when token/session possession is the gate; ordinary workflow booleans such as isRead, job leases, and UI expansion state are excluded. “Authoritative” means the server or PostgreSQL path enforces the decision. “Advisory” means client projection, navigation, or tool exposure is rechecked elsewhere. This is an inventory of the current model, not a proposed replacement.

Manifest

name layer (platform/server/membership/grant/channel/audience) type who writes who reads what it actually gates file:line
users.account_status platform persisted enum: active, disabled, banned Account lifecycle/support execution; GDPR execution sets disabled; fixtures and migrations seed it Channel/server calculators, auth/read models, notifications, media, search, moderation Non-active accounts lose effective membership/channel authority and are omitted from recipient/read projections database/Schema.ts:378-399; database/SettingsAuthority.ts:18-61; core/permissions/calculateChannelPermissions.ts:217-228; core/permissions/calculateServerPermissions.ts:49-60
users.is_staff platform persisted boolean, default false No production writer found; creation uses the default; tests/fixtures set it directly Permission calculators, moderation, profile visibility, media/conference/Cell and agent paths Platform-wide privileged role: bypasses channel audiences and moderation grants and qualifies for server management, but not account, membership, timeout, ancestry, or lifecycle hard clamps database/Schema.ts:378-399; core/permissions/calculateChannelPermissions.ts:239-263; core/permissions/calculateServerPermissions.ts:55-73; database/ProfileAuthority.ts:158-197
Better Auth emailVerified platform persisted boolean Better Auth verification flows; GDPR deletion resets it false No Boja production authority reader found Currently gates no Boja operation beyond Better Auth’s own authentication lifecycle database/Schema.ts:275-291; database/SettingsAuthority.ts:45-55
Profile is_profile_private, is_deleted platform persisted booleans Archive finalization/GDPR writes deletion state; no production privacy-toggle writer found ProfileAuthority, Zero profile predicates, search/presence name visibility Self bypasses privacy but not lifecycle; others require active/nondeleted profile and a shared live server. Staff/shared admin may bypass privacy, never lifecycle or blocks database/Schema.ts:419-468; database/SettingsAuthority.ts:18-61,73-116; core/profilePolicy.ts:1-31; database/ProfileAuthority.ts:111-198
Account archive pending_delete_at / recovery_until platform persisted timestamp plus append-only archive_requested, archive_canceled, archive_finalized lifecycle Fresh-session archive/cancel routes; one-minute expiry worker and GDPR finalize Session identity, profile/DM eligibility and finalizer Setting pending_delete_at immediately hides the profile, denies new DM/profile interaction, revokes sessions and makes ordinary session identity unavailable. Cancellation is allowed only during the 30-day recovery window; expiry finalizes deletion core/accountLifecycle.ts:1-19; database/Schema.ts:488-506; server/src/Auth.ts:418-458,642-778; database/SettingsAuthority.ts:73-116; worker/src/accountArchiveWorker.ts:9-33; database/ChannelAuthorization.ts:673-694
Custom status cleared_at, expires_at audience persisted nullable timestamps plus derived visibility Authenticated versioned profile status writer; five-minute expiry worker clears expired rows Profile/status projections call visibleStatus Hides a cleared status or one whose expiry is at or before the reader’s clock; it does not affect profile or channel authority database/Schema.ts:518-543; database/ProfileAuthority.ts:266-313,330-440; core/profilePolicy.ts:34-47; worker/src/statusExpiryWorker.ts:7-31
user_profiles.is_bot platform persisted boolean, default false Profile/account provisioning; no ordinary user writer found Platform support admission Excludes bot identities from platform-operator support access even if another grant/session row exists; no channel permission effect database/Schema.ts:419-468; server/src/supportAccess.ts:518-550
user_blocks platform directional pair; mutual visibility denial is derived Authenticated Zero profile block/unblock mutators Profile authority, Zero profile predicates, presence/search projections Either direction hides the other profile and retracts presence; self-block is schema-forbidden database/Schema.ts:401-416; server/src/profile.ts:81-111; database/ProfileAuthority.ts:141-197; core/zeroQueryVisibility.ts:144-170
Better Auth / Zero session validity platform signed bearer claims plus matching unexpired session Better Auth creates/revokes sessions; Zero token minting signs sub/sid Zero query and mutation wrappers A valid bearer and live matching session are prerequisites for every Zero query/mutation; mutation additionally requires a server transaction server/src/Zero.ts:362-415,916-941,963-980
Browser origin gate platform configured trusted-origin set; local HTTP loopback expansion only in development/test Deployment configuration and request origin CORS and Better Auth handler Credentialed browser requests are exposed only to the configured web origin; state-changing Better Auth requests carrying an untrusted Origin receive 403. Preview/production never derive trust from the request server/src/appMiddleware.ts:5-17; server/src/Auth.ts:214-224,288-305; server/src/authFrontendOrigin.ts:14-69
Fresh-session proof platform session age threshold Better Auth session creation time Account archive/cancel and other reauthentication-sensitive auth operations Rejects a privileged account-lifecycle operation when the session is older than ten minutes server/src/Auth.ts:622-648,743-766
platform_operator_grants: role/status/expiry/revocation platform persisted support_agent or ops_admin, lifecycle fields Manually provisioned platform-internal process; never tenant-owned supportAccess.admit, support authority calculator Admits platform support only for an active, nonexpired, nonrevoked grant attached to an active human account database/Schema.ts:3482-3522; server/src/supportAccess.ts:486-568
Better Auth MFA enrollment/verification platform twoFactorEnabled, verified factor row and operator mfa_enrolled_at Better Auth second-factor setup/verification; verification hook stamps operator enrollment Operator-session provisioning and support admission All three must be present before a platform operator counts as MFA-verified; ordinary tenant permissions do not consume them database/Schema.ts:275-291,354-369,3482-3522; server/src/Auth.ts:328-381; server/src/supportAccess.ts:486-508
platform_operator_sessions: MFA/step-up/expiry/revocation platform session-bound timestamps and revocation Better Auth second-factor verification hook provisions/refreshes proof supportAccess.admit, support.calculateAuthority Requires verified MFA and an active operator session; sensitive operations additionally require a fresh 15-minute step-up database/Schema.ts:3525-3551; server/src/Auth.ts:341-407; server/src/supportAccess.ts:486-568; core/support.ts:53-61,218-273
Support operation requirements platform derived booleans stepUp, opsAdmin per operation Static policy function Every support action admission Discovery needs only an operator role; refund/comp/session revocation need step-up; reveal/approve/reject/GDPR execution also need ops_admin core/support.ts:194-259; server/src/supportAccess.ts:565-587
Support approval_required and no-self-approval platform persisted boolean plus action-state machine actionNeedsApproval on refund currency/amount and comp days; request/decision writers transition state Support action execution/approval paths Large/non-USD refunds and more than 14 comp days require a second operator; requester cannot approve own action; expired approval cannot execute core/support.ts:19-21,275-293; server/src/createSupportActionOperations.ts:192-256,391-456,609-685; database/Schema.ts:3676-3755
Support GDPR legal_hold platform persisted boolean coupled to held status No production writer found; tests/external provisioning can set it Approved GDPR execution A held privacy request cannot execute deletion and transitions to held; the schema requires held state while true and executed state only while false database/Schema.ts:3818-3852; server/src/applySupportDatabaseAction.ts:32-110
Support email-delivery legal_hold platform persisted boolean, default false No production writer found Hourly retention sweep and support evidence read Preserves an expired support login-code/claim-link delivery row past retain_until; it does not authorize delivery or target access database/Schema.ts:3855-3895; database/db/20260818000000_boj_178_unified_channels/migration.sql:3355-3363; database/SupportRetention.ts:8-21; worker/src/supportRetentionWorker.ts:9-33
Audit-event legal_hold platform persisted boolean, default false No production writer found No production retention reader found Currently gates nothing; retain_until has a two-year minimum but no audit purge path consumes this hold database/Schema.ts:3399-3479
support_comp_grants grant append-only days and resulting subscription period Approved support comp execution Support evidence/relations; subscription period is the operational effect Records a granted 1–365-day extension after support role, step-up, approval, and no-self-approval gates; the row is evidence, not reusable actor authority database/Schema.ts:3793-3815; server/src/applySupportDatabaseAction.ts:171-202
servers.platform_tier platform persisted enum: validate, creator, scale, operator Owner-authorized tier management; schema default is validate Billing projections and tier gates Selects pricing/usage bands and feature capability values; owner command currently accepts only validate/creator database/Schema.ts:586-605; database/OwnerBillingManagement.ts:159-199; server/src/OwnerBillingManagement.ts:68-80; core/billing.ts:257-303
Platform plan billing_state platform append-only active or winding_down event Active owner billing path cancels/resumes plan Owner billing tier changes, billing read model/UI Winding down blocks tier changes and projects closure/payout-hold state; it is separate from server lifecycle database/Schema.ts:869-902; database/OwnerBillingManagement.ts:114-243; server/src/BillingReadModels.ts:448-495
kyc_states.status grant persisted none, pending, verified, rejected No production writer found No production reader found Currently gates neither commerce nor payout; payout management never joins KYC database/Schema.ts:905-927; database/OwnerBillingManagement.ts:244-378
tierCapabilities.canCoupons platform static boolean by tier Core billing table Coupon creation service Authoritatively rejects coupon creation below Creator; coupon deactivation is not tier-gated core/billing.ts:257-303; server/src/ConsoleAffiliates.ts:130-155
broadcastMonthlyLimit platform static numeric limit by tier Core billing table Authoritative announcement recorder and console projection Rejects a console announcement after the tier’s UTC-month quota is reached; records usage before transport, which is currently unconfigured core/billing.ts:257-303; database/EmailManagement.ts:293-363
tierCapabilities.canNativeLive platform static boolean; web advisory, server duplicates tier list Core billing table; server reads platformTier directly Channel header and conference go-live command UI disables native-live controls on Validate; server independently admits only creator/scale/operator rather than consuming this boolean core/billing.ts:257-303; webapp/src/components/chat/ChannelHeader.tsx:89-99,303-325; database/Conference.ts:1222-1235
canCustomDomain, canAutomation, canAdvancedAnalytics platform static booleans by tier Core billing table No production consumers found Currently gate nothing core/billing.ts:257-303
videoStoredMinutes, mauAllowance, aiActions platform static numeric tier limits Core billing table Console usage projection Display usage bands/meters; no operation-level rejection was found core/billing.ts:257-303; core/consoleUsage.ts:1-40; server/src/ConsoleCommerce.ts:53-130
validatedGmvCapMinor / tierCheckoutOutcome platform monetary limit and derived outcome Core billing policy over GMV/refund facts Checkout/console projections Intended to pause new Validate memberships at the cap; no production checkout mutation enforcement was found core/billing.ts:188-189,327-343; database/ProductManagement.ts:411-423; server/src/ConsoleReadModels.ts:540-544
Capability manifest platform static bounded names: server.manage, channel.view, channel.manage, message.send, message.moderate, thread.create, course.view, course.manage, stream.join, stream.start, server.billing.manage Source declaration only Permission route, SDK/agent runtime, mobile display Defines the maximum capability vocabulary; declaration alone grants nothing and is separate from channel/server calculators core/permissions/capabilityManifest.ts:3-25; server/src/permissionRoutes.ts:5-8; server/src/AgentConversations.ts:504-546
SDK method capability metadata platform Capability or undefined per read/mutation SDK manifest and mutation contract maps Agent allowed-method/tool runtime Exposes a method only when its method, lens, and capability are present; final DB mutation authority is rechecked separately sdk/manifest.ts:24-38,78-154,191-271; sdk/mutationContracts.ts:154-169; server/src/manifestToTools.ts:23-75,79-124
SDK entity lenses / conversation entity_lens audience owner or member; persisted conversation lens Manifest declares accepted lenses; DB derives and stores current lens at conversation creation/load Agent conversation listing, runtime methods, approval intent checks Only the conversation owner with active membership may use it; stale owner/member lens is rejected and channel conversations also require current View sdk/manifest.ts:112-154,191-271; database/Schema.ts:4642-4663; database/AgentConversations.ts:1341-1348,1610-1691,1923-2037
Diagnostic MCP tool allowlist platform static 11-name read-only registry with authority labels Monitor source declaration Repository MCP tool listing/execution Exposes only enumerated production diagnostic operations; the current MCP implementation executes only axiom_query and rejects names outside its registry. External bearer/service-account credentials remain the actual provider authority monitor/src/mcpPolicy.ts:3-37; scripts/boja-mcp.ts:1-95; monitor/src/axiomQuery.ts:47-61; monitor/src/productionMonitor.ts:170-203
Deployment operator allowlists platform configured email allowlists and read-only Kubernetes RBAC/token Deployment configuration and operator script Cloudflare Access and Kubernetes API Admits named operators to preview or K3s dashboard surfaces for 24h or 12h sessions; Headlamp gets get/list/watch and the helper mints a 15-minute viewer token. This is infrastructure access, not tenant authority deployment/src/resources/k3sDashboardEdge.ts:19-60,82-128; deployment/src/resources/k3sVisibility.ts:45-145; scripts/k3s-dashboard:6-9
servers.owner_user_id / derived membership isOwner server nullable FK; calculator boolean derived by equality Account/server provisioning and community creation; no transfer writer found Permission calculators, moderation/hierarchy, billing and agent paths Grants privileged channel authority and server manage; owner/staff, not admin alone, may manage lifecycle database/Schema.ts:560-606; database/provisionAccount.ts:88-115; database/ChannelAuthorization.ts:166-205,299-320; core/permissions/calculateServerPermissions.ts:57-73
servers.lifecycle_state server persisted enum: active, winding_down, read_only, archived Server lifecycle service; channel lifecycle service writes channel state separately Channel/server calculators, agent/read paths Winding down removes destructive management; read-only/archived remove ordinary management and writes while preserving owner/staff lifecycle authority database/Schema.ts:586-605; database/ServerLifecycle.ts:140-199; core/permissions/calculateChannelPermissions.ts:300-321; core/permissions/calculateServerPermissions.ts:61-73
servers.is_deleted, servers.is_suspended server persisted booleans Platform/server lifecycle processes; ordinary tenant management does not write them Authorization projections, Zero visibility, onboarding/profile/search Makes the server unavailable before calculator input or row visibility; no role bypasses it database/Schema.ts:579-584; database/ChannelAuthorization.ts:164-205; core/zeroQueryVisibility.ts:13-23; database/ProfileAuthority.ts:119-140
servers.is_public server persisted boolean, default false ServerManagement.updateSettings under server manage Console projection/UI Authoring flag says whether anyone can find the community in Discover; no production discovery reader was found database/Schema.ts:560-571; database/ServerManagement.ts:84-123; webapp/src/features/console/ConsoleDialog.tsx:924-925,1110-1114
channels.is_private channel persisted boolean, default false No production writer found No production reader found outside schema/fixtures Currently gates nothing; community access is audience-based and participant-channel privacy is participant-row based database/Schema.ts:1060-1087; core/zero-schema/zeroSchemaServers.ts:39-52
servers.affiliate_earnings_as_plan_credit server persisted boolean, default false Owner-authorized affiliate management command Affiliate read model Selects whether Boja affiliate earnings are presented/settled as plan credit; no channel, membership, or referral-admission authority effect database/Schema.ts:560-579; database/AffiliateManagement.ts:526-540,788-839
servers.rated server persisted boolean, default false ServerManagement.updateSettings under server manage Invite and checkout projections/UI Mature-content metadata is carried to invite/checkout surfaces; no repository admission/filter enforcement consumer was found database/Schema.ts:560-571; database/ServerManagement.ts:84-123; database/CommunityOnboarding.ts:790-831; database/ProductManagement.ts:398-423
servers.feature_flags server JSON object, default {} No production writer found No production reader found Currently gates nothing; architecture explicitly treats feature flags separately from permission/entitlement database/Schema.ts:582-592; docs/architecture/03-permissions.md:81-86
servers.authorization_epoch server persisted integer snapshot Authorization-changing server paths increment it Agent approval decision/execution rechecks Invalidates staged agent approval when server authorization changes database/Schema.ts:590-593; database/AgentConversations.ts:1106-1115,1269-1275,1411-1466
Server manage server derived PermissionDecision calculateServerPermissions Route authorization, server settings, channel creation, billing/read models Requires active account/membership, staff/owner/admin, and no active timeout; read-only/archived deny it core/permissions/calculateServerPermissions.ts:48-73; server/src/RouteAuthorization.ts:96-105; database/ServerManagement.ts:84-97; database/ChannelManagement.ts:777-791
Server manageDestructive server derived PermissionDecision calculateServerPermissions Channel archive/delete transitions and web prediction Same role prerequisite as manage, but denied in winding-down as well as read-only/archived core/permissions/calculateServerPermissions.ts:59-73; database/ChannelManagement.ts:540-568; webapp/src/features/permissions/useServerManagement.ts:39-74
Server manageLifecycle server derived PermissionDecision calculateServerPermissions Server lifecycle service and UI projection Only active, untimed-out owner or staff may change lifecycle; admin alone is denied; survives read-only/archived core/permissions/calculateServerPermissions.ts:61-73; database/ServerLifecycle.ts:140-147
server_memberships.status membership persisted enum: active, suspended, banned, left; core maps non-active to suspended Onboarding/invite and member management; ban/unban/cancel change it Nearly all server/channel authorities and recipient projections Active is prerequisite for server/channel authority; non-active states deny and are omitted from recipient/admission projections database/Schema.ts:1012-1039; database/MemberManagement.ts:395-444,788-818; database/CommunityOnboarding.ts:922-1000; core/permissions/calculateChannelPermissions.ts:225-228
server_memberships.is_admin membership persisted boolean, default false Account/bootstrap provisioning inserts it; no production promotion/demotion writer found Calculators, moderation, hierarchy, conference/Cell Server-local privileged role: bypasses audiences/mod grants and gets manage, but not manageLifecycle; timeout/status/lifecycle still constrain it database/Schema.ts:1012-1039; database/provisionAccount.ts:69-115; core/permissions/calculateChannelPermissions.ts:239-263; core/permissions/calculateServerPermissions.ts:57-73
server_memberships.timeout_until membership nullable timestamp; active exactly while timeoutUntil > now Moderation timeout/lift-timeout path Channel/server calculators, moderation, conference/Cell Only View survives an active timeout; all server management and other channel actions are denied database/Schema.ts:1021-1026; database/Moderation.ts:1370-1468; core/permissions/calculateChannelPermissions.ts:294-298; core/permissions/calculateServerPermissions.ts:59-60
server_memberships.can_rejoin membership persisted boolean, default true Ban/cancel set it; unban restores it Community invite/redemption eligibility Controls whether a former member may re-enter; does not itself authorize current channel access database/Schema.ts:1021-1027; database/MemberManagement.ts:395-444,459-515,788-818; database/CommunityOnboarding.ts:922-958
Server invite token lifecycle membership hashed credential plus active/revoked, intended email, expiry, max_uses/use_count Server manager issues/revokes; redemption increments count Invite preview/redemption Authoritatively creates active membership only for a matching high-entropy token, active available server/account, eligible former member, capacity, expiry, and intended email; failures collapse to non-enumerating outcomes database/Schema.ts:802-862; database/CommunityOnboarding.ts:680-850,851-1043
Entitlement validity: is_active, validity window, revoked_at grant persisted booleans/timestamps plus Zero validity projection Subscription/purchase/admin/reward flows; product deletion and ban revoke; validity worker updates sync projection Channel audience calculator/Zero visibility and media playback Product atoms count only while active, in validFrom <= now < validUntil, and unrevoked; product/channel/media access disappears on revocation database/Schema.ts:4202-4248; core/permissions/calculateChannelPermissions.ts:230-238; core/zeroQueryVisibility.ts:38-49; server/src/MediaProgress.ts:109-157
Billing subscription status and pause/cancel windows grant persisted active, past_due, grace, canceled, ended plus period/pause/cancel timestamps Member billing and console member-management paths Product/member projections, email recipients, agent subscription lens Shapes active/canceling/paused membership commerce state and recipient eligibility; channel access is enforced through membership and entitlements rather than this status directly database/Schema.ts:3352-3404; database/MemberBillingManagement.ts:43-76,198-257; database/ProductManagement.ts:148-186,325-330; database/EmailManagement.ts:108-131
Payment method is_active, is_default grant persisted booleans with one-active-default uniqueness Member billing add/remove/default commands Membership resume, media checkout, billing read/UI Only active methods are selectable; resume requires an active method and media checkout charges the active default. Removing a default can require promoting another method first database/Schema.ts:2977-3000; database/MemberBillingManagement.ts:146-193,269-363,364-455; database/MediaCommerce.ts:270-288
Payout destination active grant persisted boolean with one-active-per-server uniqueness Owner payout destination/method commands Owner billing read model and payout configuration Selects the server’s current destination and speed; setting one deactivates the others. No verified-KYC prerequisite is enforced database/Schema.ts:3129-3168; database/OwnerBillingManagement.ts:244-378; server/src/BillingReadModels.ts:420-440
Media purchase grant durable item/rail purchase row Media checkout after membership, target, price, ledger and payment checks Playback/progress and library projection Unlocks its item or rail independently of product entitlement database/Schema.ts:2572-2610; database/MediaCommerce.ts:119-231,334-365; server/src/MediaProgress.ts:93-106
Media access mode and product atoms grant rail all or products, optional item override, product join rows Owner-authorized media management validates active products and rewrites access Playback/progress and library projection Item access overrides rail access; all admits active members, while products requires purchase or matching valid entitlement database/Schema.ts:2383-2489; database/MediaManagement.ts:568-610; server/src/MediaProgress.ts:74-157; core/mediaDerivations.ts:85-107
products.is_active grant persisted boolean Product lifecycle; deletion sets false and revokes matching entitlements Audience/media configuration and active product projections Inactive products cannot be newly selected for audience/media access; deletion removes entitlement-based access database/Schema.ts:2615-2618; database/ProductManagement.ts:518-521,600-633; database/ChannelManagement.ts:272-275,357-359; database/MediaManagement.ts:193-211
products.checkout_enabled grant persisted boolean Owner-authorized product create/update/toggle; deletion forces false Console/public-checkout projections Controls sellable presentation; does not revoke existing entitlement. A public checkout server enforcement consumer was not located database/Schema.ts:2615-2618; database/ProductManagement.ts:307-309,648-685,762-847; webapp/src/features/console/CheckoutPreview.tsx:19-22
products.cap grant nullable positive integer Owner product create/update Checkout/read-model UI Computes remaining seats and disables sold-out selection in web checkout preview; no server checkout mutation cap enforcement was found database/Schema.ts:2605-2624; database/ProductManagement.ts:386-399,761-847; webapp/src/features/console/CheckoutPreview.tsx:199-238
plans.is_active grant persisted boolean, default true Product/plan lifecycle Checkout/read-model selection and plan updates Only active plans are selected or updated as the current sellable plan; no separate channel/media authority effect database/Schema.ts:2792-2811; database/ProductManagement.ts:296-299,761-835
Affiliate program enabled, mode, invitation, accepted terms grant persisted boolean/enum plus invitation and acceptance rows Owner-authorized affiliate configuration/invite; member terms acceptance Referral/link issuance and attribution Actor needs active membership; disabled program denies; invited mode additionally requires invite; attribution requires affiliate terms acceptance and forbids self-referral database/Schema.ts:2814-2875; database/AffiliateManagement.ts:93-125,178-225,328-360
Coupon active, ends_at, max_redemptions grant persisted boolean/timestamp/nullable cap Owner coupon create/deactivate; redemption flow appends uses Checkout/read models and coupon binding Active is checked when binding a referral coupon; checkout projection treats inactive, expired, or capped coupons as unavailable. Full ends/cap enforcement at a public checkout mutation was not found database/Schema.ts:2897-2939,3093-3135; database/AffiliateManagement.ts:183-199,369-474; database/ProductManagement.ts:416-448
member_mod_grants.capability grant persisted enum: moderate, delete, timeout, ban Console member promote/set-capability/demote service ChannelAuthorization, Moderation, hierarchy, agent tool projection Four independent delegated actions; capability row does not create server admin/staff authority database/Schema.ts:2707-2738; database/MemberManagement.ts:517-539,618-648,731-787; database/ChannelAuthorization.ts:90-104
member_mod_grants.granted grant persisted boolean, default false Promote writes only moderate=true; capability command toggles delete/timeout/ban; demote deletes all rows Calculator, moderation/hierarchy, console projection Effective on/off switch; a stored false row does not authorize database/Schema.ts:2719; database/MemberManagement.ts:623-640,731-778; core/permissions/calculateChannelPermissions.ts:247-255
member_mod_grants.max_duration_seconds grant nullable positive integer No production writer found; production promote/toggle omit it; fixtures set it Moderation action loader/executor Caps delegated timeout duration; owner/staff/admin are treated as unbounded database/Schema.ts:2720-2733; database/Moderation.ts:211-268,890-968,1385-1402
member_mod_grants.max_message_age_seconds grant nullable positive integer No production writer found; production promote/toggle omit it; fixtures set it Moderation queue/action/executor Caps age of messages a delegated deleter may remove/redact; owner/staff/admin are unbounded database/Schema.ts:2721-2738; database/Moderation.ts:156-201,936-951,1003-1009,1203-1251
Channel audiences audience one persisted everyone or products row for each of view, send, conf, attach, react, threadStart, threadReply Channel create/set-permissions replaces rows and product joins; Zero wrapper passes actor to DB service Channel calculator, Zero visibility, web prediction Nonprivileged action admission. products needs intersection with valid entitlements; missing/malformed rows deny core/permissions/audience.ts:3-35; database/Schema.ts:2627-2667; database/ChannelManagement.ts:269-343; core/permissions/calculateChannelPermissions.ts:230-275
channel_audience_products.product_id audience persisted product atoms Channel permission writer, after validating active products Authorization/Zero and denial projection Narrows an action to matching entitled products; empty products means staff/owner/admin-only, never Everyone database/Schema.ts:2651-2667; database/ChannelManagement.ts:288-327; core/zeroQueryVisibility.ts:34-53; docs/architecture/03-permissions.md:14-17,57-61
Channel presets: open, readonly, premium, staff audience authoring shorthand, never persisted Create/edit UI/mutator expands preset Audience editor and channel creation staff is all empty product audiences, not a role or audience kind; readonly leaves View/React open; premium selects the first product core/permissions/audience.ts:20-23,82-105; docs/architecture/03-permissions.md:14-17; database/Schema.ts:2627-2667
Day-7 email day7_flow_enabled server persisted nullable boolean constrained to the day7 template Server-manager console email command Console template read/UI only Advertises whether the day-7 member email flow is on, but no production sender/worker consumes it; currently gates no delivery database/Schema.ts:930-959; database/EmailManagement.ts:365-436; webapp/src/features/console/EmailsSection.tsx:68-91
Channel/thread lifecycle and deletion channel persisted active, winding_down, read_only, or archived plus deletion flags Channel management archive/restore/delete and thread lifecycle paths Calculator, Zero visibility, route/search/read paths Deleted targets are unavailable; archived rows are hidden by ordinary Zero reads; read-only/archived channel or thread preserves View but denies every other channel permission core/permissions/calculateChannelPermissions.ts:24,277-321; core/zeroQueryVisibility.ts:10-12,56,79-87; database/ChannelManagement.ts:540-591
Thread audiences audience optional persisted everyone/products for attach, react, threadReply Set-thread-audiences command rewrites rows/products Channel calculator and Zero/thread UI Overrides those three actions only; absent override inherits parent audience; parent View remains the ceiling core/permissions/calculateChannelPermissions.ts:22,277-292; database/Schema.ts:2669-2706; database/ChannelManagement.ts:1207-1229
Channel view channel derived PermissionDecision Calculator from audience/entitlements/privilege All channel reads, Zero row visibility, realtime/search/media/notifications Read ceiling for every other action. Staff/owner/admin bypass audience only; account/membership/server/channel hard clamps still apply core/permissions/calculateChannelPermissions.ts:217-246; core/zeroQueryVisibility.ts:4-89; server/src/RouteAuthorization.ts:52-73
Channel send channel derived decision Calculator from send audience; thread aliases threadReply Message send/typing/Cell publish and composer Creates messages/realtime publish; active timeout or read-only/archive removes it core/permissions/calculateChannelPermissions.ts:243-298,303-321; server/src/cells/CellAuth.ts:65-111; webapp/src/components/chat/Composer.tsx:304-329,573-609
Channel conf channel derived decision Calculator from conf audience; not applicable to threads Conference visibility/admission Requires ordinary View plus conf audience; threads are denied as action-not-applicable core/permissions/calculateChannelPermissions.ts:270-292; core/zeroQueryVisibility.ts:91-102; database/Conference.ts:111-127
Channel attach channel derived decision Calculator from attach or thread override Attachment/message edit/upload UI and server mutators Adds/edits attachments in the channel; client check is advisory and server authorization remains authoritative core/permissions/calculateChannelPermissions.ts:270-287; webapp/src/components/chat/MessageRow.tsx:193-197; server/src/Zero.ts:518-534
Channel react channel derived decision Calculator from react or thread override Reaction mutators/UI Adds/removes reactions; hard clamps can only narrow it core/permissions/calculateChannelPermissions.ts:270-287,294-321; webapp/src/components/chat/MessageRow.tsx:191-200
Channel threadStart channel derived decision Calculator from thread-start audience Thread creation UI/mutator Starts a thread from a non-thread channel; denied as not applicable inside a thread core/permissions/calculateChannelPermissions.ts:270-292; webapp/src/components/chat/MessageRow.tsx:191-200,354-391
Channel threadReply channel derived decision Calculator from channel or thread override Thread composer/realtime Sends a thread reply; on thread targets it is also the send decision core/permissions/calculateChannelPermissions.ts:277-292; webapp/src/components/chat/ThreadPanel.tsx:59-80,125-145
Channel editOwn, deleteOwn channel derived decisions Calculator maps own-message operations to send audience Message/attachment server authorization and UI Edit/delete actor’s own message; non-owner edit is null and non-owner delete falls through to moderation delete core/permissions/calculateChannelPermissions.ts:264-268; core/permissions/calculateMessagePermissions.ts:3-15; server/src/Zero.ts:483-516
Channel moderate grant derived decision Calculator from privilege or granted moderate row Queue/navigation, moderation action loading, agent moderation tool exposure Opens moderation surface and is prerequisite for action-specific delete/timeout/ban; not sufficient by itself for those actions core/permissions/calculateChannelPermissions.ts:247-255; database/Moderation.ts:823-889,890-914; server/src/AgentConversations.ts:164-234
Channel delete grant derived independent decision Calculator from privilege or granted delete row Message moderation loader/executor Deletes another member’s message only after moderate, hierarchy and message-age checks core/permissions/calculateChannelPermissions.ts:247-255; database/Moderation.ts:211-268,924-951,1203-1251
Channel timeout grant derived independent decision Calculator from privilege or granted timeout row Timeout/lift-timeout loader/executor Changes membership timeout only after moderate, hierarchy, target-state and max-duration checks core/permissions/calculateChannelPermissions.ts:247-255; database/Moderation.ts:924-951,1370-1468
Channel ban grant derived independent decision Calculator from privilege or granted ban row Ban/unban loader/executor Changes membership ban state only after moderate, hierarchy and target-state checks; only owner path may pair refund core/permissions/calculateChannelPermissions.ts:247-255; database/Moderation.ts:924-968; database/MemberManagement.ts:156-184,395-444
Channel manage channel derived decision Calculator from staff/owner/admin privilege Route authorization and channel setting/permission operations Non-destructive channel administration; server/channel read-only or archived states deny it core/permissions/calculateChannelPermissions.ts:258-263,300-321; server/src/RouteAuthorization.ts:75-94; database/ChannelManagement.ts:145-185
Channel manageDestructive channel derived decision Calculator from staff/owner/admin privilege Move/archive/delete and destructive moderation path Destructive channel changes; winding-down denies it before read-only/archive clamps core/permissions/calculateChannelPermissions.ts:261-263,300-321; database/ChannelManagement.ts:540-568,993-1008; database/Moderation.ts:674-678
Moderation hierarchy grant derived rank: staff > owner > admin > moderator > member DB derives role/granted-moderate facts Every moderation/member-management target check Actor cannot enforce against self or owner and must strictly outrank target; action capability is checked separately core/moderation.ts:98-124; database/decideMemberHierarchy.ts:16-31,52-90
Web channel/server permission prediction channel advisory recomputation of channel decisions and server manage family from synced Zero context Client derives from account, membership, audience, entitlement, grant, lifecycle, and a one-second clock Composer, realtime mode, message actions, sidebar and management controls Hides/disables controls and chooses publish versus subscribe; every mutation/token/API path rechecks authority server-side webapp/src/features/permissions/useChannelPermissions.ts:1-183; webapp/src/features/permissions/useServerManagement.ts:1-81; webapp/src/components/chat/Composer.tsx:304-317,573-609; webapp/src/components/shell/AppSidebar.tsx:36-80,189-249
Console member allowedActions membership projected array: ban, unban, refund, pause, resume, cancel Console read model derives hierarchy, membership, refund and subscription state Members console UI Shows only contextually plausible controls; DB member-management commands independently recheck server authority, hierarchy and state core/consoleMembers.ts:24-36; server/src/ConsoleReadModels.ts:749-820; webapp/src/features/console/MembersSection.tsx:288-368
Console moderatorCaps projection grant projected delete/timeout/ban booleans plus optimistic granted Read model derives stored grants; console writes through member-management API Moderation console checkboxes Displays/toggles grant rows; no Zero path exists and final capability use is rechecked by moderation services server/src/ConsoleReadModels.ts:812-820; webapp/src/features/console/ModerationSection.tsx:25-29,160-184; database/MemberManagement.ts:731-787
hasModerationAuthority grant derived async boolean; no stored writer Reporter-free scan of active memberships/roles/grants plus calculator Moderation navigation and queue load Availability only: true if any live channel has effective moderate; actual operation rechecks action grant, hierarchy, limits and target state database/Moderation.ts:822-889,970-978; server/src/Moderation.ts:56-60
Zero channel row visibility audience reactive ZQL predicate Derived from persisted account/server/membership/participant/audience/product/entitlement state Nearly all channel/message/thread/media/home queries and server visible-ID query Community visibility requires active account/member and owner/staff or audience entitlement; DMs require an active participant; threads require visible parent and live root core/zeroQueryVisibility.ts:4-89; core/zeroQueries.ts:261-307,539-576,755-789; server/src/Zero.ts:916-941
Participant-channel membership (role, left_at) membership persisted owner or member plus nullable departure DM/group/self creation and participant lifecycle Zero visibility, DM send/read, search and notifications Role identifies conversation owner but does not grant server privilege; only rows with no left_at admit participant-channel visibility or send/read operations database/Schema.ts:1135-1157; core/zeroQueryVisibility.ts:66-77,215-230; server/src/Zero.ts:684-720; server/src/dm.ts:134-148
Participant hidden_at / hidden_after_sort_id membership per-viewer nullable visibility cursor Authenticated DM hide/unhide Zero mutator Direct-message list and notification recipient filter Hides a conversation until a newer message appears and suppresses notification candidacy while hidden; does not revoke channel participation database/Schema.ts:1148-1151; server/src/dm.ts:286-321; webapp/src/features/direct-messages/directMessages.ts:54-60; database/Notifications.ts:165-196
Participant is_muted membership persisted boolean, default false DM creation writes false; no mutation/read consumer found No production consumer found Currently gates nothing database/Schema.ts:1135-1151; server/src/dm.ts:134-148
Zero profile visibility audience candidate predicate plus server-only mutual-block predicate Derived from profile/account/shared-membership/block state Profile/activity/presence/search queries Self is visible; others require active/nondeleted shared-server profile, privacy exception, and no block. Client IVM candidate cannot express the final NOT EXISTS block check core/zeroQueryVisibility.ts:104-185; database/ProfileAuthority.ts:111-198
Zero mutator operation authorization channel authenticated server-only wrapper plus per-operation DB decision Wrapper supplies actor; each DB service recalculates authority in the transaction All registered Zero mutators Client optimistic writes are advisory. Server verifies session/location and then View/send/ownership/manage/action permission before committing server/src/Zero.ts:362-386,436-516,657-720; core/zeroMutators.ts:11-28
Console member/grant path membership authenticated route plus transactional DB service Console routes call ConsoleMemberManagement; DB MemberManagement writes membership/grants Console only; no Zero grant/admin writer found Route wrapper proves signed-in identity only; DB service authoritatively checks server-manage/channel-ban authority and hierarchy before ban/refund/pause/cancel/promote/demote/capability writes server/src/consoleRoute.ts:17-67; server/src/ConsoleMemberManagement.ts:26-111; database/MemberManagement.ts:140-184,517-787
Channel-management Zero path channel authenticated Zero conductor into authoritative DB service Web/client invokes Zero; server passes actor to ChannelManagement Channel create/edit/move/archive/restore/delete/audience writers Unlike member grants, channel management is Zero-reachable; authoritative DB service uses server/channel manage or manageDestructive, revision and lifecycle checks server/src/channelManagement.ts:14-139; database/ChannelManagement.ts:145-185,540-568,777-791,993-1011
Route authorization channel 404-style view, channel-manager, server-manager, owner gates Derived on each request HTTP/API handlers View accepts community calculator or participant channel; manager uses channel/server manage; owner route requires active server ownership server/src/RouteAuthorization.ts:52-123
Conference admission/visibility channel authoritative View+Conf decision and participant revocation Conference/channel commands and authorization state Conference load/admit and Cell token mint Hidden/denied channel cannot admit; revoked participant cannot load; livestream marker additionally must be upcoming/live and unexpired database/Conference.ts:111-127,275-341,718-743
Conference role/moderation grant host/listener/participant/staff role plus enforced mute/revision Admission, host and moderation commands Conference provider/Cell/client Only current host may remotely mute; target must be admitted and cannot be the host; Cell token embeds derived role and enforced mute database/Conference.ts:342-379,395-457,718-743; server/src/cells/CellAuth.ts:156-238
Cell publish/subscribe/presence token channel signed operation-scoped token CellAuth after authoritative checks Celld realtime plane Channel publish requires send, subscribe requires view; presence subscribe requires profile visibility; conference token requires admitted call/membership authority server/src/cells/CellAuth.ts:65-154,156-238
CellD connection and ingress claims channel short-lived HMAC JWT with issuer, audience, time, subject/session, cell allowlist, mode; ingress adds exact scope and cell Server CellAuth/CellIngress; push worker mints presence-read ingress claims CellD WebSocket, roster, metrics and revoke ingress Possession is the realtime-plane gate: connection token must name the exact cell; internal token must match metrics:read, presence:read, or revoke and exact cell. CellD does not synchronously recheck Better Auth or PostgreSQL server/src/cells/CellAuth.ts:57-224; server/src/cells/CellIngress.ts:28-66; worker/src/pushLive.ts:91-116; cells/src/main.ts:39-65,184-290,509-601
CellD session/authorization revocation channel session id or monotonic epoch/revision carried in socket attachment and revoke projection Auth/session, channel/server lifecycle and conference paths publish revocations CellD closes stale sockets and applies newer conference authority/mute revisions Narrows token lifetime asynchronously: matching session or stale epoch sockets close; conference role/mute updates apply only when revision increases database/Schema.ts:1198-1258; cells/src/main.ts:66-81,612-636,791-893; cells/src/socketAttachment.ts:371-392; server/src/cells/CellIngress.ts:189-250
Attachment readability/cancellation channel compound channel/participant/emoji/owner and readiness gate Attachment, message, channel and emoji lifecycle; owner cancellation Download/URL/cancel endpoints Read requires view/participant, approved emoji, or unlinked ownership; cancel requires owner, nondeleted, unused attachment. Ingest download instead trusts an unexpired operation token server/src/files/Attachments.ts:280-380,383-431
message_revisions.is_restricted audience persisted boolean on historical evidence, default false No production writer sets true; moderation inserts ordinary redaction revisions Moderation redaction/evidence path Prevents already-restricted revision content from being selected/redacted again; currently reachable only through externally/fixture-provisioned true rows database/Schema.ts:2115-2135; database/Moderation.ts:506-539
attachments.legal_hold platform persisted boolean, default false No production writer found; tests set directly Moderation redaction cleanup A held attachment is excluded from detachment/deletion when messages are redacted; it does not itself grant attachment readability database/Schema.ts:2219-2273; database/Moderation.ts:568-593
Search ACL and reload channel visible-channel ID set plus final DB recheck Active membership/participant and ChannelAuthorization projections Meilisearch filtering/result assembly Empty ACL hard-denies; results are dropped after current nondeleted membership/participant/View recheck; hidden profile names are masked, not the hit server/src/SearchService.ts:137-150,238-307,309-421
Notification scope/recipient visibility audience channel/server scope authorization and recipient filter User scope setting; message notification projector Notification rows, unread and push jobs Scope write needs View or active server membership; recipients must remain active and authorized channel viewers/participants; actor excluded server/src/notifications.ts:113-171; database/Notifications.ts:75-224
Notification user/kind/scope preferences audience user booleans; per-kind enabled/sound; nearest-scope default, all, mentions, nothing Authenticated Zero setting mutators; scoped writes require View or active server membership Push preparation and web desktop delivery; home projection reads badge flag Suppresses delivery by kind/scope or while viewing, removes sound, and hides the home badge count. Preferences do not authorize notification source rows database/Schema.ts:4283-4359; core/notifications.ts:69-99,115-168; server/src/notifications.ts:101-211; database/Push.ts:319-398,579-585; webapp/src/features/home/useHomeProjection.ts:10-39
channel_read_states.notification_preference audience persisted default, all, mentions, nothing DM creation writes the default; no production update writer found No production delivery reader found Currently gates nothing. The live thread/channel notification UI writes separate notification_scope_settings, not this column database/Schema.ts:2187-2215; server/src/dm.ts:134-159,227-252; server/src/notifications.ts:142-211
Push source/subscription authorization audience final source recheck plus subscription permission_state, session and revocation fields Notification/message lifecycle, push registration, session reconciliation/provider failure Push preparation/delivery Suppresses inactive/self/deleted/stale/unauthorized sources; sends only through matching unexpired sessions and granted, nonrevoked subscriptions. Provider permission-denied changes the stored state to denied database/Schema.ts:4361-4407; database/Push.ts:275-330,578-614,981-1102,1160-1190
Media playback/progress access membership compound authoritative grant Media/product/purchase/entitlement/member writers Playback URL/progress recorder Requires active account/membership and live hosted item; admits staff/admin, all-access content, purchase, or current unrevoked entitlement server/src/MediaProgress.ts:42-167,141-211
Agent allowed tools/methods grant ephemeral method/capability sets Runtime derives from lens, privilege and current moderation grants Model tool exposure and per-call wrapper Advisory exposure only: privileged/mod-granted actor sees matching operations; DB staging/execution remains authoritative server/src/AgentConversations.ts:164-234,504-546; server/src/manifestToTools.ts:69-75,100-124
Agent approval authority snapshot server persisted actor/conversation/tool/status, authorization epoch, target/tool versions, expiry and canonical-args hash Approval-intent creation; decision/execution transitions Approval endpoint and execution claim Prevents actor/lens/membership changes, permission epoch changes, target edits, retired tools, expiry, or argument tampering between proposal and execution database/Schema.ts:4762-4847; database/AgentConversations.ts:1023-1189,1191-1317,1391-1489,2176-2248
Agent tool-card/status projection server frozen JSON/status booleans Intent/event projection History/UI Presents approval/output state only; never substitutes for DB authority rechecks core/agent.ts:7-20,300-386; database/AgentConversations.ts:80-107,1244-1317,1483-1487,1606-1613
Economy eligibility interval membership persisted half-open membership eligibility interval Membership/economy lifecycle projection Economy fact ingestion Credits an economy fact only when the user was eligible at the authoritative occurrence time; delayed facts before a later leave/ban remain valid database/Schema.ts:1622-1650; database/Economy.ts:100-125
Economy badge grant revocation grant persisted grant with revoked_at and reason Economy goal/badge reconciliation Self badge Zero query and UI Retains revoked badge evidence and renders it struck through; it affects badge presentation, not channel or economy-operation authority database/Schema.ts:1900-1943; database/Economy.ts:181-285; core/zeroQueries.ts:998-1010; webapp/src/features/economy/EconomyPointsCard.tsx:70-82
Checkout claim token lifecycle grant hashed single-use credential with expiry, consumed/revoked/replacement state Support resend-claim execution issues/replaces tokens No production redemption consumer found Intended to gate account claim for a completed unclaimed checkout, but currently only issuance/replacement exists; no repository path consumes it database/Schema.ts:3898-3932; server/src/applySupportDatabaseAction.ts:335-363
Billing webhook is_verified platform persisted boolean No production writer found No production reader found Currently gates nothing; unlike the conference webhook, no billing webhook verification/processing path was found database/Schema.ts:3333-3349
Conference webhook signature platform HMAC signature plus five-minute timestamp freshness Daily provider signs; server verifies raw delivered bytes Conference event ingestion Rejects an actual event with missing, malformed, stale, or non-constant-time-matching credentials before applying it. The exact inert registration probe is intentionally accepted unsigned and changes no durable state server/src/confWebhook.ts:126-162,415-447

Named gaps

  • BOJ-237 confirmed: no production writer sets max_duration_seconds or max_message_age_seconds; promote and capability-toggle commands leave both null. The bounded grant fields exist and are enforced only when data is externally/fixture-provisioned.
  • BOJ-232 context: staff is not an audience kind and does not mean “moderators.” It expands to empty product audiences, so effective access is staff/owner/admin privilege. A moderator with only moderate cannot enter a staff-preset room unless another audience admits them.
  • No production writer was found for users.is_staff, server-owner transfer, membership-admin promotion/demotion, profile privacy, KYC, any legal-hold field, restricted message revisions, or attachment legal holds. Owner/admin creation occurs in provisioning; staff/operator provisioning and the currently-readable true-only fields are external/manual.
  • No Zero writer exists for platform staff, membership admin, member moderation grants, or their caps. Member/grant changes are console/API-to-database paths. Channel/thread audience changes are Zero-reachable but reauthorized transactionally.
  • servers.feature_flags has no production writer or reader. servers.is_public has an authoritative settings writer and UI meaning, but no repository discovery consumer was found.
  • canCustomDomain, canAutomation, and canAdvancedAnalytics are unconsumed. videoStoredMinutes, mauAllowance, and aiActions are meters, not enforcement; broadcastMonthlyLimit is enforced on announcement recording. canNativeLive is duplicated as a direct tier check on the server rather than shared. Validated-GMV checkout denial is calculated/projected but not wired to a production checkout mutation.
  • thread.create, stream.join, and stream.start are capability-manifest names without SDK method metadata. message.moderate metadata and member grant vocabulary (moderate, delete, timeout, ban) remain separate mappings.
  • permissionErrors.raise has tests but no production caller. Callers currently use direct decisions and local error adapters.
  • Attachment ingest download trusts possession of an unexpired asset-operation token and does not re-evaluate actor/channel authority. Livestream marker visibility is enforced, but no separate provider/CDN playback permission evaluator was found.
  • No product permission evaluator was found in mobile/src; worker product authorization is absent except for a signed worker-to-Celld presence service token. Web permission checks are advisory and server paths recheck.
  • Agent allowedTools, allowedMethods, and runtime capabilities are ephemeral derived projections. Intent expired is enforced at decision/claim time; no proactive expiry worker was found.
  • Schema/state without a complete production path: channels.is_private, channel_participants.is_muted, channel_read_states.notification_preference, KYC status, billing webhook is_verified, and checkout claim tokens have no production consumer; day-7 flow and server feature flags have no delivery/feature consumer. Restricted message revisions and attachment/support legal holds have production readers but no production writer setting them true; audit-event legal hold has neither.
  • Mobile is a shell: it displays static capability names but has no network, Zero-mutator, or product-permission consumer. Deployment/MCP gates are separate platform-operator controls, not tenant roles.
  • Searches covered core/, database/, server/, sdk/, webapp/, mobile/, worker/, scripts/, schema/migrations, Zero schemas/queries/mutators, console routes, runtime token issuers, and direct consumers of the named fields and decisions. Test-only writers were not reported as production writers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment