Compare commits

...

3 commits

Author SHA1 Message Date
d7e044cf5c update: project documentation and build scripts
- Add smoke-compose script for compose validation
- Update build, lint, test scripts
- Update agent roadmap and phase documentation
- Update project README and docs
2026-05-30 19:10:05 +09:00
8c07405b31 sync: agent-ops from agentic-framework v1.1.105 2026-05-30 19:05:50 +09:00
e82990ddff chore: upstream sync and roadmap updates
- Update README with latest project status
- Archive upstream-runtime milestone and update roadmap
- Update Mattermost Android build configuration
- Sync upstream references for core and push-proxy services
2026-05-30 15:44:06 +09:00
18 changed files with 376 additions and 76 deletions

View file

@ -64,6 +64,8 @@ docker compose up
| `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는 필요한 로컬 도구가 없으면 일부 검증을 건너뛸 수 있다. 작업 보고에는 건너뛴 검증을 함께 적는다.
@ -97,6 +99,52 @@ docker compose up
- staging pull 결과를 이 저장소에 자동 반영하지 않는다. 스냅샷 diff와 관련 smoke 검증을 확인한 뒤 merge 요청한다.
- Nexo 전용 패치는 가능한 한 업스트림 스냅샷 밖의 compose, 문서, 래퍼, 작고 명시적인 패치로 둔다.
## 업스트림 스냅샷 운영
workspace script를 둘 때의 계약은 자동 merge가 아니라 snapshot 후보 준비다.
script는 외부 `mattermost/` staging clone을 기록된 branch로 update하고,
선택한 commit을 이 repo의 대응 경로로 복사할 수 있다. script 실행만으로
baseline을 변경한 것으로 보지 않는다.
snapshot 반영은 다음 단계를 분리한다.
1. staging clone update와 후보 commit 선택
2. repo별 snapshot copy: `apps/mattermost`, `services/core`, `services/push-proxy` 중 하나
3. 해당 `UPSTREAM.md`의 source, branch, tag/commit, snapshot date 갱신
4. snapshot diff 확인과 nexo-local patch inventory 정리
5. 변경 범위에 맞는 smoke 검증
6. 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 위험을 기록하고 검증한다. |
## 개발 흐름
1. 변경할 경로의 domain rule을 읽는다.
@ -125,6 +173,8 @@ docker compose up
| `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` |
## 참고 문서

View file

@ -1 +1 @@
1.1.101
1.1.105

View file

@ -1,10 +1,11 @@
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

View file

@ -22,21 +22,21 @@ Implementation may stop early by filling the active review stub's `사용자 리
- Trigger: Korean or English active-task review requests, including `리뷰 진행해` and `리뷰해줘`, must use this skill when an active `CODE_REVIEW-*-G??.md` or `USER_REVIEW.md` exists under `agent-task/*/` or `agent-task/*/*/`, excluding `agent-task/archive/**`.
- Finalize every selected active state: for `CODE_REVIEW-*-G??.md`, append one verdict, archive the active review and plan files, then create exactly one next state; for `USER_REVIEW.md` completion, update the stop state, write `complete.log`, and archive the task. Do not report before finalization is complete.
- Next state: `PASS` writes `complete.log` and moves the task under `agent-task/archive/YYYY/MM/`; if the task group is `m-<milestone-slug>`, report completion metadata for the runtime event. `WARN` or `FAIL` normally writes the next active `PLAN-{build_lane}-GNN.md` and `CODE_REVIEW-{review_lane}-GNN.md`; if the user-review gate triggers, write `USER_REVIEW.md` instead. A completed `USER_REVIEW.md` uses the same terminal `complete.log` and archive path as `PASS`.
- A filled implementation-owned `사용자 리뷰 요청` is a review input, not a next state by itself. If it is a genuine user-only decision, external environment prerequisite, or scope conflict, the user-review gate triggers and this skill writes `USER_REVIEW.md`; if it is vague, unsupported, or repo-fixable, write a normal WARN/FAIL follow-up plan instead.
- A filled implementation-owned `사용자 리뷰 요청` is a review input, not a next state by itself. If it is a genuine user-only decision, user-owned external environment prerequisite, or scope conflict, the user-review gate triggers and this skill writes `USER_REVIEW.md`; if it is vague, unsupported, repo-fixable, or only missing evidence that a follow-up agent can produce by rerunning commands or collecting artifacts, write a normal WARN/FAIL follow-up plan instead.
- Do not ask for confirmation before WARN/FAIL follow-up files unless the user-review gate triggers. If details are uncertain but the gate does not trigger, write the smallest concrete follow-up plan with file references and verification commands.
- Recovery: if a prior turn appended a verdict without archive or next-state files, or resolved `USER_REVIEW.md` without `complete.log`, resume at the matching finalization step and finish the missing artifacts first.
## User Review Gate
`USER_REVIEW.md` is a loop stop state for cases where automatic follow-up is likely to waste cycles or needs a human decision.
`USER_REVIEW.md` is a loop stop state for loop-limit exhaustion or user-owned blockers. Default to a normal WARN/FAIL follow-up; the gate requires positive evidence that another implementation/review agent cannot resolve the blocker without user action.
- Compute `review-number` as `count(agent-task/{task_name}/code_review_*.log) + 1` before archiving the active review.
- If `review-number >= 5` and the verdict is `WARN` or `FAIL`, stop the automatic loop and write `USER_REVIEW.md`.
- If `review-number == 1`, the verdict is `FAIL`, and the blocking issue is a test environment problem rather than a repo-fixable implementation issue, stop the automatic loop and write `USER_REVIEW.md`.
- If the active review file has a filled `사용자 리뷰 요청` with `상태` other than `없음`, and the blocker is a user-only decision, external environment prerequisite, or scope conflict that the repository cannot safely resolve by code changes alone, stop the automatic loop and write `USER_REVIEW.md`.
- Treat a first-review failure as a test environment problem only with evidence: missing SDK/tool/runtime, unavailable external service, absent secret/credential, unsupported OS/device/interactive environment, or another prerequisite outside the repository. Record the exact command and stdout/stderr. Before claiming a tool is missing, require `command -v <tool>` or the project-equivalent check.
- Treat an implementation-owned `사용자 리뷰 요청` as valid only with specific decision questions, evidence, attempted commands/output or a reason commands could not run, and clear resume conditions. Vague uncertainty, repo-owned setup bugs, and ordinary incomplete implementation become normal WARN/FAIL follow-up plans instead.
- Do not classify repo-owned setup bugs as environment problems. If a manifest, bootstrap script, test fixture, or documented project entrypoint should provide the dependency, write a normal follow-up plan instead.
- If `review-number == 1`, the verdict is `FAIL`, and the blocking issue is a test environment problem that requires user action rather than repo-owned setup or evidence a follow-up agent can produce by rerunning commands or collecting artifacts, stop the automatic loop and write `USER_REVIEW.md`.
- If the active review file has a filled `사용자 리뷰 요청` with `상태` other than `없음`, and the blocker is a user-only decision, user-owned external environment prerequisite, or scope conflict that the repository and a capable next agent cannot safely resolve by code changes or verification reruns, stop the automatic loop and write `USER_REVIEW.md`.
- Treat a first-review failure as a test environment problem only with evidence from an attempted command: missing SDK/tool/runtime, unavailable external service, absent secret/credential, unsupported OS/device/interactive environment, or another prerequisite outside the repository. Record the exact command and stdout/stderr. Before claiming a tool is missing, require `command -v <tool>` or the project-equivalent check. Missing or non-verbatim verification evidence is a verification-trust failure, not a test environment problem.
- Treat an implementation-owned `사용자 리뷰 요청` as valid only with specific decision questions, evidence, attempted commands/output or a reason commands could not run, and clear resume conditions. The not-run reason must identify user-owned action or an external prerequisite; agent execution limits, missing handoff evidence, or incomplete verification records become normal WARN/FAIL follow-up plans when a capable follow-up lane can produce the evidence.
- Do not classify repo-owned setup bugs or verification evidence gaps as environment problems. If a manifest, bootstrap script, test fixture, documented project entrypoint, or follow-up agent can provide the dependency or evidence, write a normal follow-up plan instead.
- `USER_REVIEW.md` is created from `agent-ops/skills/common/code-review/templates/user-review-template.md`, filled with the archived loop history, current archived plan/review paths, verdict, loop count, blocking evidence, and user decision options.
## User Review Resolution
@ -101,7 +101,7 @@ Directory states:
| State | Meaning |
|-------|---------|
| `PLAN-*-G??.md` + `CODE_REVIEW-*-G??.md` stub or placeholders | Implementation is pending/incomplete; review should fail completeness if invoked |
| `PLAN-*-G??.md` + `CODE_REVIEW-*-G??.md` with filled `사용자 리뷰 요청` | Implementation is blocked on user input; review validates the request and writes `USER_REVIEW.md` if justified |
| `PLAN-*-G??.md` + `CODE_REVIEW-*-G??.md` with filled `사용자 리뷰 요청` | Implementation claims a user-only blocker; review validates the request and writes `USER_REVIEW.md` only if justified |
| `PLAN-*-G??.md` + filled `CODE_REVIEW-*-G??.md` | Ready for code-review skill |
| `complete.log` + `*.log` files | Task complete (PASS or user-review-resolved PASS), before final task-directory archive move |
| `USER_REVIEW.md` + `*.log` files | Automatic loop stopped; user decision is required before creating another plan |
@ -151,8 +151,8 @@ Before writing the verdict:
- Compare the plan `구현 체크리스트` and review stub `구현 체크리스트`; item text/order must match.
- If a checklist item contains integrated verification for a feature, treat that feature item as incomplete until both implementation evidence and the matching verification output are present. Do not accept a separate unchecked completion-criteria item as a substitute.
- Confirm the implementation marked the matching checklist items in the active review file, including the final mandatory `CODE_REVIEW-*-G??.md` completion item.
- Treat blank placeholder sections, missing actual implementation notes, missing checklist completion, or missing actual stdout/stderr in the active review file as a completeness or verification-trust failure.
- Read the `사용자 리뷰 요청` section. If `상태` is not `없음`, validate the exact decision needed, blocker evidence, command output or not-run reason, and resume condition before deciding whether the user-review gate triggers.
- Treat blank placeholder sections, missing actual implementation notes, missing checklist completion, or missing actual stdout/stderr in the active review file as a completeness or verification-trust failure. This alone does not trigger `USER_REVIEW.md`; route it to a normal follow-up plan unless there is separate user-only blocker evidence.
- Read the `사용자 리뷰 요청` section. If `상태` is not `없음`, validate the exact decision needed, blocker evidence, command output or not-run reason, why automatic follow-up cannot resolve it, and resume condition before deciding whether the user-review gate triggers.
- Grep renamed/removed symbols for stale references.
- Confirm every required test exists, name matches, and assertions are meaningful.
- Cross-check claimed verification output in the active review file against actual code and project commands.
@ -231,12 +231,13 @@ If the user-review gate does not trigger, write new routed plan/review files usi
- If the selected task group is `m-<milestone-slug>`, write the follow-up plan/review under the same `m-<milestone-slug>` task group.
- Base the follow-up scope directly on the archived review findings. Keep it narrow and actionable.
- Choose lane/grade again; preserve the prior route only when it was adequate, otherwise raise `GNN` and/or move `local -> cloud`.
- If the finding is only missing or untrusted verification evidence that an appropriate follow-up lane can produce by rerunning commands or collecting artifacts, do not write `USER_REVIEW.md` solely for that reason. Write a follow-up plan that reruns the exact commands in an appropriate lane and records actual stdout/stderr.
- Before choosing the follow-up route, apply this escalation gate:
- If the archived plan was `local-*` and the verdict is `FAIL` for correctness, completeness, test coverage, or verification trust, move the follow-up build lane to `cloud` unless the issue is trivially deterministic and review-detectable without live environment behavior.
- If the follow-up work is terminal-agent work (shell/CLI workflow implementation, bin script orchestration, process control, stdout/stderr parsing, exit-status contracts, long-running command diagnosis, or terminal benchmark-style tasks), use `cloud-G07` or higher.
- If unit tests passed but a real bin/smoke/integration command failed, use `cloud-G07` or higher.
- If the task depends on interactive TUI/PTY/browser/external CLI behavior, screen repaint/cursor stream parsing, or live command-palette state, use `cloud-G07` or higher.
- If recorded verification output was reconstructed, stale, or mismatched on rerun, use `cloud-G07` or higher and make verification trust recovery a plan item.
- If verification evidence is missing, reconstructed, stale, untrusted, or mismatched on rerun, use `cloud-G07` or higher and make verification trust recovery a plan item.
- `FAIL`: one plan item per Required issue.
- `WARN`: one grouped plan item for Suggested issues, plus related Nit issues if useful.
- Each plan item needs problem, solution with before/after when non-trivial, checklist, test decision, intermediate verification.
@ -255,7 +256,7 @@ Routed review stub template (fill `{…}` placeholders; everything else is fixed
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
@ -317,13 +318,14 @@ _구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
@ -368,7 +370,7 @@ Sections and their ownership:
| 구현 체크리스트 (항목 텍스트/순서) | follow-up plan에서 복사해 스텁 생성 시 고정 | 구현 에이전트가 `[ ]``[x]` 체크만 수행; 마지막 체크박스는 저장 전 필수 |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | 구현 에이전트가 채움 | placeholder 텍스트를 실제 내용으로 교체 |
| 사용자 리뷰 요청 | 구현 에이전트가 채움 | 진행에 사용자 입력이 필요하지 않으면 `상태: 없음` 유지; 필요하면 결정 항목, 근거, 명령 출력, 재개 조건을 기록 |
| 사용자 리뷰 요청 | 구현 에이전트가 채움 | 진행에 사용자 입력이 필요하지 않으면 `상태: 없음` 유지; 필요하면 결정 항목, 근거, 명령 출력, 자동 후속 불가 이유, 재개 조건을 기록 |
| 리뷰어를 위한 체크포인트 | 스텁 생성 시 고정 | 계획에서 추출한 리뷰 포인트 |
| 검증 결과 (섹션 제목 + 명령) | 스텁 생성 시 고정 | 실행 출력만 구현 에이전트가 채움; 명령 변경은 `계획 대비 변경 사항`에 기록 |
| 코드리뷰 결과 | 리뷰 에이전트가 append | 스텁에 포함하지 않음 |

View file

@ -16,9 +16,9 @@ code-review skill -> verdict + archive, complete.log, and PASS/user-review-resol
runtime -> for m-prefixed PASS completion events, state check and optional update-roadmap call
```
`code-review` may stop the automatic loop with `USER_REVIEW.md` when repeated non-PASS reviews or first-review test environment blockers require a user decision. Plan creation after `USER_REVIEW.md` requires an explicit user decision. If the user decision closes the task as complete/PASS, code-review resolves `USER_REVIEW.md`, writes `complete.log`, and archives the task instead of creating a new plan.
`code-review` may stop the automatic loop with `USER_REVIEW.md` when repeated non-PASS reviews or first-review test environment blockers require a user decision. Verification evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are not user decisions by themselves; they should become normal follow-up plans that record the required evidence. Plan creation after `USER_REVIEW.md` requires an explicit user decision. If the user decision closes the task as complete/PASS, code-review resolves `USER_REVIEW.md`, writes `complete.log`, and archives the task instead of creating a new plan.
The plan file and review stub must be self-sufficient for implementation agents that do not read this skill. If implementation discovers a user-only decision, external environment prerequisite, or scope conflict that blocks safe progress, the implementing agent records a `사용자 리뷰 요청` in the active `CODE_REVIEW-*-G??.md`, leaves active files in place, and reports ready for review. The code-review skill validates that request and writes `USER_REVIEW.md` when the stop is justified. Use `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` as the shared section template.
The plan file and review stub must be self-sufficient for implementation agents that do not read this skill. If implementation discovers a user-only decision, user-owned external environment prerequisite, or scope conflict that blocks safe progress, the implementing agent records a `사용자 리뷰 요청` in the active `CODE_REVIEW-*-G??.md`, leaves active files in place, and reports ready for review. The code-review skill validates that request and writes `USER_REVIEW.md` when the stop is justified. Use `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` as the shared section template.
## Workflow Contract
@ -44,7 +44,7 @@ Filename rules:
Role boundary rules:
- Implementing agents fill implementation-owned `CODE_REVIEW-*-G??.md` sections, keep active files in place, and report ready for review.
- If implementation cannot continue without user input, implementing agents fill the review stub's `사용자 리뷰 요청` section with the exact decision needed, evidence, commands/output, and resume condition, then stop with active files in place.
- If implementation cannot continue without user input, implementing agents fill the review stub's `사용자 리뷰 요청` section with the exact decision needed, evidence, commands/output, and resume condition, then stop with active files in place. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts should be recorded in `검증 결과` or `계획 대비 변경 사항`, not escalated to user review.
- Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, review-only checklist) is code-review-skill only.
Split decision policy:
@ -91,7 +91,7 @@ Routing rules:
- Use `cloud` for weak tests, broad API/call-site impact, ambiguity, storage/concurrency/protocol/auth risk, or prior local failure.
- Use `cloud-G07` or higher for terminal-agent work: shell/CLI workflow implementation, bin script orchestration, process control, stdout/stderr parsing, exit-status contracts, long-running command diagnosis, or terminal benchmark-style tasks. Merely running deterministic tests such as `go test` does not make a task terminal-agent work.
- Use `cloud-G07` or higher when acceptance depends on a real interactive external tool, TUI, PTY, browser, screen repaint/cursor stream, or bin-level smoke output. This is mandatory when unit tests pass but the real smoke/integration command fails.
- Use `cloud-G07` or higher when a prior review found verification trust failure, reconstructed command output, or claimed stdout/stderr that does not match a rerun.
- Use `cloud-G07` or higher when a prior review found missing, untrusted, reconstructed, or rerun-mismatched verification evidence.
- Keep high-risk design judgment on `cloud` with a higher grade; the runtime may map `cloud-GNN` to frontier-class models.
- Review may be `local` for narrow/low-risk checks and `cloud` for multi-file/API/test-meaning reviews, security/auth, storage/migration, concurrency, protocol/schema, cross-domain, or repeated Required issues.
- Raise `GNN` with scope, ambiguity, missing tests, irreversible behavior, and blast radius; keep grade model-independent.
@ -102,7 +102,7 @@ Directory states:
|-------|---------|
| `PLAN-*-G??.md` only | Invalid; plan skill always writes both active files |
| `PLAN-*-G??.md` + `CODE_REVIEW-*-G??.md` stub | Implementation is pending/in progress |
| `PLAN-*-G??.md` + `CODE_REVIEW-*-G??.md` with filled `사용자 리뷰 요청` | Implementation is blocked on user input; ready for code-review to validate and create `USER_REVIEW.md` if justified |
| `PLAN-*-G??.md` + `CODE_REVIEW-*-G??.md` with filled `사용자 리뷰 요청` | Implementation claims a user-only blocker; ready for code-review to validate and create `USER_REVIEW.md` only if justified |
| `PLAN-*-G??.md` + filled `CODE_REVIEW-*-G??.md` | Ready for code-review skill |
| `complete.log` + `*.log` files | Task complete (PASS or user-review-resolved PASS), before final task-directory archive move |
| `USER_REVIEW.md` + `*.log` files | Automatic loop stopped; user decision is required before creating another plan |
@ -210,7 +210,7 @@ Header line must be exactly:
Required sections:
- Title.
- `이 파일을 읽는 구현 에이전트에게`: warn that filling implementation-owned `CODE_REVIEW-*-G??.md` sections is mandatory. Tell the implementer to run verification, fill actual notes/output, keep active files in place, and report ready for review; finalization is code-review-skill only. Also state that if implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, the implementer must fill the review stub's `사용자 리뷰 요청` section with exact evidence and stop for code-review; the implementer does not create `USER_REVIEW.md`, archive logs, or write `complete.log`.
- `이 파일을 읽는 구현 에이전트에게`: warn that filling implementation-owned `CODE_REVIEW-*-G??.md` sections is mandatory. Tell the implementer to run verification, fill actual notes/output, keep active files in place, and report ready for review; finalization is code-review-skill only. Also state that if implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, the implementer must fill the review stub's `사용자 리뷰 요청` section with exact evidence and stop for code-review; the implementer does not create `USER_REVIEW.md`, archive logs, or write `complete.log`. State that evidence gaps a follow-up agent can close by rerunning commands or collecting artifacts are not user-review requests by themselves.
- `배경`: 2-4 sentences explaining why the work is needed.
- `사용자 리뷰 요청 흐름`: state that implementation-time blockers are recorded in the active review stub's `사용자 리뷰 요청` section, copied from `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`; code-review owns validation and the actual `USER_REVIEW.md` file write.
- `분석 결과`: record the findings from Step 2 and Step 3. This section is the written output of the analysis — not a summary, but the actual findings that justify the plan's scope and decisions. Must include all of the following subsections:
@ -282,7 +282,7 @@ Copy `agent-ops/skills/common/_templates/implementation-user-review-request-sect
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
@ -344,13 +344,14 @@ _구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
@ -395,7 +396,7 @@ Sections and their ownership:
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]``[x]` only; final checkbox is mandatory before saving |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required to proceed; when filled, include exact decision, evidence, commands/output, and resume condition |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required to proceed; when filled, include exact decision, evidence, commands/output, why automatic follow-up cannot resolve it, and resume condition |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan |
| 검증 결과 (section headings + commands) | Fixed at stub creation | Implementing agent fills in command output only; command changes require a `계획 대비 변경 사항` entry |
| 코드리뷰 결과 | Review agent appends | Not included in stub |

View file

@ -12,7 +12,7 @@ Mattermost server, webapp, push-proxy를 nexo runtime으로 계승하면서도 u
## 상태
[진행중]
[완료]
## 승격 조건
@ -44,28 +44,28 @@ Mattermost server, webapp, push-proxy를 nexo runtime으로 계승하면서도 u
server/webapp/push-proxy가 어떤 upstream 버전을 기준으로 움직이는지 추적 가능하게 만든다.
- [ ] [source-baseline] server와 webapp의 upstream tag/commit, 적용 patch, nexo-local 변경 범위를 기록하는 기준을 정리한다.
- [ ] [snapshot-script] 외부 `mattermost/` staging clone을 git update하고 선택한 snapshot을 `apps/mattermost`, `services/core`, `services/push-proxy`로 복사하는 workspace script 계약을 정리한다. 검증: script가 staging pull 결과를 자동 merge하지 않고, repo별 commit SHA 기록, snapshot diff 확인, smoke 검증 단계를 분리한다.
- [ ] [push-proxy-baseline] push-proxy를 image-only로 추적할지 source mirror/fork를 둘지 판단 기준과 현재 선택을 문서화한다.
- [ ] [release-watch] Mattermost monthly/ESR release, security patch, push-proxy update를 확인하는 주기와 담당 문서를 정리한다.
- [x] [source-baseline] server와 webapp의 upstream tag/commit, 적용 patch, nexo-local 변경 범위를 기록하는 기준을 정리한다.
- [x] [snapshot-script] 외부 `mattermost/` staging clone을 git update하고 선택한 snapshot을 `apps/mattermost`, `services/core`, `services/push-proxy`로 복사하는 workspace script 계약을 정리한다. 검증: script가 staging pull 결과를 자동 merge하지 않고, repo별 commit SHA 기록, snapshot diff 확인, smoke 검증 단계를 분리한다.
- [x] [push-proxy-baseline] push-proxy를 image-only로 추적할지 source mirror/fork를 둘지 판단 기준과 현재 선택을 문서화한다.
- [x] [release-watch] Mattermost monthly/ESR release, security patch, push-proxy update를 확인하는 주기와 담당 문서를 정리한다.
### Epic: [patch-policy] Patch boundary
nexo 변경이 upstream merge를 어렵게 만들지 않도록 허용 경계를 만든다.
- [ ] [thin-branding] webapp은 기본 메시지 앱/reference front로 유지하고, branding과 기능 숨김은 얇은 patch로 제한하는 기준을 정리한다.
- [ ] [no-deep-rename] server/webapp/push-proxy upstream-owned 코드의 대량 rename과 deep fork를 금지하고 예외 조건을 문서화한다.
- [ ] [feature-triage] upstream 새 기능을 keep/hide/defer/remove 후보로 분류하는 기준을 정리한다.
- [x] [thin-branding] webapp은 기본 메시지 앱/reference front로 유지하고, branding과 기능 숨김은 얇은 patch로 제한하는 기준을 정리한다.
- [x] [no-deep-rename] server/webapp/push-proxy upstream-owned 코드의 대량 rename과 deep fork를 금지하고 예외 조건을 문서화한다.
- [x] [feature-triage] upstream 새 기능을 keep/hide/defer/remove 후보로 분류하는 기준을 정리한다.
## 완료 리뷰
- 상태: 없음
- 요청일: 없음
- 완료 근거: 없음
- 상태: 승인됨
- 요청일: 2026-05-30
- 완료 근거: `services/core/UPSTREAM.md`, `services/push-proxy/UPSTREAM.md`, `README.md`에 upstream baseline, snapshot script 계약, push-proxy 추적 방식, release watch, patch boundary 기준을 정리했다.
- 리뷰 필요:
- [ ] 사용자가 완료 결과를 확인했다
- [ ] archive 이동을 승인했다
- 리뷰 코멘트: 없음
- [x] 사용자가 완료 결과를 확인했다
- [x] archive 이동을 승인했다
- 리뷰 코멘트: 2026-05-30 사용자 승인에 따라 완료 처리하고 archive로 이동한다.
## 범위 제외

View file

@ -7,9 +7,9 @@
## 활성 Milestone
- [진행중] 업스트림 팔로잉 기준선
- [계획] 내부 검증 파이프라인과 업데이트 대응 루프
- Phase: `agent-roadmap/phase/upstream-runtime/PHASE.md`
- 경로: `agent-roadmap/phase/upstream-runtime/milestones/upstream-following.md`
- 경로: `agent-roadmap/phase/upstream-runtime/milestones/cicd-operations.md`
## 선택 규칙

View file

@ -7,7 +7,7 @@
## 목표
Mattermost server, webapp, push-proxy를 nexo의 upstream-followable 메시징 런타임으로 유지한다.
보안/버그/기능 업데이트를 계속 흡수할 수 있도록 baseline 기록, patch 경계, CI/CD, 배포 검증, 이슈 대응 루프를 만든다.
보안/버그/기능 업데이트를 계속 흡수할 수 있도록 baseline 기록, patch 경계, 내부 검증, 이슈 대응 루프를 만든다.
## Milestone 흐름
@ -15,12 +15,12 @@ Mattermost server, webapp, push-proxy를 nexo의 upstream-followable 메시징
완료, 검토중, 진행중, 계획, 스케치 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
스케치 Milestone은 아직 구현 가능한 계획이 아니므로 계획 Milestone보다 아래에 둔다.
- [진행중] 업스트림 팔로잉 기준선
- 경로: `agent-roadmap/phase/upstream-runtime/milestones/upstream-following.md`
- [완료] 업스트림 팔로잉 기준선
- 경로: `agent-roadmap/archive/phase/upstream-runtime/milestones/upstream-following.md`
- 요약: server/webapp/push-proxy의 upstream baseline, patch 경계, update 판단 기준을 정한다.
- [계획] CI/CD와 운영 업데이트 루프
- [계획] 내부 검증 파이프라인과 업데이트 대응 루프
- 경로: `agent-roadmap/phase/upstream-runtime/milestones/cicd-operations.md`
- 요약: upstream update, compose 배포, 검증 실패 이슈화를 반복 가능한 파이프라인으로 만든다.
- 요약: upstream update와 SDK 변경을 내부 검증, compose smoke, 실패 분류 루프로 확인한다.
## Phase 경계
@ -28,4 +28,4 @@ Mattermost server, webapp, push-proxy를 nexo의 upstream-followable 메시징
- upstream 코드의 대량 rename, deep fork, 제품 UI 재작성은 별도 결정 전 진행하지 않는다.
- `services/core/webapp`은 기본 메시지 앱 또는 reference front로 유지하되, nexo embedded SDK와 책임을 섞지 않는다.
- `packages/messaging_flutter`는 nexo-owned embedded SDK이며 Mattermost mobile code를 팔로잉하는 대상이 아니다.
- nexo 변경은 compose, docs, CI/CD, patch inventory, 얇은 branding/compatibility layer에 우선 둔다.
- nexo 변경은 compose, docs, 내부 검증, patch inventory, 얇은 branding/compatibility layer에 우선 둔다.

View file

@ -1,4 +1,4 @@
# Milestone: CI/CD와 운영 업데이트 루프
# Milestone: 내부 검증 파이프라인과 업데이트 대응 루프
## 위치
@ -7,8 +7,8 @@
## 목표
Mattermost server/webapp/push-proxy update와 nexo Flutter SDK 검증을 반복 가능한 CI/CD와 운영 runbook으로 연결한다.
upstream 업데이트에 따른 이슈를 빠르게 분류하고, 수정/보류/rollback 결정을 남길 수 있는 흐름을 만든다.
Mattermost server/webapp/push-proxy update와 nexo Flutter SDK 검증을 내부 검증 파이프라인과 운영 기록 루프로 연결한다.
upstream 업데이트 또는 SDK 변경 후 깨진 지점을 빠르게 감지하고, 수정/보류/rollback 판단을 남길 수 있는 흐름을 만든다.
## 상태
@ -20,39 +20,38 @@ upstream 업데이트에 따른 이슈를 빠르게 분류하고, 수정/보류/
## 구현 잠금
- 상태: 잠금
- 상태: 해제
- 결정 필요:
- [ ] CI/CD 실행 위치를 GitHub Actions, 자체 runner, 원격 테스트 서버 중 어디에 둘지 결정한다.
- [ ] production-like 배포 대상과 secret 보관 방식을 결정한다.
- 없음
- 결정 완료:
- [x] 2026-05-27: upstream update를 쉽게 따라가기 위한 CI/CD와 이슈 대응 루프를 프로젝트 방향성에 포함한다.
- [x] 2026-05-27: upstream update를 쉽게 따라가기 위한 검증 자동화와 이슈 대응 루프를 프로젝트 방향성에 포함한다.
- [x] 2026-05-30: 현 단계에서는 외부 Jenkins, production-like 배포, secret 정책, CD 파이프라인을 요구하지 않고 내부 검증 파이프라인을 먼저 만든다.
## 범위
- workspace `bin/test`, `bin/lint`, `bin/build` 기반 기본 검증
- optional Go test/vet/build와 webapp/npm 검증
- compose smoke, server ping, webapp 접근, push-proxy smoke
- local/internal compose smoke, server ping, webapp 접근, push-proxy smoke
- Flutter SDK Dart/integration/Android native test
- upstream update 실패 이슈화, rollback, release note 흐름
- upstream update 실패 분류, 수정/보류/rollback 판단 기록, release note 입력 흐름
## 기능
### Epic: [ci] Continuous verification
### Epic: [ci] Internal verification
upstream-followable runtime과 nexo SDK를 같은 변경 흐름에서 검증한다.
- [ ] [workspace-checks] CI에서 `bin/test`, `bin/lint`, `bin/build`를 실행하고 skip된 도구를 보고하는 기준을 만든다.
- [x] [workspace-checks] 내부 검증에서 `bin/test`, `bin/lint`, `bin/build`를 실행하고 skip된 도구를 보고하는 기준을 만든다.
- [ ] [core-checks] optional Go test/vet/build와 webapp 검증을 upstream update 또는 core 변경 시 실행하는 기준을 만든다.
- [ ] [compose-smoke] compose로 core, webapp, db, push-proxy를 올리고 최소 smoke를 확인하는 CI 또는 원격 검증 흐름을 만든다.
- [ ] [compose-smoke] compose로 core, webapp, db, push-proxy를 올리고 최소 smoke를 확인하는 local/internal 검증 흐름을 만든다.
- [ ] [sdk-checks] Flutter SDK Dart test, client integration test, Android native unit test를 환경별로 나누어 실행하는 기준을 만든다.
### Epic: [cd] Deployment loop
### Epic: [cd] Update response loop
업데이트와 배포 실패가 추적 가능한 이슈로 남도록 운영 루프를 만든다.
업데이트와 검증 실패가 추적 가능한 기록으로 남도록 대응 루프를 만든다.
- [ ] [update-branch] Mattermost server/webapp/push-proxy baseline update용 branch, diff, patch inventory 절차를 정리한다.
- [ ] [deploy-pipeline] dev/test/production-like compose 배포, secret 주입, rollback 절차를 정리한다.
- [ ] [issue-loop] upstream update 실패를 server, webapp, push-proxy, SDK contract, infra 중 하나로 분류하고 후속 이슈로 남기는 절차를 만든다.
- [ ] [issue-loop] upstream update 또는 SDK 변경 실패를 server, webapp, push-proxy, SDK contract, infra 중 하나로 분류하고 후속 기록으로 남기는 절차를 만든다.
- [ ] [release-note] server/front/push-proxy baseline과 Flutter SDK compatibility를 한 번에 볼 수 있는 release note 기준을 만든다.
## 완료 리뷰
@ -67,14 +66,14 @@ upstream-followable runtime과 nexo SDK를 같은 변경 흐름에서 검증한
## 범위 제외
- production hardening 전체 구현은 배포 대상과 secret 정책 결정 전까지 진행하지 않는다.
- 외부 Jenkins, production-like 배포, secret 관리 정책, CD 파이프라인 구현은 후속 Milestone 전까지 포함하지 않는다.
- 외부 공개용 landing page나 marketing site는 포함하지 않는다.
- billing, organization management, 별도 admin console은 포함하지 않는다.
## 작업 컨텍스트
- 관련 경로: `.github/`, `bin/`, `services/core/`, `services/core/compose/`, `packages/messaging_flutter/`, `apps/flutter-test/`, `docs/`
- 표준선(선택): 먼저 private/internal deployment loop를 만들고, runner와 secret 정책이 확정되면 production-like CD로 확장한다
- 표준선: 먼저 local/internal verification loop를 만들고, 외부 runner나 CD는 배포 필요성이 생긴 뒤 별도 Milestone으로 확장한다.
- 선행 작업: 업스트림 팔로잉 기준선
- 후속 작업: 운영 runbook, release/versioning 고도화
- 확인 필요: CI/CD 실행 위치와 production-like 배포 대상
- 후속 작업: 운영 runbook, release/versioning 고도화, production-like CD 검토
- 확인 필요: 없음

View file

@ -207,10 +207,9 @@ dependencies {
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
implementation "com.google.firebase:firebase-messaging:$firebaseVersion"
androidTestImplementation('com.wix:detox:+')
androidTestImplementation 'com.wix:detox:20.47.0'
androidTestImplementation 'androidx.test:core:1.6.1'
androidTestImplementation 'androidx.test:runner:1.6.2'
androidTestImplementation 'com.wix:detox:20.26.2'
// For animated GIF support
implementation 'com.facebook.fresco:animated-gif:3.6.0'

View file

@ -26,3 +26,15 @@ if [ -f "$root/services/core/server/go.mod" ]; then
echo "skip services/core/server: set NEXO_CORE_GO_BUILD=1 to run the Go build"
fi
fi
if [ -f "$root/services/core/webapp/package.json" ]; then
if [ "${NEXO_CORE_WEBAPP_BUILD:-0}" = "1" ]; then
if command -v npm >/dev/null 2>&1; then
(cd "$root/services/core/webapp" && npm run build)
else
echo "skip services/core/webapp: npm not found"
fi
else
echo "skip services/core/webapp: set NEXO_CORE_WEBAPP_BUILD=1 to run the webapp npm build"
fi
fi

View file

@ -31,3 +31,15 @@ if [ -f "$root/services/core/server/go.mod" ]; then
fi
fi
if [ -f "$root/services/core/webapp/package.json" ]; then
if [ "${NEXO_CORE_WEBAPP_LINT:-0}" = "1" ]; then
if command -v npm >/dev/null 2>&1; then
(cd "$root/services/core/webapp" && npm run check)
else
echo "skip services/core/webapp: npm not found"
fi
else
echo "skip services/core/webapp: set NEXO_CORE_WEBAPP_LINT=1 to run the webapp npm check"
fi
fi

111
bin/smoke-compose Executable file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env bash
#
# nexo compose smoke helper
# Checks the status of the local Docker Compose runtime and validates key services.
#
set -euo pipefail
# Print help/usage if requested
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
echo "Usage: bin/smoke-compose [options]"
echo ""
echo "Options:"
echo " -h, --help Show this help message and exit"
echo ""
echo "Checks performed:"
echo " 1. Verify presence of required commands: docker, docker compose, curl, grep"
echo " 2. Verify that Docker Compose services are running (docker compose ps)"
echo " 3. Ping the Mattermost Core API (system/ping)"
echo " 4. Check PostgreSQL database readiness (pg_isready)"
echo " 5. Request Mattermost WebApp index"
echo " 6. Verify push-proxy container status"
echo " 7. Validate that Core points to the compose push-proxy server configuration"
echo ""
echo "Environment Variables:"
echo " NEXO_CORE_PORT Core port (default: 18065)"
exit 0
fi
# 1. Check for required commands
echo "Checking required commands..."
MISSING_TOOLS=()
if ! command -v docker &>/dev/null; then
MISSING_TOOLS+=("docker")
else
if ! docker compose version &>/dev/null; then
MISSING_TOOLS+=("docker compose")
fi
fi
if ! command -v curl &>/dev/null; then
MISSING_TOOLS+=("curl")
fi
if ! command -v grep &>/dev/null; then
MISSING_TOOLS+=("grep")
fi
if [ ${#MISSING_TOOLS[@]} -ne 0 ]; then
echo "error: The following required tools are missing: ${MISSING_TOOLS[*]}" >&2
exit 1
fi
# Locate compose directory relative to this script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMPOSE_DIR="$PROJECT_ROOT/services/core/compose"
if [ ! -d "$COMPOSE_DIR" ]; then
echo "error: Compose directory not found at $COMPOSE_DIR" >&2
exit 1
fi
cd "$COMPOSE_DIR"
PORT="${NEXO_CORE_PORT:-18065}"
# 2. Check running compose status
echo "Checking Docker Compose services status..."
if ! docker compose ps; then
echo "error: docker compose services are not running or failed to query" >&2
exit 1
fi
# 3. Ping core system
echo "Pinging Mattermost Core API at http://localhost:${PORT}/api/v4/system/ping..."
if ! curl -fsS "http://localhost:${PORT}/api/v4/system/ping"; then
echo "error: Core API ping failed on port ${PORT}" >&2
exit 1
fi
# 4. Check PostgreSQL database readiness
echo "Checking PostgreSQL database readiness..."
if ! docker compose exec -T db pg_isready -U mmuser -d mattermost; then
echo "error: Database is not ready" >&2
exit 1
fi
# 5. Check WebApp HTTP access
echo "Checking Mattermost WebApp access at http://localhost:${PORT}..."
if ! curl -fsSI "http://localhost:${PORT}"; then
echo "error: WebApp is not accessible on port ${PORT}" >&2
exit 1
fi
# 6. Check Push-Proxy container running status
echo "Checking push-proxy service running status..."
if ! docker compose ps --services --status running push-proxy | grep -x "push-proxy" &>/dev/null; then
echo "error: push-proxy service is not running (stopped or missing)" >&2
exit 1
fi
# 7. Validate Push Notification Server configuration in docker compose config
echo "Verifying push notification server URL configuration..."
if ! docker compose config | grep -E "MM_EMAILSETTINGS_PUSHNOTIFICATIONSERVER[=: ]+[\"']?http://push-proxy:8066[\"']?" &>/dev/null; then
echo "error: Push notification server URL is not configured to http://push-proxy:8066" >&2
exit 1
fi
echo "All smoke checks passed successfully!"

View file

@ -31,3 +31,66 @@ if [ -f "$root/services/core/server/go.mod" ]; then
fi
fi
if [ -f "$root/services/core/webapp/package.json" ]; then
if [ "${NEXO_CORE_WEBAPP_TEST:-0}" = "1" ]; then
if command -v npm >/dev/null 2>&1; then
(cd "$root/services/core/webapp" && npm run test-ci)
else
echo "skip services/core/webapp: npm not found"
fi
else
echo "skip services/core/webapp: set NEXO_CORE_WEBAPP_TEST=1 to run the webapp npm test suite"
fi
fi
if [ -f "$root/apps/flutter-test/pubspec.yaml" ]; then
if [ "${NEXO_FLUTTER_INTEGRATION_TEST:-0}" = "1" ]; then
if command -v flutter >/dev/null 2>&1; then
(cd "$root/apps/flutter-test" && flutter test integration_test)
else
echo "skip apps/flutter-test integration_test: flutter not found"
fi
else
echo "skip apps/flutter-test integration_test: set NEXO_FLUTTER_INTEGRATION_TEST=1 to run integration tests"
fi
fi
if [ "${NEXO_ANDROID_NATIVE_TEST:-0}" = "1" ]; then
if [ -f "$root/apps/flutter-test/android/gradlew" ]; then
if command -v java >/dev/null 2>&1; then
# Check if Android SDK is available
has_android_sdk=0
if [ -n "${ANDROID_HOME:-}" ] && [ -d "$ANDROID_HOME" ]; then
has_android_sdk=1
elif [ -n "${ANDROID_SDK_ROOT:-}" ] && [ -d "$ANDROID_SDK_ROOT" ]; then
has_android_sdk=1
else
local_sdk_dir=""
if [ -f "$root/apps/flutter-test/android/local.properties" ]; then
# Extract non-commented sdk.dir value
sdk_line=$(grep -E '^[[:space:]]*sdk\.dir[[:space:]]*=' "$root/apps/flutter-test/android/local.properties" || true)
if [ -n "$sdk_line" ]; then
local_sdk_dir=$(echo "$sdk_line" | cut -d'=' -f2- | xargs || true)
fi
fi
if [ -n "$local_sdk_dir" ] && [ -d "$local_sdk_dir" ]; then
has_android_sdk=1
fi
fi
if [ "$has_android_sdk" = "1" ]; then
(cd "$root/apps/flutter-test/android" && ./gradlew testDebugUnitTest)
else
echo "skip apps/flutter-test Android native tests: Android SDK not found (ANDROID_HOME, ANDROID_SDK_ROOT, and local.properties sdk.dir are all missing or point to invalid directories)"
fi
else
echo "BLOCKED apps/flutter-test Android native tests: java not found"
fi
else
echo "skip apps/flutter-test Android native tests: gradlew not found"
fi
else
echo "skip apps/flutter-test Android native tests: set NEXO_ANDROID_NATIVE_TEST=1 to run Android native tests"
fi

View file

@ -8,10 +8,11 @@ Module-specific instructions stay with the module that owns them.
## Runtime Baseline Index
- Workspace runtime and upstream policy: `../README.md`
- Internal verification baseline: `../README.md#내부-검증-기준`
- Core compose runtime, smoke checks, remote parity, and secret boundary:
`../services/core/compose/README.md`
- Core upstream snapshot baseline: `../services/core/UPSTREAM.md`
- Mattermost mobile app upstream snapshot baseline: `../apps/mattermost/UPSTREAM.md`
- Mattermost push-proxy upstream snapshot baseline: `../services/push-proxy/UPSTREAM.md`
- Runtime Image Validation details: `runtime-image-validation.md`
- Compose smoke helper utility: `../bin/smoke-compose`

