Building Real-Time Workspaces with Zero
How Epicat combines Postgres, Drizzle, and Rocicorp Zero for secure real-time workspace data.
Epicat uses PostgreSQL as its system of record, Drizzle for its schema, and Rocicorp Zero for reactive client reads.
Server-Authorized Queries
Zero forwards named queries to Epicat's API. The API verifies the signed Better Auth token and creates a trusted query context containing the current user ID. Every workspace query starts from that context and only traverses organizations where the user has a membership.
export const organizationProjects = defineQuery(({ args, ctx }) =>
zql.member
.where("userId", ctx?.userId ?? "")
.where("organizationId", args.organizationId)
.related("organization", (organization) => organization.related("projects"))
.one(),
);The browser never gets to choose its authenticated identity. Project writes go through the typed API, which repeats the organization-membership check before changing PostgreSQL.
One Schema Chain
The Drizzle schema generates the database migration and Zero schema. The Elysia API generates an OpenAPI document, and that document generates the @epicat/sdk client types. Keeping these artifacts generated makes drift visible during review instead of at runtime.
Why This Shape
- PostgreSQL remains the durable source of truth.
- Zero pushes committed changes to open project views without polling.
- Authorization stays on the server at both read and write boundaries.
- Shared generated types keep the web app, SDK, and API documentation aligned.