| Rol | Alcance |
|---|---|
| platform_admin | Todo (soporte interno) |
| entidad_admin | Datos de su tenant (convocatorias, municipios, evaluaciones) |
| municipio_user | Sus submissions + convocatoria asignada |
Todas las tablas con datos de negocio tienen RLS activado. Las policies siguen este patrón:
-- El usuario solo ve registros de su tenant
CREATE POLICY "tenant_isolation" ON tabla
USING (tenant_id = (SELECT tenant_id FROM profiles WHERE id = auth.uid()));-- municipio_user solo ve sus propias submissions
CREATE POLICY "municipio_own_submissions" ON submissions
USING (
municipio_id IN (
SELECT municipio_id FROM profiles WHERE id = auth.uid()
)
);- Riesgo: Usuario inyecta instrucciones maliciosas en campos MGA que llegan al LLM.
- Mitigación:
- System prompt con instrucciones estrictas y output schema fijo (Zod).
- Separación clara entre instrucciones del sistema y datos del usuario.
- No ejecutar código generado por el LLM.
- Rate limiting por usuario/tenant.
- Riesgo: Un tenant accede a datos de otro tenant.
- Mitigación:
- RLS en todas las tablas.
- RAG filtrado por
convocatoria_id(aislamiento de embeddings). - Queries server-side siempre pasan por Supabase client autenticado.
- Nunca usar
service_rolekey en el frontend.
- Riesgo: Usuario sin autenticación accede a rutas protegidas.
- Mitigación:
- Middleware de Next.js verifica sesión en todas las rutas protegidas.
- Supabase Auth con refresh automático de tokens.
- Redirects a /login si no hay sesión válida.
- Mitigación:
.env.examplesin valores reales..envy.env.localen.gitignore.- Variables sensibles solo en Vercel Environment Variables.
SUPABASE_SERVICE_ROLE_KEYsolo en server-side.
- Endpoint IA: máx 10 requests/minuto por usuario.
- Implementación vía contador en tabla o middleware simple.