diff --git a/AGENTS.md b/AGENTS.md index 7016c01..ccade07 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,15 +18,55 @@ Refactoring must always: ## Repository structure -Backend (FastAPI) -- control/app.py (main API) +Backend (FastAPI modular monolith) + +Bootstrap +- control/app.py (application bootstrap & router wiring ONLY) + +System / platform router +- control/app_system.py + +Feature routers +- control/app_containers.py +- control/app_pods.py +- control/app_networks.py +- control/app_files.py - control/app_images.py +Shared infrastructure +- control/common.py + WebUI (static Apache) - webui/html/index.html - webui/html/assets/js/tabs/ - webui/conf/httpd.conf +### Backend architecture rule (HARD) + +control/app.py is a bootstrap layer only. + +It may: +- create FastAPI app +- include routers +- register startup events + +It must NOT: +- contain feature endpoints +- contain system logic +- contain Podman or systemctl implementations + +All endpoints belong in routers. + +### Module ownership rule + +If unsure where new logic belongs: + +- shared logic → control/common.py +- system/platform logic → control/app_system.py +- feature logic → corresponding app_.py router + +Never introduce new endpoints in control/app.py. + --- ## Runtime architecture (IMPORTANT) @@ -123,8 +163,11 @@ New functionality must be added via: Security rules: - No shell=True - subprocess must be explicit and safe -- Respect allowed_units.txt -- Never assume systemd states. +- Never assume systemd states + +Legacy notice: +allow_list / allowed_units.txt functionality has been removed +and must NOT be reintroduced. --- diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..b512444 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,82 @@ +# ARCHITECTURE.md — podman-mvp (WebUI + API) + +## Purpose +This document describes **where code lives** and **which module owns what**. +It is a factual map of the system for reviewers and agents. + +## Runtime + Test Base URLs + +### WebUI +- http://127.0.0.1:8081/ + +### API (via WebUI reverse proxy) +- Base URL: http://127.0.0.1:8081/api + +**All verification commands must target `127.0.0.1:8081` unless explicitly stated otherwise.** + +Example: +- `curl -fsS http://127.0.0.1:8081/api/health` + +## Architecture Overview (Modular Monolith) +Single deployable backend service, split into modules (routers) by domain. + +### Layers +1. **Bootstrap / Composition Root** + - `control/app.py` + - Responsibilities: + - create FastAPI app + - include routers + - register startup events (if needed) + - Hard rule: **no feature endpoints** and **no system logic** here. + +2. **System / Platform Router** + - `control/app_system.py` + - Owns platform endpoints such as: + - `/health` + - `/daemon-reload` + - systemctl endpoints (`/{action}/{unit}`, legacy `/api//`) + - diagnostic endpoints (e.g. `/test-hybrid`, if present) + - Route ordering rule: broad patterns like `/{action}/{unit}` must be defined **last**. + +3. **Feature Routers (UI Tabs / Domains)** + - `control/app_containers.py` — containers tab endpoints (dashboard, inspect, logs, stats stream) + - `control/app_pods.py` — pods tab endpoints (dashboard, pod actions) + - `control/app_networks.py` — networks tab endpoints + - `control/app_files.py` — files/workloads endpoints (tree/read/save/etc.) + - `control/app_images.py` — images endpoints + +4. **Shared Infrastructure Layer** + - `control/common.py` + - Owns: + - Podman HTTP helpers (unix-socket requests) + - systemctl/subprocess helpers (when shared) + - shared parsing/normalization utilities + - Hard rule: routers should not duplicate shared helpers. + +## Boundaries (Hard Rules) +- `control/app.py` is **bootstrap-only**. +- Endpoints must live in the appropriate router module: + - system/platform → `app_system.py` + - domain feature → `app_.py` +- Shared helpers belong in `common.py` (not copied into routers). +- Legacy `allow_list` / `allowed_units.txt` functionality is removed and must NOT be reintroduced. + +## Contracts +API response shapes are governed by: +- `contracts/API_GOLDEN.md` + +No endpoint response keys may be removed or renamed without explicit approval. + +## Required Verification (Minimal) +After any change affecting backend routing or shared helpers, run: + +```bash +python3 -m py_compile control/app.py control/common.py control/app_system.py \ + control/app_containers.py control/app_pods.py control/app_networks.py \ + control/app_files.py control/app_images.py + +curl -fsS http://127.0.0.1:8081/api/health | jq +curl -fsS http://127.0.0.1:8081/api/pods-dashboard >/dev/null && echo OK +curl -fsS http://127.0.0.1:8081/api/containers-dashboard >/dev/null && echo OK +curl -fsS http://127.0.0.1:8081/api/files/tree >/dev/null && echo OK +curl -fsS http://127.0.0.1:8081/api/networks/meta | jq diff --git a/SAFE_FILES.md b/SAFE_FILES.md index 2454a4b..71f320e 100644 --- a/SAFE_FILES.md +++ b/SAFE_FILES.md @@ -47,7 +47,12 @@ Changes must be proposed first. Files requiring caution: control/app.py +control/app_files.py control/app_images.py +control/app_networks.py +control/app_pods.py +control/app_system.py +control/common.py Rules: - Never rewrite structure without agreement. diff --git a/control/app.py b/control/app.py index fa23611..e0c2691 100644 --- a/control/app.py +++ b/control/app.py @@ -26,7 +26,6 @@ def _systemctl(cmd): # --- ROUTERS --- # Images API lives in dedicated modules to keep this file from growing further. -app.include_router(init_system_router(SESSION, PODMAN_API_BASE, WORKLOADS_DIR)) app.include_router(init_images_router(SESSION, PODMAN_API_BASE)) app.include_router(init_files_router(SESSION, PODMAN_API_BASE, WORKLOADS_DIR)) app.include_router(init_networks_router(SESSION, PODMAN_API_BASE)) @@ -42,6 +41,7 @@ app.include_router(init_pods_router( WORKLOADS_DIR, _systemctl, )) +app.include_router(init_system_router(SESSION, PODMAN_API_BASE, WORKLOADS_DIR)) def run(cmd):