0002. Stack de herramientas y librerías de svc-identidad¶
Estado: Aceptado Fecha: 2026-08-31 Autor: Duval Alcivar Módulo(s) afectado(s): svc-identidad (todo el servicio)
Contexto¶
El ADR 0001 define svc-identidad como un microservicio FastAPI dentro del
core de plataforma, dueño de usuarios, empresas, sucursales y permisos. Su
implementación toca datos sensibles (credenciales, tokens, tenencia), así
que la elección de librerías y herramientas determina directamente la
seguridad, la mantenibilidad y la capacidad de testearla. Falta fijar el
stack concreto: ORM, migraciones, validación, autenticación, gestión de
dependencias, testing, calidad de código, documentación y contenedores —
consistente con el resto del backend (ADR 0001 y 0005 globales).
Decisión¶
svc-identidad usa el siguiente stack, uniforme con el resto de los
microservicios y fijado por norma (no por preferencia de cada developer):
| Área | Herramienta | Justificación |
|---|---|---|
| Lenguaje | Python 3.12+ | versión LTS del proyecto (ADR 0005 global); typing moderno (X \| None) y mejor rendimiento de asyncio |
| Framework | FastAPI | estándar del proyecto; emite el JWT (ADR 0006) y expone el JWKS; OpenAPI autogenerado |
| ORM | SQLAlchemy 2.0 | mapeo declarativo con integración a FastAPI; consultas siempre parametrizadas (inmunes a inyección SQL) |
| Migraciones | Alembic | cada cambio de esquema es un archivo versionado y reproducible |
| Validación | Pydantic v2 | contrato tipado en toda frontera de entrada/salida; interopera con FastAPI |
| Autenticación | JWT (access + refresh) + Argon2 | tokens firmados RS256 (ADR 0006 transversal) y hash de contraseñas Argon2id (ADR 0011) |
| Dependencias | Poetry + pyproject.toml |
gestión de venv + dependencias + lockfile (poetry.lock) reproducible en un solo comando (ADR 0005 global) |
| Testing | pytest + pytest-cov + httpx | unitario e integración con cobertura; httpx asíncrono para probar endpoints sin levantar servidor |
| Calidad | Ruff + Black + mypy | lint, formato y tipado estático en CI: catálogo de errores antes de producir |
| Documentación | OpenAPI (Swagger / Redoc) | autogenerada por FastAPI desde los schemas Pydantic |
| Contenedores | Docker + docker-compose | entornos locales reproducibles idénticos a los del pipeline |
| CI | Pipeline (lint + type-check + tests) | puerta de cada pull request; nada se mergea sin pasar las 3 etapas |
Detalles por herramienta¶
ORM — SQLAlchemy 2.0. Todo acceso a datos pasa por el repository (ADR
0001 global) usando consultas parametrizadas (posición de parámetros o
text() con bind params). Queda prohibido concatenar valores del usuario en
un string SQL. El aislamiento por empresa lo garantizan RLS + el
middleware (ADR 0012): el middleware setea app.current_empresa_id una vez
por request; los repositorios no inyectan ni filtran por empresa_id en
cada query (no escriben WHERE empresa_id ni SET). RLS filtra
automáticamente.
Migraciones — Alembic. Una migración por cambio de esquema, versionada
en alembic/versions/ y aplicada por el pipeline. Queda prohibido alterar
el esquema por fuera de Alembic (ej. create_table manual en producción).
Validación — Pydantic v2. Cada request y cada response del servicio se define con un schema Pydantic (estructura del ADR 0001/0004 global). FastAPI valida entrada/salida automáticamente y alimenta el OpenAPI.
Autenticación — JWT + Argon2. Firma RS256 del JWT y hashing Argon2id de
contraseñas, según el detalle del ADR 0011 (login) y el ADR 0006 global.
svc-identidad es el único que firma; los demás validan (ADR 0006).
Gestión de dependencias — Poetry. Poetry gestiona el venv, las
dependencias (declaradas en pyproject.toml, sección [tool.poetry]) y el
lockfile (poetry.lock) reproducible en un solo comando (ADR 0005 global).
Cada desarrollador corre poetry install en el proyecto y queda con el mismo
entorno que CI.
Testing — pytest + pytest-cov + httpx. Estructura
tests/unit/<dominio> e tests/integration/<dominio> (ADR 0001). pytest-cov
exige cobertura mínima; httpx prueba los endpoints FastAPI con un
AsyncClient sin necesidad de arrancar el servidor.
Calidad — Ruff + Black + mypy. Ruff para lint (reemplaza flake8 + isort), Black para formato y mypy en modo estricto para tipado estático. Los tres corren en CI antes que los tests.
Documentación — OpenAPI. FastAPI genera Swagger (/docs) y Redoc
(/redoc) desde los schemas Pydantic, sin código extra; es el contrato que
consume el frontend (ADR 0007 global).
Contenedores — Docker + docker-compose. Dockerfile multi-etapa (build →
runtime) y docker-compose.yml que levanta el servicio + Postgres local.
El entorno local equivale al de producción, eliminando el "en mi máquina
funciona".
CI — lint + type-check + tests en cada PR. El pipeline ejecuta, en orden: Ruff → Black --check → mypy → pytest (con cobertura). Un fallo en cualquier etapa bloquea el merge del PR.
Alternativas descartadas¶
- ORM: Django ORM — descartado: arrastra Django REST Framework y su modelo de app completo; sobre FastAPI ya elegido (ADR 0001) añade peso sin ventaja.
- ORM: Tortoise-ORM / asyncpg a pelo — descartados: menor ecosistema y documentación que SQLAlchemy 2.0; SQL crudo dificulta el testeo y el refactor del repository.
- Gestión de dependencias: pip + requirements.txt — descartado por no
fijar resolución reproducible; no separa dev/runtime ni genera un lockfile
como Poetry (
poetry.lock). - Testing: unittest / doctest — descartado: no manejan bien el
pytestavanzado (fixtures, parametrize, asyncio) ni la cobertura con scripts propios. - Calidad: flake8 + isort por separado — descartado: herramientas duplicadas y configuración repartida; Ruff unifica lint + formato en una sola con velocidad Rústica.
- No usar mypy — descartado: sin tipado estático, los contratos Pydantic/SQLAlchemy no se verifican en compile-time y los errores escalan a producción.
Consecuencias¶
- Un solo stack estandarizado reduce la curva de onboarding y hace que
cualquier developer del equipo pueda abrir y tocar
svc-identidad. - La seguridad por defecto: consultas parametrizadas (sin inyección SQL), Argon2id (sin claves en texto plano/usables) y JWT firmado (sin tokens falsificables por servicios no autorizados).
- La CI actúa como puerta obligatoria: ningún PR sin pasar Ruff + Black + mypy + pytest se mergea.
- Los parámetros concretos de Argon2id y los tiempos de expiración de tokens quedan resueltos en el ADR 0020; el catálogo inicial de permisos por módulo quedó resuelto en el ADR 0014 (definido en el 0007).
- El stack es común al resto del backend: cualquier decisión de este ADR que se cambie en un servicio debe replicarse aquí (o compartirse en el core/Autores ADR global).
Este ADR fija el cómo se construye svc-identidad; el ADR 0011 define el
cómo se autentica (login, firma JWT, claves) y el ADR 0001 define el qué
domina.