- Schemas Zod:
packages/contracts/src/v1 - Tipos TypeScript:
@maxflow/contractsy@maxflow/contracts/v1 - Guia de versionado:
docs/30-api/OpenAPI.md - Estrategia de validacion:
docs/30-api/ValidationStrategy.md - OpenAPI estatico:
packages/contracts/v1/openapi.yaml packages/contractsdefine el contrato HTTP estructural publico.packages/domaindefine las validaciones semanticas/cross-field que no conviene expresar solo con schema.- El OpenAPI y los JSON Schema publicados son artefactos formales estaticos; en este MVP no son la fuente primaria.
GET /health- Uso: healthcheck para desarrollo y CI.
- Response
200:{ "status": "ok" }
POST /v1/solve- Uso: validar y resolver una instancia del problema.
- Content-Type:
application/json
- Endpoints de autenticacion.
- Endpoints CRUD de hospitales/medicos/dias persistidos.
- Endpoints de historial de corridas (solo si luego se agrega DB en v1.1).
{
"instanceId": "demo-001",
"maxDaysPerMedic": 2,
"periods": [
{ "id": "p1", "dayIds": ["d1", "d2"] },
{ "id": "p2", "dayIds": ["d3"] }
],
"days": [
{ "id": "d1", "date": "2026-04-17" },
{ "id": "d2", "date": "2026-04-18" },
{ "id": "d3", "date": "2026-04-20" }
],
"medics": [
{ "id": "m1", "name": "Ana" },
{ "id": "m2", "name": "Luis" }
],
"availability": [
{ "medicId": "m1", "dayId": "d1" },
{ "medicId": "m1", "dayId": "d3" },
{ "medicId": "m2", "dayId": "d2" }
]
}- Forma base del payload JSON.
- Tipos primitivos, campos requeridos y
additionalProperties=false. - La implementacion objetivo usa Zod como fuente primaria compartida por API y web.
maxDaysPerMedic >= 0.- IDs unicos en
periods,days,medics. days[*].datedebe ser unica.- Todo
dayIddeperiods[*].dayIdsexiste endays. - Cada dia pertenece a exactamente un periodo.
- Toda tupla de
availabilityreferencia medico y dia existentes. - Un periodo puede contener dias no contiguos; no se valida continuidad de fechas en v1.
- Se permiten medicos sin disponibilidad.
- El orden de entrada de arrays no afecta el resultado; la implementacion normaliza internamente para lograr determinismo.
Ademas del schema estructural y las reglas semanticas, la API aplica limites operativos para acotar el MVP:
days.length <= 500medics.length <= 500periods.length <= 100availability.length <= 100000- payload HTTP <=
2.5 MB
Si se excede un limite, la API responde 400 con code=INVALID_INPUT y details accionable. Los limites completos viven en docs/40-quality/NonFunctionalLimits.md.
{
"instanceId": "demo-001",
"feasible": true,
"requiredFlow": 3,
"maxFlow": 3,
"assignments": [
{ "dayId": "d1", "medicId": "m1", "periodId": "p1" },
{ "dayId": "d2", "medicId": "m2", "periodId": "p1" },
{ "dayId": "d3", "medicId": "m1", "periodId": "p2" }
],
"stats": {
"nodes": 13,
"edges": 18,
"runtimeMs": 2
}
}{
"instanceId": "demo-001",
"feasible": false,
"requiredFlow": 3,
"maxFlow": 2,
"assignments": [],
"stats": {
"nodes": 13,
"edges": 18,
"runtimeMs": 1
},
"diagnostics": {
"summaryCode": "INSUFFICIENT_COVERAGE",
"message": "Unable to cover all days under current constraints.",
"uncoveredDays": ["d3"]
}
}diagnosticsaparece si y solo sifeasible=false.summaryCodees fijo en v1:INSUFFICIENT_COVERAGE.messagees un resumen legible y estable a nivel funcional.uncoveredDayslista losdayIdno cubiertos en la solucion de max-flow.uncoveredDaysdebe venir sin duplicados y ordenado ascendentemente pordayId.- En
feasible=true,diagnosticsno debe estar presente.
- La API debe devolver
assignmentsordenado ascendentemente pordayId. diagnostics.uncoveredDaysdebe devolverse ordenado ascendentemente pordayId.stats.edgescuenta aristas dirigidas del grafo de trabajo del motor antes de expandir residual.stats.runtimeMsmide solo el tiempo del motor, no el tiempo total HTTP.
- Export JSON: serializa exactamente la respuesta de
POST /v1/solve. - Export CSV: solo disponible si
feasible=true. - Export CSV: se deriva de
solveResponse.assignmentsunido con elinstanceDraftactual del frontend. - Columnas CSV v1:
dayId,date,periodId,medicId,medicName. - Filas CSV ordenadas por
dayId. dayId,periodId,medicId: salen deassignments.date: se resuelve desdedays.medicName: se resuelve desdemedics.
200: ejecucion correcta (factible o infactible) yGET /health.400: validacion de input fallida (POST /v1/solve).500: error interno en API o motor.
El listado completo de error.code y la forma esperada de details por codigo vive en docs/30-api/ErrorCatalog.md.
{
"error": {
"requestId": "8e950b8f-f8c3-49fc-835b-4015f4963ca1",
"timestamp": "2026-03-06T23:30:00.000Z",
"code": "INVALID_INPUT",
"message": "Each day must belong to exactly one period.",
"details": {
"dayId": "d2"
}
}
}