gnit-api / README.md
Laevateinn707's picture
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
a863251
|
Raw
History Blame Contribute Delete
40 kB
---
title: GNIT API
emoji: 🐳
colorFrom: purple
colorTo: gray
sdk: docker
app_port: 7860
---
# GNIT API
API REST para la plataforma GNIT — gestión de miembros, contactos, estudios bíblicos, reportes, finanzas y más.
- **Stack:** FastAPI + SQLAlchemy asyncio + PostgreSQL 16 (Neon)
- **Documentacion interactiva:** `/docs` (Swagger UI) | `/redoc` (ReDoc)
- **Health check:** `/health`
---
## Base de Datos
### Geografia
#### `continentes`
| Campo | Tipo | Nulleable | Default |
|----------|---------------|-----------|---------|
| id | Integer PK | NO | |
| nombre | String(100) | NO | |
#### `paises`
| Campo | Tipo | Nulleable | Default |
|---------------|--------------------------|-----------|------------|
| id | Integer PK | NO | |
| iso | String(2) | SI | |
| nombre | String(100) | NO | |
| continente_id | Integer FK → continentes | SI | SET NULL |
#### `ciudades`
| Campo | Tipo | Nulleable | Default |
|--------------|--------------------------|-----------|------------|
| id | Integer PK | NO | |
| nombre | String(100) | NO | |
| nombre_ascii | String(100) | SI | |
| lat | Numeric(10,7) | SI | |
| lng | Numeric(10,7) | SI | |
| pais_iso2 | String(2) FK → paises | SI | SET NULL |
| admin_name | String(100) | SI | |
| capital | String(20) | SI | |
| population | BigInteger | SI | |
| worldcity_id | BigInteger | SI | |
---
### Usuarios y Roles
#### `usuarios`
| Campo | Tipo | Nulleable | Default |
|---------------|--------------------------|-----------|------------|
| id | String(30) PK | NO | |
| nombre | Text | NO | |
| email | Text | NO | UNIQUE |
| password_hash | Text | NO | |
| rol | Integer FK → roles | NO | |
| fecha_registro| DateTime | NO | utcnow |
| activo | Boolean | NO | false |
| region | String(20) | SI | |
| pais_id | Integer FK → paises | SI | SET NULL |
| ciudad_id | Integer FK → ciudades | SI | SET NULL |
| miembro_id | String(30) FK → miembros | SI | SET NULL |
#### `roles`
| Campo | Tipo | Nulleable | Default |
|------------|---------------|-----------|---------|
| id | Integer PK | NO | |
| nombre | String(30) | NO | '' |
| descripcion| String(100) | SI | |
#### `rol_permisos`
| Campo | Tipo | Nulleable | Default |
|------------|--------------------------|-----------|---------|
| rol_id | Integer FK → roles | NO | PK |
| permiso_id | Integer | NO | PK |
| activo | Boolean | SI | true |
#### `usuario_permisos`
| Campo | Tipo | Nulleable | Default |
|-------------|----------------------------|-----------|----------|
| id | Integer PK | NO | |
| usuario_id | String(30) FK → usuarios | NO | CASCADE |
| permiso_id | Integer | NO | |
| tiene_acceso| Boolean | SI | true |
---
### Personas
#### `miembros`
| Campo | Tipo | Nulleable | Default |
|-------------------|--------------------------|-----------|------------|
| id | String(30) PK | NO | |
| nombre | Text | NO | |
| identidad | String(30) | SI | |
| pais | Text | SI | |
| ciudad | Text | SI | |
| edad | Integer | SI | |
| evangelizado_por | Text | SI | |
| estado_civil | Text | SI | |
| profesion | Text | SI | |
| comentarios | Text | SI | |
| tipo_miembro | String(20) | NO | |
| pais_id | Integer FK → paises | SI | SET NULL |
| ciudad_id | Integer FK → ciudades | SI | SET NULL |
| cargo_funcion | Text | SI | |
| ministerio_of | Text | SI | |
| avance_audio | Text | SI | |
#### `miembros_info_adicional`
| Campo | Tipo | Nulleable | Default |
|--------------------|----------------------------|-----------|------------|
| id | String(30) PK FK → miembros| NO | CASCADE |
| nombre_padre | Text | SI | |
| telefono_padre | String(30) | SI | |
| nombre_madre | Text | SI | |
| telefono_madre | String(30) | SI | |
| tipo_sangre | String(5) | SI | |
| correo_electronico | String(255) | SI | |
| fecha_creacion | DateTime | NO | utcnow |
| fecha_actualizacion| DateTime | NO | utcnow |
#### `contactos`
| Campo | Tipo | Nulleable | Default |
|-----------------------|------------------------------|-----------|------------|
| id | Integer PK | NO | |
| miembro_responsable | Text | NO | |
| nombre | Text | NO | |
| telefono | Text | SI | |
| pais | Text | SI | |
| notas | Text | SI | |
| profesion | Text | SI | |
| fecha_creacion | DateTime | SI | utcnow |
| pais_id | Integer FK → paises | SI | SET NULL |
| miembro_responsable_id| String(30) FK → miembros | SI | SET NULL |
| ciudad_id | Integer FK → ciudades | SI | SET NULL |
---
### Misiones y Estudios
#### `ciudades_mision`
| Campo | Tipo | Nulleable | Default |
|--------------------------|---------------------------|-----------|---------------|
| id | Integer PK | NO | |
| ciudad_id | Integer FK → ciudades | NO | SET NULL |
| region | String(150) | SI | |
| estado_presencia | String(30) | NO | 'En proceso' |
| fecha_inicio_trabajo | Date | SI | |
| pastor_encargado_id | String(30) | SI | |
| pastor_encargado_nombre | Text | SI | |
| cantidad_miembros_activos| Integer | SI | 0 |
| notas | Text | SI | |
| fecha_creacion | DateTime | NO | utcnow |
| fecha_actualizacion | DateTime | NO | utcnow |
#### `reportes`
| Campo | Tipo | Nulleable | Default |
|------------------------|--------------------------|-----------|------------|
| id | Integer PK | NO | |
| miembro_que_reporta | Text | NO | |
| fecha | Date | NO | |
| tiempo_evangelizacion | Interval | SI | |
| contactos_obtenidos | Integer | SI | 0 |
| contactos_estudian | Integer | SI | 0 |
| numero_estudios_dados | Integer | SI | 0 |
| total_estudiantes | Integer | SI | 0 |
| pais | Text | SI | |
| fecha_creacion | DateTime | SI | utcnow |
| pais_id | Integer FK → paises | SI | SET NULL |
| miembro_id | String(30) FK → miembros | SI | SET NULL |
| ciudad_id | Integer FK → ciudades | SI | SET NULL |
#### `estudios_diarios`
| Campo | Tipo | Nulleable | Default |
|-----------------|------------------------------|-----------|------------|
| id | Integer PK | NO | |
| miembro_id | String(30) FK → miembros | NO | CASCADE |
| pais_id | Integer FK → paises | SI | SET NULL |
| contacto_id | Integer FK → contactos | SI | RESTRICT |
| mes | Integer | NO | |
| anio | Integer | NO | |
| dia | Integer | NO | |
| capitulo | String(255) | SI | |
| horas | Numeric(5,2) | SI | |
| tipo | String(50) | SI | |
| donde | String(255) | SI | |
| dijeron_si | Integer | SI | 0 |
| nuevos_contactos| Integer | SI | 0 |
| fecha_creacion | DateTime | NO | utcnow |
> `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`.
### Miembros
`/miembros`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/miembros` | Listar miembros | `?tipo=&pais_id=` |
| GET | `/miembros/{id}` | Obtener miembro por ID | |
| POST | `/miembros` | Crear miembro | Body: MiembroCreate |
| PATCH | `/miembros/{id}` | Actualizar miembro | Body: MiembroUpdate |
| DELETE | `/miembros/{id}` | Eliminar miembro | |
### Miembros Info Adicional
`/miembros-info-adicional`
| Metodo | Ruta | Descripcion | Parametros |
|--------|-------------------------------------------|---------------------------|--------------------------------|
| GET | `/miembros-info-adicional` | Listar info adicional | `?id=` |
| GET | `/miembros-info-adicional/{id}` | Obtener por ID de miembro | |
| POST | `/miembros-info-adicional` | Crear info adicional | Body: MiembroInfoAdicionalCreate |
| PATCH | `/miembros-info-adicional/{id}` | Actualizar info adicional | Body: MiembroInfoAdicionalUpdate |
| DELETE | `/miembros-info-adicional/{id}` | Eliminar info adicional | |
### Contactos
`/contactos`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|------------------------------------------------|
| GET | `/contactos` | Listar contactos | `?miembro_responsable_id=&pais_id=` |
| GET | `/contactos/{id}` | Obtener contacto | |
| POST | `/contactos` | Crear contacto | Body: ContactoCreate |
| PATCH | `/contactos/{id}` | Actualizar contacto | Body: ContactoUpdate |
| DELETE | `/contactos/{id}` | Eliminar contacto (**409** si tiene estudios) | |
### Estudios Diarios
`/estudios-diarios`
| Metodo | Ruta | Descripcion | Parametros |
|--------|------------------------------|--------------------------|--------------------------------------|
| GET | `/estudios-diarios` | Listar estudios diarios | `?miembro_id=&pais_id=&anio=&mes=` |
| GET | `/estudios-diarios/{id}` | Obtener estudio | |
| POST | `/estudios-diarios` | Crear estudio | Body: EstudioDiarioCreate |
| PATCH | `/estudios-diarios/{id}` | Actualizar estudio | Body: EstudioDiarioUpdate |
| DELETE | `/estudios-diarios/{id}` | Eliminar estudio | |
### Reportes
`/reportes`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/reportes` | Listar reportes | `?miembro_id=&pais_id=&anio=` |
| GET | `/reportes/{id}` | Obtener reporte | |
| POST | `/reportes` | Crear reporte | Body: ReporteCreate |
| PATCH | `/reportes/{id}` | Actualizar reporte | Body: ReporteUpdate |
| DELETE | `/reportes/{id}` | Eliminar reporte | |
### Estadisticas Generales
`/estadisticas`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|------------------------------------------------------------------|------------|
| GET | `/estadisticas` | Dashboard: comparacion estudios, rendimiento, evangelismo, crecimiento | `?anio=` |
### Estadisticas por Pais
`/estadisticas-paises`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------------|--------------------------|--------------------------|
| GET | `/estadisticas-paises` | Listar estadisticas | `?pais_id=&anio=&mes=` |
| GET | `/estadisticas-paises/{id}` | Obtener estadistica | |
| POST | `/estadisticas-paises` | Crear estadistica | Body: EstadisticaPaisCreate |
| PATCH | `/estadisticas-paises/{id}` | Actualizar estadistica | Body: EstadisticaPaisUpdate |
| DELETE | `/estadisticas-paises/{id}` | Eliminar estadistica | |
### Paises
`/paises`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/paises` | Listar paises | |
| GET | `/paises/{id}` | Obtener pais | |
| POST | `/paises` | Crear pais | Body: PaisCreate |
| PATCH | `/paises/{id}` | Actualizar pais | Body: PaisUpdate |
| DELETE | `/paises/{id}` | Eliminar pais | |
### Continentes
`/continentes`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/continentes` | Listar continentes | |
| GET | `/continentes/{id}` | Obtener continente | |
| POST | `/continentes` | Crear continente | Body: ContinenteCreate |
| PATCH | `/continentes/{id}` | Actualizar continente | Body: ContinenteUpdate |
| DELETE | `/continentes/{id}` | Eliminar continente | |
### Ciudades
`/ciudades`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|-----------------------------------|
| GET | `/ciudades` | Listar ciudades | `?pais_iso2=&limit=&offset=` |
| GET | `/ciudades/{id}` | Obtener ciudad | |
| POST | `/ciudades` | Crear ciudad | Body: CiudadCreate |
| PATCH | `/ciudades/{id}` | Actualizar ciudad | Body: CiudadUpdate |
| DELETE | `/ciudades/{id}` | Eliminar ciudad | |
### Ciudades Mision
`/ciudades-mision`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------------|--------------------------|--------------------------------|
| GET | `/ciudades-mision` | Listar ciudades mision | `?ciudad_id=&estado_presencia=` |
| GET | `/ciudades-mision/{id}` | Obtener ciudad mision | |
| POST | `/ciudades-mision` | Crear ciudad mision | Body: CiudadMisionCreate |
| PATCH | `/ciudades-mision/{id}` | Actualizar ciudad mision| Body: CiudadMisionUpdate |
| DELETE | `/ciudades-mision/{id}` | Eliminar ciudad mision | |
### Cotizaciones
`/cotizaciones`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------------|
| GET | `/cotizaciones` | Listar cotizaciones | `?estado=&miembro_id=&anio=&mes=` |
| GET | `/cotizaciones/{id}` | Obtener cotizacion | |
| POST | `/cotizaciones` | Crear cotizacion | Body: CotizacionCreate |
| PATCH | `/cotizaciones/{id}` | Actualizar cotizacion | Body: CotizacionUpdate |
| DELETE | `/cotizaciones/{id}` | Eliminar cotizacion | |
### Presupuestos
`/presupuestos`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------------|
| GET | `/presupuestos` | Listar presupuestos | `?pais_id=&anio=&mes=&tipo_gasto=` |
| GET | `/presupuestos/{id}` | Obtener presupuesto | |
| POST | `/presupuestos` | Crear presupuesto | Body: PresupuestoCreate |
| PATCH | `/presupuestos/{id}` | Actualizar presupuesto | Body: PresupuestoUpdate |
| DELETE | `/presupuestos/{id}` | Eliminar presupuesto | |
### Ejecuciones
`/ejecuciones`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/ejecuciones` | Listar ejecuciones | `?pais_id=&anio=&mes=` |
| GET | `/ejecuciones/{id}` | Obtener ejecucion | |
| POST | `/ejecuciones` | Crear ejecucion | Body: EjecucionCreate |
| PATCH | `/ejecuciones/{id}` | Actualizar ejecucion | Body: EjecucionUpdate |
| DELETE | `/ejecuciones/{id}` | Eliminar ejecucion | |
### Gastos Reales
`/gastos-reales`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/gastos-reales` | Listar gastos reales | `?ejecucion_id=` |
| GET | `/gastos-reales/{id}` | Obtener gasto | |
| POST | `/gastos-reales` | Crear gasto | Body: GastoRealCreate |
| PATCH | `/gastos-reales/{id}` | Actualizar gasto | Body: GastoRealUpdate |
| DELETE | `/gastos-reales/{id}` | Eliminar gasto | |
### Ingresos
`/ingresos`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|----------------------------------------------|
| GET | `/ingresos` | Listar ingresos | `?pais_id=&anio=&mes=&tipo=&donde_ingresa=` |
| GET | `/ingresos/{id}` | Obtener ingreso | |
| POST | `/ingresos` | Crear ingreso (genera `numero` RC-###) | Body: IngresoCreate |
| PATCH | `/ingresos/{id}` | Actualizar ingreso | Body: IngresoUpdate |
| DELETE | `/ingresos/{id}` | Eliminar ingreso | |
### Saldos Caja / Banco
`/saldos-caja-banco`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------------|--------------------------|--------------------------|
| GET | `/saldos-caja-banco` | Listar saldos | `?pais_id=` |
| GET | `/saldos-caja-banco/{id}` | Obtener saldo | |
| POST | `/saldos-caja-banco` | Crear saldo | Body: SaldoCajaBancoCreate |
| PATCH | `/saldos-caja-banco/{id}` | Actualizar saldo | Body: SaldoCajaBancoUpdate |
| DELETE | `/saldos-caja-banco/{id}` | Eliminar saldo | |
### Traslados
`/traslados`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|--------------------------------|--------------------------------|
| GET | `/traslados` | Listar traslados | `?pais_id=&anio=&mes=` |
| GET | `/traslados/{id}` | Obtener traslado | |
| POST | `/traslados` | Crear traslado | Body: TrasladoCreate |
| PATCH | `/traslados/{id}` | Actualizar traslado | Body: TrasladoUpdate |
| DELETE | `/traslados/{id}` | Eliminar traslado | |
### Archivos
`/archivos`
| Metodo | Ruta | Descripcion | Parametros |
|--------|--------------------------|-----------------------------------------------|-----------------------------------------------------|
| GET | `/archivos` | Listar adjuntos | `?tipo=&referencia_id=` |
| POST | `/archivos` | Subir adjunto y asociarlo a un ingreso/gasto | 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
```bash
# 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
```