486 lines
12 KiB
Markdown
486 lines
12 KiB
Markdown
# Update Server - Product Specification
|
|
|
|
## 1. Goal
|
|
|
|
Build a small self-hosted update server for distributing application updates.
|
|
|
|
The system should allow an administrator to:
|
|
|
|
- create projects;
|
|
- upload update files for those projects;
|
|
- manage client API keys;
|
|
- configure which API keys can access which projects and which actions are allowed;
|
|
- group projects with tags;
|
|
- provide a simple web UI for administration;
|
|
- expose an HTTP API for client applications to check, fetch, and manage updates.
|
|
|
|
Primary implementation language: Go.
|
|
|
|
## 2. Product idea in one sentence
|
|
|
|
An admin uploads versioned update artifacts into projects, and client applications use API keys to securely discover and download only the updates they are allowed to access.
|
|
|
|
## 3. Main entities
|
|
|
|
### 3.1 Project
|
|
|
|
A project represents one distributable application, file, package, or update stream.
|
|
|
|
Suggested fields:
|
|
|
|
- `id`
|
|
- `name`
|
|
- `slug`
|
|
- `description`
|
|
- `created_at`
|
|
- `updated_at`
|
|
- `is_active`
|
|
|
|
Notes:
|
|
|
|
- In MVP, one project can simply correspond to one app or one downloadable file family.
|
|
- Later this can be extended with channels like `stable`, `beta`, `nightly`.
|
|
- Projects should support tags from the start.
|
|
|
|
### 3.2 Release / Update
|
|
|
|
A release is an uploaded update artifact belonging to a project.
|
|
|
|
Suggested fields:
|
|
|
|
- `id`
|
|
- `project_id`
|
|
- `version`
|
|
- `build`
|
|
- `filename`
|
|
- `storage_path`
|
|
- `checksum_sha256`
|
|
- `size_bytes`
|
|
- `content_type`
|
|
- `release_notes`
|
|
- `created_at`
|
|
- `uploaded_by_user_id`
|
|
- `is_active`
|
|
|
|
Optional future fields:
|
|
|
|
- `channel`
|
|
- `min_client_version`
|
|
- `rollout_percent`
|
|
- `metadata_json`
|
|
|
|
### 3.3 API Key
|
|
|
|
An API key is used by client software to authenticate against the update API.
|
|
|
|
Suggested fields:
|
|
|
|
- `id`
|
|
- `name`
|
|
- `key_prefix`
|
|
- `key_hash`
|
|
- `description`
|
|
- `scope_mode`
|
|
- `is_active`
|
|
- `expires_at`
|
|
- `created_at`
|
|
- `updated_at`
|
|
- `last_used_at`
|
|
|
|
Security note:
|
|
|
|
- store only a hash of the full API key, never the raw key;
|
|
- show the full key only once when created.
|
|
|
|
### 3.4 User
|
|
|
|
At least one admin user is needed for the web UI.
|
|
|
|
Suggested fields:
|
|
|
|
- `id`
|
|
- `email` or `login`
|
|
- `password_hash`
|
|
- `role`
|
|
- `is_active`
|
|
- `created_at`
|
|
- `updated_at`
|
|
- `last_login_at`
|
|
|
|
MVP note:
|
|
|
|
- start with one admin user;
|
|
- design schema so multiple users can be supported without a major rewrite.
|
|
|
|
### 3.5 Tag
|
|
|
|
A tag is a reusable label attached to projects and later used in access rules.
|
|
|
|
Examples:
|
|
|
|
- `windows`
|
|
- `beta`
|
|
- `internal`
|
|
- `customer-acme`
|
|
- `desktop`
|
|
|
|
Suggested fields:
|
|
|
|
- `id`
|
|
- `name`
|
|
- `slug`
|
|
- `description`
|
|
- `created_at`
|
|
|
|
Relations:
|
|
|
|
- one project can have many tags;
|
|
- one tag can be attached to many projects;
|
|
- API keys can reference tags in access rules.
|
|
|
|
## 4. Access control model
|
|
|
|
Each API key should have both action permissions and project scope.
|
|
|
|
### 4.1 Action permissions
|
|
|
|
Suggested permissions:
|
|
|
|
- `updates.read` - check available updates and download files
|
|
- `updates.upload` - upload releases
|
|
- `updates.delete` - delete releases
|
|
- `projects.read` - list accessible projects
|
|
- `projects.write` - create or edit projects
|
|
- `admin.read` - view admin-level metadata
|
|
- `admin.write` - manage API keys and access rules
|
|
|
|
For MVP, this can be simplified to:
|
|
|
|
- `can_download`
|
|
- `can_upload`
|
|
- `can_delete`
|
|
- `can_manage_projects`
|
|
|
|
### 4.2 Scope strategies
|
|
|
|
Each API key should support one access scope strategy:
|
|
|
|
- access to all projects;
|
|
- project white list;
|
|
- project black list;
|
|
- tag white list;
|
|
- tag black list.
|
|
|
|
Recommended v1 model:
|
|
|
|
- mode `all_projects`
|
|
- mode `project_allow_list`
|
|
- mode `project_deny_list`
|
|
- mode `tag_allow_list`
|
|
- mode `tag_deny_list`
|
|
|
|
Why:
|
|
|
|
- this supports both explicit project lists and future tag-based grouping;
|
|
- it avoids the complexity of mixing many overlapping rule types in one key;
|
|
- it keeps evaluation logic predictable and safer.
|
|
|
|
### 4.3 Access evaluation
|
|
|
|
Recommended effective access logic:
|
|
|
|
- `all_projects`: key can access all active projects;
|
|
- `project_allow_list`: key can access only linked projects;
|
|
- `project_deny_list`: key can access all active projects except linked projects;
|
|
- `tag_allow_list`: key can access projects that have at least one linked tag;
|
|
- `tag_deny_list`: key can access all active projects except projects that have one of the blocked tags.
|
|
|
|
Recommended v1 restriction:
|
|
|
|
- one API key uses exactly one scope strategy at a time.
|
|
|
|
This keeps the admin UI and permission checks much simpler.
|
|
|
|
## 5. Admin web UI
|
|
|
|
### 5.1 Pages for MVP
|
|
|
|
1. Login page
|
|
2. Dashboard
|
|
3. Projects list
|
|
4. Create/edit project page
|
|
5. Project detail page
|
|
6. Release upload page or upload block inside project detail
|
|
7. Tags list
|
|
8. Create/edit tag page
|
|
9. API keys list
|
|
10. Create API key page
|
|
11. API key detail/edit page
|
|
12. Users page or at least admin bootstrap settings page
|
|
|
|
### 5.2 Minimal UI capabilities
|
|
|
|
Projects:
|
|
|
|
- create project;
|
|
- edit project;
|
|
- archive or disable project;
|
|
- view releases for a project;
|
|
- upload new release;
|
|
- delete or disable release;
|
|
- attach and detach tags.
|
|
|
|
API keys:
|
|
|
|
- generate key;
|
|
- disable key;
|
|
- set expiration;
|
|
- select scope strategy;
|
|
- assign project white list or black list;
|
|
- assign tag white list or black list;
|
|
- assign action permissions;
|
|
- inspect last usage.
|
|
|
|
Tags:
|
|
|
|
- create tag;
|
|
- edit tag;
|
|
- delete unused tag;
|
|
- attach tags to projects;
|
|
- use tags in API key access rules.
|
|
|
|
Users:
|
|
|
|
- login/logout;
|
|
- change password;
|
|
- optionally create another admin/editor later.
|
|
|
|
## 6. Client API
|
|
|
|
The API should support both admin operations and client update retrieval.
|
|
|
|
### 6.1 Auth model
|
|
|
|
- web UI uses session or secure cookie auth;
|
|
- external clients use API key auth via header, for example:
|
|
- `Authorization: Bearer <api_key>`
|
|
- or `X-API-Key: <api_key>`
|
|
|
|
Recommendation:
|
|
|
|
- use `Authorization: Bearer <api_key>` for external API consistency.
|
|
|
|
### 6.2 Suggested client endpoints
|
|
|
|
#### Check accessible projects
|
|
|
|
- `GET /api/v1/projects`
|
|
|
|
Returns only projects accessible to the API key.
|
|
|
|
#### Check latest release for a project
|
|
|
|
- `GET /api/v1/projects/{projectSlug}/releases/latest`
|
|
|
|
Possible query parameters:
|
|
|
|
- `current_version`
|
|
- `channel`
|
|
- `platform`
|
|
- `arch`
|
|
|
|
#### List releases for a project
|
|
|
|
- `GET /api/v1/projects/{projectSlug}/releases`
|
|
|
|
#### Download release file
|
|
|
|
- `GET /api/v1/releases/{releaseID}/download`
|
|
|
|
Alternative:
|
|
|
|
- `GET /api/v1/projects/{projectSlug}/releases/{version}/download`
|
|
|
|
#### Get release metadata
|
|
|
|
- `GET /api/v1/releases/{releaseID}`
|
|
|
|
### 6.3 Suggested admin endpoints
|
|
|
|
- `POST /api/v1/admin/projects`
|
|
- `PATCH /api/v1/admin/projects/{id}`
|
|
- `DELETE /api/v1/admin/projects/{id}`
|
|
- `GET /api/v1/admin/tags`
|
|
- `POST /api/v1/admin/tags`
|
|
- `PATCH /api/v1/admin/tags/{id}`
|
|
- `DELETE /api/v1/admin/tags/{id}`
|
|
- `POST /api/v1/admin/projects/{id}/releases`
|
|
- `DELETE /api/v1/admin/releases/{id}`
|
|
- `GET /api/v1/admin/api-keys`
|
|
- `POST /api/v1/admin/api-keys`
|
|
- `PATCH /api/v1/admin/api-keys/{id}`
|
|
- `DELETE /api/v1/admin/api-keys/{id}`
|
|
- `GET /api/v1/admin/users`
|
|
- `POST /api/v1/admin/users`
|
|
|
|
## 7. Storage
|
|
|
|
### 7.1 Database recommendation
|
|
|
|
Recommended for this project: `SQLite`.
|
|
|
|
Reasoning:
|
|
|
|
- single file database;
|
|
- easy to ship inside one container;
|
|
- good fit for low-to-medium admin traffic;
|
|
- excellent support in Go;
|
|
- no need to run a separate DB service.
|
|
|
|
Important clarification:
|
|
|
|
- `SQLite` is likely what was meant by "MySQL Lite";
|
|
- `MySQL` itself is a separate server database and would add complexity.
|
|
|
|
### 7.2 File storage
|
|
|
|
Store uploaded release files on local disk in the container or in a mounted volume.
|
|
|
|
Suggested layout:
|
|
|
|
- `/data/db.sqlite`
|
|
- `/data/artifacts/{project_slug}/{version}/{filename}`
|
|
|
|
Important:
|
|
|
|
- use a mounted persistent volume in deployment, not only container-local ephemeral storage;
|
|
- keep uploaded files outside any public static web root;
|
|
- downloads should be authorized by the app, not exposed as open file URLs.
|
|
|
|
## 8. Roles and authentication
|
|
|
|
### 8.1 Web users
|
|
|
|
Suggested roles:
|
|
|
|
- `admin` - full access
|
|
- `editor` - can upload and manage projects, but not system settings
|
|
- `viewer` - read-only, optional future role
|
|
|
|
MVP:
|
|
|
|
- implement `admin` first;
|
|
- keep schema ready for extra roles later.
|
|
|
|
### 8.2 Initial bootstrap
|
|
|
|
At first startup:
|
|
|
|
- create admin user from environment variables;
|
|
- or provide a one-time bootstrap CLI command.
|
|
|
|
Recommended env vars:
|
|
|
|
- `ADMIN_EMAIL`
|
|
- `ADMIN_PASSWORD`
|
|
|
|
## 9. Security requirements
|
|
|
|
Because this server may be reachable from the public internet, security is a first-class requirement.
|
|
|
|
Core requirements:
|
|
|
|
- every admin page must require authenticated session access;
|
|
- every API endpoint must enforce permission checks;
|
|
- uploaded files must never be executed or unpacked on the server;
|
|
- artifacts must be stored outside the public web root;
|
|
- downloads must go through authorization checks, not open static directories;
|
|
- passwords must be hashed with a modern password hash;
|
|
- API keys must be hashed and shown only once;
|
|
- rate limiting should protect login and API key endpoints;
|
|
- request size limits and timeouts must be enabled;
|
|
- CSRF protection must be enabled for admin forms;
|
|
- path traversal and arbitrary file overwrite must be prevented;
|
|
- audit logs should record login attempts, uploads, deletions, and key usage;
|
|
- TLS should be terminated by a reverse proxy such as Caddy or Nginx;
|
|
- security headers should be enabled;
|
|
- dependencies should be kept updated.
|
|
|
|
Recommended additional protection:
|
|
|
|
- optionally restrict admin UI by IP allow-list or VPN;
|
|
- disable deleted or compromised API keys immediately;
|
|
- back up both SQLite DB and artifacts;
|
|
- never process uploaded files with shell commands;
|
|
- keep secrets in environment variables, not in repository files.
|
|
|
|
## 10. Non-functional requirements
|
|
|
|
- easy local development;
|
|
- deployable as one container;
|
|
- persistent storage via volume mount;
|
|
- secure API key handling;
|
|
- auditability of uploads and key usage;
|
|
- basic request logging;
|
|
- simple backup strategy for DB and artifacts.
|
|
|
|
## 11. MVP scope
|
|
|
|
The first usable version should include:
|
|
|
|
- admin login;
|
|
- project CRUD;
|
|
- project tags;
|
|
- release upload;
|
|
- release listing;
|
|
- API key generation and revocation;
|
|
- API key white-list or black-list by project;
|
|
- schema support for tag-based access rules;
|
|
- API endpoint to fetch latest release metadata;
|
|
- API endpoint to download release;
|
|
- SQLite database;
|
|
- local disk artifact storage;
|
|
- Docker deployment;
|
|
- reverse-proxy-ready setup for HTTPS.
|
|
|
|
## 12. Post-MVP ideas
|
|
|
|
- release channels (`stable`, `beta`);
|
|
- semantic version comparison;
|
|
- delta updates / patch files;
|
|
- signed manifests;
|
|
- download tokens with short TTL;
|
|
- release publishing workflow as draft/published;
|
|
- webhook notifications;
|
|
- S3-compatible artifact storage;
|
|
- rate limiting;
|
|
- audit log UI;
|
|
- per-platform binaries;
|
|
- automatic cleanup rules;
|
|
- client usage analytics.
|
|
|
|
## 13. Open product decisions
|
|
|
|
These should be decided before implementation starts:
|
|
|
|
1. Should clients always download the latest version, or should they first request metadata and decide themselves?
|
|
2. Do releases need channels like `stable` and `beta` from day one?
|
|
3. Should upload via API key be allowed in MVP, or only through the web admin UI?
|
|
4. Are deleted releases truly removed, or just soft-deleted/hidden?
|
|
5. Should one project contain only one file per version, or potentially multiple files per release?
|
|
6. Do clients need platform-specific assets like Windows/Linux/macOS builds?
|
|
7. Should tag-based access be fully active in v1, or should the schema/UI be prepared first and enforcement added in v1.1?
|
|
|
|
## 14. Recommended simplifications for v1
|
|
|
|
To keep the first version small and reliable:
|
|
|
|
- one artifact file per release;
|
|
- one main admin user;
|
|
- SQLite only;
|
|
- local filesystem storage only;
|
|
- one scope strategy per API key;
|
|
- project white-list and black-list in v1;
|
|
- tags supported in schema and project UI from day one;
|
|
- session auth for web UI, API key auth for clients;
|
|
- soft delete for projects/releases/API keys when possible.
|