Harden CI and switch release builds to tagged immutable images
All checks were successful
CI / Backend (push) Successful in 29s
CI / Frontend (push) Successful in 9m27s
CI / Contracts and repository policy (push) Successful in 7s
CI / Container (push) Successful in 18s

This commit is contained in:
Elijah 2026-07-15 19:21:07 -07:00
parent bed2e6cfb6
commit f24e96efa7
60 changed files with 4710 additions and 64 deletions

View file

@ -0,0 +1,6 @@
# ADR-0001: PostgreSQL on btrfs with CoW
Status: Accepted
PostgreSQL data remains on the mirrored exclusive btrfs cache with copy-on-write and PostgreSQL page checksums enabled. `chattr +C` is not used because it would remove btrfs data checksums and mirror self-healing for database files. Capacity, WAL growth, and fragmentation will be monitored when operations work is implemented.

View file

@ -0,0 +1,6 @@
# ADR-0002: Opaque object IDs and same-directory promotion
Status: Accepted
Managed objects use opaque physical IDs. PostgreSQL maps SHA-256 content identities to physical objects. Partials and completed blobs share one shard directory so final promotion is a same-directory rename. Blob-manifest export is required because the filesystem alone is not self-describing.

View file

@ -0,0 +1,6 @@
# ADR-0003: Protect commits, not incomplete transfers
Status: Accepted
Committed content and metadata must recover consistently. Incomplete uploads may be failed or discarded after an unclean shutdown. Restart recovery reconciles partial length with the persisted offset and may recompute hashes instead of making incremental hash state crash-durable.

View file

@ -0,0 +1,6 @@
# ADR-0004: Single application service
Status: Accepted
Production runs HTTP handling and PostgreSQL-leased background workers in one Drive container beside PostgreSQL. This favors simple operation on one private Unraid host. Worker failures must be isolated and observable, and durable state must allow later separation without changing domain behavior.

View file

@ -0,0 +1,6 @@
# ADR-0005: HTTP precondition and conflict semantics
Status: Accepted
Failed `If-Match` or equivalent representation preconditions return `412 Precondition Failed`. Name collisions, invalid hierarchy operations, and other domain conflicts return `409 Conflict`. Both use RFC 9457 problem documents with stable codes and current state where useful.

View file

@ -0,0 +1,6 @@
# ADR-0006: Stable-v1 product scope
Status: Accepted
Stable v1 includes file management, resumable transfers, importer, sharing, OnlyOffice, core previews, PWA, backup/recovery foundations, and future-sync-ready file APIs. Desktop sync, Calendar, archive browsing, and 3D previews are deferred without speculative APIs. Other Google-suite categories require separate proposals.

View file

@ -0,0 +1,6 @@
# ADR-0007: Open first-run setup
Status: Accepted risk
An uninitialized server exposes the owner-creation page without a bootstrap secret. Owner creation is an atomic single-winner transaction and setup becomes permanently unavailable afterward. Operations documentation requires completing setup before proxy exposure. The owner accepts the takeover risk if an uninitialized instance is exposed.

14
docs/adr/README.md Normal file
View file

@ -0,0 +1,14 @@
# Architecture decision records
ADRs are immutable after acceptance. Supersede an earlier decision with a new ADR rather than rewriting its history.
| ADR | Decision | Status |
| --- | --- | --- |
| 0001 | PostgreSQL remains on btrfs with CoW | Accepted |
| 0002 | Opaque object IDs and same-directory promotion | Accepted |
| 0003 | Protect commits, not incomplete transfers | Accepted |
| 0004 | Single application service | Accepted |
| 0005 | HTTP precondition and conflict status codes | Accepted |
| 0006 | Stable-v1 and deferred product scope | Accepted |
| 0007 | Open first-run setup | Accepted risk |

24
docs/architecture.md Normal file
View file

@ -0,0 +1,24 @@
# Architecture guide
The detailed baseline is `Drive_v2_final_plan.md`. This guide is a short implementation map.
## Request flow
```text
HTTP transport -> application use case -> domain rules
|-> PostgreSQL repository
|-> storage/external adapter
```
Transport code handles protocol concerns only. Application services own transactions and coordinate database-plus-storage work. Domain code contains no infrastructure dependencies.
## Durable work
No authoritative state lives only in memory. Upload sessions, commit intents, jobs, leases, and cursors are persisted in PostgreSQL. Committed blobs are immutable and become visible only after storage promotion and metadata commit.
## Frontend
Each feature owns its routes, API hooks, components, state, and tests. Cross-feature access goes through a small public entrypoint. Server state stays in TanStack Query and local UI state remains close to the component or feature that owns it.
Preview rendering is capability-driven and lazy-loaded. Adding a format must not require editing the file manager.

