FK estudios->contactos (RESTRICT), correlativo RC en ingresos, codigos contables en saldos, endpoint /archivos (Supabase), pais_id en JWT y login; migraciones idempotentes en startup
contacto_id usa ON DELETE RESTRICT: no se puede eliminar un contacto que tenga estudios registrados (el DELETE /contactos/{id} devuelve 409).
Finanzas
cotizaciones
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
fecha
Date
NO
solicitante
Text
NO
concepto
Text
NO
monto
Numeric(15,2)
NO
moneda
String(10)
NO
'USD'
estado
String(20)
NO
'pendiente'
agregado_a_gastos
Boolean
NO
false
mes_agregado
Integer
SI
anio_agregado
Integer
SI
notas
Text
SI
fecha_creacion
DateTime
NO
utcnow
fecha_actualizacion
DateTime
NO
utcnow
miembro_id
String(30) FK → miembros
SI
SET NULL
presupuestos
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
pais
String(100)
NO
mes
Integer
SI
anio
Integer
NO
tipo_gasto
String(100)
NO
concepto
Text
SI
monto
Numeric(15,2)
NO
moneda
String(10)
NO
tasa_cambio
Numeric(15,6)
SI
notas
Text
SI
fecha_registro
DateTime
SI
utcnow
pais_id
Integer FK → paises
SI
SET NULL
ejecuciones
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
pais
String(100)
NO
mes
Integer
NO
anio
Integer
NO
monto_recibido_usd
Numeric(15,2)
NO
presupuesto_id
Integer FK → presupuestos
SI
SET NULL
notas
Text
SI
fecha_creacion
DateTime
NO
utcnow
fecha_actualizacion
DateTime
NO
utcnow
pais_id
Integer FK → paises
SI
SET NULL
gastos_reales
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
ejecucion_id
Integer FK → ejecuciones
NO
CASCADE
concepto
Text
NO
monto
Numeric(15,2)
NO
tipo_gasto
String(100)
NO
fecha_creacion
DateTime
NO
utcnow
ingresos
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
numero
String(20)
SI
pais_id
Integer FK → paises
SI
SET NULL
mes
Integer
NO
anio
Integer
NO
tipo
String(100)
NO
origen
Text
SI
donde_ingresa
String(10)
NO
valor
Numeric(15,2)
NO
observaciones
Text
SI
fecha
Date
NO
fecha_creacion
DateTime
NO
utcnow
numero es un correlativo automático por país + año + mes con formato RC-001, RC-002… Lo genera el POST /ingresos y lo devuelve en la respuesta.
saldos_caja_banco
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
pais_id
Integer FK → paises
SI
SET NULL
saldo_caja
Numeric(15,2)
NO
0
saldo_banco
Numeric(15,2)
NO
0
codigo_contable_caja
String(20)
SI
codigo_contable_banco
String(20)
SI
updated_at
DateTime
NO
utcnow
codigo_contable_caja / codigo_contable_banco guardan los códigos contables de cada cuenta (ej. 11050501 Caja General, 11200501 cuenta bancaria).
traslados
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
pais_id
Integer FK → paises
SI
SET NULL
de
String(10)
NO
a
String(10)
NO
valor
Numeric(15,2)
NO
observaciones
Text
SI
fecha
Date
NO
fecha_creacion
DateTime
NO
utcnow
archivos
Adjuntos (PDF/imagen) asociados a un ingreso o gasto. Referencia polimórfica (tipo + referencia_id), sin FK dura porque apunta a dos tablas.
Campo
Tipo
Nulleable
Default
Notas
id
Integer PK
NO
tipo
String(20)
NO
'ingreso' | 'gasto' (CHECK)
referencia_id
Integer
NO
id del ingreso / gasto asociado
nombre_original
Text
SI
content_type
String(100)
SI
tamano_bytes
BigInteger
SI
storage_path
Text
SI
ruta interna en el bucket
url
Text
NO
URL pública del archivo
fecha_creacion
DateTime
NO
utcnow
Los archivos se almacenan en Supabase Storage (el disco del Space es efímero). Requiere las variables SUPABASE_URL, SUPABASE_SERVICE_KEY, SUPABASE_BUCKET; si faltan, POST /archivos responde 503.
Configuracion
configuracion
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
clave
String(100)
NO
UNIQUE
valor
Text
NO
descripcion
Text
SI
fecha_actualizacion
DateTime
NO
utcnow
Estadisticas
estadisticas_paises
Campo
Tipo
Nulleable
Default
id
Integer PK
NO
nombre_pais
String(100)
NO
cantidad_miembros
Integer
SI
0
cantidad_estudios
Integer
SI
0
cantidad_reportes
Integer
SI
0
color
String(20)
SI
mes
Integer
SI
anio
Integer
NO
fecha_creacion
DateTime
SI
utcnow
fecha_actualizacion
DateTime
SI
utcnow
pais_id
Integer FK → paises
SI
SET NULL
Endpoints de la API
Auth
/auth
Metodo
Ruta
Descripcion
Parametros
POST
/auth/login
Iniciar sesion, devuelve JWT
Body: email, password
GET
/auth/mis-permisos
Permisos del usuario autenticado
Header: Authorization
El JWT incluye sub, rol y pais_id en el payload. La respuesta del login trae el objeto usuario con pais_id y pais_nombre.
multipart: tipo, referencia_id, file → devuelve la URL
DELETE
/archivos/{id}
Eliminar adjunto
POST /archivos sube el archivo a Supabase Storage. Valida que tipo sea ingreso/gasto (422), que la referencia exista (404) y que el almacenamiento esté configurado (503).
Usuarios
/usuarios
Metodo
Ruta
Descripcion
Parametros
GET
/usuarios
Listar usuarios
GET
/usuarios/{id}
Obtener usuario
POST
/usuarios
Crear usuario
Body: UsuarioCreate
PATCH
/usuarios/{id}
Actualizar usuario
Body: UsuarioUpdate
DELETE
/usuarios/{id}
Eliminar usuario
GET
/usuarios/{id}/permisos
Listar permisos
POST
/usuarios/{id}/permisos
Agregar permiso
Body: permiso_id
PATCH
/usuarios/{id}/permisos/{permiso_id}
Actualizar permiso
Body: tiene_acceso
DELETE
/usuarios/{id}/permisos/{permiso_id}
Quitar permiso
Roles y Permisos
/roles
Metodo
Ruta
Descripcion
Parametros
GET
/roles
Listar roles
GET
/roles/{id}
Obtener rol
POST
/roles
Crear rol
Body: RolCreate
PATCH
/roles/{id}
Actualizar rol
Body: RolUpdate
DELETE
/roles/{id}
Eliminar rol
GET
/roles/{rol_id}/permisos
Listar permisos del rol
POST
/roles/{rol_id}/permisos
Agregar permiso al rol
Body: permiso_id
PATCH
/roles/{rol_id}/permisos/{permiso_id}
Actualizar permiso del rol
Body: activo
DELETE
/roles/{rol_id}/permisos/{permiso_id}
Quitar permiso del rol
Configuracion
/configuracion
Metodo
Ruta
Descripcion
Parametros
GET
/configuracion
Listar configuracion
GET
/configuracion/{clave}
Obtener valor por clave
POST
/configuracion
Crear clave de configuracion
Body: ConfiguracionCreate
PATCH
/configuracion/{clave}
Actualizar valor
Body: ConfiguracionUpdate
DELETE
/configuracion/{clave}
Eliminar clave
Setup
# Variables de entorno requeridas
DATABASE_URL=postgresql://usuario:password@host:5432/neondb
SECRET_KEY=clave-secreta-para-jwt
ENVIRONMENT=development
# Almacenamiento de archivos (Supabase Storage) — para POST /archivos
SUPABASE_URL=https://TU_PROYECTO.supabase.co
SUPABASE_SERVICE_KEY=tu_service_role_key
SUPABASE_BUCKET=archivos
# Ejecutar con Docker
docker build -t gnit-api .
docker run -p 7860:7860 gnit-api
# Ejecutar localmente
pip install -r requirements.txt
uvicorn app.main:app --reload --port 7860