nexo/services/core/compose/README.md

152 lines
6.6 KiB
Markdown

# Core Compose
This compose file mirrors the current Mattermost-based runtime shape inside the
`services/core` module.
## Local Runtime
```sh
cd services/core/compose
cp -n .env.example .env
docker compose pull
docker compose up -d
```
`latest` is the verified stable pointer for nexo-owned runtime images.
When running or updating, you should run `docker compose pull && docker compose up -d` to fetch the latest stable images.
Runtime state is written to `services/core/data/`, which is ignored by git.
Place push-proxy configuration under
`services/core/data/push-proxy/config/mattermost-push-proxy.json` when FCM smoke
testing is needed.
The default host ports are `18065` for core and `18066` for push-proxy so this
test deployment can run beside the existing Mattermost service.
The Docker network subnet is fixed to `172.38.0.0/16`. Treat this range as
reserved for nexo and do not reuse it for other Docker networks.
## Secret Boundary
Commit only `.env.example`. Keep `.env`, runtime data, logs, push-proxy
credentials, certificates, and license files out of git. If a new credential or
runtime path is added, first add the example variable or documented path here,
then confirm the concrete value or generated file is ignored.
## Smoke Checks
Run these checks after `docker compose up -d`.
```sh
curl -fsS "http://localhost:${NEXO_CORE_PORT:-18065}/api/v4/system/ping"
docker compose exec db pg_isready -U mmuser -d mattermost
curl -fsSI "http://localhost:${NEXO_CORE_PORT:-18065}"
```
The core ping response should report `status` as `OK`, Postgres should accept
connections for the `mattermost` database, and the Mattermost app should return
an HTTP response from the mapped core port.
For the minimum push-proxy smoke, confirm the service is running and the core
service still points at the compose-network DNS name:
```sh
docker compose ps push-proxy
docker compose config | rg --fixed-strings \
"MM_EMAILSETTINGS_PUSHNOTIFICATIONSERVER=http://push-proxy:8066"
```
FCM/APNS credential validation is not part of the default smoke. Run it only
when a real push-proxy config is present outside git.
## SDK Contract Anchors
The Flutter SDK side of this contract is documented in
[`packages/messaging_flutter/README.md`](../../../packages/messaging_flutter/README.md#server-and-push-runtime-contract).
This compose runtime keeps the Mattermost-compatible server and push-proxy shape
that the SDK consumes.
Server source anchors:
- Push payload model: `services/core/server/public/model/push_notification.go`
- ACK endpoint route and handler: `services/core/server/channels/api4/system.go`
- Push signing and push-proxy dispatch: `services/core/server/channels/app/notification_push.go`
- Reference webapp client behavior: `services/core/webapp/platform/client/src/client4.ts`,
`services/core/webapp/platform/client/src/websocket.ts`, and
`services/core/webapp/channels/src/`
SDK-facing payload fields are `type`, `ack_id`, `server_id`, `device_id`,
`post_id`, `category`, `team_id`, `channel_id`, `root_id`, `channel_name`,
`message`, `sender_id`, `sender_name`, `version`, `is_crt_enabled`,
`is_id_loaded`, and `signature`. The server signs push notifications with the
`ack_id` and raw device token after splitting the stored device id into platform
and token parts. The Android SDK stores device tokens with the
`android_rn-v2:` compatibility prefix and validates the raw token portion.
ACK delivery uses `POST /api/v4/notifications/ack` with `id`, `received_at`,
`platform`, `type`, `post_id`, and `is_id_loaded`. When id-loaded ACK is enabled
for a message notification, the server may return post and routing fields that
the SDK merges into the notification bundle.
The webapp remains the reference browser front. Compose and server updates must
keep webapp messaging, replies, post acknowledgements, channel navigation, and
thread behavior upstream-followable. Flutter embedded SDK compatibility is
limited to payload fields, ACK/reply endpoints, signing-key verification,
device-token format, and opened channel/thread routing events; product UI parity
belongs to consuming apps or a separate roadmap item.
## Remote Parity
The remote development copy lives under `~/docker/services/nexo/compose`. Local
and remote compose inputs should match unless a work report explicitly records
an intentional temporary drift.
```sh
cd services/core/compose
sha256sum docker-compose.yml .env.example
ssh <host> 'cd ~/docker/services/nexo/compose && sha256sum docker-compose.yml .env.example'
```
The two `sha256sum` outputs should match for both files before remote runtime
smoke is treated as equivalent to local compose smoke.
## Deployment Loop
The compose deployment loop uses the same input contract for dev, test, and
production-like lanes. The lane changes the target and promotion gate, not the
tracked compose file.
### Deployment Lanes
| Lane | Purpose | Promotion gate |
| --- | --- | --- |
| `dev` | Disposable runtime for local feature checks and compose iteration. | Compose config renders, services start, and the smoke checks above pass. |
| `test` | Shared validation lane for upstream baseline or image updates before release notes. | Compose inputs match the candidate branch, images pull by immutable tag or digest, smoke passes, and failures are classified. |
| `production-like` | Internal release rehearsal before a stable pointer is treated as deployable. | Image refs, compose input hashes, secret profile label, smoke evidence, and rollback ref are recorded together. |
Use immutable tags or digests for `test` and `production-like` candidates.
`latest` remains the stable pointer only after the candidate evidence is already
recorded.
### Secret Injection
Start each lane from `.env.example`, then keep the concrete env profile outside
git. A tracked report may name the secret profile label and rotation decision,
but must not include raw values, credential files, hostnames, ports, tokens, or
private endpoint paths.
Push-proxy FCM/APNS credentials stay under ignored runtime data. If a new secret
path is needed, add only the example variable or sanitized path contract here,
then confirm the concrete file remains ignored.
### Rollback Contract
Before applying a candidate, record the previous image refs, compose input
hashes, secret profile label, and data snapshot reference in the private run log.
The public release note or follow-up issue records only the rollback ref,
classification, and sanitized evidence pointer.
A rollback restores the previous image refs and secret profile, starts the same
compose services, and reruns the smoke checks above. If rollback smoke fails,
classify the failure as `server`, `webapp`, `push-proxy`, `SDK contract`, or
`infra`, then open the follow-up before another promotion attempt.