Skip to content

Seed de Dados ​

O mecanismo de seed popula o banco de dados (D1 no backend e SQLite WASM no frontend) com dados de demonstração assim que a aplicação é acessada pela primeira vez em ambientes de desenvolvimento. Em produção, o seed é completamente desabilitado — todos os dados são reais, cadastrados pelos próprios usuários.

v0.54.0: Guard ENVIRONMENT — o seed só roda se ENVIRONMENT != 'production' (backend) e DEPLOY_ENV != 'prod' (frontend). Um deploy com NODE_ENV=production automaticamente desabilita o seed.

O seed cria 5 usuários com papéis distintos e senha compartilhada senha123: admin@neemias.local (ADMIN), chamador@neemias.local (CHAMADOR), relatorios@neemias.local (RELATORIOS), cadastro@neemias.local (CADASTRO), e um usuário multi-role com CHAMADOR + RESPONSAVEL simultâneos (v0.56.0+). Cada um possui o conjunto de permissões definido pelo sistema de RBAC (packages/permissions), permitindo testar os diferentes níveis de acesso logo após a inicialização.

Além dos usuários, o seed insere estudantes (padrão: 150 no backend — configurável via SEED_STUDENT_COUNT; 150 no seed demo do frontend via VITE_SEED_STUDENTS) com nomes realistas (combinação de ~100 nomes e ~50 sobrenomes brasileiros), avatares via DiceBear adventurer-neutral (cartoon infantil, sem gênero — zero mistura de traços — determinístico), dados de responsável, telefones, endereços completos, alergias, necessidades especiais e campos sociodemográficos completos (estrutura familiar, vulnerabilidade econômica, violência doméstica, situação escolar, etc.). São criadas 7 turmas (Berçário, Maternal, Jardim de Infância, Infantil, Juniores 1, Juniores 2, Pré-Adolescentes) com distribuição em curva sino (mais alunos nas turmas intermediárias) e 20 núcleos (14 na região Azul Celeste com crianças, 1 em cada uma das outras 6 regiões). O seed gera eventos de presença baseados em personas (consistente 60%, esporádico 25%, em risco 10%, crônico 5%) com efeito sazonal (queda de 15% na 4ª semana de cada ciclo), distribuídos em 4 slots de turma (Terça-feira 20h, Sexta-feira 19h30, Domingo 9h, Domingo 19h) com sessões pré-calculadas para as últimas 8 semanas (56 dias).

Teto de tamanho (Workers Free): o Worker da Cloudflare no plano gratuito tem orçamento de 10ms de CPU por invocação (erro 1102 exceededCpu). O seed gera ~11,6 statements D1 por estudante; 500 estudantes consomem ~11-14ms de CPU e morrem com INTERNAL_ERROR (medido localmente, 2026-08). O padrão de 150 estudantes fica em ~metade do orçamento com folga. Para seeds maiores (ex. 500), use o plano Workers Paid (30s de CPU) e ajuste SEED_STUDENT_COUNT.

A geração de dados é feita pelo pacote compartilhado @neemias/seed-data (packages/seed-data/), garantindo que frontend (SQLite WASM) e backend (D1) produzam dados idênticos a partir das mesmas funções puras.

O controle de ambiente é feito pela variável DEPLOY_ENV (ou VITE_DEPLOY_ENV no frontend). O frontend (app/src/modules/_dev/seed.ts) verifica se __DEPLOY_ENV__ === "prod" e aborta o seed nesse caso; caso contrário, popula o IndexedDB local via Dexie. O backend expõe o endpoint POST /api/v1/_seed (disponível apenas em desenvolvimento), que insere os mesmos dados diretamente no D1 da Cloudflare. Esse endpoint possui uma guarda de idempotência: se a tabela users já contiver registros, retorna HTTP 409 (ALREADY_SEEDED), evitando duplicação acidental.

O disparo é automático no primeiro acesso (frontend) ou sob demanda via chamada HTTP (backend). Para acionar o seed do backend manualmente, basta enviar um POST para /api/v1/_seed com o Worker rodando localmente (wrangler dev). A senha padrão pode ser alterada pela variável de ambiente SEED_PASSWORD no wrangler.toml ou .dev.vars.

Refresh semanal — demo sempre "vivo" (rolling seed) ​

