KOLOS — Single User, Multiple Contexts (Multi-atores)
Documentação KOLOS

KOLOS — Single User, Multiple Contexts (Multi-atores)

🧭 Contexto

O KOLOS tem “atores” (papéis) e o mesmo usuário pode exercer múltiplos deles.

Atores suportados no App (Flux):

Ícone Ator Role UI Descrição
🏟️ Arena Owner venue_owner App Custom (Flux) Dono da arena: gestão de quadras, operação e negócio local.
🏆 Organizer organizer App Custom (Flux) Produtor de torneios: mesa de controle, chaves e horários.
🎓 Coach coach App Custom (Flux) Professor: aulas, turmas e evolução técnica.
🛡️ Staff staff App Custom (Flux) Equipe da arena: operação (gatekeeper/check-in etc.).
🏃 Athlete player App Custom (Flux) Usuário final: “play”, reservas, inscrições e stats.

Super Admin fica isolado:

Ícone Ator Role UI Regra
👑 Super Admin super_admin Filament (/admin) Isolado do app Flux; acesso global apenas no painel.

A pergunta arquitetural é: um único login deve suportar múltiplos papéis (multi-role), e como fazemos isso sem:

  • confundir UX ("onde estou?")
  • criar brechas de segurança ("escape" de permissões)
  • acoplar tudo a middleware de role de forma rígida

Nossa stack já favorece isso:

  • Spatie Permission para roles/permissões.
  • Policies para escopo por recurso (ex.: dono da arena).
  • Livewire 4 + Flux UI no app principal.
  • Filament isolado para Super Admin.

✅ Avaliação de estratégias (prós/cons)

1) Contas separadas por ator (multi-account)

  • ✅ Simplicidade mental (cada conta tem um papel)
  • ✅ Segurança por isolamento
  • ❌ UX ruim (múltiplos logins, duplicação de dados)
  • ❌ Gestão de identidade e suporte vira problema (troca de e-mail/telefone etc.)

Conclusão: útil apenas como fallback, não como padrão.

2) Um usuário com múltiplas roles ativas (multi-role sem “modo”)

  • ✅ Menos complexidade de estado (não existe “contexto ativo”)
  • ✅ Navegação pode mostrar tudo que o usuário pode acessar
  • ❌ UX pode ficar confusa (“quais dados estou vendo?”)
  • ❌ Fácil cair em N+1 de regras na UI e esquecer de aplicar Policy

Conclusão: bom para segurança (se Policies forem a fonte da verdade), mas pode degradar UX conforme crescem features.

3) Um usuário com múltiplas roles + “Contexto Ativo” (switcher)

Exemplos de produto (analogia): Facebook/Instagram (perfil vs página), GitHub (pessoal vs organização), Google Workspace (contas/organizações).

  • ✅ UX clara: usuário escolhe “como está operando agora”
  • ✅ UI fica mais simples (navegação e defaults mudam)
  • ✅ Prepara bem “escopo de arena” (venue selecionada)
  • ⚠️ Requer disciplina: contexto ativo não pode ser usado como segurança

Conclusão: melhor estratégia para KOLOS.

🏁 Decisão

Adotar Single User + Multiple Roles, com Contexto Ativo apenas para UX.

Regras de ouro:

  1. Segurança sempre por Policy/Permission, nunca por contexto de sessão.
  2. Contexto ativo define:
    • o “modo” do app (Player / Venue / Coach …)
    • o “escopo” padrão (ex.: venue selecionada)
    • a navegação, landing pages e filtros default
  3. O mundo Super Admin continua isolado no Filament (/admin).

🔐 Modelo de autorização (fonte da verdade)

  • Permissions: capacidade geral (ex.: venue.manage_courts, venue.declare_maintenance).
  • Policies: escopo por recurso (ex.: VenuePolicy::declareMaintenance(User, Venue) valida dono/escopo).
  • Middlewares de role podem existir para “portas grossas” (ex.: esconder rotas do mundo Player), mas não substituem Policies.

🧠 O que é “Contexto Ativo” (e o que não é)

Contexto ativo é um estado leve (em sessão) para UX:

  • active_actor: enum/string (ex.: player, venue_owner, coach)
  • active_venue_id: opcional, quando o ator depende de escopo de arena

O contexto ativo não pode:

  • conceder acesso a rotas
  • permitir escrita sem Policy
  • substituir a checagem can()/authorize()

🧩 Modelagem de escopo (o ponto crítico)

A parte realmente difícil em apps multi-atores não é “ter múltiplas roles”, e sim o escopo:

  • Venue Owner tem escopo claro: é dono (venues.owner_user_id).
  • Staff/Coach precisa de vínculo explícito com arena.

Recomendação (quando chegarmos nisso): criar uma tabela de vínculo (exemplo):

  • venue_memberships
    • id
    • venue_id
    • user_id
    • role (ex.: staff, coach)
    • status (active/inactive)
    • timestamps

Assim, Policies conseguem validar:

  • “usuário é staff desta arena?”
  • “usuário é coach desta arena?”

Sem isso, qualquer liberação para staff/coach vira gambiarra.

🖥️ UX recomendada (Livewire/Flux)

  • No x-app-shell, adicionar um Profile Switcher (ex.: menu do avatar):
    • mostra papéis disponíveis ao usuário
    • troca active_actor
    • quando aplicável, pede/define active_venue_id
  • Landing page pós-login:
    • se só existe 1 ator → vai direto
    • se existem vários → sugere seleção (sem bloquear acesso, apenas UX)

Importante: se o usuário trocar para “Venue Owner”, a UI deve guiar para “Minhas arenas” e permitir escolher a arena (escopo).

🛠️ Diretrizes de implementação (quando formos codar)

  • Criar um serviço de contexto (ex.: App\Support\ActorContext) que:
    • lê/grava session('actor.active_actor')
    • lê/grava session('actor.active_venue_id')
    • valida consistência (ex.: venue selecionada pertence ao usuário)
  • Middleware opcional “UX-only” para garantir que o contexto está setado antes de certas telas (redireciona para seleção).
  • Livewire:
    • preferir #[Locked] para IDs derivados do contexto quando necessário.
    • nunca confiar em IDs vindos do client sem Policy.

🧪 Validação

  • Testes de Policy continuam sendo a garantia real.
  • Feature tests garantem:
    • usuário multi-role acessa as áreas que pode
    • troca de contexto muda navegação/landing, mas não “cria permissão”

📦 Impacto

  • Impacto imediato: documentação + direção arquitetural.
  • Impacto futuro: criação do switcher e do modelo de membership para staff/coach.