Repositório público — PWA comunitário + API backend para alertas anônimos no Centro de Florianópolis.
O código é público para que qualquer pessoa possa auditar que não há rastreamento.
O painel admin fica em repositório privado separado (safe-city-admin).
safe-city-app/
├── web/ React + Vite + TypeScript — PWA público (Vercel)
├── api/ Node.js + Fastify + TypeScript — Backend (Railway)
└── docs/ Documentação técnica
| Camada | Tecnologia |
|---|---|
| PWA | React + Vite + TypeScript + PWA |
| API | Node.js + Fastify + TypeScript |
| Banco | Supabase (PostgreSQL + Realtime) |
| ORM | Prisma |
| Cache / Bot sessions | Redis |
| IA | Anthropic Claude Haiku |
| Evolution API (self-hosted) | |
| Mapa | Leaflet + OpenStreetMap |
| Deploy web | Vercel CLI |
| Deploy api | Railway CLI |
Cada pasta (api/, web/) é um projeto independente com seu próprio package.json, pnpm-lock.yaml e .env.
cd api
docker compose up -d- Redis (porta 6379): sessões do bot. Sem ele a API não sobe.
- Postgres (porta 5432): opcional. Use Supabase em nuvem (recomendado) ou este Postgres. Credenciais do container:
shield/shield/ bancoshield.
cd api
pnpm install
cp .env.example .envNo api/.env: Mínimo REDIS_URL=redis://localhost:6379 e FINGERPRINT_SALT (veja docs/ENV.md). Para persistência: Supabase (DATABASE_URL, DIRECT_URL, SUPABASE_*) ou Postgres local (DATABASE_URL=postgresql://shield:shield@localhost:5432/shield).
cd api
pnpm db:migrate
pnpm db:seedcd web
pnpm install
cp .env.example .envOpcional: preencha web/.env com VITE_API_URL, VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY, VITE_VAPID_PUBLIC_KEY (ver web/.env.example).
Em dois terminais:
# Terminal 1 — API
cd api && pnpm dev# Terminal 2 — Web
cd web && pnpm dev- PWA: http://localhost:5173
- API: http://localhost:3000
- Health: http://localhost:3000/health
Na raiz do repo (logos-circle): ENV.md, EVOLUTION_LOCAL.md, BACKLOG.md.
Pasta docs/: ARCHITECTURE.md, API.md, PRIVACY.md, BOT_FLOW.md, DATABASE.md.
- Sem login no app público
- IP nunca armazenado
- Fingerprint sempre SHA-256 hasheado antes de persistir
- Nenhuma foto de pessoa aceita
- Alertas expiram automaticamente em 45min
- Autoridade vê o mesmo mapa público que qualquer cidadão