# AroFlo Connector - App Manual

## Contract

- App ID: `aroflo_connector_app`
- App version: `1.5.0-dev`
- Platform contract: `1.0`
- Provider: AroFlo
- Strategy: official API first; controlled UI transport only where the API
  does not provide the required operation

`APP_MANIFEST` in `__init__.py` is the machine-readable source of truth. This
is an incremental migration. Legacy zones, CLI commands, blueprint routes, and
UI automation are not Standard v1 capabilities until explicitly published in
the manifest.

## Credentials

The initial API credential set contains:

- `aroflo_base_url`
- `aroflo_u_encoded`
- `aroflo_p_encoded`
- `aroflo_api_secret`
- `aroflo_org_encoded`
- optional `aroflo_host_ip`

Bridge Core writes these values to the encrypted tenant/app vault. Values are
write-only and are never returned to WordPress, browsers, agents, logs, or
response envelopes.

**Not configured** means one or more required API values do not exist.
**Configured** means all required encrypted values exist. **Connected** means
the latest explicit `test_connection_v1` call completed a real read-only
AroFlo request. Configured and Connected are different states.

Bot login credentials, MFA challenges, shared browser sessions, and worker
pool management are planned for a later contract block. Existing local UI
session files are legacy runtime state and are not used by these capabilities.

Bridge Core's credential form supports the fixed API fields in the manifest.
Multiple BOT identities require a connector-owned tenant resource because the
number of BOTs and their zone assignments are dynamic. The planned resource
stores BOT metadata separately from write-only password secrets and includes a
per-BOT concurrency lease, assigned zones, enabled state, session state, and
last safe connection result.

## Exported capabilities

### `health_v1` - `platform.health`

Reports `healthy`, `vault_ready`, `api_credentials_configured`, and
`provider_checked`. It has no input, no side effects, requires no credentials,
does not contact AroFlo, and uses internal data classification.

Example data:

```json
{
  "healthy": true,
  "vault_ready": true,
  "api_credentials_configured": false,
  "provider_checked": false
}
```

### `test_connection_v1` - `platform.credentials.test`

Resolves credentials for the trusted tenant and performs a bounded GET against
the AroFlo `lastupdate` zone. The provider response is discarded after
validation. The action is read-only, idempotent, synchronous, limited to 20
seconds, and uses internal data classification.

Example data:

```json
{
  "connected": true,
  "provider": "AroFlo",
  "transport": "api",
  "tested_at": "2026-07-29T00:00:00+00:00"
}
```

No capabilities are agent-exposed in this migration block.

### `zones_v1` - `aroflo.catalog.read`

Returns the registered zones and safe metadata for each legacy operation. It
does not resolve credentials, contact AroFlo, or execute an operation. Every
entry includes `published=false`; an operation becomes callable only after it
receives its own reviewed Standard v1 contract.

### BOT pool and session actions

- `bots_v1` / `aroflo.bots.list` returns safe profiles and assignments.
- `configure_bot_v1` / `aroflo.bot.configure` writes profile metadata and
  write-only credentials to the tenant vault.
- `bot_status_v1` / `aroflo.bot.status` returns the live safe session state.
- `connect_bot_v1` / `aroflo.bot.connect` starts or resumes one browser session.
- `submit_bot_mfa_v1` / `aroflo.bot.mfa.submit` accepts one six-digit code and
  requires an idempotency key. The code is never stored or returned.
- `disconnect_bot_v1` / `aroflo.bot.disconnect` closes the runtime while
  preserving reusable encrypted browser state.

Valid safe states are `offline`, `not_configured`, `not_connected`,
`mfa_required`, `online`, and `unknown`. BOT actions never accept usernames,
passwords, session cookies, or storage state from ordinary operation payloads.

## Error contract

- `action_not_found` - HTTP 404, not retryable; the action is not exported.
- `tenant_context_missing` - HTTP 400, not retryable; trusted tenant context is absent.
- `credential_not_configured` - HTTP 409, not retryable; required values are missing.
- `credential_vault_unavailable` - HTTP 503, retryable; encrypted storage cannot be read.
- `provider_connection_failed` - HTTP 502, retryable; AroFlo rejected the probe or did not respond safely.

