matheus@devops:~$ cat sobre.txtTemplate pra um dashboard de operação que agrega dado de uma ou mais fontes upstream atrás de um BFF (Backend-For-Frontend), com auth JWT, caching, e front-end Next.js construído em torno de Recharts.
O template é intencionalmente pequeno (~60 arquivos source) e vem com um domínio de exemplo (sistema de tickets genérico) cabeado end-to-end. Troca o domínio — mantém a arquitetura.
matheus@devops:~$ ls stack/matheus@devops:~$ ls packages/multi-instance-ops-dashboard/
├── packages/
│ ├── shared/ Schemas zod compartilhados + tipos TypeScript
│ ├── api-source/ Service Fastify que lê das fontes upstream
│ │ (DB, mocks, APIs externas) e serve /v1/*
│ ├── api-bff/ Fastify BFF — auth, cache, fan-out pro api-source,
│ │ Drizzle pra estado de user/session
│ └── web/ Dashboard Next.js 15 — KPI cards, charts, tabelas
├── package.json pnpm workspace root
├── pnpm-workspace.yaml
└── tsconfig.base.json
matheus@devops:~$ cat arquitetura.txt browser
│
│ fetch /api/...
▼
┌──────────────────────────┐
│ Next.js web (packages/ │ Next 15 + React 19 + Recharts + Radix UI
│ web) │
└─────────┬────────────────┘
│ fetch BFF_URL/v1/... (Bearer JWT)
▼
┌──────────────────────────┐
│ api-bff (Fastify) │ JWT auth (argon2 + HS256)
│ - Valida JWT │ Redis caching (LRU + TTL)
│ - Tenant scope │ Tabelas de user/session/audit (Drizzle)
│ - Agrega + cacheia │
└─────────┬─┬──────────────┘
│ │
reads ┘ └── fetch SOURCE_URL/v1/... (X-API-Key)
estado
do tenant
(Postgres) ┌────────────────────────────────┐
│ api-source (Fastify) │
│ - Adapters: mocks, DBs, APIs │
│ - Serve /v1/tickets, /v1/... │
└────────────────────────────────┘
│
│ lê das fontes upstream
▼
┌───────────────────────┐
│ Postgres / mocks / │
│ APIs externas │
└───────────────────────┘
Duas razões pra separar BFF da source:
- Níveis de confiança diferentes. O BFF segura identidade de user e PII; o source é adapter thin read-only, idealmente deployável perto (ou dentro) do dado que ele lê.
- Cadência de deploy diferente. Você muda UI + BFF todo dia. Muda os adapters do source uma vez por trimestre.
matheus@devops:~$ cat por-que-existe.txtA maioria dos boilerplates de "dashboard executivo" acopla a camada de leitura direto na UI: o front fala SQL através de um wrapper client thin. Isso funciona até:
- Você adicionar uma segunda fonte de dado.
- Precisar de cache server-side (Redis) sem expor pro browser.
- Precisar escopar toda query por tenant e por role de user.
- Precisar trocar uma data source por outra sem tocar na UI.
A divisão aqui — api-source (adapters de dado) → api-bff (auth, cache, fan-out) → web (apresentação) — resolve esses casos sem ceremônia de microservice. Dois processos Fastify + um processo Next. Todos compartilhando tipos via packages/shared.
matheus@devops:~$ cat exemplo-tickets.txtEnd-to-end, o template cabeia um sistema genérico de tickets:
GET /v1/tickets/by_status— contagem de tickets por statusGET /v1/tickets/by_priority— contagem de tickets por prioridadeGET /v1/tickets/volume— timeseries diário de tickets novosGET /v1/tickets/resolution_time— tempo médio de resolução diário
O api-source serve esses dos mocks JSON em packages/api-source/mocks/. O api-bff reformata/cacheia e expõe em /v1/dashboards/*. O web renderiza KPI cards, bar chart, e line chart por cima.
Substitui pelo seu domínio real — pagamento, suporte, fleet status, o que for — mudando três arquivos: route handler em api-source, shape em packages/shared, e página em web.
matheus@devops:~$ ./quick-start.shPré-requisitos: Node 22+, pnpm, Postgres (pro api-bff), Redis (pro cache).
git clone https://github.com/MatheusHenriquePrates/multi-instance-ops-dashboard
cd multi-instance-ops-dashboard
pnpm install
# 1. api-source (sem DB, só mocks)
cd packages/api-source
cp .env.example .env
pnpm dev # http://localhost:4000
# 2. api-bff (precisa de Postgres + Redis)
cd ../api-bff
cp .env.example .env
# preenche DATABASE_URL, REDIS_URL, JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, SOURCE_API_KEY
pnpm db:migrate
pnpm db:seed # cria tenant demo + admin
pnpm dev # http://localhost:5000
# 3. web
cd ../web
cp .env.example .env.local
pnpm dev # http://localhost:3000Loga com as credenciais semeadas (impressas pelo pnpm db:seed). O dashboard puxa do api-bff que fan-outa pro api-source que serve os mocks.
matheus@devops:~$ cat extending.txtAdicionar um adapter novo de fonte de dado:
- Cria
packages/api-source/src/routes/v1/<sua-resource>.ts. - Registra a rota em
packages/api-source/src/server.ts. - Define a shape em
packages/shared/src/schemas/<sua-resource>.ts.
Adicionar um endpoint novo no BFF que agrega/cacheia:
- Adiciona rota em
packages/api-bff/src/routes/v1/dashboards.ts. - Usa helpers do
cache.ts—cacheKey('namespace', ...args)→cache.get(...)→ busca da source →cache.set(...).
Adicionar uma página nova na web:
packages/web/src/app/dashboard/<page>/page.tsx— usalib/api.tspra chamar BFF.- Adiciona na sidebar em
components/dashboard/sidebar.tsx.
matheus@devops:~$ cat o-que-NAO-e.txt- Não é framework SaaS. Sem provisioning de tenancy, sem billing, sem console admin.
- Não é opinativo sobre fonte de dado. Os mocks são JSON; seu
api-sourcepode ler Postgres, BigQuery, Snowflake, REST API, qualquer coisa. - Não é UI library. Componentes são intencionalmente plain (primitives Radix + CSS). Plugue seu design system se tem um.
- Não é production-ready. Vai querer: structured logging, request tracing, rate limit, CSP header, session management real, etc. O esqueleto tá aqui; o acabamento é seu.
matheus@devops:~$ cat LICENSEMIT. Veja LICENSE.
matheus@devops:~$ contactmatheus@devops:~$ _matheus@devops:~$ cat about.txtA template for an operations dashboard that aggregates data from one or more upstream sources behind a BFF (Backend-For-Frontend), with JWT auth, caching, and a Next.js front-end built around Recharts.
The template is intentionally small (~60 source files) and ships with one example domain (a generic ticketing system) wired end-to-end. Replace the domain — keep the architecture.
matheus@devops:~$ ls stack/matheus@devops:~$ cat architecture.txtapi-source (data adapters) → api-bff (auth, cache, fan-out) → web (presentation). Two Fastify processes + one Next process. All sharing types via packages/shared.
Two reasons to split BFF from source:
- Different trust levels. The BFF holds user identity and PII; the source is a thin read-only adapter, ideally deployable closer to (or inside) the data it reads.
- Different deploy cadences. You change UI + BFF every day. You change the source adapters once a quarter.
matheus@devops:~$ cat example-tickets.txtEnd-to-end, the template wires up a generic ticketing system:
GET /v1/tickets/by_status— count tickets by statusGET /v1/tickets/by_priority— count tickets by priorityGET /v1/tickets/volume— daily new-tickets timeseriesGET /v1/tickets/resolution_time— daily avg resolution time
Replace this with your real domain by changing three files: a route handler in api-source, a shape in packages/shared, and a page in web.
matheus@devops:~$ ./quick-start.shPrereqs: Node 22+, pnpm, Postgres (for api-bff), Redis (for cache).
git clone https://github.com/MatheusHenriquePrates/multi-instance-ops-dashboard
cd multi-instance-ops-dashboard
pnpm install
# 1. api-source (no DB, just mocks)
cd packages/api-source && cp .env.example .env && pnpm dev
# 2. api-bff (needs Postgres + Redis)
cd ../api-bff && cp .env.example .env
pnpm db:migrate && pnpm db:seed && pnpm dev
# 3. web
cd ../web && cp .env.example .env.local && pnpm devmatheus@devops:~$ cat extending.txtAdd a data source adapter: create packages/api-source/src/routes/v1/<resource>.ts, register in server.ts, define shape in packages/shared/src/schemas/<resource>.ts.
Add a BFF endpoint that aggregates/caches: add route in packages/api-bff/src/routes/v1/dashboards.ts, use cache.ts helpers.
Add a web page: packages/web/src/app/dashboard/<page>/page.tsx, add to sidebar.
matheus@devops:~$ cat what-this-is-NOT.txt- Not a SaaS framework. No tenancy provisioning, no billing, no admin console.
- Not opinionated about the data source. Mocks are JSON; your
api-sourcecould read anything. - Not a UI library. Plain Radix primitives + CSS.
- Not production-ready. You'll want structured logging, tracing, rate limit, CSP, real session management.
matheus@devops:~$ cat LICENSEMIT. See LICENSE.
matheus@devops:~$ contactmatheus@devops:~$ _