- Add iOS notification preflight plan and code review (PLAN/CODE_REVIEW-cloud-G07) - Add iOS notification smoke evidence template - Update iOS notification test guide with preflight steps - Add Flutter test app iOS fixtures (APNS payloads, GoogleService config, entitlements) - Update README files for flutter-test, messaging_flutter, and docs |
||
|---|---|---|
| .claude | ||
| agent-ops | ||
| agent-roadmap | ||
| agent-task | ||
| apps | ||
| bin | ||
| docs | ||
| packages/messaging_flutter | ||
| scratch | ||
| services | ||
| .aiexclude | ||
| .clineignore | ||
| .clinerules | ||
| .cursorignore | ||
| .cursorrules | ||
| .geminiignore | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| GEMINI.md | ||
| opencode.json | ||
| README.md | ||
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다.
빠른 시작
개발 진입점을 확인한다.
bin/dev
Flutter 패키지와 flutter-test 호스트 검증을 실행한다.
bin/test
bin/lint
core compose 런타임을 실행한다.
cd services/core/compose
cp .env.example .env
docker compose up
주요 명령
| 목적 | 명령 | 비고 |
|---|---|---|
| 개발 진입점 확인 | 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, 문서, 래퍼, 작고 명시적인 패치로 둔다.
개발 흐름
- 변경할 경로의 domain rule을 읽는다.
- 소유 모듈 안에서 변경 범위를 좁게 유지한다.
- 변경에 맞는 가장 작은 유효 검증을 실행한다.
- workspace 수준 검증이 필요하면
bin/test,bin/lint,bin/build를 사용한다. - 서버 런타임 검증이 필요하면
services/core/compose/를 사용한다.
운영 업데이트/배포 흐름
upstream baseline이나 runtime image가 바뀌면 하나의 변경 기록에서 다음 항목을 함께 남긴다.
- server, webapp, push-proxy baseline ref와 nexo Flutter SDK compatibility 범위.
- 배포 후보 image tag 또는 digest, compose input hash, 적용 lane.
- secret profile label과 주입 방식. 실제 값, credential, host, port는 tracked 문서와 task/review log에 쓰지 않는다.
- smoke 결과와 실패 분류. 실패는 server, webapp, push-proxy, SDK contract, infra 중 하나로 후속 이슈화한다.
- 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.mdagent-ops/rules/project/rules.mdagent-ops/skills/common/router.mdservices/core/UPSTREAM.mdservices/core/compose/README.mdpackages/messaging_flutter/README.mdpackages/messaging_flutter/docs/android-test-environment.mdapps/flutter-test/README.mddocs/README.md