495 lines
11 KiB
Markdown
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.
|