ngx-zero playground
July 20, 2026 · View on GitHub
A fully functional integration harness for the ngx-zero public API against a
real Zero backend: Postgres (Docker) → zero-cache → an embedded Hono API →
this Angular app. The app imports only from the package entry point.
Architecture
┌────────────────────────────┐ ┌───────────────┐ ┌──────────────────┐
│ Vite :5173 │ │ zero-cache │ │ Postgres :5430 │
│ ├─ Angular playground │◄────►│ :4848 │◄────►│ (docker, │
│ └─ Hono /api/* │ │ │ WAL │ wal_level= │
│ /api/login │ │ forwards │ │ logical) │
│ /api/zero/query ◄───┼──────┤ query/mutate │ └──────────────────┘
│ /api/zero/mutate ◄───┼──────┘ │
└────────────────────────────┘ └───────────────┘
- Drizzle is the source of truth for the database schema
(
src/db/schema.ts).pnpm generateregenerates the Zero schema (src/zero/schema.gen.ts) viadrizzle-zero. - Queries and mutators are shared registries (
src/zero/queries.ts,src/zero/mutators.ts) — the same code runs optimistically in the browser and authoritatively in the API server. - Auth is a fake token flow:
/api/loginmints an HS256 JWT for any user name; the query/mutate endpoints verify it and build thectxpassed to queries and mutators.
Running it
From the repository root (requires Docker):
pnpm playground:db # once: start Postgres, push the schema, seed
pnpm playground # build ngx-zero, then run zero-cache + vite
Open http://localhost:5173.
What to try
- Add / complete / delete issues — optimistic mutations synced through the
real backend. Open two windows to watch them converge. The header's
“Mutation” readout is driven by the
pendingsignals oninjectMutator. - Add a title containing “rollback” — a server-only rule rejects it after
the optimistic apply succeeds; watch the row appear and roll back, and the
mutator's
errorsignal surface the rejection. - Delete someone else's issue — the owner check fails during the optimistic apply, before the server is ever involved.
- Switch user —
userID(and context) change, soprovideZerocloses and recreates the instance (watch the instance counter). - Rotate auth — a same-user token rotation reconnects in place via
zero.connection.connect({auth}); the instance counter must not move. - 15s token — a short-lived token; after it expires the API returns 401
and Zero enters
needs-auth(thewithAuthRefreshopen question indocs/DESIGN.md). - Show only mine — swaps the materialized query to
queries.issue.mine, whose filter is applied server-side from the verified JWT context.
Housekeeping
pnpm --filter ngx-zero-playground db:setupre-runs push + seed.docker compose down -v(in this directory) resets the database..envis checked in on purpose; nothing in it is secret.