decomposer: generate deliverable files for Define the service contract and project architecture for the FastAPI endpoint monitoring service.; Implement the typed monitor CRUD API and concurrency-safe in-memory state according to the service design.; Implement secure on-demand endpoint checks with status updates, latency measurement, robust error handling, and redacted structured logs.; Add operational API endpoints and environment-driven runtime configuration to the monitoring service.; Create automated tests for the monitoring service.; Package the service with Docker and developer documentation.; Validate the complete project.
Some checks failed
ci / container (push) Has been cancelled
ci / quality (push) Has started running

This commit is contained in:
2026-08-09 16:03:38 +00:00
parent c332e4c06b
commit a78b24c424

31
docs/SERVICE_DESIGN.md Normal file
View File

@@ -0,0 +1,31 @@
# Service contract and architecture
## Resource
A monitor has an immutable UUID `id`, `name`, HTTP(S) `url`, timestamps, and current status. `status` is `unknown` until checked, `up` for a final HTTP 200399 response, `down` for a final HTTP 400599 response, and `error` when no accepted HTTP response is obtained. Check metadata comprises `checked_at`, non-negative `latency_ms`, optional `http_status`, and a bounded, non-sensitive `error` category.
## API
All JSON is UTF-8. Routes are under `/api/v1` except operational probes.
* `POST /api/v1/monitors` -> 201 and monitor; duplicate names are allowed.
* `GET /api/v1/monitors` -> 200 list sorted by creation time and id.
* `GET /api/v1/monitors/{id}` -> 200 or 404.
* `PUT /api/v1/monitors/{id}` -> 200 or 404. Updating name/URL resets check state to `unknown`.
* `DELETE /api/v1/monitors/{id}` -> 204 or 404.
* `POST /api/v1/monitors/{id}/check` -> 200 and atomically persisted check result, or 404 if absent/deleted during the check.
* `GET /api/v1/monitors/{id}/status` -> 200 current status projection or 404.
* `GET /healthz` -> liveness 200; `GET /readyz` -> readiness 200 after app initialization.
FastAPI's validation errors use 422. Application errors use `{"detail":"..."}` and do not expose network exception text. There is intentionally no authentication.
## Checker and SSRF policy
Only HTTP(S), non-credentialed URLs are accepted. Before every request and after every redirect, the host is resolved and every returned address must be globally routable. Loopback, private, link-local, multicast, reserved, unspecified, and non-global addresses are rejected. Redirects are followed manually up to the configured bound. Timeouts and response-body streaming are bounded. This validation substantially reduces SSRF risk, but DNS validation and connection are separate operations in the standard HTTP stack; production deployments should additionally enforce an egress proxy/firewall to eliminate DNS-rebinding TOCTOU risk.
Checks use a monotonic timer. Store mutation occurs under one asyncio lock. A delete that races with a check wins and the result is not resurrected.
## Lifecycle and deployment
`MonitorStore` is process-local and starts empty on every process start. It is concurrency-safe within one event loop, not shared across workers, and has no persistence. Run exactly one worker. Readiness describes initialization, not durability or external dependency health.
Configuration is environment-driven and validated at startup. Logs are one-line JSON. Logged URLs have credentials, query, and fragment removed; only controlled error categories are logged.
## Project layout
`app/models.py` defines the contract; `store.py` owns state; `security.py` validates targets; `checker.py` performs checks; `main.py` wires HTTP routes and lifecycle. Tests inject DNS and HTTP transports so outbound calls are deterministic.