View file

@ -3,10 +3,45 @@
`services/core/` is derived from the Mattermost server repository.
- Source: `https://github.com/mattermost/mattermost.git`
- Branch: `master`
- Baseline tag: `v11.4.2`
- Baseline commit: `bcf511968217cd0f65cbead926e03260bfcd1011`
- Snapshot date: `2026-05-30`
- Snapshot source: `/config/workspace/mattermost/mattermost/`
- Snapshot target: `/config/workspace/nexo/services/core/`
Keep product-specific changes small and easy to compare against this baseline
until the long-term fork and rebranding strategy is settled.
## Component Baseline
Server and webapp are tracked from the same upstream repository baseline, but
they should be reviewed as separate runtime surfaces when a snapshot is updated.
| Component | Workspace path | Upstream path | Baseline tag | Baseline commit |
| --- | --- | --- | --- | --- |
| Server | `services/core/server/` | `server/` | `v11.4.2` | `bcf511968217cd0f65cbead926e03260bfcd1011` |
| Webapp | `services/core/webapp/` | `webapp/` | `v11.4.2` | `bcf511968217cd0f65cbead926e03260bfcd1011` |
## Update Record
When the server or webapp baseline changes, update this file with:
- upstream branch, tag, and commit SHA used for the snapshot
- snapshot date, source clone path, and target workspace path
- component scope: server, webapp, or both
- patch inventory: upstream snapshot patches, nexo-local patches, and removed patches
- validation summary or a link to the evidence document used before merge
Do not change the baseline tag or commit only because a staging clone was pulled.
A new baseline is recorded after snapshot diff review and the relevant smoke
checks pass.
## Patch Boundary
Keep product-specific changes small and easy to compare against this baseline.
Prefer compose files, workspace docs, helper wrappers, or narrowly documented
compatibility patches over direct edits to upstream-owned server or webapp code.
Any nexo-local patch inside `services/core/server/` or `services/core/webapp/`
must be listed in the update record with its path, reason, upstream rebase risk,
and validation result. Existing patch-package files under
`services/core/webapp/patches/` are treated as part of the upstream snapshot
unless the update record explicitly marks one as nexo-local.