Pós-1.0: app.neemias.app e api.neemias.app rodam com configuração de produção (DEPLOY_ENV=production, AUTH_MODE=jwt), mas funcionam como ambiente de demonstração. Para que o demo pareça um sistema vivo, um cron semanal — [triggers] crons = ["0 0 * * 1"] em workers/wrangler.toml (segunda-feira 00:00 UTC) — apaga todos os dados de demonstração e re-insere um dataset fresco ancorado em new Date(): a janela de sessões (últimas 8 semanas) e a frequência (check-ins por persona) sempre parecem recentes.

Como funciona:

  1. scheduled handler (workers/src/index.ts): o cron da Cloudflare invoca o handler apenas quando DEMO_MODE=true (var em [vars] do wrangler.toml). Além do cron, DEMO_MODE=true também registra POST /api/v1/_demo/refresh, a versão manual do mesmo refresh (bearer token = SEED_PASSWORD, obrigatório — sem fallback senha123; o endpoint falha fechado e é limitado por IP) — útil para re-gerar o demo sob demanda sem esperar a segunda-feira. A rota HTTP POST /api/v1/_seed continua restrita a dev (SEED_ENABLED + ENVIRONMENT), então produção configurada não expõe endpoint de seed.
  2. refreshDemoData() (workers/src/routes/seed.ts): chama wipeDemoTables() — DELETE em todas as tabelas demo/operacionais em ordem segura de FKs (filhos antes dos pais) — e depois insertDemoData(), as mesmas funções puras de @neemias/seed-data usadas pela rota HTTP.
  3. Frequência gerada (novo): além de usuários/estudantes/sessões, o seed insere eventos de presença em check_in_events (CHECK_IN/CHECK_OUT) por persona (consistente 60%, esporádico 25%, em risco 10%, crônico 5%) com efeito sazonal (queda de 15% na 4ª semana de cada ciclo de 4 semanas) e popula session_capacity.occupied espelhando os check-ins — os relatórios e telas de presença das últimas 8 semanas mostram dados realistas.

Trade-offs:

  • Mudanças feitas por visitantes do demo durante a semana são descartadas no refresh seguinte — o demo é sempre consistente com a baseline.
  • O frontend em app.neemias.app é um build de produção, mas com VITE_DEMO_MODE=true roda o seed local rico (ver seção abaixo); sem o flag, o seed IndexedDB local não roda e os dados vêm da API.
  • O refresh é idempotente por construção (wipe + insert); se o cron falhar, a Cloudflare tenta novamente e o log [demo-seed] registra o resultado.

Seed local no demo (VITE_DEMO_MODE) ​

O app em app.neemias.app é construído com VITE_DEMO_MODE=true (app/.env.production): mesmo sendo um build de produção, o frontend roda o seed local rico (app/src/modules/_dev/seed.ts, mesmas funções puras de @neemias/seed-data) — alunos com todos os campos (telefones, endereços, alergias, necessidades especiais, estrutura familiar, foto adventurer-neutral), turmas, núcleos, slots, sessões de 8 semanas e presenças (CHECK_IN → attendance_events MARK_PRESENT). É o que alimenta os relatórios (assiduidade, cobertura de chamada, engajamento por turma, membros, pico de frequência) — check-ins sozinhos não bastam.

  • Limpeza antes do seed: quando a versão do seed local muda (constante DEMO_SEED_VERSION, marcador em localStorage), o app apaga as tabelas demo locais (DELETE FROM em DEMO_WIPE_TABLES) e re-seeda — depois de um deploy novo, o demo aparece limpo; nos loads seguintes as mudanças dos visitantes são preservadas até o próximo deploy.
  • Sem duplicação com o backend: em demo mode o hydrateStudents() (login) é pulado — o seed local é a fonte dos alunos; hidratar do D1 duplicaria (mesmos nomes, ids diferentes).
  • Credenciais: VITE_SEED_PASSWORD deve casar com o SEED_PASSWORD do worker (default local senha123); o unlock local de campos sensíveis usa a mesma senha do login do backend.
  • Builds de produção sem VITE_DEMO_MODE continuam sem seed local (guarda shouldSeedLocal()).

⚠️ Seção em expansão.


Fonte: workers/src/routes/seed.ts e app/src/modules/_dev/seed.ts

Distribuído sob licença MIT.