14
docs/dependencies.md Normal file
View file

@ -0,0 +1,14 @@
# Dependency policy
Dependencies are pinned in `go.mod`, `web/package.json`, the npm lockfile, container tags, and CI workflow references. Add a runtime dependency only when its functionality is actively used, and record architectural additions in an ADR before merging.
## Phase 0 baseline
Backend production code currently uses the Go standard library. Chi, pgx, sqlc, and the migration runner are approved by the architecture baseline and will be pinned when their first Phase 1 implementation is added.
Frontend runtime dependencies are React, React DOM, TanStack Query, and TanStack Router. Development dependencies provide TypeScript, Vite, Vitest, ESLint, React tooling, and type declarations.
Container baselines are Go 1.26 on Debian Bookworm, Node 24 on Debian Bookworm, PostgreSQL 18.4 on Debian Bookworm, and a Debian Bookworm slim runtime. Production deployment should pin tested image digests as part of its release configuration.
Dependency updates must pass the full repository check and production image build. Avoid packages that duplicate standard-library functionality or introduce background network behavior, telemetry, install scripts, or unreviewed native binaries.

37
docs/development.md Normal file
View file

@ -0,0 +1,37 @@
# Development guide
## Structure
- `cmd/drive` owns process startup and CLI dispatch.
- `internal/domain` contains dependency-free business rules.
- `internal/application` coordinates use cases through interfaces.
- `internal/adapters` implements PostgreSQL, storage, and external-service ports.
- `internal/transport` maps HTTP contracts to application calls.
- `internal/workers` executes persistent leased jobs.
- `web/src/features` owns frontend product features; `web/src/shared` contains reusable primitives.
- `api/openapi.yaml`, migrations, and sqlc queries are reviewed source contracts.
## Canonical checks
Native:
```text
go test ./cmd/... ./internal/...
npm --prefix web ci
npm --prefix web run check
```
Containerized:
```text
docker compose run --rm verify
docker compose up --build
```
## Contract workflow
Do not add an API handler before its OpenAPI operation exists. Do not write SQL directly in transport or application code; add a named sqlc query. Generated files are outputs and are never edited by hand. CI will add strict generation-drift checks when the first generated client and repository are introduced in Phase 1.
## Architectural changes
Create an ADR before changing storage semantics, public API conventions, package boundaries, deployment topology, or approved dependencies. An ADR records context, decision, consequences, and superseded decisions.

View file

@ -0,0 +1,6 @@
# Operations documentation
The production runbook will cover Unraid share layout, permissions, Nginx Proxy Manager, OnlyOffice networking, graceful shutdown timers, backups, restore, importer use, capacity alerts, and troubleshooting.
Phase 0 provides development Compose only. Do not treat it as a production deployment template until the Phase 7 production checklist is complete.

36
docs/threat-model.md Normal file
View file

@ -0,0 +1,36 @@
# Threat model
## Protected assets
- File contents, metadata, previews, and replacement-recovery blobs.
- Password, sessions, TOTP secrets, recovery codes, API tokens, share tokens, and OnlyOffice secrets.
- Database-to-object mapping, backup data, and blob manifests.
## Trust boundaries
- Browser to Nginx Proxy Manager to Drive HTTP service.
- Drive to PostgreSQL on the private container network.
- Drive to managed cache/array mounts.
- Drive to the existing OnlyOffice Document Server.
- Public-link visitors to explicitly shared resources.
- Read-only importer mounts to managed Drive storage.
## Primary threats
- Unclaimed-instance takeover before first-run setup.
- Session theft, CSRF, credential guessing, token leakage, and proxy-address spoofing.
- Path traversal, symlink following, MIME confusion, malicious previews, and archive expansion.
- SSRF or forged OnlyOffice callbacks.
- Stale writes, duplicate requests, interrupted commits, and premature GC.
- Secret disclosure through logs, images, configuration, backups, or repository history.
## Phase 0 controls
- Production setup must finish before proxy exposure; setup is disabled atomically after owner creation.
- Secrets are environment/file inputs and ignored by Git.
- Non-root container, explicit mounts, private PostgreSQL network, and health endpoints.
- Architectural boundaries prevent HTTP code from reaching database or managed storage directly.
- Security headers, CSRF, authentication, rate limits, scoped tokens, and callback validation are implemented with their Phase 1 features.
Review this document whenever a new external integration, public endpoint, preview processor, or authentication mechanism is introduced.