{"id":"repo/auth-rbac-data-scope-plan","source":"repo","sourceLabel":"repository root","sourcePath":"AUTH_RBAC_DATA_SCOPE_PLAN.md","routePath":"/fastapp/public-docs/page/repo/auth-rbac-data-scope-plan","rawPath":"/fastapp/public-docs/raw/repo/auth-rbac-data-scope-plan","slug":["repo","auth-rbac-data-scope-plan"],"slugPath":"repo/auth-rbac-data-scope-plan","title":"Auth/RBAC por App Membership em /api/v1/data","description":"Atualizado em: 2026 02 27","headings":["Auth/RBAC por App Membership em /api/v1/data","Objetivo","Status Atual","Implementado","Ajuste de abilities","Plano Tecnico por Camadas","1) Frontend","2) Backend (Nuxt BFF)","3) Backend (Laravel API)","4) Schema","5) Dados","Criterios de Aceite","Validacao de Regressao","Observacoes"],"wordCount":518,"markdown":"# Auth/RBAC por App Membership em `/api/v1/data`\r\n\r\nAtualizado em: 2026-02-27\r\n\r\n## Objetivo\r\nGarantir isolamento de acesso por `app` e por papel do usuario em todas as rotas `GET/POST/PATCH/DELETE` de `/api/v1/data/*`, com suporte a restricao por propriedade (`constraint_property`) quando configurada.\r\n\r\n## Status Atual\r\n\r\n### Implementado\r\n- Enforce global no BFF Nuxt para toda rota `/api/v1/data/*`.\r\n- Decisao de acesso central no Laravel via `GET /api/v1/auth/app-access/{appName}`.\r\n- Aplicacao de constraint por dado nos handlers de:\r\n  - listagem;\r\n  - lookup;\r\n  - dashboard metrics;\r\n  - leitura por id;\r\n  - update por id;\r\n  - delete por id;\r\n  - create.\r\n- Suporte a aliases de app (`-` e `_`) na validacao.\r\n- Suporte a membership curinga `app='*'` no endpoint `app-access` (acesso global por membership).\r\n- Usuarios privilegiados com membership `owner` em todos os apps conhecidos e tambem em `task-board`/`task_board`.\r\n\r\n### Ajuste de abilities\r\n- Como o schema atual de `users` neste ambiente nao possui colunas `role` e `custom_abilities`, o calculo de abilities globais foi adaptado:\r\n  - se houver membership ativo `app='*'` com role `owner/admin`, `allAbilities()` retorna `['*']`.\r\n- Resultado esperado apos novo login: `abilities` no auth devem incluir `*`.\r\n\r\n## Plano Tecnico por Camadas\r\n\r\n### 1) Frontend\r\n- Continuar enviando `auth_token` (cookie) e/ou `Authorization: Bearer`.\r\n- Enviar contexto de `app` quando necessario (`?app=` ou `x-fastapp-app`) em casos ambiguos.\r\n- Exibir UX consistente:\r\n  - `401` para sessao/token invalido;\r\n  - `403` para bloqueio de escopo/permissao.\r\n\r\n### 2) Backend (Nuxt BFF)\r\n- Middleware `server/middleware/rbac-data-scope.ts`:\r\n  - intercepta `/api/v1/data/*`;\r\n  - resolve `object` e `action` (`read/create/update/delete/lookup/metrics`);\r\n  - resolve `app` por query/header/referer + metadata do objeto;\r\n  - valida no Laravel (`/api/v1/auth/app-access/{app}`), com fallback em `/api/v1/auth/me` para compatibilidade;\r\n  - injeta escopo em `event.context.rbacDataScope`.\r\n- Utilitario `server/utils/rbac-data-scope.ts`:\r\n  - injeta constraint no `where`;\r\n  - injeta/valida constraint no body de escrita;\r\n  - valida registro por `id` dentro do escopo;\r\n  - injeta constraint na query forward para fontes externas.\r\n\r\n### 3) Backend (Laravel API)\r\n- Endpoint `GET /api/v1/auth/app-access/{appName}`:\r\n  - valida membership no app solicitado;\r\n  - considera aliases e membership curinga `*`;\r\n  - resolve permissao por role + acao + objeto;\r\n  - aplica fallback conservador para leitura quando nao ha matriz de permissao;\r\n  - retorna `constraint` quando existir `constraint_property`.\r\n\r\n### 4) Schema\r\n- `fastapp_permission` deve manter convencao de nomes de permissao:\r\n  - `objeto-read|create|update|delete`, `data.read`, `data:create`, etc.\r\n- Para escopo por dono/equipe, preencher `constraint_property` (ex.: `owner_id`, `team_id`).\r\n\r\n### 5) Dados\r\n- `fastapp_user_app` e a fonte principal de autorizacao por app.\r\n- Para acesso total administrado por membership, manter:\r\n  - memberships por app com role `owner`; ou\r\n  - membership curinga `app='*'` com role `owner`.\r\n- Garantir `reference_id`/`reference_object` quando `constraint_property` exigir.\r\n\r\n## Criterios de Aceite\r\n1. Sem token, qualquer rota `/api/v1/data/*` retorna `401`.\r\n2. Sem membership valido no app (nem curinga `*`), retorna `403`.\r\n3. Com membership `owner/admin`, operacoes `POST/PATCH/DELETE` sao permitidas.\r\n4. Com membership de leitura apenas, escrita retorna `403`.\r\n5. Com `constraint_property`, leitura e escrita respeitam o escopo por registro.\r\n6. Com membership curinga `*` role `owner`, acesso deve funcionar em app novo sem cadastro manual previo.\r\n7. `GET /api/v1/auth/me` e login devem refletir `abilities: ['*']` para usuario com membership curinga `*` owner/admin (apos novo login/token).\r\n\r\n## Validacao de Regressao\r\n1. Smoke por rota:\r\n   - `GET /api/v1/data/:object`\r\n   - `POST /api/v1/data/:object`\r\n   - `GET /api/v1/data/:object/:id`\r\n   - `PATCH /api/v1/data/:object/:id`\r\n   - `DELETE /api/v1/data/:object/:id`\r\n   - `GET /api/v1/data/:object/lookup`\r\n   - `GET /api/v1/data/:object/dashboard-metrics`\r\n2. Matriz de papeis por app:\r\n   - `owner/admin/member/viewer` x `read/create/update/delete`.\r\n3. Casos de app ambiguo:\r\n   - mesmo `object` em apps diferentes com `?app=` distinto.\r\n4. Casos de aliases:\r\n   - `task-board` vs `task_board`;\r\n   - `central-filtros` vs `central_filtros`.\r\n5. Caso curinga:\r\n   - usuario com app `*` consegue acessar app nao previamente cadastrado no membership nominal.\r\n6. Fontes externas:\r\n   - confirmar forward de constraint e bloqueio por membership.\r\n7. Nao regressao funcional:\r\n   - envelope legado `{ total, limit, skip, data }` preservado.\r\n\r\n## Observacoes\r\n- O projeto legado `api-fastapp-cloud` nao entra no fluxo ativo.\r\n- Base ativa considerada: `laravel-api`.\r\n- O typecheck global do `lead-nuxt` possui erros preexistentes fora deste escopo; validar regressao focando nas rotas RBAC e no fluxo de auth.\r\n"}