isidora
Observaobserva

Observa

Multi-tenant incident management with AI-generated dashboards

Personal project · 2026 · Full-stack
C#
.NET 10
Marten
Wolverine
PostgreSQL
SignalR
Google Gemini
React
TypeScript
Vite
TanStack Query
Tailwind CSS
Recharts
Docker
Caddy
Railway
Neon
GitHub Actions
  • Teams report incidents and move them through statuses and custom fields they define themselves, then ask a question in plain English and get back a dashboard of metric cards, charts, and tables over their own data — savable, re-runnable, and exportable as CSV or PDF
  • Isolated every tenant with row-level security enforced by Postgres, not the query builder: the app connects as a NOBYPASSRLS role, policies cover both document and event tables, and a separate admin role applies schema through a migrate step that aborts if that role could bypass RLS
  • Built the API in ASP.NET Core on .NET 10 with clean architecture and CQRS vertical slices — one file per use case carrying its command or query, validator, precondition, and handler — dispatched by Wolverine as mediator, with cookie auth over ASP.NET Core Identity on a Marten-backed user store
  • Kept the model out of the query path: Gemini fills in a declarative dashboard spec instead of writing SQL, a resolver validates every name against the tenant's own schema, and a compiler turns each widget into one parameterized statement run in a read-only, UTC-pinned transaction — so saved dashboards replay with no AI involved
  • Guarded model cost with plan caching in HybridCache — the plan is cached, never the numbers — plus per-user and per-company daily allowances and IP-partitioned rate limiting
  • Event-sourced incidents in Marten, document store and event store in one, so the audit trail is the source of truth: commands append to the stream, an inline projection folds it into the document queries read, and changes reach other browsers over per-tenant SignalR groups through Wolverine's outbox
  • Shipped the frontend in React 19 and TypeScript on Vite with TanStack Query driven by realtime cache invalidation, Tailwind v4 over Base UI primitives, Recharts widgets, Zod-mirrored API contracts, light/dark theming, and client-side CSV and PDF export captured from the rendered dashboard
  • Deployed both apps on Railway with Neon Postgres — the API as a multi-stage Docker image, the SPA behind Caddy proxying /api and /hubs over the private network for a single origin — with schema applied by an idempotent migrate release step, GitHub Actions CI, and 200+ unit tests
BrowserReact SPA · SignalRRAILWAYira-webReact + Vite · static buildCaddy · single originira-backendASP.NET Core · WolverineMarten · SignalR hubHTTPS · one origin · cookie auth/api + /hubsprivate networkread only tx · app.tenant_idquestion · specNeon PostgreSQLMarten documents + eventsRLS · NOBYPASSRLS app roleGoogle Geminiplans a dashboard specnever authors SQL