nexo/README.md
toki caafd4f320 feat(messaging): Web 알림 API 기준을 추가한다
Flutter Web foreground 알림을 준비하기 위해 초기화 옵션과 token prefix 경계를 public API로 고정한다.

포트/환경 기준 문서와 로드맵 정리, agent-task 리뷰 산출물도 함께 반영한다.
2026-06-07 10:59:12 +09:00

167 lines
11 KiB
Markdown

# nexo
`nexo`는 여러 Flutter 앱이 메시징과 푸시 알림 기능을 공통으로 사용할 수 있게 만드는 패키지 워크스페이스다. 핵심 산출물은 `packages/messaging_flutter`이며, 각 앱이 네이티브 메시징/푸시 런타임을 다시 구현하지 않고도 같은 기반을 소비할 수 있게 한다.
이 패키지는 여러 소비 제품이 Mattermost 호환 메시징 동작은 필요하지만 Mattermost의 전체 제품 형태를 그대로 물려받고 싶지는 않을 때 쓰는 공통 메시징 계층이다.
Mattermost 업스트림 저장소는 이 패키지 주변의 기준선과 검증 참조로 둔다. `apps/mattermost`는 원래 Mattermost 앱, `services/core`는 Mattermost 서버, `services/push-proxy`는 Mattermost 푸시 서버 스냅샷이다. 이 저장소는 별도의 nexo 제품 앱을 담지 않으며, 넓은 Mattermost 포크가 되는 것도 목표가 아니다. Nexo 전용 커스터마이징은 가능한 한 플러그인, compose/런타임 래퍼, 문서, 작고 명시적인 패치에 둔다.
## 이름
`nexo``nexus`에서 온 이름이다. 여러 앱, 메시지, 알림, 서비스 인프라가 만나는 연결 지점을 뜻한다.
## 제품 경계
- `packages/messaging_flutter/`는 Nexo가 소유하는 제품 표면이다. 여러 Flutter 앱이 소비할 수 있는 메시징, 푸시 알림, 네이티브 브리지, 알림 탭/수신 동작을 이곳에 둔다.
- 이 패키지를 소비하는 앱은 각자의 제품 UI, 워크플로우 의미, 앱별 비즈니스 로직을 소유한다. 공통 메시징 런타임은 Nexo에 의존하고, 앱별 동작은 각 프로젝트에 남긴다.
- Mattermost 업스트림 코드는 비교와 검증을 위한 기준선이지 주 커스터마이징 표면이 아니다. 명시적인 업스트림 갱신이나 작은 대상 패치를 검토하는 경우가 아니라면 `apps/mattermost`, `services/core`, `services/push-proxy`는 기록된 업스트림 스냅샷에 가깝게 유지한다.
- Mattermost 제품 동작이 소비 앱에 맞지 않을 때는 업스트림 스냅샷을 직접 크게 바꾸기보다 좁은 Nexo 플러그인 계약, 래퍼, 설정 지점, 문서화된 통합 경로를 추가한다.
## 현재 상태
- `packages/messaging_flutter/`는 Android 우선 Flutter 메시징/푸시 알림 플러그인 패키지이며, 이 저장소의 주 제품 표면이다.
- `apps/flutter-test/`는 플러그인을 검증하는 테스트용 Flutter 앱이다.
- `apps/mattermost/`는 원래 Mattermost 모바일 앱 저장소 스냅샷이다. 기준선은 `apps/mattermost/UPSTREAM.md`를 본다.
- `services/core/`는 Mattermost 서버 저장소 clone이다.
- `services/push-proxy/`는 Mattermost push-proxy 저장소 스냅샷이다. 기준선은 `services/push-proxy/UPSTREAM.md`를 본다.
- 공개 package, import, 네이티브 identifier는 Nexo 소유 이름으로 전환 중이다.
- iOS와 macOS 플러그인 scaffold는 있지만, 현재 구현 대상은 Android다.
## 빠른 시작
개발 진입점을 확인한다.
```sh
bin/dev
```
Flutter 패키지와 `flutter-test` 호스트 검증을 실행한다.
```sh
bin/test
bin/lint
```
core compose 런타임을 실행한다.
```sh
cd services/core/compose
cp .env.example .env
docker compose up
```
## 워크스페이스 포트 기준
Nexo가 소유한 runtime 기본값은 core HTTP `18065`, push-proxy HTTP
`18066`이다. 두 포트는 외부 소비자가 있을 수 있는 compatibility
baseline이므로 즉시 바꾸지 않는다. Flutter/web preview가 필요해지는
후속 작업에서는 frontend slot `13040`을 우선 후보로 쓰고, backend
포트 이동이 필요하면 `18040` 계열 후보를 별도 migration plan에서
다룬다.
Mattermost upstream 개발 compose가 쓰는 DB/cache/object/search/mail/metrics
포트는 upstream dev auxiliary로 취급한다. Nexo compose는 기본적으로
Postgres를 host에 publish하지 않고 compose network 내부 `db:5432`로만
사용한다. 상세 inventory와 secret boundary는
`services/core/compose/README.md`의 Port And Environment Inventory를 본다.
## 주요 명령
| 목적 | 명령 | 비고 |
| --- | --- | --- |
| 개발 진입점 확인 | `bin/dev` | 테스트 호스트, 플러그인, core compose 명령을 출력한다. |
| 기본 테스트 실행 | `bin/test` | Flutter 테스트를 실행하고, 기본값에서는 Go 테스트를 건너뛴다. |
| 기본 lint 실행 | `bin/lint` | Flutter analyze를 실행하고, 기본값에서는 Go vet을 건너뛴다. |
| 기본 build 실행 | `bin/build` | 설정된 앱 build를 실행한다. web 설정이 없으면 `apps/flutter-test` web build를 건너뛰고, 기본값에서는 Go build를 건너뛴다. |
| 서버 Go 테스트 포함 | `NEXO_CORE_GO_TEST=1 bin/test` | 로컬 `go`가 필요하다. |
| 서버 Go vet 포함 | `NEXO_CORE_GO_LINT=1 bin/lint` | 로컬 `go`가 필요하다. |
| 서버 Go build 포함 | `NEXO_CORE_GO_BUILD=1 bin/build` | 로컬 `go`가 필요하다. |
| `flutter-test` 호스트 직접 실행 | `cd apps/flutter-test && flutter run` | Flutter SDK가 필요하다. |
| 플러그인 직접 테스트 | `cd packages/messaging_flutter && flutter test` | Flutter SDK가 필요하다. |
| Android 네이티브 단위 테스트 실행 | `cd apps/flutter-test/android && ./gradlew testDebugUnitTest` | Android SDK가 필요하다. |
`bin/*` helper는 필요한 로컬 도구가 없으면 일부 검증을 건너뛸 수 있다. 작업 보고에는 건너뛴 검증을 함께 적는다.
## 구조
| 경로 | 역할 |
| --- | --- |
| `packages/messaging_flutter/` | 주 Flutter 메시징/푸시 알림 패키지 |
| `apps/flutter-test/` | 패키지 통합 검증용 `flutter-test` 앱 |
| `apps/mattermost/` | Mattermost 모바일 앱 저장소 스냅샷 |
| `services/core/` | Mattermost 서버 저장소 clone과 현재 compose 런타임 |
| `services/push-proxy/` | Mattermost push-proxy 저장소 스냅샷 |
| `docs/` | 모듈 간 제품, migration, 운영 문서 |
| `bin/` | workspace helper 진입점 |
| `agent-ops/` | agent 규칙, domain rule, 공통 skill 진입점 |
## 작업 맥락
- 작업을 시작할 때는 `AGENTS.md`를 읽고, 이어서 `agent-ops/rules/project/rules.md`를 읽는다.
- 변경 경로에 맞는 domain rule은 `agent-ops/rules/project/domain/*/rules.md`에서 확인한다.
- README, plan, review, commit/push 같은 표준 작업은 `agent-ops/skills/common/router.md`를 통해 공통 skill로 라우팅한다.
- `packages/messaging_flutter/`를 주 제품으로 본다. 앱별 제품 UI와 비즈니스 로직은 이 저장소가 아니라 패키지를 소비하는 앱의 책임이다.
- 여러 sibling 또는 외부 제품이 Nexo 메시징 계층을 소비할 수 있다. 공통 동작은 플러그인에 두고, 앱별 동작은 각 프로젝트에 둔다.
- `apps/flutter-test/`는 플러그인 통합 검증용 호스트로만 본다. 제품 앱으로 키우거나 플러그인 내부 동작을 복제하지 않는다.
- `apps/mattermost`, `services/core`, `services/push-proxy`는 Mattermost 원본 저장소 clone으로 본다. nexo 소유 앱이나 독자 서버 제품으로 재정의하지 않는다.
- 명시적인 업스트림 결정 없이 `services/core/UPSTREAM.md`의 기준선 정보를 바꾸지 않는다.
- 업스트림 작업 clone은 이 저장소 밖의 sibling/external `mattermost/` staging 폴더에 원본 저장소별로 둔다.
- 업스트림 저장소는 기록된 branch를 따라간다. `mattermost-mobile``main`, `mattermost``mattermost-push-proxy``master`를 기준으로 하며, branch 변경 시점이나 의도적으로 정한 갱신 시점에 스냅샷을 떠서 이 저장소로 merge 요청한다.
- 이 저장소에 들어오는 스냅샷은 원본 저장소별 정확한 commit SHA를 기록한다.
- merge 요청은 원칙적으로 업스트림 저장소별로 분리한다. `apps/mattermost`, `services/core`, `services/push-proxy` 스냅샷을 한 요청에 섞지 않는다.
- staging pull 결과를 이 저장소에 자동 반영하지 않는다. 스냅샷 diff와 관련 smoke 검증을 확인한 뒤 merge 요청한다.
- Nexo 전용 패치는 가능한 한 업스트림 스냅샷 밖의 compose, 문서, 래퍼, 작고 명시적인 패치로 둔다.
## 개발 흐름
1. 변경할 경로의 domain rule을 읽는다.
2. 소유 모듈 안에서 변경 범위를 좁게 유지한다.
3. 변경에 맞는 가장 작은 유효 검증을 실행한다.
4. workspace 수준 검증이 필요하면 `bin/test`, `bin/lint`, `bin/build`를 사용한다.
5. 서버 런타임 검증이 필요하면 `services/core/compose/`를 사용한다.
## 운영 업데이트/배포 흐름
upstream baseline이나 runtime image가 바뀌면 하나의 변경 기록에서 다음 항목을 함께 남긴다.
1. server, webapp, push-proxy baseline ref와 nexo Flutter SDK compatibility 범위.
2. 배포 후보 image tag 또는 digest, compose input hash, 적용 lane.
3. secret profile label과 주입 방식. 실제 값, credential, host, port는 tracked 문서와 task/review log에 쓰지 않는다.
4. smoke 결과와 실패 분류. 실패는 server, webapp, push-proxy, SDK contract, infra 중 하나로 후속 이슈화한다.
5. rollback ref와 rollback evidence 위치. 공개 기록에는 private run log 참조와 판정만 남긴다.
compose lane, secret 주입, rollback 기준은 `services/core/compose/README.md`
Deployment Loop를 따른다.
## 환경 변수
### Core Compose
| 이름 | 설명 | 필수 |
| --- | --- | --- |
| `NEXO_DB_PASSWORD` | Postgres `mmuser` 계정 password | 예 |
| `NEXO_SITE_URL` | core service가 사용하는 site URL | 예 |
| `NEXO_CORE_PORT` | core `8065`에 매핑할 host port | 아니오 |
| `NEXO_PUSH_PROXY_PORT` | push-proxy `8066`에 매핑할 host port | 아니오 |
예시는 `services/core/compose/.env.example`를 본다. 실제 `.env` 파일이나 런타임 데이터는 커밋하지 않는다. Docker network subnet은 `172.38.0.0/16`으로 고정되어 있으므로, 이 범위는 nexo용으로 예약하고 다른 Docker network에서 재사용하지 않는다.
### 선택 검증
| 이름 | 설명 | 기본값 |
| --- | --- | --- |
| `NEXO_CORE_GO_TEST` | `bin/test`에서 서버 Go 테스트를 실행한다. | `0` |
| `NEXO_CORE_GO_LINT` | `bin/lint`에서 서버 Go vet을 실행한다. | `0` |
| `NEXO_CORE_GO_BUILD` | `bin/build`에서 서버 Go build를 실행한다. | `0` |
## 참고 문서
- `AGENTS.md`
- `agent-ops/rules/project/rules.md`
- `agent-ops/skills/common/router.md`
- `services/core/UPSTREAM.md`
- `services/core/compose/README.md`
- `packages/messaging_flutter/README.md`
- `packages/messaging_flutter/docs/android-test-environment.md`
- `apps/flutter-test/README.md`
- `docs/README.md`