Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PT-BR   EN

PT-BR

matheus@devops:~$ cat sobre.txt

Template 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/

TypeScript Next.js Fastify React PostgreSQL Redis Drizzle

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:

  1. 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ê.
  2. 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.txt

A 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.txt

End-to-end, o template cabeia um sistema genérico de tickets:

  • GET /v1/tickets/by_status — contagem de tickets por status
  • GET /v1/tickets/by_priority — contagem de tickets por prioridade
  • GET /v1/tickets/volume — timeseries diário de tickets novos
  • GET /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.sh

Pré-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:3000

Loga 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.txt

Adicionar um adapter novo de fonte de dado:

  1. Cria packages/api-source/src/routes/v1/<sua-resource>.ts.
  2. Registra a rota em packages/api-source/src/server.ts.
  3. Define a shape em packages/shared/src/schemas/<sua-resource>.ts.

Adicionar um endpoint novo no BFF que agrega/cacheia:

  1. Adiciona rota em packages/api-bff/src/routes/v1/dashboards.ts.
  2. Usa helpers do cache.ts — cacheKey('namespace', ...args) → cache.get(...) → busca da source → cache.set(...).

Adicionar uma página nova na web:

  1. packages/web/src/app/dashboard/<page>/page.tsx — usa lib/api.ts pra chamar BFF.
  2. 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-source pode 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 LICENSE

MIT. Veja LICENSE.

matheus@devops:~$ contact

LinkedIn Email

matheus@devops:~$ _

EN

matheus@devops:~$ cat about.txt

A 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/

TypeScript Next.js Fastify React PostgreSQL Redis Drizzle

matheus@devops:~$ cat architecture.txt

api-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:

  1. 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.
  2. Different deploy cadences. You change UI + BFF every day. You change the source adapters once a quarter.
matheus@devops:~$ cat example-tickets.txt

End-to-end, the template wires up a generic ticketing system:

  • GET /v1/tickets/by_status — count tickets by status
  • GET /v1/tickets/by_priority — count tickets by priority
  • GET /v1/tickets/volume — daily new-tickets timeseries
  • GET /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.sh

Prereqs: 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 dev
matheus@devops:~$ cat extending.txt

Add 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-source could 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 LICENSE

MIT. See LICENSE.

matheus@devops:~$ contact

LinkedIn Email

matheus@devops:~$ _

About

Operations dashboard template - Fastify BFF + api-source pattern, Next.js 15 + Recharts UI, JWT/Argon2 auth, Drizzle ORM, Redis cache-aside, pnpm workspaces.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages