Files
DoGaMa-serv/docs/PROJECT-STATE.md
T
codex 4ed3c8ae58
CI / validate (pull_request) Successful in 26m33s
refactor(catalog): make template artwork fully local
2026-08-26 21:58:30 +02:00

18 KiB

DoGaMa project state

Read this compact operational baseline before starting a milestone. Open detailed domain documents only when the current work affects them.

Baseline

  • Current reference: post-v0.1.1 release-gate correction based on tagged baseline 88a45c7.
  • Source-facing HTML templates, CSS and browser JavaScript are structurally formatted for maintainability; the primary assets are exposed as app.css, theme.css and app.js with simple development-friendly cache headers.
  • SQLite is initialized directly from one embedded current schema and can be reopened safely after first initialization. Development databases from earlier revisions are intentionally unsupported until versioned production migrations are introduced.
  • Roadmap milestones 1-10 are implemented; this is the V1 feature baseline.

Architecture

  • Go main application: HTTP API, embedded server-rendered UI, authentication/authorization, SQLite, workflows, backups and WASM runtime.
  • Private restricted Go agent: sole Docker-socket owner; authenticated typed API; registered-instance and plan-digest binding; no generic Docker proxy.
  • Integrations: capability-scoped WebAssembly adapters only. Palworld REST is the reference module.
  • Data: SQLite plus canonical allowed server, import and backup roots. Persistent game data lives outside containers.
  • Contracts: declarative YAML templates and module manifests validated against JSON Schemas; released snapshots are immutable.

Implemented capabilities

  • Bootstrap administrator with required email and persisted language preference, local authentication, secure sessions and CSRF protection.
  • Validated embedded catalog, deterministic deployment previews and instance registry.
  • Restricted instance create/inspect/start/stop/restart/delete and reconciliation.
  • Per-instance memberships, overrides and installation requests with backend authorization.
  • Backup scheduling/retention, safe imports, export and restore with safety backups.
  • Sandboxed WASM runtime and normalized module API with Palworld reference adapter.
  • Game-container configuration: global and per-instance labels, safe label variables, derived instance slug, immutable Docker-user selection, tracked/pinned image tags, immediate or deferred container recreation, and public game-logo/artwork routes.
  • Administration stores persistent game-container UID/GID defaults (1000:1000) with decimal uint32 validation. Managed templates use them as Docker User; user_mode: image is authoritative and omits Docker User. Templates can map the values to declared runtime environment variables; V Rising uses PUID/PGID while retaining its root entrypoint and capabilities.
  • Deployment forms expose published template ports as distinct host-port inputs. Host bindings default to the template container port, remain persisted in the instance preview, validate decimal range and same-protocol uniqueness, and never publish publish: false ports.
  • Controlled digest-aware game updates with confirmation, policy-driven pre-update backups, readiness verification, mod warnings and automatic container-plan rollback.
  • Redacted configuration history retained to the latest 10 revisions, with pinned-template revalidation and immediate or deferred rollback.
  • Declarative Steam Workshop item configuration with numeric-ID validation, stable ordering and backend mods.manage enforcement.
  • Encrypted write-only SMTP, generic HTTPS webhook, Discord and Gotify channels with explicit disabled-by-default state, persisted safe administration fields, event filters, queued test delivery, bounded retry and redacted terminal errors; SMTP event email is filtered by persistent personal preferences and instance access.
  • SSRF-resistant HTTPS webhook delivery with redirect/address revalidation, event IDs, timestamps and optional HMAC-SHA256 signatures.
  • Compact allow-listed audit events for authentication and significant mutations, administrator filtering, bounded manual purge, daily retention and maximum-count enforcement.
  • Responsive server-rendered application shell with synthwave-derived design tokens, permission-aware navigation, the official DoGaMa wordmark in the sidebar, searchable real instance cards, lifecycle summaries, server-only recent Audit activity and resilient agent/database/storage/backup/audit status on the Dashboard.
  • The responsive shell exposes a keyboard-accessible mobile navigation toggle on every authenticated SSR page; all recent-administrator form mutations return an explicit CSRF denial when request verification fails.
  • Dedicated administrator Audit and Settings pages; notification channels, audit retention/purge and game-container labels retain their existing backend contracts outside the Dashboard.
  • Audit uses server-side filtering and 50-event pagination; timestamps remain UTC in SQLite and are rendered in the Compose TZ IANA timezone with an invalid-zone fallback to UTC. Instance audit events retain a minimal game/name/slug snapshot so history stays readable after instance deletion.
  • Separate personal account settings and administrator user management, including email/password preferences, active-state session revocation, protected global roles, per-instance memberships and permission overrides.
  • Personal account settings display the authenticated email and support CSRF-protected email updates plus local PNG/JPEG avatar upload, replacement and deletion; avatars are normalized to private 256px PNG files and fall back to username initials in the identity header.
  • Administrator-configurable browser session policy: seven-day absolute lifetime and 24-hour inactivity timeout by default, bounded validation, optional inactivity expiry, dynamic enforcement for existing sessions, and throttled activity persistence. Normal authorized operations no longer require an arbitrary recent-authentication window.
  • Restrictive browser headers and bounded public HTTP headers.
  • Hardened read-only two-service Compose, capability dropping, private agent networking and distinct minimal OCI image targets.
  • Linux black-box bootstrap/authentication E2E coverage plus a documented disposable-Docker V1 release verification matrix.
  • Deterministic Linux amd64/arm64 archives with embedded build identity, SPDX module SBOM and SHA-256 checksums.
  • Minimal production Compose containing only dogama and agent; docker compose up -d is the complete first-start workflow with no initializer, setup command, host UID/GID preparation or user-managed internal secrets.
  • compose-dev.yml is a local-only overlay for the production Compose: it builds the two local image targets and adds Caddy 2.10.2 with tls internal at https://dogama.lan. Caddy PKI and configuration are isolated in development named volumes; production imposes no reverse proxy.
  • Service-owned persistent secrets: the agent atomically creates and validates its mode-0640 shared token in the internal agent_auth volume; the application mounts only that secret directory read-only and independently creates and validates its mode-0600 master key below the application data path. The application tolerates concurrent first start by waiting up to 60 seconds for the token and authenticated agent health.
  • The agent token is exactly 32 opaque random bytes. Readers preserve terminal carriage-return and newline byte values instead of treating the secret as text.
  • Two service networks: an administrator-named application/reverse-proxy network plus a private Compose control network. The agent safely ensures the fixed DOGAMA_GAMES_NETWORK exists and applies it to every game-container create or replacement; it is not caller-selectable through the lifecycle API.
  • Portable fresh bind-mount startup uses root identities inside the read-only, capability-free container namespaces and a private process umask. No recursive ownership change is performed; game-container UID/GID is controlled by Administration only for managed templates.
  • Gitea CI for pull requests and main, plus tag-only multi-architecture image publication and Gitea Release creation.

Durable decisions

  • Editable Docker labels apply only to game-server instance containers.
  • Labels on the DoGaMa application container remain Compose configuration and are never read, copied or edited by DoGaMa.
  • Merge order is global labels, then instance labels; instance values win. Internal technical labels are applied last and cannot be overridden.
  • dogama.* and io.dogama.* are reserved label namespaces.
  • Label values support only the explicit allowlist in internal/instance/container_config.go; unknown variables are errors, not arbitrary templates.
  • {{game.icon_url}} is the public icon for the game. {{instance.slug}} remains supported.
  • Template game artwork contains separate required local logo and horizontal image assets; template validation rejects missing files. Deployment previews expose distinct logo and artwork URLs while retaining icon_url as a compatible logo alias. Palworld template 1.1.0 is the first snapshot with this contract.
  • All official and local template artwork is bundled locally, served through generic template-scoped routes with detected raster Content-Type, and retained in SQLite snapshots for historical rendering. Remote, absolute, traversal and escaping-symlink asset paths are rejected; no artwork checksum is required.
  • Embedded catalog validation is collection-based: every discovered template is schema- and cross-field-validated, including referenced assets, declared template-local integration modules and ports/configuration. A module bundle lives at <template>/module/, is declared by module.path, is path-confined and is retained with the selected snapshot; no game-specific internal registry exists. Template asset contents are not SHA-256-pinned, allowing administrator-maintained local assets while preserving required-path validation. A template version identifies a DoGaMa snapshot, whereas container.tag selects the game-server image; the official Palworld template follows Pocketpair's latest tag for new deployments and ordinary pulls.
  • Instance slugs are derived from the display name, not canonical IDs. Accents are normalized to ASCII; whitespace, /, punctuation and special characters become safe hyphen separators; repeated and edge hyphens are removed.
  • Docker user mode is fixed at creation to the administrator's managed game-container UID/GID or image-defined user. Image-defined templates cannot be overridden. Never perform automatic recursive ownership changes.
  • A pinned image tag is an explicit mutable tag, not an immutable digest. Tracked mode follows the template's declared default tag.
  • Replacement-requiring changes use the generic container_config_pending desired-versus-applied state. Replacements preserve bind-mounted data and prior running/stopped intent.
  • The main app never gains Docker-socket access; the agent remains deny-by-default and independently validates privileged plan fields.
  • Update candidates are explicit tag@sha256:digest references. Mutable tags alone are rejected; automatic updates remain disabled.
  • Mod configuration is data-only. Provider commands, scripts and arbitrary download URLs are forbidden.
  • The application generates and retains its 32-byte master key outside SQLite; the agent never receives it. Ciphertext is authenticated AES-GCM and secrets are never returned by list APIs.
  • agent_state and agent_auth remain durable security state: the former stores the MAC-protected instance-to-container registry and the latter stores its shared authentication key. Losing either must never trigger automatic adoption.
  • The canonical public deployment has exactly two services. Setup sidecars, init containers, host bootstrap scripts and user-managed internal secrets require an explicit architectural decision.
  • compose.yaml is the canonical minimal production Compose definition; compose-dev.yml is its intentionally small local HTTPS/testing overlay. Documentation references the canonical files instead of duplicating either configuration.
  • DOGAMA_NETWORK names the application-facing network. DOGAMA_GAMES_NETWORK names the single agent-approved network for all created and recreated game containers; API input cannot override either bootstrap boundary.
  • DoGaMa services never recursively change ownership of application, game-server or backup roots.
  • Notification delivery attempts are capped at five with exponential minute-scale backoff and never determine the originating operation result.
  • Administration notification forms update one channel at a time. SMTP and Gotify non-secret fields are rendered from the encrypted persisted configuration through an allowlist; SMTP/Discord/Gotify secrets are write-only, with empty edits retaining the existing secret.
  • Audit retention defaults to 30 days and 10,000 entries; zero explicitly selects unlimited retention/count within documented bounds.
  • At least one active global administrator is always retained; deactivation revokes that user's sessions atomically.
  • Session policy is stored in the existing system_settings table. created_at remains the absolute lifetime anchor, last_seen_at tracks inactivity with writes no more often than every five minutes, and logout/deactivation/expiry revoke server-side session rows.
  • The local template directory (/var/lib/dogama/templates, under the application data bind mount) is the catalog source of truth for administrator-owned customizations. Bundled templates are copied only when their destination files are absent; after every local scan, the current bundled immutable snapshots are synchronized into SQLite and selected for new deployments while older snapshots remain available for existing instances, audit and diagnostics.
  • Administrators can persist bounded HTTP(S) template-repository definitions for future use. They are configuration only: remote retrieval, authentication, synchronization and automatic updates are deliberately unavailable, and Catalog Scan remains local-only.
  • V Rising is the first template-scoped TCP RCON module. Its manifest currently declares only verified connectivity/status; command operations are not advertised until validated end-to-end against a real server. Go/WASI reactor modules use -buildmode=c-shared and initialize through _initialize; the V Rising success path uses concrete results to avoid Go 1.26 WASI reactor nil-interface traps. Wazero is pinned at v1.12.0.
  • Module TCP access is instance-scoped and template-bound: the guest supplies no destination, only bounded bytes; the host pins the instance network address and declared integration port, enforces deadlines and response limits, and rejects arbitrary/unsafe destinations.
  • Published port selection is generic: templates own container ports and protocols, while administrators choose host ports at deployment; TCP and UDP may reuse a host number because Docker treats those bindings independently.

Known limitations and debt

  • Scheduled backup outcomes and repeated authentication blocks are audited/logged, but broader scheduler-origin notification coverage remains intentionally limited to events emitted by implemented workflows.
  • The Dashboard links to an SSR instance detail page through opaque registry IDs. It uses existing lifecycle and backup services for CSRF-protected actions and a validated sandboxed WASM facade for declared live server info, metrics, player lists, banned-player lists and permitted player/announcement actions. Unban uses a fresh adapter list_bans result when available; otherwise, it accepts a bounded manual game identifier for the module to validate. Update availability is limited to immutable candidates explicitly approved in a template; games without one remain safely unknown and no registry browsing is performed.
  • Template configuration targets are applied during deployment: container environment and argv are included in the signed agent plan; INI changes are applied atomically after an optional restore and before start. Instance secrets are encrypted outside preview JSON.
  • Linux is the deployment target. Native Windows execution of the full Go suite is blocked by Unix Statfs code; use Linux/WSL/CI for complete execution.
  • The two DoGaMa services run as root inside their container namespaces for bind-mount portability. Risk is bounded with read-only image filesystems, all capabilities dropped, no-new-privileges, no Docker socket in the main application and a private typed agent API; rootless Docker and user-namespace remapping remain host-level deployment choices.
  • In-place migration of a successfully initialized v0.1.0 data directory has not been validated because that release wrote the application key under a different container identity. Preserve all stores and test a copied deployment rather than assuming compatibility.
  • staticcheck, golangci-lint and Python specification dependencies may not be installed on every development host; report missing tooling rather than silently skipping or installing it.

Validation and CI

  • .gitea/workflows/ci.yml validates pull requests and main; .gitea/workflows/release.yml publishes only tagged SemVer releases after the same required gate.
  • Normal completion gate for Go changes is the validation set in AGENTS.md on Linux.
  • Specification validation is python tools/validate_spec.py with tools/requirements-validation.txt available.
  • Start with package/file-specific tests, then run global tests, build, race detection, vet, static analysis and schema validation as applicable.

Next known work

  • No V1 milestone remains. Do not begin V1.x or V2 work without an explicit accepted scope.

  • Update this file after every merged milestone or durable architectural change; keep it compact and remove stale statements.

  • Web access and i18n are stored in the initial SQLite schema. HTTP defaults to working session/CSRF cookies without Secure and without HSTS; HTTPS enforcement is explicit.

  • Lifecycle failures retain a bounded diagnostic record separate from Audit. The restricted agent captures Docker inspection state (including exit/OOM/timestamps/health) and a bounded log tail after a failed start; the application persists this record under the operation ID and writes a stable DGM-* error category. Existing SQLite stores receive the additive diagnostic table at open time.

  • Approved template helper assets are immutable mode 0555, so an image-defined non-root user can execute a bind-mounted entrypoint while retaining no write access.