Skip to content

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íciePúblicoTecnologiaComo consome o backend
App do responsávelresponsável / famíliamobile Expo (React Native)cliente REST puro (/api/v1/*)
Painel administrativostaff da escola/redeweb Inertia + Reactservido pelo próprio monólito
Monitor de portariaoperador (porteiro)PWA Vite + Reactcliente REST puro (/api/v1/*)
Painel público / kiosktela na portaria/recepçãoPWA autenticada por tokencliente 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

CamadaStack principal
backendLaravel 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)
mobileExpo 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)
monitorVite 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 em localStorage (monitor.authToken). Um 401 limpa 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 rotasServe
API REST v1 do responsável/mobileraiz do grupo v1
Rotas do operador/monitorsubconjunto do grupo v1
Painel administrativo (Inertia) e operaçõespá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 painelfluxos 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ínioModelo de domínio
As transições de estado da retiradaCiclo de retirada
Como o tempo real é transmitidoTempo real
Os dois fluxos de auth (responsável × operador)Autenticação e autorização
A integração com o hardwareIntegração com o hardware (controle de acesso)
Cada superfície em detalheApp do responsável · painel administrativo · monitor de portaria · painel público
O produto e as personasProduto · personas e superfícies · glossário

Documentação do ionCLASS