B2BEA.org V1 Entitlement Model Spec
internal prototype · canonical JSON + Dreamborn Forge HTML
internal generated
entitlement-model-spec · supabase_json

B2BEA.org V1 Entitlement Model Spec

entitlement-model-spec artifact · for B2BEA.org Rebuild · status approved

Planning Surface

Use this to decide what happens next.

Status

approved

Agent Handoff
Start Here

entitlement-model-spec artifact · for B2BEA.org Rebuild · status approved

Completion Evidence
  • A developer can answer “why does this person have access?” from one entitlement decision path.
  • Protected resources cannot be downloaded by editing client state or bypassing the UI.
  • Pro, vendor, company, and admin access are separately testable and can coexist on one person account.
  • Seat assignment and revocation changes access immediately or within a documented cache window.
  • All entitlement-changing operations create an audit event.
  • The old persons-table access path is gone or intentionally shimmed and covered by tests.
Artifact Shape
  • gaps: 9 items
  • title: B2BEA.org V1 Entitlement Model Spec
  • version: 1
  • decisions: 7 items
  • next specs: 5 items
  • project id: a820dd0c-6cef-4133-bfbd-d802fd806e44
  • updated at: 2026-05-06T23:32:25.356Z
  • source repo: name: string, local_path: string, live_supabase_host: string
  • artifact type: entitlement-model-spec
  • entitlement keys: 20 items
  • source artifacts: 5 items
  • v1 access matrix: 17 items
Structured Payload

Machine-readable source fields

gaps
idareacurrentrequiredseverity
ENT-GAP-001Legacy identity tableauthbridge.js checks persons for Pro access while live schema uses people.Replace persons usage with people or create/test an intentional compatibility view before launch.P0
ENT-GAP-002Fragmented Pro truthpeople.is_pro, person_roles.pro_member, active memberships, and course fields can disagree.Centralize Pro decision logic and backfill/derive display fields from canonical entitlement state.P0
ENT-GAP-003Client-side gatingSome reports/guides/course paths rely on client authbridge checks.Server-side checks for protected reads/downloads/enrollments/mutations with RLS/function parity.P0
ENT-GAP-004Course access consistencyCourses have price fields, member prices, access_tier values, and is_included_with_pro flags that are not normalized.Define a course access policy contract and migrate course rows to consistent values.P0
ENT-GAP-005Company seatsmembership_seats and organization_members exist but are empty.Implement org-held membership, employee role, seat assignment, revocation, and academy/careers benefit checks.P0
ENT-GAP-006Vendor membershipvendor_memberships is empty and not clearly tied to portal access.Choose canonical vendor commercial source and wire vendor portal read/write/analytics checks to it.P0
ENT-GAP-007AuditabilityNo central entitlement audit event model observed.Record grants, revocations, admin overrides, seat changes, purchases/cancellations, and denials.P1
ENT-GAP-008Surveys/formsGeneralized survey/form capability is missing.New survey and form models must declare entitlement keys before implementation.P1
ENT-GAP-009ExportsAnalytics tables exist but export entitlement rules are not centralized.Implement own-account bounded export checks for vendors and companies.P1
title

B2BEA.org V1 Entitlement Model Spec

version

1

decisions
idtopicdecision
ENT-DEC-001Canonical entitlement truthActive memberships, membership_tiers.access_rules, and membership_seats are the canonical source for paid/product access. Roles are permissions and operational responsibility, not paid entitlement truth.
ENT-DEC-002people.is_propeople.is_pro may remain as a denormalized display/cache flag during migration, but it must not be treated as authoritative access truth.
ENT-DEC-003Server-side enforcementProtected reads, protected downloads, enrollments, mutations, exports, and portal actions require a server-side entitlement check. Client-side checks may only improve UX.
ENT-DEC-004Company workspacePractitioner company workspace uses organization-held memberships plus membership_seats for employee access to academy/careers benefits. Company public profiles are excluded from V1.
ENT-DEC-005Vendor portalVendor portal access requires a vendor relationship role and an active/approved vendor commercial entitlement when commercial gating is required. Vendor public profiles remain V1.
ENT-DEC-006Course enrollmentcourse_enrollments represents participation/progress after eligibility is granted. Eligibility to enroll comes from entitlement policy, purchase, admin grant, or company seat assignment.
ENT-DEC-007HubSpot boundaryHubSpot remains CRM primary for sales and renewals. B2BEA Supabase stores product entitlements and operational access state; HubSpot can mirror status but does not enforce site access.
next specs
  • company-workspace-data-spec
  • survey-system-spec
  • notification-spec
  • academy-certification-spec
  • vendor-portal-workflow-spec
project id

