- Add smoke-compose script for compose validation - Update build, lint, test scripts - Update agent roadmap and phase documentation - Update project README and docs
12 KiB
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가 필요하다. |
| Flutter SDK integration 테스트 포함 | NEXO_FLUTTER_INTEGRATION_TEST=1 bin/test |
apps/flutter-test에서 flutter test integration_test를 실행한다. Flutter SDK가 필요하다. |
| Android native 단위 테스트 포함 | NEXO_ANDROID_NATIVE_TEST=1 bin/test |
apps/flutter-test/android에서 ./gradlew testDebugUnitTest를 실행한다. Java/Gradle/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, 문서, 래퍼, 작고 명시적인 패치로 둔다.
업스트림 스냅샷 운영
workspace script를 둘 때의 계약은 자동 merge가 아니라 snapshot 후보 준비다.
script는 외부 mattermost/ staging clone을 기록된 branch로 update하고,
선택한 commit을 이 repo의 대응 경로로 복사할 수 있다. script 실행만으로
baseline을 변경한 것으로 보지 않는다.
snapshot 반영은 다음 단계를 분리한다.
- staging clone update와 후보 commit 선택
- repo별 snapshot copy:
apps/mattermost,services/core,services/push-proxy중 하나 - 해당
UPSTREAM.md의 source, branch, tag/commit, snapshot date 갱신 - snapshot diff 확인과 nexo-local patch inventory 정리
- 변경 범위에 맞는 smoke 검증
- repo별 merge 요청
release watch는 월 1회 Mattermost server/webapp release 흐름과 push-proxy
master 변경을 확인하고, security patch 또는 ESR 영향이 있으면 정기 주기와
별도로 snapshot 후보를 만든다. watch 결과는 해당 모듈의 UPSTREAM.md에
baseline 후보 또는 보류 사유로 남기고, 검증 증거는 필요하면
docs/runtime-image-validation.md나 merge 요청 본문에 연결한다.
업스트림 Patch 경계
services/core/server, services/core/webapp, services/push-proxy는
upstream-owned runtime으로 취급한다. Nexo 변경은 upstream snapshot과 다시
비교하기 쉬운 얇은 layer에 둔다.
webapp은 기본 메시지 앱 또는 reference front로 유지한다. branding, copy, 기능 숨김은 설정, wrapper, 작은 compatibility patch로 제한하고, 제품별 화면 흐름이나 앱별 business logic은 Nexo Flutter SDK를 소비하는 앱 쪽에서 소유한다.
대량 rename, directory 재배치, formatting-only churn, deep fork는 금지한다.
예외는 보안 패치, upstream update 차단 해소, Nexo runtime 계약 유지에 필요한
최소 변경일 때만 허용하며, 해당 모듈의 UPSTREAM.md에 변경 path, 사유,
rebase 위험, 검증 결과를 남긴다.
upstream 새 기능은 다음 후보로 분류한 뒤 반영한다.
| 후보 | 기준 | 처리 |
|---|---|---|
| keep | runtime 호환성, 보안, 기본 메시징 동작에 필요 | snapshot에 유지하고 smoke 검증에 포함한다. |
| hide | 기본 메시지 앱에서 노출하면 혼선을 주지만 upstream 유지에는 유리 | 설정, feature flag, 얇은 UI patch로 숨긴다. |
| defer | Nexo 계약 영향이 불명확하거나 검증 비용이 큰 기능 | 별도 follow-up으로 보류 사유와 재검토 조건을 남긴다. |
| remove | 보안, 라이선스, runtime 안정성 문제로 유지할 수 없는 기능 | 제거 사유와 upstream rebase 위험을 기록하고 검증한다. |
개발 흐름
- 변경할 경로의 domain rule을 읽는다.
- 소유 모듈 안에서 변경 범위를 좁게 유지한다.
- 변경에 맞는 가장 작은 유효 검증을 실행한다.
- workspace 수준 검증이 필요하면
bin/test,bin/lint,bin/build를 사용한다. - 서버 런타임 검증이 필요하면
services/core/compose/를 사용한다.
환경 변수
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 |
NEXO_FLUTTER_INTEGRATION_TEST |
bin/test에서 apps/flutter-test integration 테스트를 실행한다. |
0 |
NEXO_ANDROID_NATIVE_TEST |
bin/test에서 apps/flutter-test/android Android 네이티브 단위 테스트를 실행한다. |
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