# App Store Platform-Aligned Upload Design

## Goal

Upgrade `WWW/appstore` from a Debian-only batch submitter into a platform-aligned upload tool that can model:

- Debian packages and Linglong packages
- Multiple packages per release
- Multiple architectures per release
- Per-package system-line and baseline targeting using the store's native parameter values

The tool should match the UnionTech app store's real submission model instead of forcing the platform into the current simplified `apps + releases(deb_path/system_platform/arch)` workbook.

## Context

The current tool assumes one enabled release row maps to one `.deb` file and one target platform/arch pair. That does not match the store's actual model.

From the platform UI and frontend bundle behavior:

- The core submission payload is organized around `app_origin_pkgs`
- One submission can contain multiple package records
- Each package has its own architecture, package metadata, and system-version targeting
- System-version targeting is not a single `system_platform` field; each package carries store-native targeting fields such as `supSys`, `supBlineVer`, `unsupportBlineVers`, plus structured `system_platform` and baseline data
- The platform supports Debian packages and Linglong packages, but they cannot be mixed within the same app submission
- Linglong upload supports both `.uab` and `layer`-style artifacts
- The platform UI explicitly supports multiple CPU architectures in one app
- The platform UI explicitly supports one architecture targeting multiple systems, and different packages for different systems of the same architecture, as long as versioning does not conflict

Because of this, the current manifest schema is too small. Adding more columns to the existing `releases` sheet would create an ambiguous and fragile model.

## Goals

- Represent the platform's actual hierarchy: app -> release -> packages -> targets
- Support package families `deb` and `linglong`
- Support package formats `deb`, `uab`, and `layer`
- Support multiple packages in one release
- Support multiple package targets in one release
- Store system-line and baseline identifiers as raw store values, not only as local human-readable aliases
- Validate the same package-family and targeting constraints the store UI enforces
- Keep batch execution, reporting, dry-run validation, and reuse of uploaded assets

## Non-Goals

- Backward-compatible parsing of the old workbook schema
- Automatic migration of old workbooks
- Reproducing every interactive detail of the web UI
- Supporting mixed Debian and Linglong packages in a single release
- Reverse-engineering every store dictionary without authentication when the platform already exposes them after login

## Architecture

The upgraded tool will use a normalized manifest plus a platform-capability cache:

1. Workbook sheets define apps, releases, packages, and package targets.
2. Package inspectors derive authoritative metadata from each package file.
3. Capability sync pulls current system-line and baseline choices from the store under an authenticated session.
4. Validation resolves the workbook against synced platform capabilities and store rules.
5. Payload building emits one release submission that contains multiple `app_origin_pkgs`, each with its own targeting data.
6. Upload execution submits release groups while preserving current row-level reporting behavior.

This keeps the tool aligned with the platform's model while remaining batch-friendly.

## Manifest Model

### `apps` sheet

Application-level metadata. One row per store app.

Required columns:

- `app_key`
- `app_name_zh`
- `pkg_name`
- `category_id`
- `website`
- `short_desc_zh`
- `full_desc_zh`
- `icon_path`
- `screenshot_1`
- `screenshot_2`
- `screenshot_3`

Optional columns:

- `keywords_zh`
- `app_id_override`

### `releases` sheet

Release-level metadata. One row per submission batch within an app.

Required columns:

- `enabled`
- `app_key`
- `release_key`
- `release_name`

Optional columns:

- `region`
- `note`

Rules:

- `release_key` must be unique within an app
- One release groups multiple package rows
- One release must use exactly one package family: `deb` or `linglong`

### `packages` sheet

Package-level rows. One file per row.

Required columns:

- `enabled`
- `app_key`
- `release_key`
- `package_key`
- `package_family`
- `package_format`
- `file_path`

Optional columns:

- `declared_arch`
- `pkg_channel`
- `note`

Definitions:

- `package_family`: `deb` or `linglong`
- `package_format`: `deb`, `uab`, or `layer`

Rules:

- `package_family=deb` only allows `package_format=deb`
- `package_family=linglong` only allows `package_format=uab` or `package_format=layer`
- Packages in the same `(app_key, release_key)` must all share the same `package_family`
- `package_key` must be unique within a release

### `targets` sheet

Targeting rows. One row per package-target combination.

Required columns:

- `enabled`
- `app_key`
- `release_key`
- `package_key`
- `sup_sys_code`

Optional columns:

- `baseline_id`
- `unsupport_baseline_ids`
- `target_note`

Definitions:

- `sup_sys_code` is the store-native system-line identifier, such as `11`, `21`, `22`
- `baseline_id` is the store-native baseline/version selector value used by the UI
- `unsupport_baseline_ids` is a comma-separated list of store-native baseline/version selector values

Rules:

- A target row always belongs to exactly one package row
- A package can have multiple target rows
- `unsupport_baseline_ids` expands into per-package unsupported baseline entries
- Empty `baseline_id` is allowed only if the platform capability metadata says the chosen `sup_sys_code` does not require one

### Capability cache

The tool will maintain a local cache file under `appstore/cache/`, populated by an authenticated sync command. This cache stores:

- available package families and formats
- available system lines for Debian uploads
- available system lines for Linglong uploads
- available baseline/version options keyed by system line
- architecture metadata and labels as exposed by the store

The cache is input to validation and template generation. It is not the source of truth when stale; the sync command refreshes it.

## Package Inspection

### Debian

Debian inspection remains authoritative for:

