Aparência
Visão Arquitetural
O que é este documento — a fotografia de alto nível de como o ionCLASS é montado: o monólito Laravel no centro, as quatro superfícies que ele atende, o hardware de controle de acesso conectado por webhooks (inbound) e chamadas (outbound), e o contrato REST que amarra tudo. É o mapa para entender onde as coisas moram antes de mergulhar em qualquer subsistema.
1. O que é o ionCLASS
O ionCLASS é uma plataforma de retirada (saída) escolar voltada ao momento da saída dos alunos. Ele tem quatro superfícies de uso, todas alimentadas por um único backend:
| Superfície | Público | Tecnologia | Como consome o backend |
|---|---|---|---|
| App do responsável | responsável / família | mobile Expo (React Native) | cliente REST puro (/api/v1/*) |
| Painel administrativo | staff da escola/rede | web Inertia + React | servido pelo próprio monólito |
| Monitor de portaria | operador (porteiro) | PWA Vite + React | cliente REST puro (/api/v1/*) |
| Painel público / kiosk | tela na portaria/recepção | PWA autenticada por token | cliente REST puro (token de painel) |
O backend é um monólito Laravel 13 / PHP 8.5 que serve as duas naturezas ao mesmo tempo: o painel web via Inertia (SSR + React, sem SPA separada) e a API REST versionada /api/v1/* consumida pelo mobile, pelo monitor e pelo painel público. Fora do produto, ele pode, opcionalmente, conversar com um sistema de controle de acesso de terceiros (catraca/controle de acesso facial) — a arquitetura é agnóstica a provedores — por integração inbound/outbound. Sem essa integração, o ionCLASS funciona normalmente (modo operador/manual).
Nomenclatura: o produto é o ionCLASS. O controle de acesso, sozinho, é o hardware de terceiros com o qual ele se integra — nunca é um nome de produto do ionCLASS.
2. Diagrama de contexto
┌───────────────────────────────────────────────┐
│ MONÓLITO LARAVEL 13 / PHP 8.5 │
│ (o backend) │
painel web ◀────▶ │ Inertia v3 + React ── páginas do painel │
(mesmo host) │ │
│ API REST v1 ──── endpoints versionados │
│ Regras de negócio ── camada de ações │
│ Drivers ──────── controle de acesso │
└───┬───────────┬───────────┬─────────┬─────────┘
│ │ │ │
Sanctum │ │ │ │ webhooks (inbound, FLUXO A)
bearer │ │ │ │ chamadas (outbound, FLUXO B)
│ │ │ │
┌─────────────────▼──┐ ┌─────▼──────┐ ┌─▼────────┐│ ┌──────────────────────┐
│ APP RESPONSÁVEL │ │ MONITOR │ │ PAINEL ││ │ CONTROLE DE ACESSO │
│ (app Expo) │ │ PORTARIA │ │ PÚBLICO │└──▶│ catraca / facial │
│ REST + X-School-Id│ │ (PWA) │ │ (kiosk) │◀───│ (terceiro) │
└────────┬───────────┘ └─────┬──────┘ └────┬─────┘ └──────────────────────┘
│ │ │
│ tempo real (WebSocket / laravel-echo + pusher-js)
▼ ▼ ▼
┌────────────────────────────────────────────────────┐
│ REVERB (WebSockets) ── canais privados/públicos │
└────────────────────────────────────────────────────┘
Suporte assíncrono do monólito:
Redis ──▶ Filas / HORIZON (workers) ──▶ broadcast dos eventos, jobs, outbound
PostgreSQL ── banco (UUIDs, trilha de auditoria imutável)Pontos de leitura do diagrama:
- Três clientes REST puros (mobile, monitor, painel público) + um painel web servido pelo próprio monólito via Inertia. Os três clientes REST não compartilham código com o backend nem entre si — só o contrato.
- O controle de acesso entra por dois fluxos: inbound (webhooks de evento/roster do hardware → backend) e outbound (comandos do backend → hardware). Detalhe nos documentos de integração com o hardware (visão geral, eventos inbound e comandos outbound).
- Reverb entrega o tempo real por WebSocket; os eventos saem assíncronos pela fila Redis processada pelo Horizon, não no caminho síncrono da requisição. Ver o documento de tempo real.
3. Repositórios independentes — não é monorepo
As quatro superfícies são versionadas e implantadas de forma independente — cada uma evolui no seu próprio ritmo, sem um "pacote guarda-chuva" que amarre todas de uma vez. O único elo entre elas é o contrato REST descrito adiante.
Consequências práticas:
- ⚠️ Nada é atômico entre superfícies. O backend pode subir sem que os clientes (app, monitor, painel público) sejam atualizados junto.
- Uma feature transversal vira várias entregas — uma por superfície afetada —, coordenadas apenas pelo contrato da API.
- Compatibilidade primeiro. Mudanças de API são aditivas (novos campos, sem renomear em silêncio) e o lado do backend vai primeiro: ele é publicado e estabilizado antes de os clientes passarem a consumir a novidade.
O painel público é a 4ª interface (adição da v2 da plataforma). Onde ele é servido/hospedado está detalhado no documento do painel público.
4. Stack por superfície
| Camada | Stack principal |
|---|---|
| backend | Laravel 13 · PHP 8.5 · Inertia v3 + React · Fortify (auth) · Sanctum (bearer API) · Wayfinder (rotas tipadas p/ o front Inertia) · Reverb (WebSockets) · Horizon (filas Redis) · Pest v5 (testes) · Larastan/PHPStan v3 · Pint (estilo) |
| mobile | Expo SDK 55 · Expo Router · React Native 0.83 · NativeWind 4 · MMKV (storage do token) · axios · zod · laravel-echo + pusher-js (tempo real) · Firebase FCM + Notifee (push) |
| monitor | Vite 6 · React 19 · TypeScript · Tailwind 4 · react-router 7 · @tanstack/react-query 5 · @dnd-kit (kanban) · laravel-echo + pusher-js (tempo real) · vite-plugin-pwa |
Observações:
- Wayfinder só serve ao front Inertia (gera funções tipadas para rotas do painel web). Os clientes REST (mobile/monitor/painel público) não usam Wayfinder — eles espelham as respostas manualmente com Zod/TypeScript.
- Cada superfície carrega as regras próprias do seu projeto (padrão de código, testes e quality gate no backend; tema e rotas tipadas no mobile; board e verificações de tipo/build no monitor). Essas regras não valem entre projetos — cada equipe segue a do seu.
5. O contrato entre cliente e backend
Os clientes REST são puros: nenhum pacote ou código compartilhado entre superfícies. O único elo é o contrato HTTP versionado.
- Versionamento
v1. Endpoints REST versionados no backend. Nada de quebra silenciosa — mudanças devem ser aditivas. - Auth Sanctum bearer sob o guard
auth:sanctum. O mobile guarda o token em MMKV; o monitor emlocalStorage(monitor.authToken). Um401limpa token + usuário nos dois. Detalhe dos dois fluxos de auth (responsável vs. operador) no documento de autenticação e autorização. - Espelhamento manual de schema. Cada cliente reflete as respostas com Zod/TS como fonte de verdade dos tipos. ⚠️ Nada automatiza esse elo: ao mudar a forma de request/response de um endpoint v1, o cliente correspondente (mobile e/ou monitor) e seu schema Zod precisam ser atualizados em lockstep.
- Escopo de escola difere por cliente. O responsável tem vínculo N:N com escolas e o mobile envia a ativa em
X-School-Id; o operador pertence a uma escola, então o monitor não envia header — o backend resolve a escola pelo token.
Onde as rotas moram
| Conjunto de rotas | Serve |
|---|---|
| API REST v1 do responsável/mobile | raiz do grupo v1 |
| Rotas do operador/monitor | subconjunto do grupo v1 |
| Painel administrativo (Inertia) e operações | páginas web servidas pelo monólito |
| Autorização dos canais de tempo real (Reverb) | handshake de assinatura dos canais |
| Autenticação e configurações do painel | fluxos de login e ajustes |
Integração com o hardware: ver o documento de visão geral da integração para os endpoints de webhook (inbound) e as chamadas outbound.
6. Organização do backend e as ações de negócio
A regra de ouro do backend é: a lógica de negócio vive em ações de negócio dedicadas, não nos controllers.
- Ações de negócio. Cada regra de negócio é uma classe de ação, nomeada pelo que faz, com um único ponto de entrada. Essas ações são chamadas de qualquer lugar — do controller HTTP, de um job de fila ou de um comando agendado. As dependências entram pelo construtor; operações que tocam vários registros rodam dentro de uma transação de banco.
Por exemplo, a confirmação de uma retirada é uma ação dedicada: recebe o aluno e o operador, aplica a regra e dispara o broadcast de tempo real — tudo num só lugar, nunca espalhado pelo controller.
Blocos mais relevantes da organização do backend:
- regras de negócio (as ações);
- endpoints REST versionados (mobile + monitor + público);
- validação de entrada por audiência;
- serialização das respostas da API;
- entidades do domínio (ver o modelo de domínio);
- os tipos/estados de domínio (ex.: estado de retirada, tipo de usuário);
- drivers de controle de acesso (integração com o hardware e um driver de simulação);
- serviços transversais (ex.: o difusor central do tempo real).
Quality gate obrigatório antes de considerar qualquer mudança pronta: estilo → testes (exigem DB) → análise estática. Detalhes e pegadinhas ficam na documentação técnica do backend.
7. Para onde ir a seguir
| Quero entender… | Documento |
|---|---|
| As entidades e os tipos do domínio | Modelo de domínio |
| As transições de estado da retirada | Ciclo de retirada |
| Como o tempo real é transmitido | Tempo real |
| Os dois fluxos de auth (responsável × operador) | Autenticação e autorização |
| A integração com o hardware | Integração com o hardware (controle de acesso) |
| Cada superfície em detalhe | App do responsável · painel administrativo · monitor de portaria · painel público |
| O produto e as personas | Produto · personas e superfícies · glossário |