update_server/IMPLEMENTATION_PLAN.md
2026-06-10 20:51:17 +03:00

495 lines
11 KiB
Markdown

# Update Server - Implementation Strategy
## 1. Recommended stack
### Backend
- Go 1.24+
- Router: `chi` or `gin`
- HTML templates for admin UI, or server-rendered pages first
- Database: `SQLite`
- ORM/query layer: `sqlc`, `bun`, `gorm`, or plain `database/sql`
- Migrations: `golang-migrate` or `goose`
- Auth:
- web admin via secure cookie session
- client API via bearer API key
### My recommendation
For this project, a pragmatic Go stack would be:
- `chi` for routing;
- `database/sql` + `sqlc` or `bun`;
- `SQLite` with `modernc.org/sqlite` or `mattn/go-sqlite3`;
- server-rendered HTML templates for admin pages;
- `goose` for migrations.
Why this stack:
- simple to deploy;
- less JS and frontend complexity;
- good fit for an internal admin panel;
- easier to keep maintainable for a small self-hosted tool.
## 2. Quick glossary
`GUI`
- graphical user interface;
- here it simply means the admin web panel in a browser.
`chi`
- a small and fast HTTP router for Go;
- this is not `CI`;
- it helps map routes like `/api/v1/projects/{id}` to handlers.
`CI`
- continuous integration;
- automated checks that run on commits, for example tests, linting, or building Docker images.
`server-rendered HTML`
- the Go server itself generates HTML pages and returns them to the browser;
- this keeps the admin panel simpler than building a separate frontend app.
## 3. Architecture proposal
Suggested project structure:
```text
/cmd/server
/internal/app
/internal/http
/internal/auth
/internal/projects
/internal/releases
/internal/apikeys
/internal/users
/internal/tags
/internal/storage
/internal/db
/internal/config
/web/templates
/web/static
/migrations
/data
```
### Main modules
`projects`
- create/update/list/archive projects
- manage project tags
`releases`
- upload artifact
- compute checksum
- store metadata
- provide release lookup and download
`apikeys`
- generate secure random API keys
- hash and persist
- enforce permissions and project scope
`tags`
- CRUD for tags
- attach tags to projects
- resolve tag-based access rules
`users`
- admin authentication
- password hashing
- role checks
`storage`
- local filesystem storage abstraction
- future option to swap to S3-compatible storage
## 4. Suggested data model
Core tables:
- `users`
- `projects`
- `tags`
- `project_tags`
- `releases`
- `api_keys`
- `api_key_project_access`
- `api_key_tag_access`
- `sessions` if server-side sessions are used
- optionally `audit_logs`
### Example relations
- one `project` has many `releases`
- one `user` uploads many `releases`
- one `project` has many tags through `project_tags`
- one `api_key` can reference many projects through `api_key_project_access`
- one `api_key` can reference many tags through `api_key_tag_access`
Suggested key columns in `api_keys`:
- `scope_mode` with values:
- `all_projects`
- `project_allow_list`
- `project_deny_list`
- `tag_allow_list`
- `tag_deny_list`
## 5. Permission strategy
Recommended first implementation:
- API key has boolean flags:
- `can_download`
- `can_upload`
- `can_delete`
- `can_manage_projects`
- API key has access mode:
- `all_projects`
- `project_allow_list`
- `project_deny_list`
- `tag_allow_list`
- `tag_deny_list`
- linked projects stored in `api_key_project_access`
- linked tags stored in `api_key_tag_access`
Recommended evaluation rules:
- `all_projects`: allow every active project
- `project_allow_list`: allow only linked projects
- `project_deny_list`: allow every active project except linked projects
- `tag_allow_list`: allow projects matching at least one linked tag
- `tag_deny_list`: allow every active project except projects matching blocked tags
Recommended constraint for v1:
- each key uses exactly one scope mode at a time.
This supports whitelist, blacklist, and future grouping without building a full RBAC engine upfront.
## 6. API design strategy
Split API into two logical areas:
### Client API
Used by application clients:
- authenticate by bearer API key
- list accessible projects
- query latest release
- download release artifact
### Admin API
Used by web UI and optionally automation:
- manage projects
- manage tags
- manage releases
- manage API keys
- manage users
Keep both under `/api/v1`, but separate middleware and handlers clearly.
## 7. File upload strategy
Recommended upload flow:
1. admin uploads file;
2. backend stores temporary stream;
3. checksum is calculated;
4. file is moved into final artifact path;
5. release metadata is inserted into DB;
6. transaction/state is finalized.
Important safeguards:
- limit file size;
- sanitize filenames;
- prevent path traversal;
- avoid duplicate version collisions unless explicitly replacing;
- validate project exists before storing;
- store uploads outside any static web root;
- never execute or unpack uploaded files.
## 8. Security checklist
- hash passwords with `bcrypt` or `argon2id`
- hash API keys before storing
- show full API key only once
- secure cookies with `HttpOnly`, `Secure`, `SameSite`
- CSRF protection for admin forms
- upload size limits
- permission checks on every API endpoint
- request logging without leaking secrets
- rate limiting for login and API key endpoints
- store artifacts outside the web root
- serve downloads only after auth and permission checks
- set server timeouts: read, write, idle, header
- add security headers such as `Content-Security-Policy`, `X-Frame-Options`, `X-Content-Type-Options`
- terminate TLS at Caddy or Nginx
- optionally restrict admin UI by IP allow-list or VPN
- avoid shelling out to external tools for file processing
- keep dependencies updated and scan them periodically
## 9. Internet-facing deployment posture
If the server will be visible on the internet, this is the safe baseline:
- app listens only behind a reverse proxy;
- reverse proxy handles HTTPS certificates;
- admin UI uses strong password and optionally IP allow-list;
- SQLite file and artifacts live on a mounted persistent volume;
- no public directory listing for artifacts;
- uploads never become directly executable server-side content;
- logs and backups are stored separately from app code.
## 10. Development strategy
Recommended approach:
- develop locally on your Mac first;
- keep everything in one project directory;
- run the Go server natively for fast iteration;
- add Docker packaging once the core flows work locally;
- deploy to Proxmox only after the first end-to-end flow is stable.
Why local-first is better here:
- faster feedback loop;
- easier debugging;
- easier file upload testing;
- no need to fight remote networking while core logic is still changing.
Good compromise:
- write code locally on Mac;
- keep deployment target from day one in mind;
- periodically verify that the Docker image still builds.
## 11. Deployment strategy
Single container is realistic.
Recommended runtime layout:
- app binary in container
- reverse proxy in front of container
- mounted `/data` volume
- SQLite DB in `/data/db.sqlite`
- artifacts in `/data/artifacts`
### Environment variables
- `APP_ADDR`
- `APP_BASE_URL`
- `DATA_DIR`
- `SQLITE_PATH`
- `ADMIN_EMAIL`
- `ADMIN_PASSWORD`
- `SESSION_SECRET`
Recommended deployment target:
- Proxmox VM or LXC with Docker or Podman;
- app container plus reverse proxy;
- mounted volume for `/data`;
- regular backup of `/data`.
## 12. Delivery phases
### Phase 1 - Skeleton
- initialize Go module
- wire config
- HTTP server
- health endpoint
- migrations setup
- SQLite connection
- basic template rendering
### Phase 2 - Auth and admin bootstrap
- user table
- create initial admin user
- login/logout
- session middleware
### Phase 3 - Projects and releases
- projects CRUD
- project tags CRUD
- release upload
- release list/detail
- local artifact storage
### Phase 4 - API keys and access control
- API key generation
- hashed storage
- project white-list and black-list
- tag-based schema and access checks
- permission middleware
### Phase 5 - Client update API
- latest release endpoint
- release metadata endpoint
- download endpoint
- audit of last key usage
### Phase 6 - Hardening
- validation
- CSRF
- logging
- soft deletes
- basic audit logs
- reverse proxy config
- rate limiting
- Docker image and compose setup
## 13. Agent execution plan
If multiple AI agents or contributors will implement this, split work by vertical ownership.
### Agent 1 - Core platform
Owns:
- Go module setup
- config
- server bootstrap
- middleware skeleton
- Docker setup
### Agent 2 - Data layer
Owns:
- migrations
- schema
- repositories/queries
- SQLite integration
- tags and access-rule tables
### Agent 3 - Auth and users
Owns:
- admin login
- sessions
- password handling
- user management basics
### Agent 4 - Projects and releases
Owns:
- project CRUD
- tag assignment to projects
- release upload flow
- artifact storage abstraction
- checksum logic
### Agent 5 - API keys and client API
Owns:
- API key generation
- permission model
- whitelist/blacklist evaluation
- tag-based access evaluation
- client-facing release lookup and download endpoints
### Agent 6 - Admin UI
Owns:
- HTML templates
- forms
- tables/pages for projects, releases, keys, users, tags
### Agent 7 - Security and deployment hardening
Owns:
- secure headers
- rate limiting
- reverse proxy templates
- deployment hardening review
## 14. Recommended implementation order for agents
1. Agent 1 sets up application skeleton and app wiring.
2. Agent 2 defines schema and migrations.
3. Agent 3 implements admin auth.
4. Agent 4 implements projects, tags, and release storage.
5. Agent 5 implements API key model and client endpoints.
6. Agent 6 builds the admin UI on top of completed flows.
7. Agent 7 hardens internet-facing deployment paths.
8. Final pass integrates validation, tests, and Docker packaging.
## 15. Testing strategy
### Unit tests
- version selection logic
- permission checks
- API key hashing/lookup
- checksum generation
- tag scope matching
### Integration tests
- login flow
- create project
- attach tags to project
- upload release
- create API key
- fetch latest release via API key
- reject unauthorized project access
- reject blacklisted project or tag access
### Manual sanity tests
- upload file from admin UI
- download via curl using bearer API key
- restart container and verify persistence
- verify admin login rate limits
- verify artifacts are not directly exposed by URL guessing
## 16. My recommendations on product scope
To avoid overbuilding too early, I would start with:
- SQLite
- local filesystem storage
- server-rendered admin UI
- one file per release
- one admin role first, but schema ready for more users
- one scope mode per key
- project whitelist and blacklist in v1
- project tags in schema from day one
This version will already be useful and can stay very small operationally.
## 17. Nice first concrete milestone
The first milestone should be:
"Admin can log in, create a tagged project, upload a versioned file, create an API key with project or tag-based access, and a client can download the latest file using that key."
If that works end-to-end, the rest can be layered on safely.