AGENTS.md
Project structure
Two independent sub-projects; each has its own dependency manager and must be run separately.
chatbot-fp/
├── backend/ # FastAPI — Python 3.13, uv
└── frontend/ # Vite + TypeScript (vanilla, no framework), npm
Backend
Setup
cd backend
cp .env.example .env # required before first run
uv sync --group dev
Dev server
# from backend/
uv run uvicorn app.main:app --reload
# → http://localhost:8000
# → http://localhost:8000/docs (Swagger UI)
Tests
# must run from backend/ — pythonpath is set to "." in pyproject.toml
uv run pytest
uv run pytest tests/test_chat.py::test_health # single test
Non-obvious quirks
- No
requirements.txt. Package manager isuvexclusively.uv.lockis the lockfile. pytestbreaks if run from repo root —appwon't be importable. Always run frombackend/.asyncio_mode = "auto"is set inpyproject.toml; no@pytest.mark.asyncioneeded on test functions.- CORS reads
ALLOWED_ORIGINSfrom.env(comma-separated). During local dev the Vite proxy handles CORS, so this only matters in production. - To connect a real LLM: edit only
backend/app/services/chat_service.py. The stub shows an OpenAI example in comments. AddOPENAI_API_KEYto.env.
API contract
| Method | Path | Body | Response |
|---|---|---|---|
| GET | /health | — | {"status": "ok"} |
| POST | /api/chat/ | {"message": "<string>"} | {"respuesta": "<string>"} |
The response field is respuesta (Spanish). Missing message returns HTTP 422.
Frontend
Setup
cd frontend
npm install
Dev server
# from frontend/
npm run dev
# → http://localhost:5173
All /api/* requests are proxied by Vite to http://localhost:8000 — no CORS configuration needed in development.
Type-check + build
npm run build # runs: tsc && vite build — type errors fail the build
Non-obvious quirks
- TypeScript 6 (
~6.0.2) witherasableSyntaxOnlyenabled —enumandnamespaceare banned. Useconstobjects or union types instead. noUnusedLocalsandnoUnusedParametersare enabled. Unused variables break the build.- No framework — pure vanilla TS. Components are plain classes/functions with DOM APIs.
- No frontend tests and no linter (no ESLint, no Ruff). Only TypeScript compiler flags enforce quality.
- URL linkification in bot responses is handled in
src/components/ChatWindow.tsvia regex.
Conventions
- All user-visible strings, UI labels, error messages, and code comments are in Spanish.
- The shared data shape (
respuestafield) is mirrored in:backend/app/models/chat.py— PydanticChatResponsefrontend/src/types/index.ts— TypeScriptChatResponse- Both must stay in sync when the API contract changes.
- No automated quality CI (tests/build) and no pre-commit hooks yet. Verification is manual:
uv run pytest+npm run build. - Deployment automation is planned via GitHub Actions (see Azure deployment plan stages).
Azure deployment plan (free tier)
IaC tooling
- Infrastructure as Code: Bicep — all Azure resources are declared in
infra/main.bicep. - Deployment command:
az deployment group create(after creating the resource group manually). - The resource group itself is created imperatively with
az group createsince Bicep requires an existing scope.
Resources to create in Azure
- Resource Group:
rg-cbfp-dev-01 - Static Web App (Free):
swa-cbfp-dev-cus-01 - App Service Plan (F1 Free):
asp-cbfp-dev-free-cac-01 - Web App for backend API:
app-cbfp-api-dev-cac-01
Naming convention
- Prefix:
cbfp(project short name) - Environment:
dev - Region code:
cusforcentralus(solo SWA) ycacforcanadacentral(ASP + Web App) - Suffix rule by resource type: always end with sequential
-01 - Collision rule: if name already exists, increment only that resource type to
-02, then-03, etc.
IaC structure
infra/
├── main.bicep # declares SWA, ASP, Web App; accepts parameters
└── main.bicepparam # parameter values for the dev environment
Key Bicep parameters:
swaLocation—centralusappLocation—canadacentralswaName—swa-cbfp-dev-02aspName—asp-cbfp-dev-free-01webAppName—app-cbfp-api-dev-01allowedOrigins— SWA default hostname (set after first deploy or passed as override)
Two-stage rollout plan
Stage 1 — Provision Azure resources (one-time or on infra changes)
- Pre-flight quota check: verify Free VM quota in
canadacentral—az vm list-usage --location canadacentral. - Create resource group (imperative — scope required by Bicep):
az group create --name rg-cbfp-dev-cac-01 --location canadacentral - Deploy infrastructure with Bicep (idempotent):
az deployment group create --resource-group rg-cbfp-dev-cac-01 --template-file infra/main.bicep --parameters infra/main.bicepparam - Retrieve SWA hostname from deployment output and confirm
ALLOWED_ORIGINSis correct in Web App settings.
Stage 2 — Continuous deployment with GitHub Actions
- Create CI/CD workflows in
.github/workflows/so deployment happens from GitHub Actions, not from local machines. - Add a backend workflow (
deploy-backend.yml) with jobs to: checkout, setup Python/uv, runuv run pytestfrombackend/, package app, and deploy toapp-cbfp-api-dev-01(Zip Deploy orazure/webapps-deploy). - Add a frontend workflow (
deploy-frontend.yml) with jobs to: checkout, setup Node, runnpm ci+npm run buildfromfrontend/, and publishfrontend/dist/toswa-cbfp-dev-02. - Configure required repository secrets for workflows (at minimum):
AZURE_CREDENTIALS,AZURE_WEBAPP_NAME,AZURE_RESOURCE_GROUP,AZURE_STATIC_WEB_APPS_API_TOKEN, andOPENAI_API_KEYif real LLM is enabled. - Configure required app settings in Azure for runtime (
ALLOWED_ORIGINSand optionalOPENAI_API_KEY) so deployment and execution remain decoupled. - Use trigger strategy: automatic on push to
main, plusworkflow_dispatchfor controlled/manual releases. - Add post-deploy smoke tests as workflow steps: verify backend
GET /health,POST /api/chat/, and end-to-end call from SWA URL. - Use environment protection rules for production (required reviewers/approvals) before deploy jobs execute.
Re-deploy / update rules
- Infrastructure updates: re-run Stage 1, step 3. Bicep is idempotent and performs incremental updates by default.
- Application-only updates: use Stage 2 GitHub Actions workflows without reprovisioning infrastructure.
- To change a parameter (e.g.,
ALLOWED_ORIGINS), updateinfra/main.bicepparamand re-run Stage 1, step 3.
Name increment examples
- If
swa-cbfp-dev-01already exists, useswa-cbfp-dev-02. - If
app-cbfp-api-dev-01already exists, useapp-cbfp-api-dev-02. - Do not increment unrelated resource types when only one name collides.