Postgres, PostGraphile, RLS y SQL
Resumen
Mecanismo de capa de datos para este stack. Implementa defensa en profundidad (RLS como muro final) y la única ruta de datos legal. Específico del stack: no aplica a proyectos sin PostGraphile/Postgres.
La Ruta de Datos
Navegador → Servidor de aplicación → PostGraphile → PostgreSQL. Exactamente una ruta legal.
- El navegador nunca habla directamente con GraphQL/BD; la aplicación nunca consulta la BD directamente para datos de aplicación.
- La aplicación pasa contexto de sesión solo como cabeceras (id de usuario, pista de organización) — sin lógica de autorización en la aplicación; el contexto se valida aguas abajo, no se confía en él.
- Una sola ruta = un solo lugar para imponer contexto de autenticación, validación y RLS. Los canales laterales son los agujeros que eluden la imposición.
Reglas de Seguridad
- RLS es la capa de imposición final. Las comprobaciones a nivel de aplicación son de UX; la base de datos es el muro. Incluso un error en las capas superiores no puede filtrar filas de otro inquilino.
- Los roles modelan estados de sesión reales — no-autenticado, autenticado-sin-organización, autenticado-con-organización, un rol solo de conexión, un rol solo de migraciones. Los roles significan algo.
- El rol de conexión privilegiado nunca ejecuta consultas de aplicación. Las consultas de aplicación se ejecutan bajo un rol restringido y sujeto a RLS.
- Las funciones
SECURITY DEFINERestablecensearch_pathen línea en su definición — cada vez, sin excepciones. - La ausencia es
NULL, nunca una cadena vacía. Los centinelas de cadena vacía están prohibidos; omite el valor cuando esté ausente. - GraphQL es una superficie de Denegación de Servicio (DoS) — delimítalo. Impón límites de profundidad de consulta y análisis de costo/complejidad; rechaza consultas que excedan el presupuesto. Limita el tamaño de paginación. Establece un
statement_timeoutde BD para roles de aplicación. Desactiva la introspección en producción a menos que sea deliberadamente necesario.
Estilo SQL
- Un objeto por archivo — cada tabla, función, política, concesión en su propio archivo.
- Organizado por
schema/tipo_objeto/nombre— el directorio refleja la organización de la base de datos. - El orden de inclusión es el orden de dependencias; el manifiesto de inclusión es la tabla de contenidos.
- Documenta en línea.
COMMENT ONvive en el mismo archivo que el objeto — qué y por qué. - Alias descriptivos (singular del nombre de la tabla, no letras sueltas); sigue los modismos de Postgres (getters
current_*). - Los tipos y roles orientados al usuario son datos, no restricciones codificadas — tablas de búsqueda con clave/etiqueta/descripción, validadas por FK, extensibles sin cambios de esquema.
Referencia Rápida
| Regla | Comprobación |
|---|---|
Nueva función SECURITY DEFINER | ¿search_path establecido en línea? |
| Nueva tabla con datos de inquilino | ¿Política RLS + pruebas de denegación (ver graphql-contract-testing)? |
| Valor ausente | ¿NULL, no ''? |
| Nueva superficie GraphQL | ¿Límite de profundidad/costo y límite de paginación? |
| Nuevo objeto | ¿Archivo propio, inclusión ordenada por dependencias, COMMENT ON en línea? |
Razonamiento completo: Artículos XIII, XIV, XVIII de la constitución, empaquetados en engineering-constitution/references/engineering-constitution.md. Migraciones: zero-downtime-migrations. Pruebas de contrato: graphql-contract-testing.