- package name
- version
- architecture
- file size
- hash

The declared architecture in the workbook is optional cross-check data. Real `.deb` control metadata stays authoritative.

### UAB

`.uab` files use the Linglong path. The inspector should support the platform's current behavior:

- parse Linglong metadata when present
- derive package name, version, and architecture
- map architecture aliases into the store's expected codes and labels

### Layer

`layer` uploads also use the Linglong family. The inspector should:

- read `linglong.meta` or equivalent embedded metadata when available
- identify the application layer
- derive package name, version, and architecture from the app layer metadata

If local parsing fails for Linglong artifacts, the tool may fall back to the store's package-info detection endpoint when authenticated and when dry-run is not requested.

## Capability Sync

Add an authenticated command that pulls store capabilities and writes a local cache:

- `python3 -m appstore.upload_batch sync-capabilities`

The sync flow should:

1. log in using the existing session mechanism
2. request capability endpoints and dictionaries with store headers and tokens
3. normalize the returned data into a stable cache schema
4. write a timestamped cache file plus a `latest.json` symlink or copy

The cache should distinguish Debian and Linglong capability sets because the platform treats them differently.

## Validation Rules

Validation must happen before uploads.

### Structural rules

- all referenced `app_key`, `release_key`, and `package_key` values must exist
- empty rows are ignored
- disabled rows are skipped
- packages without targets fail validation

### Family and format rules

- one release cannot mix `deb` and `linglong`
- `deb` releases accept only `.deb` package rows
- `linglong` releases accept only `.uab` or `layer`

### Package metadata rules

- inspected package name must match the app's `pkg_name`
- inspected architecture must match declared architecture when provided
- duplicate package files within one release are allowed only if their targeting differs and their versioning is valid under store rules

### Targeting rules

- every `sup_sys_code` must exist in the synced platform capabilities for the release family
- every `baseline_id` and `unsupport_baseline_ids` value must be valid for the given `sup_sys_code`
- Debian and Linglong releases must use the capability set for their own family

### Conflict rules

The tool should reject combinations the platform UI rejects, including:

- same architecture + same system line + same version collision
- forbidden paired system-line combinations for the same architecture, such as the platform's explicit mutually-exclusive combinations
- mixed-family package groups

The validator should emit precise row-level errors with enough information to fix the workbook directly.

## Payload Construction

One grouped release submission produces one store payload.

### Release grouping

Rows are grouped by:

- `app_key`
- `release_key`

Within a group:

- one `app_info` block is built from the app row
- multiple `app_origin_pkgs` entries are built from package rows

### Per-package fields

Each package entry must contain:

- package name
- package version
- package architecture code and display label
- file metadata
- package type and install mode
- family-specific system text fields
- `supSys`
- `supBlineVer`
- `unsupportBlineVers`
- structured `system_platform`
- structured baseline data where required by the endpoint

### Upload behavior

Uploads remain content-addressed and reusable within one run:

- one icon upload per app
- one screenshot upload per screenshot file
- one package upload per package file

Identical files reuse the cached upload result during the same run.

## CLI Surface

The upgraded CLI should become subcommand-based:

- `sync-capabilities`
- `validate`
- `upload`
- `generate-template`

### `sync-capabilities`

Refresh store-native system-line and baseline metadata into the local cache.

### `validate`

Read the workbook, inspect local files, resolve capability cache, and emit reports without performing uploads.

### `upload`

Perform validation, then uploads, then grouped release submission.

### `generate-template`

Create a workbook template and example asset/package layout that matches the new normalized schema.

`--dry-run` remains available on validation and upload paths where appropriate.

## Reporting

Report output remains under `appstore/output/<timestamp>/`.

Reports must grow to include:

- `release_key`
- `package_key`
- `package_family`
- `package_format`
- `sup_sys_codes`
- `baseline_ids`
- `status`
- `message`
- `app_id`
- `pkg_name`
- `pkg_version`

When a grouped release fails because one package or target is invalid, the report should identify the exact package-target row that caused the failure.

## Migration

This design intentionally replaces the current workbook schema.

Migration strategy:

- stop supporting the old workbook format in the main path
- ship a new example workbook and README that only document the new schema
- fail fast with a clear error when an old workbook is detected

This keeps implementation simpler and avoids ambiguous partial compatibility.

## Testing Strategy

### Unit tests

- manifest parsing for `apps`, `releases`, `packages`, `targets`
- package family and format validation
- grouped release resolution
- target capability validation
- Debian inspector
- UAB inspector
- Layer inspector
- payload construction for multi-package release groups

### Integration-style tests

- one app with multiple Debian packages
- one app with multiple Linglong packages
- same release with multiple targets per package
- conflict rejection for same architecture/system/version collisions
- rejection of mixed Debian and Linglong package groups
- dry-run validation with local-only checks

### Documentation verification

- example workbook generation
- README command examples
- output report generation

## Trade-Offs

This is a larger refactor than incremental patching, but it avoids baking the wrong abstraction deeper into the tool. The cost is a workbook schema break and more implementation work now. The benefit is that future additions will map to the store cleanly instead of adding another layer of exceptions around a Debian-only model.

## Recommended Implementation Direction

Implement this as a schema and pipeline upgrade, not as a compatibility patch. The codebase should treat:

- app metadata
- release grouping
- package inspection
- target resolution
- payload building

as separate responsibilities. That separation is necessary now that one submission can contain multiple package rows with independent targeting.
