# Test1 L1 Application deployment

Test1 deploys the L1 application through one standalone workflow:

```text
.github/workflows/deploy-test1-l1-application.yml
```

For the complete Test1 sequence and the smallest-operation decision table, see
[`test1-standalone-deployment.md`](test1-standalone-deployment.md).

Its `deploy` operation reads two exact official image digests and replaces only:

- the SFCRM AppService container;
- the published frontend files used by the existing Test1 nginx route.

It does not install or upgrade the AppRelease, change Catalog or database data,
or replace, restart, or activate any L0 process. Run it after AppRelease install
and L0 activation:

```bash
gh workflow run deploy-test1-l1-application.yml \
  --repo pingcap-inc/nexuscrm-pingcap-pack \
  --ref main \
  -f operation=deploy \
  -f sfcrm_app_service_image='ghcr.io/pingcap-inc/nexuscrm-sfcrm-appservice@sha256:<digest>' \
  -f frontend_image='ghcr.io/pingcap-inc/nexuscrm-frontend-assets@sha256:<digest>'
```

Running the same command again is the upgrade path: the exact AppService image
and frontend are replaced by the selected immutable images. There is no separate
deployment state machine or install/upgrade mode.

Its `stop` operation quiesces only the workflow-owned AppService and proves that
the Test1 backend port has no listener. It leaves the published frontend, L0,
AppRelease, and database unchanged:

```bash
gh workflow run deploy-test1-l1-application.yml \
  --repo pingcap-inc/nexuscrm-pingcap-pack \
  --ref main \
  -f operation=stop
```

Use `stop` before an AppRelease upgrade, together with the separate L0 stop.
After AppRelease upgrade and L0 activation, run `deploy` with the desired exact
AppService and frontend images. When the L1 images did not change, redeploy the
same immutable references that were serving before the stop.

The controller runs only from L2 `main`. Before removing the current
AppService, it starts the exact candidate on a temporary port and proves that it
is ready against the live L0. The frontend is extracted into its immutable
digest directory and published only after the replacement AppService is ready.
The workflow then verifies the public `/health` and `/version.json` routes.

There is no previous AppService container, frontend rollback pointer, or
recovery state. A host or process failure is repaired by rerunning the same
desired immutable images.

This path owns standalone Test1 only. It refuses to run when Test1 has an active
full-D3 deployment, so the standalone and full-stack controllers cannot both
own the AppService or frontend.

## Verified evidence

The successful AppService/UI replacement, immutable images, and public probes
are recorded once in the
[integrated Test1 runbook](test1-standalone-deployment.md#verified-complete-deployment).
