# Developer reference
This section is for people changing this repository — not just calling the npm client. If you’re integrating a product app, you can stop at Troubleshooting.
# Standing up an environment from scratch
Need a new staging/production stack (database included)? Follow the guided walkthrough:
- Setup — From scratch (including the database) — Supabase migration, Cognito, Worker secrets, smoke test
- docs/setup.md — same path with CI/GitHub Environments detail
Do not invent a parallel schema: apply supabase/migrations/0001_notifications.sql only. Keep RLS deny-all; the Worker service role is the sole DB client.
# Integrating from another app (agent context)
If you are wiring a product app (not this repo), give your coding agent the full contents of docs/AGENT.md — it is the self-contained integration brief (auth, client APIs, dedupeKey, do/don’t).
# Repo map
org.inovus.notifications/
├── packages/
│ ├── core/ # Zod schemas + pure TS types (wire contract)
│ ├── api/ # Cloudflare Worker (Hono + OpenAPI + stores + V1 compat)
│ └── client/ # @inovus-medical/notifications (published)
├── supabase/migrations/
├── docs/ # ops + design companions
│ └── userguide/ # this guide
├── DESIGN.md # architecture decisions
└── CLAUDE.md # agent/dev invariants and commands
flowchart TB Core["packages/core schemas"] --> API["packages/api validation + OpenAPI"] Core --> Client["packages/client types inlined at build"] API --> Memory["store/memory"] API --> Supa["store/supabase"] Supa --> PG[(Postgres)]
# Commands you’ll use constantly
pnpm install
pnpm test # all packages
pnpm test:coverage # ≥90% lines/branches — CI fails below
pnpm lint # biome
pnpm typecheck
pnpm openapi:generate # refresh packages/api/openapi.json (committed)
pnpm --filter @inovus-medical/notifications-api dev
pnpm --filter @inovus-medical/notifications build
Single file:
pnpm --filter @inovus-medical/notifications-api exec vitest run test/routes.test.ts
# Invariants (do not break)
These are load-bearing. Full list in CLAUDE.md:
- Every
NotificationStoremethod is user-scoped — handlers don’t re-check ownership ad hoc sourceis token-derived — never client-supplied on V2- Dedupe is
(user_guid, source, dedupe_key)and race-safe at the DB - Wire = camelCase; DB = snake_case — mapping only in the Supabase adapter
- Errors are RFC 9457 problem+json on V2 (V1 envelope is the exception)
openapi.jsonmust match code — regenerate after route/schema changes- No Supabase Auth / RLS policies for authz — Worker is the trusted path
- Client retries publishes because
dedupeKeymakes them idempotent — keep both sides of that contract (no key → no publish retry)
# Adding an API route
- Extend Zod schemas / types in
packages/core - Register an OpenAPI route in
packages/api/src/app.ts - Add route tests in
packages/api/test/routes.test.ts - Run
pnpm openapi:generateand commit the snapshot - Expose a client method if apps need it; add a changeset under
.changeset/
# Storage adapters
Implement NotificationStore (packages/api/src/store/types.ts). See adapters.md.
Today:
memory— tests + localsupabase— PostgREST overfetch(Workers-native)
Selected by DB_DRIVER.
# Auth internals
joseverifies JWTs against JWKS (cached in-isolate + Cache API)- Multi-issuer via comma-separated
AUTH_ISSUER - Publisher = groups ∩
PUBLISHER_GROUPSor scopes ∩PUBLISHER_SCOPES - Cognito M2M tokens carry scopes, not groups — that’s why scopes exist
# V1 compat code
Lives in packages/api/src/v1compat.ts. Contract: v1-compatibility.md.
Don’t change V1 behaviour casually — existing callers depend on the envelope. Prefer adding V2 features on /v1/*.
# Client packaging notes
- Zero runtime deps; React optional peer for
/react - Core types imported by relative path so tsup inlines them
- Convenience façade:
createNotificationServiceinpackages/client/src/notification-service.ts - Publish retries gated on
dedupeKeyinNotificationsClient.publish/publishSelf
User-visible client changes need a changeset (pnpm changeset).
# Release pipeline
High level (see .github/workflows/release.yml):
- PR includes a changeset
- Merge to default branch → Version Packages PR
- Merge that → npm publish (provenance) → staging deploy + smoke → production deploy + smoke
Also watch for branch-name mismatch (main vs master) if CI never fires.
# Design & deeper reading
| Doc | Contents |
|---|---|
| DESIGN.md | Requirements, data model, trade-offs, milestones |
| why-v2.md | Exhaustive V1 gap mapping |
| setup.md | Full ops walkthrough |
| cognito-setup.md | Resource server / M2M |
| adapters.md | New store backends |
Live /docs |
Generated OpenAPI UI |
# Contributing mindset
- Prefer small, reviewable PRs
- Keep OpenAPI + tests in the same change as behaviour
- Don’t add toast/bell UI to this repo — headless by design
- When in doubt, re-read the invariants above
Back to the User Guide home.