Files
distribution/PLAN.md

322 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Distribution Platform in sx
## Goal
Build an App Store-like distribution platform in `sx`, but not limited to iOS
apps. It should distribute mobile, desktop, and server/client artifacts through
a CI-friendly release workflow.
Supported targets for the first product direction:
- iOS: IPA metadata, TestFlight links, Enterprise/MDM manifests, artifact-only
downloads
- Android: APK first, AAB later
- macOS: app archives, dmg/pkg metadata, signing and notarization status
- Linux: tarballs first, then deb/rpm/AppImage metadata
- Windows: zip/installer first, then MSIX/signing metadata
The main commands are:
- `distd`: the HTTP API, install page, and artifact server
- `dist`: the CI/admin CLI
The release workflow must be easy to integrate into CI. A CI job should be able
to upload artifacts, create a release, attach platform variants, promote a
channel, and receive machine-readable JSON output.
Product code should live in `sx`. C or system APIs are acceptable only as thin
platform backends for capabilities that `sx` cannot express yet.
## Product Shape
This is an operational distribution tool first, not a public marketplace. The
initial product should feel like a release console: quiet, dense, fast to scan,
and optimized for repeated internal/private release work.
Core principles:
- CI is the primary writer.
- Humans inspect, promote, revoke, download, and audit.
- Releases are immutable.
- Channels are mutable pointers to releases.
- Artifacts are content-addressed and never silently replaced.
- Every upload, publish, promotion, token change, and deletion writes an audit
event.
- The first version should be understandable from the filesystem and SQLite
database during development.
## Users And Actors
- CI runner: publishes releases with `dist ci publish`.
- Release manager: promotes channels, checks validation, and reads audit logs.
- Developer/tester: downloads the current artifact for a platform/channel.
- Admin: creates apps, manages tokens, and configures identity constraints.
- `distd`: server/API/artifact store.
- `dist`: CLI for CI and local admin work.
## Core Concepts
App:
- Product being distributed.
- Owns identity rules, allowed platforms, releases, channels, and tokens.
Release:
- Immutable version/build record for one app.
- Contains one or more platform artifacts.
Artifact:
- Uploaded file for a platform.
- Stored by digest and linked to release metadata.
Channel:
- Mutable pointer such as stable, beta, internal, nightly.
- Promotion changes the pointer, not the release.
Token:
- Scoped credential for CI and automation.
- Stored hashed, expires or can be revoked.
Audit event:
- Immutable record of important actions.
## Main Workflows
CI publish:
1. CI builds artifacts.
2. CI writes or updates `dist.json`.
3. CI runs `dist ci publish --server "$DIST_SERVER" --token "$DIST_TOKEN"
--manifest dist.json --json`.
4. `dist` validates the manifest and streams artifact uploads.
5. `distd` validates metadata and stores artifacts by digest.
6. The release is published.
7. A requested channel is promoted if policy allows it.
8. CI receives JSON with release ids, artifact ids, digests, and URLs.
Human release management:
1. Release manager opens the admin UI.
2. They inspect release status, artifact validation, and audit history.
3. They promote, rollback, revoke tokens, or download artifacts.
Install/download:
1. User opens an app/channel install page.
2. Platform detection chooses the most relevant artifact or install path.
3. The page shows accurate platform-specific actions and metadata.
4. Access policy determines whether the user can download or install.
## iOS Install Policy
iOS needs special handling. The platform must not imply that a normal iPhone can
install an arbitrary IPA from a web page.
Supported iOS modes:
- TestFlight: store a TestFlight link and open Apple's install flow.
- Enterprise/MDM: serve a valid HTTPS manifest plist for enrolled devices.
- Artifact only: allow authenticated IPA download, without presenting it as a
normal mobile install action.
This distinction must be visible in both the API model and admin/install UI.
## Architecture Overview
The intended stack is:
```text
sx language and std primitives
-> infra libraries: http, json, hashing, storage, db, auth, archive
-> distribution domain: app, artifact, release, channel, token, audit
-> interfaces: CLI, HTTP API, install pages, admin UI
-> deployment: Docker image, NAS-friendly config, persistent data volume
```
Storage direction:
- SQLite first.
- Local filesystem artifact storage first.
- Object storage adapter later.
Deployment direction:
- Docker/OCI image.
- One persistent `/data` volume for database, artifacts, uploads, config, and
logs.
- One HTTP port.
- `/healthz` endpoint.
- Runs behind a reverse proxy for TLS.
- Runs as a non-root user.
- UGREEN NAS deployment through Docker/Container Manager is a first-version
requirement.
## sx Foundation Status
Re-evaluated 2026-06-11 against the current sx tree. The original foundation
asks have largely landed, with one design difference: sx has no `pub` keyword.
Visibility is import-scoped; aliases are the re-export mechanism
(`print :: core.print`), and a module's namespace tail carries one level into
flat importers. `modules/std.sx` is the curated barrel this plan asked for.
Delivered in sx and used by this repo:
- Module system: alias imports, alias re-exports, namespace barrels,
one-level carry, dir-vs-file ambiguity rejection.
- Error handling: the `!` error channel with `raise`/`catch`/`onfail`
(bindings take parens), `?T` optionals.
- `std` modules under `modules/std/`: core, fmt, list, mem (typed allocator
helpers over `alloc_bytes`/`dealloc_bytes`), fs, process, socket (raw TCP),
json, xml, cli, hash (streaming SHA-256), log (leveled, no timestamps yet),
test (bare assert).
Still missing from sx — the forward wishlist; each item either blocks a later
subplan or has an explicit local workaround:
- Collections: `HashMap` (linear scan over `List` pairs meanwhile).
- Strings: validated UTF-8 `String`, `StringBuilder`, explicit Unicode model
(byte length, scalar values, grapheme clusters, and display width are
distinct; invalid UTF-8 must not silently become a `String`).
- Bytes and a full path module (only `path_join`/`basename`/`dirname` today).
- `std.fs` directory listing (`src/store/cleanup.sx` shims
opendir/readdir/closedir via FFI meanwhile).
- Time/clock (publish shims `time(2)` via FFI), random, encodings
(base64url, percent).
- HTTP server/client and TLS boundary — blocks subplan 04 and remote publish
(subplan 03 Slice 3).
- SQLite — blocks subplan 02 Slice 2 (`db.json` stands in).
- Archive inspection — blocks deep IPA/APK validation (subplan 05).
- Config layering (env/file/CLI) and richer testing helpers.
## Implementation Phases
Phase 0 - sx language/module prerequisites (done, as-built):
- Delivered in sx via alias re-exports and namespace barrels; there is no
`pub` keyword.
Phase 1 - standard library foundation (partial):
- Delivered: fs, process, json, cli, hash, log, test, socket, mem.
- Outstanding: HashMap, StringBuilder/Unicode model, time, random, encodings,
HTTP/TLS, SQLite, archive (see "sx Foundation Status").
Phase 2 - product domain:
- Define apps, releases, artifacts, channels, tokens, policies, and audit
events.
Phase 3 - storage:
- Add SQLite persistence and filesystem artifact storage.
Phase 4 - CLI first:
- Make `dist ci publish --manifest dist.json --json` work before the admin UI.
Phase 5 - HTTP API:
- Expose app, release, upload, download, channel, token, and audit endpoints.
Phase 6 - artifact validation:
- Validate APK and IPA first, then desktop artifact metadata.
Phase 7 - channels and install pages:
- Add promotion, rollback, download URLs, and platform-specific install pages.
Phase 8 - admin UI:
- Build a dense operational UI for apps, releases, artifacts, tokens, settings,
install pages, and audit logs.
Phase 9 - packaging:
- Package `distd` and the admin UI into a Docker image suitable for UGREEN NAS.
## CI Contract
The primary CI command should be:
```sh
dist ci publish \
--server "$DIST_SERVER" \
--token "$DIST_TOKEN" \
--manifest dist.json \
--json
```
The command should:
1. Validate the manifest.
2. Create or find the app.
3. Create a draft release.
4. Upload all artifacts with streaming SHA-256.
5. Validate platform metadata.
6. Publish the release.
7. Promote the requested channel if specified.
8. Print JSON containing release id, artifact ids, digests, and download URLs.
## First Milestone
Milestone 1 is complete when:
- Required `sx` language/std primitives exist or have explicit temporary
boundaries.
- `distd` can run locally.
- `dist ci publish` can publish a release with at least APK and IPA artifacts.
- Artifacts are stored by digest.
- SQLite stores apps, releases, artifacts, channels, tokens, and audit events.
- A channel can be promoted and rolled back.
- Install/download pages accurately handle iOS, Android, and desktop artifacts.
- The admin UI can inspect apps, releases, validations, tokens, and audit logs.
- A Docker image can run on a UGREEN NAS with a persistent data volume.
## Milestone 1 — Flow Step ↔ Subplan Slice Mapping
The flow decomposes subplan 02 (`.agents/subplans/02-domain-and-storage.md`)
Slice 1 into two steps. This records that decomposition so each step's scope is
verifiable from the repo:
- **P2.1 — domain structs + boundary validation.** Delivers subplan-02 *Core
Structs* (App, Platform, Release, Artifact, Channel, AuditEvent) and the
*boundary validation* portion of Slice 1 — slug, version, channel name,
platform id, and required-field presence, each with a distinct typed error.
Per the PO ruling this includes `Release.published_at` and `Artifact.metadata`.
Code lives under `src/domain/`; the acceptance test is
`tests/domain_validate.sx`.
- **P2.3 — in-memory repository + persistence.** Delivers the rest of Slice 1:
the in-memory repository (create/list/get/update, find-by-slug,
find-artifact-by-digest) plus `db.json` persistence.
- **Token is in neither P2.1 nor P2.3.** Subplan 02 lists Token under *Core
Structs*, but its delivery slice is **Slice 5 — Token Security** (generation,
hashing at rest, scopes, expiration/revocation). It is out of the Slice-1
steps above.
## Non-goals For Version 1
- Public marketplace payments.
- Reviews and ratings.
- Organization billing.
- Sophisticated staged rollout targeting.
- CDN integration.
- Full signing/notarization automation.
- Object storage.
- Postgres.
## Detailed Execution
`PLAN.md` is the overview. Slice breakdowns live in `.agents/subplans/`
(0107). The active milestone slice plan and step progress live in `current/`
(`PLAN.md`, `CHECKPOINT-DISTRIBUTION.md`).
The multi-agent flow harness that originally executed this plan is retired;
work proceeds directly in-session, branch-based, with `make test` green at
each step boundary.