# Platform App Standard v1

## Purpose

Every app is independently deployable and communicates only through the
platform gateway, capabilities, or events. Apps must not import another app's
business modules, read another app's database, use another app's credentials,
or write another app's storage.

This standard is additive. Existing apps remain in legacy mode until migrated.

## Required app surface

Each app exports:

```python
APP_MANIFEST = AppManifest(...)
def handle_request(context, action): ...
```

The manifest is the machine-readable manual for the app. It declares:

- identity and semantic app version;
- supported actions and exported capabilities;
- JSON-like input and output schemas;
- required write-only credentials;
- side effects, idempotency, timeout, and data classification;
- allowed outbound capabilities;
- published and subscribed event types.

Manifest validation requires:

- SemVer for app and optional App Pack versions;
- versioned action identifiers such as `lookup_v1`;
- object output schemas with explicit required fields;
- stable snake-case error codes;
- an approved data classification;
- an idempotency key for non-idempotent side effects;
- local `platform.health` without credentials or side effects;
- `connected` and `provider` outputs from credential tests.

## Required platform capabilities

New apps must expose:

- `platform.health`: local runtime health, without external calls;
- `platform.credentials.test` when credentials are required: perform a minimal
  provider request and return `connected`, provider-safe account metadata, and
  the test time. Never return credentials.

`Configured` means encrypted values exist. `Connected` means the most recent
real provider test succeeded. These states must never be conflated.

## Calls between apps

Use:

```python
call_capability(context, "abn_lookup_app", "business.au.abn.lookup", payload)
```

The caller manifest must explicitly allow
`abn_lookup_app:business.au.abn.lookup`, and the target must export that
capability. The gateway still enforces tenant subscription, app enablement,
quotas, request context, and logging.

Direct imports and internal HTTP calls are prohibited.

## Envelope

Every standard response contains:

- `contract_version`;
- `status`;
- `app_id`, `action`, `request_id`, and UTC `timestamp`;
- `data` and `meta` on success;
- a stable `error.code`, safe message, retryability, and safe details on error.

Secret values, raw provider exceptions, stack traces, and customer credentials
must never appear in envelopes or logs.

## Data contracts

Use stable domain fields and ISO 8601 UTC timestamps. Include units and currency
explicitly. Identifiers must state their namespace where ambiguity exists
(for example `abn`, `aroflo_user_id`, or `invoice_id`). Breaking schema changes
require a new capability or contract major version.

## Events and long jobs

Synchronous capabilities are for bounded operations. Work likely to exceed the
declared timeout must enqueue a job and return a job identifier. Cross-app
notifications use versioned events declared in manifests. Event consumers must
be idempotent.

## Isolation and failure behavior

- A target app failure returns a standardized error; it does not crash the
  caller process.
- Callers must set explicit timeouts and handle retryable errors.
- Circuit breakers and queues will isolate repeatedly failing providers.
- Credentials are resolved inside the target app only.
- Tenant ID is taken from trusted gateway context, never from the payload.

## New app recipe

1. Copy `platform.apps.reference.REFERENCE_MANIFEST`.
2. Copy `docs/platform/APP_MANUAL_TEMPLATE.md` to the app as `APP_MANUAL.md`.
3. Choose namespaced capabilities, versioned actions, schemas, and error codes.
4. Declare credentials, classifications, side effects, and outbound permissions.
5. Implement health and credential-test capabilities.
6. Return standard envelopes with a support-reference `request_id`.
7. Use platform storage, quotas, jobs, secrets, and structured logging.
8. Run `scripts/validate_app_contract.py <app_id>`.
9. Add contract, tenant-isolation, error, entitlement, observability, and
   capability-permission tests.
10. Publish only after every definition-of-done item below passes.

## Definition of done

An app is Platform Standard v1 compatible only when:

- `APP_MANIFEST`, `handle_request`, `README.md`, and `APP_MANUAL.md` exist;
- the manifest and filesystem validator returns `status: valid`;
- every public operation uses a versioned action and standard envelope;
- every error has a stable code, safe message, HTTP mapping, and retry policy;
- tenant identity comes exclusively from trusted context;
- credentials are write-only and resolved inside the target app;
- storage, quotas, AI usage, and jobs use platform services;
- structured success and failure events contain `request_id` and no secrets;
- external-provider calls have bounded timeouts and safe failure behavior;
- contract, credential, isolation, entitlement, and negative tests pass;
- a WordPress App Pack, when present, is optional, reproducible, signed,
  entitlement-aware, and depends only on the public bridge API;
- the manual documents consumption from HTTP, another app, and WordPress when
  applicable;
- SemVer, compatibility, deprecation, migration, and rollback expectations are
  documented.

Passing the standard does not mean the app is production-ready. Load,
availability, provider sandbox, backup/restore, incident response, and
deployment validation remain release-gate concerns.

## Optional WordPress App Pack

An app may declare `wordpress_package` to provide optional WordPress-side
helpers and UI. This is not required for API or custom PHP consumption; Bridge
Core already provides the generic client.

Executable packs follow
`docs/platform/WORDPRESS_APP_PACK_STANDARD_V1.md`. Development source cannot be
downloaded or installed until it has been built, hashed, signed with the
artifact Ed25519 key, and published through the entitlement-aware catalog.

## Legacy migration order

For each existing app:

1. inventory actions and dependencies;
2. add the manifest without changing behavior;
3. wrap results in envelopes;
4. move credentials to the vault;
5. replace direct calls with capability calls;
6. add health/connection tests;
7. validate and then remove legacy compatibility.
