One content model, every surface
The dashboard, public reader, embed, SDK, CLI, and MCP server all follow the same publishing rules.
The management contract stays in the center
Prosewire keeps its private management schemas and HTTP API declarations in a shared contract package. The server, TypeScript SDK, CLI, and MCP server consume that contract instead of reimplementing request and response shapes independently.
The public JSON and rendered HTML endpoints use the same publication queries and visibility rules. Drafts, archived posts, and future scheduled posts remain private on every public surface.
Tenant boundaries
A Better Auth organization is a Prosewire workspace. Workspace membership carries one of five roles: owner, admin, editor, author, or viewer. Publications belong to exactly one workspace; content, public URLs, API keys, exports, and analytics remain publication-scoped.
Authorization is checked beside every server mutation and private API operation. Submitted publication, author, category, member, and invitation identifiers are resolved against the caller’s workspace before writes begin. Authors can edit only posts they created, while editors can review and publish across the workspace.
Choose your delivery surface
- JavaScript embed for the smallest integration change
- Rendered HTML for server or client composition
- Public JSON for a custom reading experience
- TypeScript SDK for typed public and management clients
- CLI and MCP for automation and agent workflows
Read Choose an integration for authentication and rendering trade-offs.
Own the runtime
The web app writes each invitation and its complete typed email intent in one Postgres transaction. That transaction also calls pg_notify; Postgres emits the notification only after the transaction commits. The request no longer depends on Redis, and a committed invitation cannot exist without a recoverable delivery intent.
The worker keeps a dedicated Postgres LISTEN connection. A notification starts an email-outbox workflow as soon as the invitation transaction commits. A 30-second scan starts the same workflow path for notifications missed during a disconnect or restart. The outbox workflow leases rows with FOR UPDATE SKIP LOCKED and starts one idempotent email workflow per outbox ID. It marks the row dispatched only after the workflow engine has accepted that execution.
Each email workflow submits its SMTP payload to Effect DurableQueue in Redis and waits for the queue worker to record the result. SMTP retries stay attached to that workflow. Postgres stores workflow messages and results in Effect-owned cluster_* tables. Redis remains the delivery queue, so it still needs AOF persistence, backups, and replication.
Scheduled publishing and analytics retention also run as named workflows. Their source records remain in Postgres, so a restart can safely run another scan without creating a second content state. Content remains exportable, and the built-in public reader remains readable without client-side JavaScript.
Effect’s SQL workflow runner in this release is single-process. Run exactly one Prosewire worker for each database and set email concurrency inside that process. The supervisor should restart it after a crash. The one-shot migration command applies both committed Drizzle migrations and Effect’s internal workflow-storage migrations before the web and worker start. The worker repeats Effect’s idempotent cluster_* migration check when it connects. The web process does not migrate, seed, or connect to Redis in production.