a820dd0c-6cef-4133-bfbd-d802fd806e44

updated at

2026-05-06T23:32:25.356Z

source repo
name

B2BEA-org-new

local path

/Users/justinking/Vaults/Projects/B2BEA-org-new

live supabase host

czqxkykbhoyyjccckpqq.supabase.co

artifact type

entitlement-model-spec

entitlement keys
keyareagrants
account.registeredIdentityBaseline authenticated account and profile access.
membership.proMembershipIndividual Pro status and Pro-only product eligibility.
resource.report.read.proResourcesRead/download Pro reports and guides.
academy.course.enroll.includedAcademyEnroll in courses included with the member tier or company seat.
academy.course.purchaseAcademyEnroll in a course through a direct purchase/admin grant path.
academy.certification.earnAcademyAttempt certification requirements and receive certificates.
event.register.memberEventsRegister for member-included or member-priced events.
vendor.portal.readVendorView vendor portal dashboard and own profile/submission state.
vendor.portal.writeVendorSubmit vendor profile edits, case studies, media, and portal updates.
vendor.analytics.exportVendorExport bounded own-vendor analytics.
company.workspace.readCompanyAccess private company workspace.
company.workspace.adminCompanyManage company users, jobs, academy assignments, and workspace settings.
company.academy.assignCompanyAssign included academy content to employees.
company.careers.submit_jobCompanyCreate job postings for admin review.
company.analytics.exportCompanyExport bounded own-company reporting.
survey.createSurveyCreate survey definitions and assignments.
survey.respondSurveyTake assigned/public surveys.
survey.results.readSurveyView permitted survey results and dashboards.
admin.content.publishInternal adminPublish standard Sanity pages or imported custom HTML.
admin.platform.manageInternal adminManage users, vendors, content review queues, and platform settings.
source artifacts
  • data-model-spec v1
  • capability-map v5
  • permission-lifecycle-matrix v3
  • production-readiness-gap-register v3
  • publishing-model-spec v1
v1 access matrix
areasourcecapabilityrequired access
Public siteSanity + Supabase public projectionsRead public content/vendor profiles/jobs/eventsanonymous/public unless explicitly gated
Member profilepeople + auth userUpdate own profileaccount.registered + owns profile
Member profileauth provider + peopleChange password/account settingsauthenticated own account
Resourcesmemberships + tier access_rules + protected resource metadataRead/download Pro report or guideresource.report.read.pro or admin override
Academymembership tier, seat, purchase/grant, course policyEnroll included courseacademy.course.enroll.included or course purchase/admin grant
Academycourse_enrollments + entitlement statusContinue enrolled courseactive course_enrollments row and not revoked
Academyperson_roles/platform_adminsCreate/manage courseadmin.platform.manage or academy admin role
Vendor portalvendor_memberships/memberships + person_roles/vendor ownershipUpdate vendor profilevendor.portal.write + vendor relationship
Vendor portalvendor entitlement + vendor_content_submissionsCreate case study/content submissionvendor.portal.write
Vendor portalvendor role + own vendor analytics filtersExport own analyticsvendor.analytics.export
Company workspaceorganization_members + membership held by orgInvite/manage employeescompany.workspace.admin
Company workspacemembership_seats + course_assignmentsAssign academy coursescompany.academy.assign + available seats/content grant
Company workspaceorganization role + admin review workflowSubmit job postingcompany.careers.submit_job
Surveysfuture survey model + rolesCreate surveysurvey.create or admin.platform.manage
Surveysfuture survey assignment/audience modelTake surveysurvey.respond + assignment/public rule
Surveysfuture survey response/reporting modelDisplay/export resultssurvey.results.read + audience/ownership filter
Internal adminsmall internal admin allowlist/role for Brett, Sarah, JustinPublish Sanity standard page or custom HTML importadmin.content.publish
target data model
use existing
roletable
Defines tier category, seat model, billing model, and structured access_rules.membership_tiers
Canonical commercial/product entitlement holder for person-held, organization-held, and vendor-held memberships.memberships
Seat assignment from an org/vendor/company membership to an individual person.membership_seats
Operational authority and relationship roles such as platform_admin, vendor_admin, company_admin, author.person_roles
Learning participation/progress after eligibility is granted.course_enrollments
add or harden
tablefieldspurpose
entitlement_grants- id - subject_type - subject_id - entitlement_key - source_type - source_id - status - starts_at - ends_at - metadata - created_at - updated_atOptional normalized/materialized grant table for fast and auditable access decisions.
entitlement_audit_events- id - actor_person_id - subject_type - subject_id - entitlement_key - event_type - source_type - source_id - reason - metadata - created_atAudit log for grants, revocations, seat assignments, admin overrides, purchases, cancellations, and policy denials.
course_assignments- id - course_id - assigned_to_person_id - assigned_by_person_id - organization_id - source_type - status - due_at - created_at - updated_atCompany/admin course assignment layer separate from course participation.
entitlement_policy_tests- id - scenario_key - subject_fixture - resource_fixture - expected_decision - created_atMachine-readable policy fixtures for production gating regressions.
target principles
  • Every protected capability resolves through one entitlement evaluator with auditable inputs and deterministic outputs.
  • Entitlement decisions are explicit: subject, action, resource, source, status, start time, end time, and reason.
  • Roles grant authority to administer or act on behalf of an account; memberships and seats grant product access.
  • A user can hold multiple contexts at once: individual Pro, vendor admin, company admin, employee seat, and internal platform admin.
  • Entitlement state should be explainable in the UI for support: why access exists, where it came from, when it expires, and who assigned it.
