# 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 ``` ## 주요 명령 | 목적 | 명령 | 비고 | | --- | --- | --- | | 개발 진입점 확인 | `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/`를 사용한다. ## 환경 변수 ### 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`