6.7 KiB
Spec — Golden Path rest-api/python
Versión del shape: 1.0.0
Status: Activo (free-trial entry point)
ADR de referencia: ADR-027 (Golden Paths Fase 5), ADR-053 (anatomía
del shape web-backend/python — referencia para decisiones de empaque),
ADR-060 Fase 1 (GATEWAY-API-MIGRATION): ingress = Traefik Proxy + Gateway
API (HTTPRoute), reemplaza el rke2-ingress-nginx de ADR-053 §11.1,
ADR-061 (workflow CI self-contained — sin uses: cross-repo; helm-deploy
inline sin container:)
Visibilidad: interna de Coralware — este spec NO se sincroniza al
repo Gitea ni al repo del cliente.
1. Propósito
Definir el comportamiento del shape rest-api/python — scaffold de API
HTTP stateless en FastAPI, sin persistencia. Es el shape entry point
para tier free-trial: el cliente arranca rápido con un endpoint REST
funcional sin tener que decidir BD, migraciones ni hooks.
Cuando un cliente necesita persistencia, debería migrar a
web-backend/python (ADR-053), no extender este shape para incluir DB.
2. Contrato del shape
2.1 Entradas
| Entrada | Origen | Descripción |
|---|---|---|
__APP_NAME__ |
placeholder | Sustituido server-side por repo-provisioner |
__TENANT_ID__ |
placeholder | UUID del tenant |
__TENANT_ID_NODASHES__ |
placeholder | UUID sin guiones, para DNS y namespaces |
__TIER__ |
placeholder | free-trial |
KUBECONFIG_TENANT_B64 |
secret de proyecto Gitea | Provisto por tenant-manager |
vars.TENANT_ID, vars.TENANT_ID_NODASHES, vars.TENANT_TIER |
vars de proyecto | Provisto por tenant-manager |
2.2 Salidas observables
| Salida | Forma |
|---|---|
| Imagen Docker | registry.coralsafety.com/t-<tenant-id-short>/<APP_NAME>:<tag> — proyecto Harbor dedicado del tenant (ADR-019 D-03) |
| Helm release | <APP_NAME> en namespace apps del cluster tenant (ADR-054) |
| App reachable | https://<APP_NAME>.<tenant-id-con-guiones>.apps.coralware.cloud/health retorna 200 (FQDN subdominio DOT, ADR-067/ADR-082 — reconciliado drift previo que usaba el host plano con guion) |
| Ingress controller | Traefik Proxy + Gateway API en traefik-system (bundle Fleet traefik-bootstrap) — ADR-060 Fase 1 (GATEWAY-API-MIGRATION); reemplaza rke2-ingress-nginx (EOL marzo 2026). El shape emite un HTTPRoute adjunto al Gateway tenant-gateway (ns apps, stack-deployer §3c). Paridad con web-backend/python |
| TLS | Wildcard per-tenant *.<tenant-id>.apps.coralware.cloud vía Secret tenant-wildcard-tls (cert-manager local del cluster, ADR-067 — reconciliado drift previo que citaba el apps-wildcard-tls compartido de Fase 0) |
| Endpoints obligatorios | /health, /docs, /openapi.json, /metrics |
2.3 Invariantes
- App stateless — ningún componente persistente requerido.
/healthretorna 200 con{"status":"ok"}siempre que el proceso esté vivo.helm upgrade --installdel chart funciona sin--no-hooks. ElServiceAccountse materializa como hookpre-install,pre-upgrade(hook-weight: -5,hook-delete-policy: before-hook-creation) por paridad con el shapeweb-backend/python. Este shape no tiene Job de migración, así que el hook no es estrictamente necesario — se mantiene para coherencia entre ambos charts.- SecurityContext:
runAsNonRoot=true,readOnlyRootFilesystem=true,drop ALL caps. - Sin IPs hardcoded; sin credenciales en código.
- Errores de servicios upstream NO crashean la app — se reportan en el endpoint que los invoca, el proceso sigue.
3. Flujo principal
flowchart TD
dev_push([Dev hace git push\nal repo Gitea del tenant]) --> quality_gate[quality_gate\nruff + black + bandit + pytest --cov 80]
quality_gate -- fail --> pipeline_failed([pipeline_failed\nHelm no se invoca])
quality_gate -- ok --> image_build[image_build\nbuildx push a Harbor t-short]
image_build -- fail --> pipeline_failed
image_build -- ok --> helm_deploy[helm_deploy\nhelm upgrade --install --wait]
helm_deploy --> rollout_apply[rollout_apply\nDeployment con nuevo image tag]
rollout_apply --> rollout_status_check[rollout_status_check\nkubectl rollout status timeout 3m]
rollout_status_check -- fail --> helm_rollback_manual([helm_rollback_manual\ndev decide rollback\npipeline_failed])
rollout_status_check -- ok --> smoke_health_check[smoke_health_check\nwget /health 200]
smoke_health_check -- fail --> investigate([investigate\nlogs + events\npipeline_failed])
smoke_health_check -- ok --> app_running([app_running])
Sin nodo alembic_hook — diferencia clave con web-backend/python.
Los node IDs son labels Prometheus futuros.
4. Estados terminales
| Estado | Significado | Acción del dev |
|---|---|---|
app_running |
Todo OK — app desplegada, /health 200 | Ninguna |
pipeline_failed |
Quality o build falló | Inspeccionar logs CI; corregir; push |
helm_rollback_manual |
Rollout no estabilizó en 3 min | helm rollback; investigar pod events |
investigate |
Smoke falla aunque rollout terminó | Logs Deployment + cluster events |
5. Comportamiento fail-safe
- Servicio upstream caído: endpoint responde 503 con detalle, app sigue.
- Imagen no disponible:
ImagePullBackOffvisible en Rancher; rollout no avanza. - Variable de entorno faltante (ej.
LOG_LEVEL): default seguro, no crash.
6. Pruebas negativas
| ID | Prueba | Estado terminal esperado |
|---|---|---|
| N1 | Test fallando | pipeline_failed en quality_gate |
| N2 | Imagen tag inexistente | ImagePullBackOff visible en Rancher |
| N3 | Probe /health removido del pod |
Rollout falla → helm_rollback_manual |
(Set reducido vs. web-backend/python; sin pruebas de DB porque no hay BD.)
7. Versionado del shape
coralware-shape.yaml declara shapeVersion (semver). Mismas reglas
que web-backend/python (ver ADR-053 §7).
8. Sincronización a Gitea
templates/rest-api-python/ (este repo IDP) → idp-templates/template-rest-api-python (Gitea).
Exclusiones del sync:
openspec/— gobernanza interna del golden path..ruff_cache/,__pycache__/,.pytest_cache/.
Mecanismo: rsync --exclude='openspec/' --exclude-from=.gitignore
desde el scaffold local hacia el clone temporal del repo Gitea.
9. Promoción a web-backend/python
Si la app crece y necesita persistencia:
- Cliente clona el template
web-backend/pythonen un repo nuevo. - Migra rutas de su app
rest-apial nuevo scaffold. - Coralware provisiona el
AddonClaimMariaDB (manual via runbook hasta ADR-052).
No hay path de migración in-place — son shapes distintos por diseño.