# Company entry deployment

> Superseded for login/switching by the agreed multi-account design in
> `plans/2026-09-11-company-accounts.md`.
> The feature remains disabled; see `company-accounts-deployment.md`.


The legacy resolver, landing and platform associations now require the separate
`AGENT_COMPANY_CODE_ENTRY_ENABLED` flag, which defaults to false. Leave it off
when using the replacement multi-account login broker.

## What is implemented

Manual company codes, HTTPS company links and QR codes use a single resolver.
Only the central deployment keeps the company-to-origin mapping. Each agency
continues to validate its own agent credentials. This does not merge databases,
provision agents, or create invitations granting membership.

Company codes are routing identifiers. Generate random codes (12 or more
uppercase letters/digits recommended), distribute only to the intended company,
and rotate by removing the old entry. Removing a code blocks new discovery;
it does not revoke already logged-in agents. Revoke accounts on their backend.

For example, generate a 12-character code locally with:

```sh
php -r 'echo strtoupper(bin2hex(random_bytes(6))).PHP_EOL;'
```

## Central petaV3 configuration

Configure these values privately in the entry deployment's environment. The
following is a non-working example; replace with generated codes and verified
production destinations. Do not copy this directory into agency deployments.

```dotenv
AGENT_COMPANY_DIRECTORY_JSON='{"REPLACEWITHRANDOMCODE":{"name":"Agency display name","api_base_url":"https://agency.example.com","enabled":true}}'
AGENT_COMPANY_LINK_ORIGIN=https://app.propertylab.com.my
AGENT_COMPANY_ANDROID_PACKAGE=tech.propertylab.agent
AGENT_COMPANY_ANDROID_FINGERPRINTS=
AGENT_COMPANY_APPLE_APP_IDS=
AGENT_COMPANY_ANDROID_DOWNLOAD_URL=
AGENT_COMPANY_IOS_DOWNLOAD_URL=
```

- Only HTTPS DNS origins on port 443 are accepted, without paths, query strings,
  credentials or fragments. Display names are required and at most 120 chars.
- `AGENT_COMPANY_ANDROID_FINGERPRINTS`: comma-separated SHA-256 fingerprints of
  the actual signed Android APK (or Play App Signing certificate when used).
  Do not trust a developer debug certificate on production.
- `AGENT_COMPANY_APPLE_APP_IDS`: comma-separated `APPLE_APP_ID_PREFIX.bundle.id`
  values matching the signed app's application-identifier entitlement. Production
  bundle ID is `tech.propertylab.salesagent`; confirm the signing prefix.
- Download URLs are optional HTTPS links. Blank values show administrator
  installation instructions rather than a fabricated store/download URL.
- Reload the config/route cache through the existing deployment procedure and
  build assets (`npm run build`, using the repository's staging/swap process).
- The central host must serve `/company/*`, `/agent-api/company-entry/resolve`,
  `/.well-known/assetlinks.json` and `/.well-known/apple-app-site-association`.
  Check the proxy/static-file rules: many servers block dotfiles by default.
  Association URLs must respond directly with JSON and HTTPS, without login,
  redirects, WAF challenges, or bot blocking.
- Do not embed directory values in JS, mobile assets, HTML, public API lists,
  exception/debug pages, or application logs. Production `APP_DEBUG` stays off.

A company link is `https://app.propertylab.com.my/company/{CODE}`. The landing
page displays its code and a locally generated QR of the canonical link; it
never queries/displays the company directory. Scan with the phone's camera.
No in-App scanner or camera permission is needed.

## Mobile build and upgrade

Flutter repo: `propertylab-sales-agent`. The build-time `PETAV3_API_BASE_URL`
remains the trusted **central directory and legacy default backend**. For the
Production package keep it `https://app.propertylab.com.my/`, including when
adding agencies. Do not rebuild that same package with VF as this value: the
old token/data namespace belongs to the original default backend. Pilot uses
its separate package and configured testing backend.

- Android: verified HTTPS intent filter for `app.propertylab.com.my/company/*`.
- iOS: associated-domain entitlement; the `app_links` plugin handles cold/warm
  links. Flutter default deep-link routing is disabled on both platforms. Enable
  Associated Domains on the Apple App ID and regenerate the signing profile.
- New users choose a company before login; a saved selection survives logout.
- Existing default-backend credentials/local UUIDs keep their legacy namespace
  so recordings and queued work survive upgrade. Other origins get separate
  secure credential keys and deterministic local account UUIDs. Backend-issued
  account UUIDs remain unchanged for login/refresh validation.
- Sign out before changing company. Existing session teardown stops the badge
  and disposes recording services. A link cannot silently switch an active
  account. A different-company link pre-fills the next company-code screen.
- Background jobs resolve the saved company, use its credentials, and compare
  its local account owner with the queued owner. Old-company jobs cannot upload
  to the new company. Pending data is retained; signing back into the original
  company/account allows its normal recovery/scheduling to resume.
- Independent deployments need independent application/JWT keys and properly
  provisioned agency databases. Cloning production data/keys is not isolation.

## Device acceptance after deployment

1. Install the correctly signed Android/iOS build. Open the company link from
   another app, with the PropertyLab app both terminated and already running.
2. Verify the displayed company, sign in with an agent on that backend, and
   reopen the app. Verify leads, WhatsApp, badge sessions and uploads there.
3. Sign out and enter another company's code. Check that no prior-company data
   appears, including when test databases contain the same agent UUID.
4. Open a different-company link during an active recording. It must only show
   guidance to sign out/change company; the recording must not be interrupted.
5. Uninstall on a test device and open the link: verify the fallback page. After
   installing, tap the original link again or enter its code. Deferred install
   link restoration is deliberately not promised. On browsers that keep links
   on the web (including same-domain Safari navigation), use the code fallback.
6. Verify invalid/disabled codes, offline resolution, and throttling behavior.

Local tests/builds do not prove deployed OS association verification or actual
cross-agency production credentials. Those checks require the configured server
and signed installed builds. No production deployment is part of this change.
