feat: initial implementation taller-wox.fitlabs.dev

Portal FastAPI + 5 endpoints REST para Bootcamp Agentic AI con
watsonx Orchestrate (FactorIT). Single container, Coolify-ready.

- Landing brandeado FIT con formulario de registro (honeypot anti-bot)
- Tokens itsdangerous para descargas (24h expiry)
- 5 endpoints API: historical/available procedures, member-insights,
  schedule, generate-report (Jinja2 + Plotly)
- SQLite con upsert-on-email para leads + log de descargas
- Admin endpoints (HTTP Basic): leads.json, leads.csv, stats
- 23 tests pytest pasando
- Dockerfile listo para Coolify con volúmenes persistentes
  (/app/leads.db, /app/app/data/reports_output, /app/material)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 03:01:44 +00:00
commit a062b45c51
57 changed files with 8035 additions and 0 deletions

38
tests/conftest.py Normal file
View File

@@ -0,0 +1,38 @@
import os
import tempfile
from pathlib import Path
import pytest
os.environ["SECRET_KEY"] = "test-secret-key-only-for-tests-not-secure"
os.environ["ADMIN_USER"] = "testadmin"
os.environ["ADMIN_PASS"] = "testpass"
os.environ["TOKEN_EXPIRY_HOURS"] = "24"
os.environ["BASE_URL"] = "http://testserver"
_tmp = Path(tempfile.mkdtemp(prefix="taller-wox-test-"))
os.environ["DB_PATH"] = str(_tmp / "test_leads.db")
os.environ["MATERIAL_DIR"] = str(_tmp / "material")
os.environ["REPORTS_OUTPUT_DIR"] = str(_tmp / "reports_output")
(_tmp / "material").mkdir(parents=True, exist_ok=True)
(_tmp / "reports_output").mkdir(parents=True, exist_ok=True)
@pytest.fixture
def client():
from fastapi.testclient import TestClient
from app.main import app
return TestClient(app)
@pytest.fixture(autouse=True)
def _init_db_each_test(tmp_path, monkeypatch):
db_file = tmp_path / "test.db"
monkeypatch.setenv("DB_PATH", str(db_file))
from app import config
config.get_settings.cache_clear()
from app.db import init_db
init_db()
yield
config.get_settings.cache_clear()