Errors use Standard v1 envelopes. Raw provider bodies, native exceptions,
signed headers, credential values, cookies, and tracebacks are never returned.

## Calling from another app

The caller must declare the capability in `outbound_capabilities` and invoke
the platform gateway:

```python
call_capability(
    context,
    "aroflo_connector_app",
    "platform.credentials.test",
    {},
)
```

Direct imports, subprocess CLI calls, and direct internal HTTP are prohibited
for new consumers. Existing legacy consumers will be migrated incrementally.

## Calling through HTTP

Use the authenticated gateway action endpoint configured for
`aroflo_connector_app`, with the site JWT scope and entitlement required by
Bridge Core. Send an empty JSON object for both initial actions. The gateway
creates trusted tenant and request context before calling `handle_request`.

Success and error responses include `contract_version`, `status`, `app_id`,
`action`, `request_id`, `timestamp`, and the appropriate `data` or `error`
object. Treat `request_id` as the support reference.

## Security and tenant isolation

Tenant identity comes only from `context.tenant.tenant_id`, never from request
payloads. Secrets are retrieved with both tenant ID and app ID, and are used
only inside the connector. This block performs no cross-app calls and declares
no outbound capabilities.

API connection tests are explicit and read-only. Loading the WordPress console
does not contact AroFlo. The connection button and catalog are restricted to
signed-in WordPress administrators and protected by a nonce. The text console
maps only `health`, `test connection`, and `list zones` to fixed actions.

Worker calls resolve `ui_worker_shared_secret` from the tenant vault. Each
worker has a unique `AROFLO_UI_WORKER_ID`. HMAC signatures
cover method, path, timestamp, nonce, and request body. Consumed nonces,
session state metadata, worker ownership, and operation leases are stored in
the shared control plane. Browser `storageState` is encrypted in the tenant
vault under the BOT namespace and is decrypted only inside the worker.

## Observability

Every Standard envelope carries a `request_id`. Safe diagnostic fields are the
action, outcome, provider name, transport, duration, and stable error code.
Credential values, HMAC material, authorization headers, provider payloads,
cookies, MFA codes, and browser storage are redacted fields.

Structured operation events will be added with the first published business
read capability. Existing legacy client logs are not the observability
contract for Standard v1 actions.

## Testing and validation

Run:

```text
PYTHONDONTWRITEBYTECODE=1 venv/bin/python -m unittest \
  apps.aroflo_connector_app.tests.contract_checks
venv/bin/python scripts/validate_app_contract.py aroflo_connector_app
php -l apps/aroflo_connector_app/wordpress-pack/aroflo-connector-wp/aroflo-connector-wp.php
```

Tests cover manifest validation, local zone catalog safety, local health,
missing credentials, trusted tenant isolation, successful and failed provider
probes, safe errors, and unknown actions. Provider calls and credentials are
mocked.

## Optional WordPress App Pack

- Package ID: `aroflo_connector_wp`
- Plugin file: `aroflo-connector-wp/aroflo-connector-wp.php`
- Shortcode: `[ams_aroflo_connector_console]`
- Helpers: `ams_aroflo_connector_health()` and
  `ams_aroflo_connector_test_connection()`
- Minimum versions: Bridge Core 0.2.0, WordPress 6.0, PHP 8.0

The pack is optional and calls only `wp_flask_bridge_invoke()`. Source must be
built, hashed, signed with Ed25519, published through the entitlement-aware
catalog, installed through Bridge Core, and explicitly activated. Updates,
rollback, and revocation follow WordPress App Pack Standard v1. Custom tenant
interfaces should be separate plugins that consume the same public actions.

## Versioning and compatibility

The current development version is `1.5.0-dev` and supports contract major
version 1. Additive fields may be introduced within v1; breaking input or
output changes require a new versioned action. Legacy routes and CLI operations
remain available during migration and receive a documented deprecation window
before removal.
