packages.wenpai.net/docs/architecture.md
Ben Word aed2fbf44b
Add public status page (#89)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:24:20 -05:00

107 lines
No EOL
4 KiB
Markdown

# Architecture
WP Packages has two primary runtime concerns:
1. Build and serve a static Composer repository.
2. Provide web/admin interfaces for package browsing and operations.
## System Components
- **Single binary** (`wppackages`) provides CLI commands and HTTP server.
- **SQLite** (WAL mode) as the sole runtime data store.
- **R2/CDN** serves Composer metadata artifacts (`packages.json`, `p2/`).
- **Caddy** reverse proxies app routes to the Go HTTP server.
- **systemd** manages the `serve` process and periodic timers.
### Build Pipeline Commands
- `wppackages discover` — discovers package slugs (config list or SVN).
- `wppackages update` — fetches and stores package metadata from WordPress.org.
- `wppackages build` — generates static Composer JSON artifacts.
- `wppackages deploy` — promotes a completed build, supports rollback/cleanup.
- `wppackages pipeline` — orchestrates discover → update → build → deploy.
### Static Repository Storage
- Immutable build directories under `storage/repository/builds/<build-id>/`.
- Atomic `current` symlink points to the promoted build.
### Web UI
- Public package browser/detail pages via server-rendered Go templates + Tailwind.
- Admin panel at `/admin` with in-app auth (email/password + session).
## Module Layout
```
cmd/wppackages/ CLI entrypoint (Cobra)
internal/
├── config/ env-first loading + optional YAML config
├── db/ SQLite connection, pragmas, Goose migrations
├── wporg/ WordPress.org API + SVN clients
├── packages/ package normalization/storage logic
├── repository/ artifact generation, hashing, integrity validation
├── deploy/ local promote/rollback/cleanup + R2 sync
├── telemetry/ event ingestion, dedupe, rollups
└── http/ stdlib router, handlers, templates, static assets
```
## Data Flow
1. **Discovery** creates/updates shell package records (`type`, `name`, `last_committed`).
2. **Update** fetches full package payloads, normalizes versions, stores to `packages.versions_json`.
3. **Build** generates:
- `packages.json` (with absolute `notify-batch` URL to app domain)
- Composer v2 metadata files under `p2/`
- `manifest.json` with build metrics and snapshot metadata
4. **Deploy** promotes a complete build by switching the `current` symlink and optionally syncing to R2.
5. **R2/CDN** serves static JSON directly; Caddy proxies dynamic routes to the Go app.
## Snapshot Consistency
- `wppackages update` stamps updated rows with `last_sync_run_id`.
- `wppackages build` snapshots `max(last_sync_run_id)` and only includes rows at or below that value.
- This prevents mixed-state builds when updates are running concurrently.
## Static Repository Layout
```
storage/repository/
├── current -> builds/20260313-140000
└── builds/
├── 20260313-140000/
│ ├── packages.json
│ ├── manifest.json
│ └── p2/
└── 20260313-130000/
```
## Public vs Admin Surface
### Public
- `GET /` — package browser with search/filter/sort/pagination
- `GET /packages/{type}/{name}` — package detail
- `POST /downloads` — Composer notify-batch endpoint (install telemetry)
- `GET /health` — status + package totals + last build metadata
### Admin
- `GET /admin/logs` — server logs viewer (auth required)
## Static Repository Deployment
Two deployment targets:
- **R2/CDN (production)** — `wppackages deploy --to-r2` syncs the build to Cloudflare R2 with appropriate `Cache-Control` headers. R2 custom domain + Cloudflare CDN serves the static files. See `docs/r2-deployment.md`.
- **Local (development)** — `wppackages deploy` updates the `current` symlink only.
## Scheduling
Periodic tasks run via systemd timers or cron (no in-process scheduler required):
- `wppackages pipeline` — every 5 minutes
- `wppackages aggregate-installs` — hourly
- `wppackages cleanup-sessions` — daily
Optional: `wppackages serve --with-scheduler` for in-process scheduling.