View file

@ -51,9 +51,8 @@ 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"
docker compose ps --services --status running push-proxy | grep -x "push-proxy"
docker compose config | grep -E "MM_EMAILSETTINGS_PUSHNOTIFICATIONSERVER[=: ]+[\"']?http://push-proxy:8066[\"']?"
```
FCM/APNS credential validation is not part of the default smoke. Run it only

View file

@ -9,4 +9,19 @@
- Snapshot source: `/config/workspace/mattermost/mattermost-push-proxy/`
- Snapshot target: `/config/workspace/nexo/services/push-proxy/`
Keep nexo-specific changes outside this snapshot where possible.
## Tracking Mode
Current choice: source snapshot plus nexo-owned runtime image build.
Use the source snapshot as the primary baseline because nexo needs reproducible
image builds, local smoke validation, and an explicit place to review FCM/APNs
delivery behavior. Do not treat push-proxy as image-only while local runtime
images are built from this workspace.
Image-only tracking is only a future candidate if nexo no longer needs local
source-level validation, no nexo-local patch is present, and runtime image
provenance can still be tied to a specific upstream commit or release artifact.
Keep nexo-specific changes outside this snapshot where possible. If a local
patch is unavoidable, record its path, reason, rebase risk, and validation
evidence in this file before merging the snapshot update.