Metadata-Version: 2.4
Name: finanfut-watchtower
Version: 0.1.0
Summary: Internal error tracking platform for the FinanFut ecosystem.
License: MIT
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: alembic>=1.13
Requires-Dist: celery>=5.4
Requires-Dist: cryptography>=43.0
Requires-Dist: fastapi>=0.115
Requires-Dist: httpx>=0.27
Requires-Dist: jinja2>=3.1
Requires-Dist: psycopg[binary]>=3.2
Requires-Dist: pydantic>=2.8
Requires-Dist: pydantic-settings>=2.4
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: uvicorn[standard]>=0.30
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == "dev"
Requires-Dist: pytest>=8.3; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Dynamic: license-file

# FinanFut Watchtower

Plataforma interna de monitoritzacio d'errors per a l'ecosistema FinanFut.

La v1 esta enfocada en capturar excepcions, agrupar-les per fingerprint, crear issues, mantenir historic d'events, enviar alertes des d'un worker i oferir un SDK Python intern.

## Estat Actual

Aquest primer tall implementa:

- Scaffold de backend FastAPI.
- Configuracio amb Pydantic Settings.
- SQLAlchemy 2.x, Alembic i models inicials.
- `GET /healthz` i `GET /readyz`.
- `POST /api/v1/events` amb HMAC.
- `POST /api/v1/events/batch` amb HMAC.
- Project keys amb secret rotables i public key estable.
- Fingerprint inicial determinista.
- Scrubbing recursiu de claus sensibles.
- UI React interna per overview, llista d'issues, detall i accions d'estat.
- Retencio d'events antics conservant issues agrupades.
- Outbox d'alertes amb worker, Slack webhook, email via Microsoft Graph i retry amb backoff.
- Login amb sessio cookie `HttpOnly` i MFA TOTP configurable per usuari admin.
- SDK Python amb captura manual, FastAPI middleware, logging handler i decorador de jobs.
- Frontend React intern a `frontend/`; en produccio es compila dins el Docker de l'API.
- Dockerfile, Docker Compose, Render config, GitHub Actions CI/CD, Makefile i tests.

## Primer Setup

```bash
cp .env.example .env
make install
docker compose up -d postgres
make migrate
.venv/bin/watchtower-admin create-user \
  --email admin@finanfut.local \
  --password change-me \
  --name "Local Admin" \
  --alert-email admin@finanfut.local
docker compose up -d app worker frontend
```

PostgreSQL local de Watchtower es publica a `localhost:55432` per evitar col·lisions amb altres serveis locals.

Amb Docker Compose:

- API: `http://localhost:8000`
- Frontend React: `http://localhost:5173`
- PostgreSQL: `localhost:55432`

L'API queda a:

Healthcheck:

```bash
curl http://localhost:8000/healthz
```

## Tests

```bash
make test
```

Lint i format:

```bash
make lint
make format
```

## Worker

```bash
make worker
```

El worker processa `notification_outbox`, envia alertes pels canals configurats i reintenta fallades amb backoff.

Per reload automatic en entorns locals que ho suportin:

```bash
make dev-reload
```

## Frontend React

```bash
docker compose up frontend
```

Vite queda a `http://localhost:5173` i proxyeja `/api`, `/healthz` i `/readyz` al backend local. Per treballar fora de Docker tambe pots fer `cd frontend && npm install && npm run dev`.

En produccio, el Dockerfile compila `frontend/` i FastAPI serveix el build React des del mateix domini que l'API.

## Exemple D'Ingesta

Genera una request signada amb Python:

```bash
python - <<'PY'
import hashlib, hmac, json, time

secret = "sk_dev_watchtower_change_me"
payload = {
    "event_id": "example-event-1",
    "service": "billing-api",
    "environment": "production",
    "release": "billing@local",
    "level": "error",
    "event": "stripe_webhook_processing_failed",
    "message": "Failed to process Stripe webhook",
    "exception_type": "StripeSignatureVerificationError",
}
body = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode()
timestamp = str(int(time.time()))
signature = hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
print(body.decode())
print(timestamp)
print(signature)
PY
```

Despres envia el body amb els headers:

```bash
curl -X POST http://localhost:8000/api/v1/events \
  -H "Content-Type: application/json" \
  -H "X-Watchtower-Project-Key: pk_dev_watchtower" \
  -H "X-Watchtower-Timestamp: <timestamp>" \
  -H "X-Watchtower-Signature: <signature>" \
  --data '<json-body>'
```

## Variables Principals

Veure `.env.example` per la llista completa.

- `DATABASE_URL`
- `WATCHTOWER_SECRET_KEY`
- `WATCHTOWER_ADMIN_TOKEN`
- `WATCHTOWER_SESSION_COOKIE_NAME`
- `WATCHTOWER_SESSION_MAX_AGE_SECONDS`
- `WATCHTOWER_SESSION_COOKIE_SECURE`
- `WATCHTOWER_TRUSTED_DEVICE_COOKIE_NAME`
- `WATCHTOWER_TRUSTED_DEVICE_MAX_AGE_DAYS`
- `WATCHTOWER_INGEST_PROJECT_KEY`
- `WATCHTOWER_INGEST_SECRET_KEY`
- `WATCHTOWER_MAX_PAYLOAD_BYTES`
- `WATCHTOWER_RATE_LIMIT_EVENTS_PER_MINUTE`
- `WATCHTOWER_EVENT_RETENTION_DAYS`
- `WATCHTOWER_SLACK_WEBHOOK_URL`
- `AZURE_TENANT_ID`
- `AZURE_CLIENT_ID`
- `AZURE_CLIENT_SECRET`
- `SMTP_USER`
- `SMTP_DEFAULT_FROM`
- `WATCHTOWER_ALERT_EMAIL_TO` (legacy fallback; policy recipients are preferred)
- `WATCHTOWER_SDK_ENDPOINT`
- `WATCHTOWER_SDK_PROJECT_KEY`
- `WATCHTOWER_SDK_SECRET_KEY`
- `WATCHTOWER_SDK_SERVICE`

## Documentacio

- `docs/architecture.md`
- `docs/api-ingestion.md`
- `docs/admin-operations.md`
- `docs/admin-cli.md`
- `docs/alerting.md`
- `docs/sdk-python.md`
- `docs/integrating-python-apps.md`
- `docs/deploy-render.md`
- `docs/security-privacy.md`
- `docs/roadmap.md`
- `docs/future-loki-grafana.md`

## Properes Tasques

- Primer deploy real a Render amb els secrets configurats i smoke post-deploy.
