Skip to content

feat: multi-tenant SaaS + distributed-tracing spans - #5

Merged
ryzrr merged 5 commits into
mainfrom
feat/multi-tenancy
Jul 19, 2026
Merged

feat: multi-tenant SaaS + distributed-tracing spans#5
ryzrr merged 5 commits into
mainfrom
feat/multi-tenancy

Conversation

@ryzrr

@ryzrr ryzrr commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Turns Liveboard into a hosted, isolated multi-tenant SaaS, and makes traces real.

Multi-tenancy (all live-tested)

  • Orgs + memberships + project ownership (migration 003)
  • Self-serve API keys: create / rotate / revoke (migration 004)
  • Postgres RLS backstop via a restricted dashboard_reader role (migration 005) — cross-tenant reads return 0 rows, fail-closed
  • Session-scoped BFF: browser never holds an API key; reads/writes gated by membership (403 on cross-tenant)
  • Provision user+org+project on login; real ProjectSwitcher (no localStorage mock)
  • Realtime (Socket.io/SSE) via short-lived, project-scoped tokens
  • Per-project ingest rate limit; CORS locked down

Honesty fixes

  • A real project never renders synthetic/mock data — real values or an honest empty state (stat cards, traces, all data panels)

Distributed tracing (Option A)

  • JS SDK now emits a span per request → real single-service traces + flame graphs
  • Header propagation (x-trace-id, x-parent-span-id) ready for multi-service traces (v2)

Fixes

  • get_timeseries interval param (timedelta); /v1/traces JSONB tags parse; 204 responses

Static-checked (tsc, eslint --max-warnings 0, py_compile) and exercised end-to-end with a real SDK-instrumented demo service.

ryzrr and others added 4 commits July 18, 2026 22:58
- Pass NEXT_PUBLIC_* as build args so they're inlined into the frontend image
- Add .dockerignore (keeps node_modules/.next/.env out of the build context)
- Rename middleware.ts -> proxy.ts (Next.js 16 renamed the middleware file)
- Wrap the sign-in form in <Suspense> (useSearchParams build requirement)
- Migrations: organizations + memberships + projects.org_id (003); api_keys
  table with rotation/revocation (004); Row-Level Security via a restricted
  dashboard_reader role scoped by app.project_id GUC (005, fails closed)
- Internal endpoints (BFF-only): provision user+org+project on login, list
  access, self-serve project/key create/rotate/delete, realtime-token mint
- Auth planes: authenticate_internal + resolve_project_id (internal token +
  project id, or x-api-key); scoped_conn runs dashboard reads under RLS
- Realtime: Socket.io + SSE accept short-lived project-scoped tokens
- Per-project ingest rate limit; CORS locked to configured origins
- Fix: get_timeseries interval param (timedelta); /v1/traces JSONB tags parse
- BFF routes: /api/projects (list/create/delete/rotate), /api/lb/* read proxy
  (session -> membership check -> backend with internal token), /api/realtime-token
- Provision user+org on login (auth.ts); session carries allowed project ids
- ProjectProvider now backend-backed (real projects, no localStorage mock);
  create dialog + switcher use the real key lifecycle
- Dashboard reads go through the BFF scoped to the active project (no browser key)
- Realtime (metrics/incidents/live-log) use short-lived project-scoped tokens
- Honesty: a real project never shows synthetic/mock data — real values or an
  empty state (stat cards, traces, and all useApiQuery-backed panels)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SpanBuffer + sendSpans() POST to /v1/spans (batched, fire-and-forget)
- Express middleware emits a root span per request (service/operation/
  duration/status/tags) and propagates x-trace-id + x-parent-span-id so
  downstream instrumented services can attach child spans
- New config: `service` name and `tracing` toggle (default on)
@ryzrr
ryzrr force-pushed the feat/multi-tenancy branch from 7d52b77 to a505ce2 Compare July 18, 2026 17:31
@ryzrr
ryzrr merged commit 109209a into main Jul 19, 2026
4 checks passed
@ryzrr
ryzrr deleted the feat/multi-tenancy branch July 19, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant