148 lines
8.6 KiB
Markdown
148 lines
8.6 KiB
Markdown
# Development conventions
|
|
|
|
## Language and style
|
|
|
|
- Documentation and stable identifiers are English-first; UI strings are localizable from the start.
|
|
- Use idiomatic current stable Go, explicit errors and small interfaces at consumer boundaries.
|
|
- Prefer server-rendered `html/template` views, progressive enhancement and small focused browser modules; do not introduce a large SPA framework without an accepted architectural reason.
|
|
- Format and lint frontend and Go code with repository-pinned tools.
|
|
- Avoid hidden global state. Inject clock, ID generator and external interfaces for deterministic tests.
|
|
- Use UTC internally and IANA timezones at scheduling boundaries.
|
|
|
|
## Repository shape
|
|
|
|
The implementation may refine this layout while preserving boundaries:
|
|
|
|
```text
|
|
cmd/dogama/
|
|
cmd/dogama-agent/
|
|
internal/ non-public Go packages
|
|
web/ embedded UI source
|
|
migrations/ append-only SQLite migrations
|
|
specs/ schemas and normalized contracts
|
|
catalog/ reference templates
|
|
modules/ reference modules and fixtures
|
|
docs/
|
|
tests/integration/
|
|
```
|
|
|
|
## Initial application development
|
|
|
|
The initial main application requires Go 1.25. SQLite is provided by the pure-Go `modernc.org/sqlite` driver, so neither cgo nor a system SQLite development library is required. It reads bootstrap settings from `DOGAMA_LISTEN_ADDRESS` (default `:8080`), `DOGAMA_DATABASE_PATH` (default `dogama.db`), `DOGAMA_AGENT_URL`, `DOGAMA_AGENT_TOKEN_FILE` and `DOGAMA_MASTER_KEY_FILE`. The two agent settings must either both be present or both be absent; lifecycle routes remain disabled when developing without an agent. The master-key file must contain exactly 32 bytes and enables encrypted notification-channel configuration; audit remains available without it. Run it with:
|
|
|
|
```sh
|
|
go run ./cmd/dogama
|
|
```
|
|
|
|
Browser sessions always use `Secure`, `HttpOnly`, and `SameSite=Strict` cookies. Place the application behind a trusted TLS reverse proxy for browser use, including development environments. The application does not accept forwarded client addresses as authoritative for authentication throttling.
|
|
|
|
The restricted agent is a separate binary:
|
|
|
|
```sh
|
|
go run ./cmd/dogama-agent
|
|
```
|
|
|
|
It fails closed unless `DOGAMA_AGENT_TOKEN_FILE` references a 32-byte-or-longer
|
|
secret and at least one of `DOGAMA_ALLOWED_SERVER_ROOT` or
|
|
`DOGAMA_ALLOWED_BACKUP_ROOT` is configured. Its bootstrap-only defaults are
|
|
`:8081`, `/var/run/docker.sock`, the fixed `dogama-games` Docker network and
|
|
`/var/lib/dogama-agent/registry.json`. The configured roots must already exist
|
|
and are canonicalized with symlinks resolved. For normal deployment, use the
|
|
secret file and private control network defined in `compose.yaml`; never publish
|
|
the agent port on the host.
|
|
|
|
The agent loads the same embedded validated catalog as the main application.
|
|
Before Docker access it independently matches image, entrypoint, arguments,
|
|
container ports, mount destinations, resource minimums and stop timeout against
|
|
the pinned template snapshot. Mount sources are created one directory at a time
|
|
below configured roots with symlinks refused. Docker containers always use the
|
|
fixed restricted baseline; callers cannot provide labels, capabilities, devices,
|
|
network modes or arbitrary Docker options.
|
|
|
|
Lifecycle API operations are authorized in the backend against the authenticated
|
|
identity and the target instance. Global administrators retain implicit access;
|
|
assigned users can inspect, view metrics, start and stop, while managers also
|
|
receive the documented operational baseline. Explicit deny overrides take
|
|
precedence over role baselines and allows. Install and container-only delete
|
|
remain administrator operations. Operations are serialized per instance and
|
|
recorded in `instance_operations`; desired and observed states are reconciled at
|
|
startup and every minute. Container-only delete removes neither the SQLite
|
|
intent nor host paths, so player data and backups remain untouched.
|
|
|
|
The authorization foundation exposes JSON APIs for local user creation,
|
|
memberships, per-user overrides and installation requests. Mutations require the
|
|
session CSRF token. User creation, membership changes, override changes and
|
|
request review additionally require an administrator session authenticated in
|
|
the previous ten minutes. Approving a request only records the decision and the
|
|
requested values; it never creates a draft or contacts the restricted agent.
|
|
|
|
Game-data backups are written below `DOGAMA_BACKUPS_ROOT` (default
|
|
`/srv/game-backups`) and may only read instance mounts below
|
|
`DOGAMA_SERVERS_ROOT` (default `/srv/game-servers`). Untrusted uploads are
|
|
isolated below `DOGAMA_IMPORTS_ROOT` (default
|
|
`/var/lib/dogama/imports/staging`). These are bootstrap path boundaries, not
|
|
ordinary product settings. The same canonical server and backup roots are
|
|
mounted into the main application and restricted agent by `compose.yaml`.
|
|
|
|
The current backup engine conservatively stops a running instance before
|
|
archiving. Once the WebAssembly runtime is active, an enabled `online_save`
|
|
module can provide the documented flush-before-archive optimization without
|
|
moving traversal or archive ownership out of the main application. Archives
|
|
are finalized before SQLite marks them available; a metadata failure removes
|
|
the orphaned file. Scheduled retention considers only successful `scheduled`
|
|
backups. Restore verifies size, checksum, manifest and pinned template version,
|
|
creates a `pre_restore` backup, extracts into sibling staging and keeps the
|
|
instance stopped with `intervention_required` if readiness cannot be restored.
|
|
Validated imports are pinned to the selected template version. Import-backed
|
|
drafts require that opaque import ID, and installation atomically places the
|
|
normalized staged tree at the template-declared mount-relative destination
|
|
before the restricted agent creates the first container. Repeated installation
|
|
submission recognizes an already attached import instead of copying it twice.
|
|
|
|
At main-application startup, every embedded `catalog/*/template.yaml` is
|
|
validated against `specs/template.schema.json`, checked for cross-reference and
|
|
asset integrity, canonicalized deterministically and synchronized into SQLite.
|
|
An existing template ID/version is immutable: changing its digest fails startup
|
|
instead of silently replacing the snapshot. Deployment previews pin that digest
|
|
and redact secret defaults before a draft instance can enter the registry.
|
|
|
|
## Contract changes
|
|
|
|
Template schema, manifest schema, normalized module API and agent deployment plan are versioned contracts.
|
|
|
|
- Backward-compatible additions do not change existing meanings.
|
|
- Breaking changes require a new schema/API major version and documented migration.
|
|
- Released examples are updated or retained as compatibility fixtures.
|
|
- Instances pin immutable versions; runtime behavior never depends on a mutable catalog file.
|
|
|
|
## Testing pyramid
|
|
|
|
- Unit: domain policies, permission evaluation, cron/timezones, state transitions, retention and redaction.
|
|
- Property/fuzz: paths, archive entries, schema inputs, agent plans and normalized module payloads.
|
|
- Integration: SQLite migrations, disposable Docker agent, real archive workflows and WASM sandbox limits.
|
|
- End-to-end: bootstrap, Palworld dry/test fixture deployment, role views, backup/restore and update rollback.
|
|
|
|
Tests must include denial and interrupted-operation cases, not only happy paths. External game APIs use recorded or purpose-built fixtures in normal CI; live Palworld verification is a separate documented test.
|
|
|
|
## Migrations and compatibility
|
|
|
|
Never rewrite a released migration. Migration execution is transactional where SQLite permits and creates a pre-migration database backup for release upgrades. Store application/schema version and test upgrade from the previous release.
|
|
|
|
## Dependencies and supply chain
|
|
|
|
Prefer standard-library or mature focused dependencies. Pin build tooling, review transitive changes and generate an SBOM/reproducible checksums for releases. Do not dynamically download executable code at runtime except administrator-installed validated WASM packages.
|
|
|
|
## Observability
|
|
|
|
Structured technical logs use stable event names and redaction. Metrics are operationally small. Correlation/operation IDs connect HTTP, job and agent errors without storing request secrets.
|
|
|
|
## Review checklist
|
|
|
|
- Correct trust boundary and backend authorization?
|
|
- Can input influence a host path, Docker plan, URL or secret?
|
|
- Are retries/idempotency and restart recovery defined?
|
|
- Could failure delete or corrupt player data?
|
|
- Do documentation, schema and examples agree?
|
|
- Are UI capability checks backed by server checks?
|
|
- Are audit and notifications appropriately minimal?
|