Projects & members
A project is the top-level tenant — workjournal, skillforests, or mindcoding. Everything else (collections, publications, promos, media, brand) belongs to exactly one project, and every access decision is scoped to project membership.
Collections
A collection groups publications. One entity covers both grouping styles:
- Campaigns — time-boxed, with
starts_on/ends_ondates and aplanned → active → donestatus. This is where campaign planning happens (batch-create stubs into a campaign). - Sections — evergreen buckets that stay
active.
A publication may belong to a collection or stand alone.
Brand
Each project has a single brand document — the context AI writers read before drafting so content stays on-brand. It's a structured JSON document covering positioning, a library of voices, audiences (with personas, goals, and voice references), topics, and proof points.
Any project member can read the brand; owners and managers can edit it. AI clients read it through the get_project_brand MCP tool before writing or reviewing.
Members & roles
Membership is a project_members(project_id, user_id, role) table. Roles are owner and manager — both can edit; the model is written per-user from day one so multi-tenant later is a policy change, not a schema rewrite.
Row-Level Security is enforced at the database. The MCP server executes queries as the calling user (its OAuth JWT), not with a service role, so an AI client sees and touches exactly what that user could. The admin UI (NocoDB) connects with its own dedicated admin_ui Postgres role.
Actors at a glance
| Actor | Interface | Typical actions |
|---|---|---|
| AI clients (Claude / ChatGPT) | MCP | write drafts, review, generate promos, report pipeline status |
| You | NocoDB admin UI | final approvals, scheduling, manual Substack publish, media curation |
| System (edge functions) | SQL + upload-post | dispatch approved promos, enforce transitions, audit log |