migration sequence
  • Inventory and remove/replace all persons table references in production code.
  • Define entitlement key enum/constants shared by server functions, RLS, and UI display.
  • Normalize membership_tiers.access_rules into versioned machine-readable rules.
  • Implement entitlement evaluator and policy test fixtures before wiring new protected features.
  • Backfill current Pro member state from memberships and reconcile people.is_pro/person_roles drift.
  • Normalize course access fields and write course enrollment eligibility tests.
  • Wire vendor portal and company workspace gates to memberships/seats/roles.
  • Add entitlement audit events and support/admin visibility.
  • Add survey/company/vendor export entitlement checks as those modules are built.
acceptance criteria
  • A developer can answer “why does this person have access?” from one entitlement decision path.
  • Protected resources cannot be downloaded by editing client state or bypassing the UI.
  • Pro, vendor, company, and admin access are separately testable and can coexist on one person account.
  • Seat assignment and revocation changes access immediately or within a documented cache window.
  • All entitlement-changing operations create an audit event.
  • The old persons-table access path is gone or intentionally shimmed and covered by tests.
enforcement contract
hard rules
  • No protected mutation trusts only localStorage, client profile state, or people.is_pro.
  • RLS policies and server routes/functions must agree on the same entitlement keys.
  • Admin override must be logged with actor, subject, reason, and expiration when temporary.
  • Exports must be filtered by own vendor/company context before data leaves Supabase.
input shape
action

named capability/action key such as academy.course.enroll or vendor.portal.write

context

request metadata, impersonation/admin mode, source surface, and time

subject

person_id plus active organization/vendor context when applicable

resource

resource type and id when relevant, such as course_id, vendor_id, report_id, organization_id

output shape
allowed

boolean

expires at

expiration timestamp when access is time-bound

reason code

machine-readable allow/deny reason

source refs

membership, role, seat, purchase, admin grant, or policy refs used for the decision

entitlement key

resolved grant key or required key

entitlement subjects
examplessubject typecurrent sources
- registered account - Pro member - course learner - company employee seat - vendor team member - platform adminperson- people - person_roles - memberships.held_by_person_id - membership_seats.assigned_person_id - course_enrollments
- private practitioner company workspace - company academy/careers accountorganization- organizations - organization_members - memberships.held_by_org_id - membership_seats
- public vendor profile - vendor management portal account - enhanced directory listingvendor- vendors - vendor_memberships - person_roles - vendor_* portal tables
live schema evidence
checked at

2026-05-06T23:32:25.356Z

code signals
  • src/assets/js/authbridge.js still checks the legacy persons table when evaluating Pro access.
  • Reports and guides call client-side authbridge.checkProAccess() for pro gating.
  • Courses combine courses.access_tier, courses.is_included_with_pro, pricing fields, and course_enrollments.
  • Admin user tooling edits people.is_pro and person_roles in ways that can drift from active memberships.
  • membership_tiers.access_rules exists but is not yet the single enforced entitlement contract.
current tiers
namecategoryseat modelbilling modelaccess summaryprice annual
RegisteredpractitionerindividualfreeFree baseline profile/account access; no premium courses, reports, events, or vendor portal.
PropractitionerindividualsubscriptionAll courses, reports, and events; no vendor portal; no enhanced directory.9500
VendorvendorcompanyinvoiceVendor portal write access and enhanced directory; no practitioner course/report/event grants by default.
current counts
courses

9

memberships

1

person roles

8

membership seats

0

membership tiers

3

course enrollments

4

vendor memberships

0

organization members

0

tables checked
  • people
  • person_roles
  • membership_tiers
  • memberships
  • membership_seats
  • vendor_memberships
  • organization_members
  • courses
  • course_enrollments
  • events
  • content_embeddings