chore(roadmap): 변경 내역을 반영한다

작업 중 누락된 문서, 테마, 테스트 변경을 모두 반영해 원격 동기화할 수 있게 정리한다.
This commit is contained in:
toki 2026-06-09 04:01:12 +09:00
parent 36969cbe85
commit 5af717d432
11 changed files with 729 additions and 46 deletions

View file

@ -29,13 +29,13 @@ AppSok을 사내 Mac에서 안정적으로 실행할 수 있도록 signing, nota
- [ ] notarization 후 `stapler`로 ticket을 붙인 `.app`, `.zip`, `.dmg`, `.pkg` 중 어떤 산출물을 배포할지 결정한다.
- [ ] "아무 맥에서나 설치" 범위를 Apple Silicon only로 볼지, Intel Mac까지 포함하는 universal build로 볼지 결정한다.
- [ ] sandbox를 유지할지, ADB 실행 때문에 sandbox 해제가 필요한지 검증한다.
- [ ] ADB binary를 앱에 bundle할지, 사용자 환경의 Android Platform Tools를 사용할지 결정한다.
## 범위
- macOS app bundle metadata
- entitlement와 sandbox 검증
- Keychain/network/ADB 실행 smoke test
- bundled ADB runtime의 nested binary/dylib signing과 실행 검증
- Developer ID signing, notarization, staple, MDM 배포 후보 문서화
## 기능
@ -46,7 +46,7 @@ AppSok을 사내 Mac에서 안정적으로 실행할 수 있도록 signing, nota
- [ ] [network] sandbox 상태에서 Jenkins HTTPS 호출이 가능한지 확인한다.
- [ ] [keychain] `flutter_secure_storage` Keychain read/write가 배포 build에서 동작하는지 확인한다.
- [ ] [adb-exec] sandbox 상태에서 `adb devices -l``adb install` 실행 가능 여부를 확인한다.
- [ ] [adb-exec] sandbox 상태에서 bundled `adb devices -l``adb install` 실행 가능 여부를 확인한다.
- [ ] [url-scheme] `appsok://` URL scheme이 설치된 앱으로 전달되는지 확인한다.
### Epic: [distribution] 배포 방식
@ -58,7 +58,7 @@ AppSok을 사내 Mac에서 안정적으로 실행할 수 있도록 signing, nota
- [ ] [notary-profile] `notarytool` Keychain profile 존재 여부와 세팅 절차를 비밀값 없이 문서화한다.
- [ ] [staple-assess] notarization 후 stapling과 `spctl --assess` 검증 절차를 문서화한다.
- [ ] [arch-policy] Apple Silicon only 또는 universal build 배포 정책을 문서화한다.
- [ ] [platform-tools] ADB binary 제공 방식과 업데이트 책임을 정한다.
- [ ] [platform-tools] bundled ADB runtime의 포함 파일, version pinning, 업데이트 책임, NOTICE 보존 방식을 문서화한다.
- [ ] [release-checklist] 배포 전 검증 checklist를 작성한다.
## 완료 리뷰
@ -75,12 +75,15 @@ AppSok을 사내 Mac에서 안정적으로 실행할 수 있도록 signing, nota
- Auth Broker 또는 Jenkins plugin 구현
- 중앙 감사 서버
- 사용자 Mac의 Android Studio 또는 Android Platform Tools 설치를 기본 전제로 삼는 배포 방식
- Windows/Linux desktop target
## 작업 컨텍스트
- 관련 경로: `macos/Runner/`, `macos/Runner.xcodeproj/`, `pubspec.yaml`
- 표준선(선택): sandbox는 가능한 유지하고, 불가능한 경우 사유와 대안을 문서화한다.
- 표준선(선택): 내부 ops 도구 기준으로 ADB는 AppSok-managed bundled runtime을 기본 제공하고, 사용자 환경의 `adb`는 override/fallback으로만 둔다.
- 검증 메모: bundled `adb`, 필요한 `lib64/*.dylib`, `NOTICE.txt`, `source.properties`를 포함하고 signing/notarization 전후 실행 여부를 remote Mac runner에서 확인한다.
- 선행 작업: 사용 가능한 MVP
- 후속 작업: Auth Broker와 Jenkins Plugin 후보 검토
- 확인 필요: 구현 잠금의 사용자 리뷰 체크리스트가 AppSok 표시명 승인, Developer ID 사용 승인, notary credential profile, 배포 산출물 형식, universal build 필요 여부, 조직 배포 정책, sandbox/ADB 실행 검증, ADB binary 제공 방식을 다룬다.
- 확인 필요: 구현 잠금의 사용자 리뷰 체크리스트가 AppSok 표시명 승인, Developer ID 사용 승인, notary credential profile, 배포 산출물 형식, universal build 필요 여부, 조직 배포 정책, sandbox/ADB 실행 검증을 다룬다.

View file

@ -7,7 +7,7 @@
## 목표
사용자가 Jenkins job의 최근 build를 보고, 설치 가능한 Android artifact를 식별해 Mac에 내려받을 수 있게 한다. 다운로드된 artifact는 이후 USB 설치 milestone의 입력이 된다.
사용자가 Jenkins job 목록에서 대상 job을 고르고, 해당 job의 최근 build 중 설치 가능한 `.apk` artifact가 있는 build만 확인해 바로 설치 흐름으로 넘길 수 있게 한다. build 목록은 build number보다 빌드한 사람을 중심으로 요약해 오설치 가능성을 낮춘다.
## 상태
@ -19,38 +19,50 @@
## 구현 잠금
- 상태: 잠금
- 결정 필요: 아래 체크리스트
- [ ] 기본 Jenkins job URL 또는 job 선택 방식을 정한다.
- [ ] artifact 필터 기준을 단일 APK로 제한할지, flavor/branch별 패턴을 둘지 결정한다.
- [ ] 다운로드 cache 위치와 보관 기간을 정한다.
- 상태: 해제
- 결정 필요: 없음
## 범위
- Jenkins recent build 조회
- build number, result, branch, flavor, artifact 표시
- APK artifact 다운로드와 로컬 cache
- Jenkins job 목록 조회와 대상 job 선택
- 선택한 job의 recent build 조회
- `.apk` artifact가 있는 build만 listing
- 빌드한 사람 중심의 build 요약 표시
- 선택한 build/artifact에서 바로 설치 CTA 노출
- 설치 시 필요한 `.apk` artifact 임시 다운로드와 설치 흐름 handoff
- 권한 없음, artifact 없음, 실패 build 상태 표시
## 기능
### Epic: [job-select] Jenkins job 선택
로그인 이후 접근 가능한 Jenkins job을 먼저 보여주고 사용자가 설치 대상 job을 고른다.
- [ ] [job-list] Jenkins job 목록을 조회하고 검색 가능한 리스트로 표시한다.
- [ ] [job-select] 사용자가 job을 선택하면 해당 job의 build 목록으로 진입한다.
- [ ] [job-empty] 접근 가능한 job이 없거나 권한이 없을 때 상태를 구분해 표시한다.
### Epic: [build-list] build 목록
Jenkins Remote API에서 최근 build와 artifact metadata를 가져온다.
Jenkins Remote API에서 선택한 job의 최근 build와 `.apk` artifact metadata를 가져온다.
- [ ] [job-query] Jenkins job URL로 build 목록을 조회한다. 검증: mock HTTP 응답 기반 parser test에서 build/result/artifact parsing이 통과한다.
- [ ] [job-query] 선택한 Jenkins job의 build 목록을 조회한다. 검증: mock HTTP 응답 기반 parser test에서 build/requestedBy/result/artifact parsing이 통과한다.
- [ ] [apk-only] `.apk` artifact가 있는 build만 목록에 남긴다.
- [ ] [requested-by] Jenkins cause의 userName/userId를 우선하고 없으면 trigger source 또는 commit author를 fallback으로 사용해 빌드한 사람을 1차 정보로 표시한다.
- [ ] [state-badges] success/failure/running/aborted 상태를 구분해 표시한다.
- [ ] [search-filter] build number, branch, flavor, artifact 이름 기준 검색/필터를 제공한다.
- [ ] [summary-row] build number, branch, flavor, result, 시간, artifact 이름은 보조 정보로 요약 표시한다.
- [ ] [search-filter] 빌드한 사람, build number, branch, flavor, artifact 이름 기준 검색/필터를 제공한다.
- [ ] [empty-error] 권한 없음, 네트워크 실패, artifact 없음 상태를 구분해 사용자에게 보여준다.
### Epic: [download-cache] 다운로드와 cache
### Epic: [install-ready] 설치 진입
선택한 APK를 Mac에 내려받고 설치 가능한 파일 경로로 관리한다.
사용자가 build를 선택하면 별도 깊은 탐색 없이 설치 버튼을 바로 노출하고, 설치 요청 시 필요한 파일만 임시로 내려받는다.
- [ ] [install-cta] build/artifact item 선택 시 설치 CTA를 바로 노출한다.
- [ ] [download-progress] artifact 다운로드 진행률과 취소 상태를 표시한다.
- [ ] [cache-path] 다운로드 파일을 앱 전용 cache 경로에 저장한다.
- [ ] [temp-download] 다운로드 파일을 앱 임시/staging 경로에 저장하고 설치 완료 또는 취소 후 삭제한다.
- [ ] [artifact-verify] 다운로드 완료 후 파일 존재, 확장자, 크기 정보를 확인한다.
- [ ] [handoff] 다운로드된 APK 경로를 USB 설치 흐름으로 넘긴다.
- [ ] [handoff] 다운로드된 APK 경로를 device 선택과 USB 설치 흐름으로 넘긴다.
## 완료 리뷰
@ -67,11 +79,14 @@ Jenkins Remote API에서 최근 build와 artifact metadata를 가져온다.
- split APK/APKS/AAB 다운로드/설치
- Teams deep link로 build를 직접 여는 흐름
- 중앙 다운로드 감사 로그
- 설치 완료 후 다운로드 파일을 장기 보관하는 cache 정책
## 작업 컨텍스트
- 관련 경로: `lib/src/features/builds/`, `lib/src/models/jenkins_build.dart`, `lib/src/services/jenkins_client.dart`
- 표준선(선택): Jenkins Remote API JSON tree를 사용하고, parsing은 모델/서비스 테스트로 보호한다.
- 표준선(선택): 다운로드 파일은 설치를 위한 임시 staging 산출물이며, 기본 정책은 설치 완료 또는 취소 후 삭제다.
- 표준선(선택): build 목록의 주 정보는 빌드한 사람이며, build number와 branch/flavor/result는 보조 정보다.
- 선행 작업: Jenkins 로그인과 credential 수명주기
- 후속 작업: USB 설치와 device 선택
- 확인 필요: Jenkins job 구조, artifact naming, cache 정책
- 확인 필요: 없음

View file

@ -7,7 +7,7 @@
## 목표
AppSok이 Jenkins에 접근할 수 있는 사용자인지 확인하고, 사용자별 권한으로 Jenkins API를 호출할 credential을 안전하게 저장한다. MVP에서는 수동 API token 입력 또는 WebView 기반 token 자동 발급 중 하나를 선택해 UX와 보안 균형을 맞춘다.
AppSok이 Jenkins에 접근할 수 있는 사용자인지 확인하고, 사용자별 권한으로 Jenkins API를 호출할 credential을 안전하게 저장한다. MVP에서는 사용자가 직접 token을 발급하지 않도록 Jenkins WebView 로그인 후 사용자별 API token을 자동 발급하고 Keychain에 저장한다.
## 상태
@ -19,38 +19,37 @@ AppSok이 Jenkins에 접근할 수 있는 사용자인지 확인하고, 사용
## 구현 잠금
- 상태: 잠금
- 잠금 해제 조건: 사용자 리뷰에서 아래 항목을 승인하거나 방향을 결정할 때까지 credential 구현 방식을 확정하지 않는다.
- 결정 필요: 사용자 리뷰 체크리스트
- [ ] MVP 인증 방식을 `수동 API token 입력`으로 시작할지, `Jenkins WebView 로그인 후 token 자동 발급`으로 시작할지 결정한다.
- [ ] Jenkins에서 사용자별 API token 자동 발급 endpoint와 crumb 발급 흐름을 사용할 수 있는지 확인한다.
- [ ] WebView 로그인 방식이 사내 보안 리뷰에서 허용 가능한지 확인한다.
- 상태: 해제
- 결정 필요: 없음
## 범위
- Jenkins base URL과 username/API token 저장
- credential 저장/삭제/검증 UI
- `/whoAmI` 또는 사용자 API 호출 기반 로그인 상태 확인
- Jenkins base URL 저장과 WebView 로그인 진입
- WebView 로그인 세션에서 crumb와 사용자별 API token 자동 발급
- 자동 발급한 username/API token을 macOS Keychain에 저장
- 앱 시작 시 저장된 credential을 읽고 `/whoAmI` 또는 사용자 API 호출로 조용히 재검증
- credential 삭제, 재로그인, token 폐기/권한 없음/네트워크 실패 상태 구분
- macOS Keychain 저장과 로그 redaction
## 기능
### Epic: [manual-token] 수동 token MVP
### Epic: [web-login] WebView 로그인과 자동 token 발급
사용자가 직접 만든 Jenkins API token을 AppSok에 저장하고 검증한다.
사용자가 Jenkins 계정으로 로그인하면 AppSok이 같은 세션에서 API token을 자동 발급해 저장한다.
- [ ] [settings-form] Jenkins base URL, username, API token 입력과 저장 UI를 제공한다.
- [ ] [keychain-store] credential을 `TokenStore`를 통해 macOS Keychain에 저장하고 삭제할 수 있다. 검증: mock storage 기반 unit test에서 save/read/clear가 통과한다.
- [ ] [whoami-check] 저장된 credential로 Jenkins 사용자 확인 API를 호출해 로그인 상태를 표시한다.
- [ ] [login-webview] Jenkins 로그인 URL을 WebView로 열고 로그인 완료를 감지한다.
- [ ] [crumb-token] WebView same-origin 요청으로 crumb를 받고 사용자별 API token을 자동 발급한다.
- [ ] [keychain-store] 자동 발급한 username/API token을 `TokenStore`를 통해 macOS Keychain에 저장하고 삭제할 수 있다. 검증: mock storage 기반 unit test에서 save/read/clear가 통과한다.
- [ ] [redaction] API token이 화면 오류, debug log, test fixture에 원문으로 남지 않도록 처리한다.
### Epic: [web-login] WebView 자동 token 후보
### Epic: [session-restore] 로그인 상태 복원
수동 token UX가 부담스러운 경우를 대비해 Jenkins 로그인 세션에서 token 발급을 자동화할 수 있는 구조를 둔다.
앱을 다시 켤 때 매번 로그인하지 않고 저장된 credential을 검증해 Jenkins 접근 상태를 복원한다.
- [ ] [login-webview] Jenkins 로그인 URL을 WebView로 열고 로그인 완료를 감지하는 화면 흐름을 설계한다.
- [ ] [crumb-token] WebView same-origin 요청으로 crumb와 generate token 호출 후보를 검증한다.
- [ ] [fallback] WebView 자동화가 실패하면 수동 token 입력으로 돌아갈 수 있다.
- [ ] [startup-check] 앱 시작 시 Keychain credential을 읽고 Jenkins 사용자 확인 API로 조용히 검증한다.
- [ ] [auth-state] 검증 성공 시 로그인 화면을 건너뛰고 build 목록으로 진입한다.
- [ ] [reauth] token 폐기, 권한 없음, Jenkins URL 변경, 네트워크 실패를 구분해 재로그인 또는 재시도 흐름으로 안내한다.
- [ ] [logout-clear] 사용자가 저장된 credential을 삭제하고 다시 로그인할 수 있다.
## 완료 리뷰
@ -67,11 +66,13 @@ AppSok이 Jenkins에 접근할 수 있는 사용자인지 확인하고, 사용
- LDAP 직접 연동
- 공용 Jenkins API token 내장
- Auth Broker 또는 Jenkins plugin 구현
- 사용자가 Jenkins에서 API token을 직접 발급해 복사하는 흐름을 기본 UX로 삼는 방식
## 작업 컨텍스트
- 관련 경로: `lib/src/features/settings/`, `lib/src/services/token_store.dart`, `lib/src/services/jenkins_client.dart`, `macos/Runner/*.entitlements`
- 표준선(선택): 사용자별 Jenkins 권한과 Keychain 저장을 기본 전제로 한다.
- 표준선(선택): 사용자별 Jenkins 권한, WebView 로그인 기반 자동 token 발급, Keychain 저장을 기본 전제로 한다.
- 표준선(선택): API token은 OAuth refresh token처럼 갱신하는 토큰이 아니라 저장 후 재검증하는 credential로 다룬다.
- 선행 작업: 제품 골격 안정화
- 후속 작업: Artifact 탐색과 다운로드
- 확인 필요: 구현 잠금의 사용자 리뷰 체크리스트가 MVP 인증 방식, Jenkins token 자동 발급 가능 여부, WebView 로그인 허용 여부를 다룬다.
- 확인 필요: 없음

View file

@ -37,7 +37,7 @@ AppSok의 Flutter macOS scaffold를 실제 기능 구현이 가능한 기준선
- [ ] [nav-shell] 좌측 navigation과 상단 Jenkins/ADB 상태 영역을 실제 상태 연결 전에도 안정적으로 표시한다. 검증: `flutter test`에서 app shell 렌더링과 navigation 전환이 통과한다.
- [ ] [responsive-ui] 기본 테스트 viewport에서 텍스트/버튼 overflow가 없도록 card, badge, toolbar 크기를 안정화한다. 검증: `flutter test`가 overflow exception 없이 통과한다.
- [ ] [theme] AppSok 이름과 업무 앱 성격에 맞는 Material theme 기준선을 유지한다.
- [x] [theme] AppSok 이름과 업무 앱 성격에 맞는 Material theme 기준선을 유지한다.
### Epic: [ops] 작업 운영 기준선

View file

@ -24,6 +24,9 @@ USB로 연결된 Android device를 표시하고, 선택한 단일 APK를 `adb in
## 범위
- AppSok에 포함된 pin된 ADB runtime을 기본 실행 경로로 사용
- 사용자 지정 또는 system `adb`는 override/fallback으로만 허용
- AppSok 전용 ADB server port를 기본값으로 사용하고 공유 server fallback 제공
- `adb devices -l` 기반 device 목록
- unauthorized/offline/device 상태 표시
- 설치 대상 device 선택
@ -32,11 +35,19 @@ USB로 연결된 Android device를 표시하고, 선택한 단일 APK를 `adb in
## 기능
### Epic: [adb-runtime] ADB 실행 환경
사용자 Mac의 Android Studio, SDK 설치, shell `PATH`에 흔들리지 않는 AppSok-managed ADB runtime을 제공한다.
- [ ] [adb-path] bundled `adb`를 기본 실행 경로로 선택하고, 사용자가 지정한 custom/system `adb`는 명시적 override 또는 fallback으로만 사용한다.
- [ ] [adb-bundle] macOS app bundle에 pin된 최소 ADB subset(`adb`, 필요한 `lib64/*.dylib`, `NOTICE.txt`, `source.properties`)을 포함한다. 검증: remote Mac runner에서 bundled `adb version`과 dylib 의존성 확인이 통과한다.
- [ ] [adb-server] AppSok 전용 ADB server port를 기본으로 사용하고, Android Studio/CLI와 같은 기존 server를 써야 하는 경우 공유 `5037` 모드로 전환할 수 있다.
- [ ] [adb-diagnostics] ADB 실행 경로, bundled version, runtime hash, server port, fallback 여부를 진단 정보로 표시한다.
### Epic: [device-list] device 탐색
연결된 Android device를 사용자가 이해할 수 있는 형태로 보여준다.
- [ ] [adb-path] 설정된 adb path 또는 PATH의 `adb` 실행 가능 여부를 확인한다.
- [ ] [parse-devices] `adb devices -l` 결과를 serial/state/model/product로 parsing한다. 검증: `device`, `unauthorized`, `offline` fixture test가 통과한다.
- [ ] [device-state] USB debugging 승인 필요, offline, ready 상태를 UI에서 구분한다.
- [ ] [refresh] 사용자가 device 목록을 새로고침할 수 있다.
@ -62,14 +73,18 @@ USB로 연결된 Android device를 표시하고, 선택한 단일 APK를 `adb in
## 범위 제외
- 전체 Android SDK 또는 Android Studio 설치 자동화
- `fastboot`, `sqlite3`, `mke2fs` 등 설치 흐름에 필요 없는 platform-tools 구성요소
- `adb install-multiple`
- AAB를 APK로 변환하는 `bundletool`
- 무선 ADB pairing
## 작업 컨텍스트
- 관련 경로: `lib/src/features/devices/`, `lib/src/models/adb_device.dart`, `lib/src/services/adb_service.dart`
- 관련 경로: `lib/src/features/devices/`, `lib/src/models/adb_device.dart`, `lib/src/services/adb_service.dart`, `macos/Runner/`
- 표준선(선택): 내부 ops 도구이므로 AppSok-managed bundled ADB를 기본값으로 삼고, shell `PATH` 의존은 fallback으로만 둔다.
- 표준선(선택): 화면 코드에서 `Process`를 직접 호출하지 않고 `AdbService`를 통해 실행한다.
- 검증 메모: macOS bundle 안의 nested binary/dylib codesign과 sandbox 상태의 USB/ADB 실행은 remote Mac runner에서 smoke 검증한다.
- 선행 작업: Artifact 탐색과 다운로드
- 후속 작업: ADB 콘솔과 logcat
- 확인 필요: 없음

View file

@ -0,0 +1,147 @@
<!-- task=m-product-baseline/01_shell_nav_status plan=0 tag=SHELL_NAV -->
# Code Review Reference - SHELL_NAV
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> 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, 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.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> 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.
## 개요
date=2026-06-09
task=m-product-baseline/01_shell_nav_status, plan=0, tag=SHELL_NAV
## Roadmap Targets
- Milestone: `agent-roadmap/phase/usable-mvp/milestones/product-baseline.md`
- Task ids:
- `nav-shell`: 좌측 navigation과 상단 Jenkins/ADB 상태 영역을 실제 상태 연결 전에도 안정적으로 표시한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-local-G05.md` -> `code_review_local_G05_N.log`, `PLAN-local-G05.md` -> `plan_local_G05_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-product-baseline/01_shell_nav_status/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [SHELL_NAV-1] Shell navigation/status baseline | [ ] |
## 구현 체크리스트
- [ ] 좌측 navigation destination 4개와 상단 `Jenkins 대기`/`ADB 대기` 상태 pill이 실제 상태 연결 전에도 안정적으로 렌더링되도록 `AppSokShell` 구조를 정리한다. 검증: `flutter test`에서 app shell 렌더링과 navigation 전환이 통과한다.
- [ ] `test/widget_test.dart`에 빌드, 디바이스, 콘솔, 설정 전환 및 top status 표시 assertion을 추가한다.
- [ ] `dart format lib/src/features/app_shell.dart test/widget_test.dart`를 실행한다.
- [ ] `flutter analyze``flutter test`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_local_G05_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_local_G05_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-product-baseline/01_shell_nav_status/``agent-task/archive/YYYY/MM/m-product-baseline/01_shell_nav_status/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-product-baseline/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-local-G05.md``CODE_REVIEW-local-G05.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- shell에서 Jenkins API, Keychain, ADB Process를 직접 호출하지 않았는지 확인한다.
- navigation destination 4개가 모두 전환 테스트로 보호되는지 확인한다.
- `Jenkins 대기`, `ADB 대기` placeholder가 실제 상태 연결 전에도 안정적으로 표시되는지 확인한다.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### SHELL_NAV-1 중간 검증
```bash
$ flutter test
(output)
```
### 최종 검증
```bash
$ dart format lib/src/features/app_shell.dart test/widget_test.dart
(output)
$ flutter analyze
(output)
$ flutter test
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.
## 섹션 소유권
| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these. |
| Roadmap Targets | Fixed at stub creation from plan | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS. |
| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only. |
| 구현 체크리스트 | Implementing agent | Check `[ ]` to `[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. |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan. |
| 검증 결과 | Implementing agent | Fill command output only; command changes require a `계획 대비 변경 사항` entry. |
| 코드리뷰 결과 | Review agent appends | Not included until review. |

View file

@ -0,0 +1,165 @@
<!-- task=m-product-baseline/01_shell_nav_status plan=0 tag=SHELL_NAV -->
# Plan - SHELL_NAV
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 필수 마지막 단계다. 구현 후 검증을 실행하고 실제 변경 내용, 검증 출력, 계획 대비 변경 사항을 기록한 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 차단, 사용자 소유 외부 환경, 범위 충돌이 생기면 리뷰 stub의 `사용자 리뷰 요청` 섹션에 근거를 남기고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 닫을 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
현재 Milestone의 첫 Epic은 macOS 업무 앱으로서 기본 shell이 안정적으로 동작하는지 고정하는 작업이다. 기존 shell은 좌측 rail과 상단 Jenkins/ADB pill을 갖고 있지만 navigation 전환 검증은 일부 화면에만 걸려 있다. 실제 Jenkins/ADB 상태 연결 전에도 사용자가 진입 지점을 놓치지 않도록 shell 상태 영역과 전환 테스트를 먼저 고정한다.
## 사용자 리뷰 요청 흐름
구현 중 차단은 active `CODE_REVIEW-local-G05.md``사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 prompt는 금지이며, code-review가 요청의 정당성을 판단하고 필요한 경우에만 `USER_REVIEW.md`를 작성한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/usable-mvp/milestones/product-baseline.md`
- Task ids:
- `nav-shell`: 좌측 navigation과 상단 Jenkins/ADB 상태 영역을 실제 상태 연결 전에도 안정적으로 표시한다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-roadmap/current.md`
- `agent-roadmap/phase/usable-mvp/PHASE.md`
- `agent-roadmap/phase/usable-mvp/milestones/product-baseline.md`
- `agent-ops/rules/project/domain/app-shell/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/app-shell-smoke.md`
- `analysis_options.yaml`
- `pubspec.yaml`
- `lib/main.dart`
- `lib/src/app.dart`
- `lib/src/features/app_shell.dart`
- `lib/src/features/builds/builds_page.dart`
- `lib/src/features/devices/devices_page.dart`
- `lib/src/features/console/console_page.dart`
- `lib/src/features/settings/settings_page.dart`
- `lib/src/theme/app_theme.dart`
- `test/widget_test.dart`
### 테스트 환경 규칙
- `test_env=local`.
- `agent-test/local/rules.md`를 읽었다.
- 매칭 profile은 `agent-test/local/app-shell-smoke.md`.
- 필수 검증은 remote Mac runner checkout에서 `flutter analyze``flutter test`.
- 현재 checkout preflight로도 같은 명령을 사용할 수 있지만, 최종 완료 evidence는 remote runner 기준이다.
- `<확인 필요>` 값은 없다.
### 테스트 커버리지 공백
- navigation initial render: 기존 `test/widget_test.dart``AppSok`, `빌드`, `디바이스`, `콘솔`, `설정` 표시를 일부 확인한다.
- navigation 전환: 기존 테스트는 `디바이스` 전환만 확인하고, `콘솔`, `설정`, 다시 `빌드` 전환은 확인하지 않는다.
- top Jenkins/ADB status: 기존 테스트가 `Jenkins 대기`, `ADB 대기` pill 표시를 직접 확인하지 않는다.
### 심볼 참조
- none. 이름 변경이나 제거 계획은 없다.
### 분할 판단
- split decision policy를 먼저 평가했다.
- 공유 task group은 `agent-task/m-product-baseline/`.
- `01_shell_nav_status`: navigation/status 구조와 전환 테스트를 고정한다. 선행 의존 없음.
- `02+01_responsive_ui`: responsive overflow 대응이며 `01_shell_nav_status`의 shell 구조가 먼저 안정화된 뒤 구현해야 한다.
- 이 plan은 `01_shell_nav_status`만 다룬다.
### 범위 결정 근거
- Jenkins API, Keychain, ADB process 호출은 app-shell domain 금지 사항이므로 제외한다.
- `BuildsPage`, `DevicesPage`, `ConsolePage`, `SettingsPage`의 실제 feature 동작 구현은 후속 Milestone 소관이므로 제외한다.
- responsive overflow 대응은 `02+01_responsive_ui` plan으로 분리한다.
### 빌드 등급
- `local-G05`: app-shell 내부와 widget test에 한정되고 검증 명령이 결정적이지만, UI shell 상태와 roadmap completion anchor가 있어 중간 등급으로 둔다.
## 구현 체크리스트
- [ ] 좌측 navigation destination 4개와 상단 `Jenkins 대기`/`ADB 대기` 상태 pill이 실제 상태 연결 전에도 안정적으로 렌더링되도록 `AppSokShell` 구조를 정리한다. 검증: `flutter test`에서 app shell 렌더링과 navigation 전환이 통과한다.
- [ ] `test/widget_test.dart`에 빌드, 디바이스, 콘솔, 설정 전환 및 top status 표시 assertion을 추가한다.
- [ ] `dart format lib/src/features/app_shell.dart test/widget_test.dart`를 실행한다.
- [ ] `flutter analyze``flutter test`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
### [SHELL_NAV-1] Shell navigation/status baseline
#### 문제
- `lib/src/features/app_shell.dart:53`-`76`에서 좌측 rail은 존재하지만, 테스트가 모든 destination 전환을 고정하지 않는다.
- `lib/src/features/app_shell.dart:151`-`162`의 top bar status pill은 `Jenkins 대기`, `ADB 대기`로 hard-coded 되어 있으나 `test/widget_test.dart:19`-`35`에서 표시 여부를 직접 검증하지 않는다.
#### 해결 방법
현재 shell ownership 안에서 route wiring과 표시 안정성만 다룬다. 필요하면 status pill에 안정적인 key/tooltip을 추가하고, navigation label과 title이 destination 변경에 맞춰 유지되도록 정리한다.
Before:
```dart
// lib/src/features/app_shell.dart:151
return SizedBox(
height: 72,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 28),
child: Row(
children: [
Text(title, style: Theme.of(context).textTheme.titleLarge),
const Spacer(),
const _StatusPill(icon: Icons.key_outlined, label: 'Jenkins 대기'),
const SizedBox(width: 8),
const _StatusPill(icon: Icons.usb_outlined, label: 'ADB 대기'),
],
),
),
);
```
#### 수정 파일 및 체크리스트
- [ ] `lib/src/features/app_shell.dart`: shell status 표시가 테스트에서 안정적으로 찾을 수 있는 구조인지 확인하고 필요 시 key/tooltip을 추가한다.
- [ ] `test/widget_test.dart`: 모든 shell destination 전환과 `Jenkins 대기`, `ADB 대기` 표시를 검증한다.
#### 테스트 작성
- 작성한다.
- 경로: `test/widget_test.dart`
- 테스트명 후보: `switches between all shell destinations`, `shows shell status placeholders`
- assertion 목표: 각 navigation label tap 후 해당 page의 대표 텍스트 또는 title이 표시되고 top status pill 2개가 렌더링된다.
#### 중간 검증
```bash
flutter test
```
기대 결과: 모든 widget test가 통과한다.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `lib/src/features/app_shell.dart` | SHELL_NAV-1 |
| `test/widget_test.dart` | SHELL_NAV-1 |
## 최종 검증
```bash
dart format lib/src/features/app_shell.dart test/widget_test.dart
flutter analyze
flutter test
```
Remote Mac runner 최종 evidence:
```bash
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter analyze'
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter test'
```
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,148 @@
<!-- task=m-product-baseline/02+01_responsive_ui plan=0 tag=RESPONSIVE_UI -->
# Code Review Reference - RESPONSIVE_UI
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> 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, 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.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> 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.
## 개요
date=2026-06-09
task=m-product-baseline/02+01_responsive_ui, plan=0, tag=RESPONSIVE_UI
## Roadmap Targets
- Milestone: `agent-roadmap/phase/usable-mvp/milestones/product-baseline.md`
- Task ids:
- `responsive-ui`: 기본 테스트 viewport에서 텍스트/버튼 overflow가 없도록 card, badge, toolbar 크기를 안정화한다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-local-G05.md` -> `code_review_local_G05_N.log`, `PLAN-local-G05.md` -> `plan_local_G05_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-product-baseline/02+01_responsive_ui/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [RESPONSIVE_UI-1] Overflow-safe shell and placeholder screens | [ ] |
## 구현 체크리스트
- [ ] `agent-task/m-product-baseline/01_shell_nav_status/complete.log`가 존재하는지 확인하고 없으면 이 plan 구현을 시작하지 않는다.
- [ ] top bar, toolbar, card, badge, button layout이 기본 테스트 viewport에서 overflow를 내지 않도록 `AppSokShell`과 placeholder page layout을 안정화한다. 검증: `flutter test`가 overflow exception 없이 통과한다.
- [ ] `test/widget_test.dart`에 작은 viewport smoke test를 추가하고 build/device/console/settings 화면을 순회해 overflow exception이 없음을 검증한다.
- [ ] `dart format lib/src/features/app_shell.dart lib/src/features/builds/builds_page.dart lib/src/features/devices/devices_page.dart lib/src/features/console/console_page.dart lib/src/features/settings/settings_page.dart test/widget_test.dart`를 실행한다.
- [ ] `flutter analyze``flutter test`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_local_G05_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_local_G05_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-product-baseline/02+01_responsive_ui/``agent-task/archive/YYYY/MM/m-product-baseline/02+01_responsive_ui/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-product-baseline/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-local-G05.md``CODE_REVIEW-local-G05.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- `01_shell_nav_status` 완료 이후 구현되었는지 확인한다.
- 작은 viewport test가 실제로 build/device/console/settings 화면을 모두 순회하는지 확인한다.
- responsive 조정이 실제 feature 구현 범위로 번지지 않았는지 확인한다.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### RESPONSIVE_UI-1 중간 검증
```bash
$ flutter test
(output)
```
### 최종 검증
```bash
$ dart format lib/src/features/app_shell.dart lib/src/features/builds/builds_page.dart lib/src/features/devices/devices_page.dart lib/src/features/console/console_page.dart lib/src/features/settings/settings_page.dart test/widget_test.dart
(output)
$ flutter analyze
(output)
$ flutter test
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.
## 섹션 소유권
| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these. |
| Roadmap Targets | Fixed at stub creation from plan | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS. |
| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only. |
| 구현 체크리스트 | Implementing agent | Check `[ ]` to `[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. |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan. |
| 검증 결과 | Implementing agent | Fill command output only; command changes require a `계획 대비 변경 사항` entry. |
| 코드리뷰 결과 | Review agent appends | Not included until review. |

View file

@ -0,0 +1,175 @@
<!-- task=m-product-baseline/02+01_responsive_ui plan=0 tag=RESPONSIVE_UI -->
# Plan - RESPONSIVE_UI
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 필수 마지막 단계다. 구현 후 검증을 실행하고 실제 변경 내용, 검증 출력, 계획 대비 변경 사항을 기록한 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 차단, 사용자 소유 외부 환경, 범위 충돌이 생기면 리뷰 stub의 `사용자 리뷰 요청` 섹션에 근거를 남기고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 닫을 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
현재 placeholder 화면들은 desktop 기본 폭에서는 읽기 쉽지만 toolbar와 row가 고정 `Row` 중심이라 좁은 테스트 viewport에서 overflow 가능성이 있다. 첫 Epic의 responsive task는 실제 Jenkins/ADB 연결 전에 텍스트, 버튼, badge, toolbar가 layout을 흔들지 않는 기준선을 만드는 일이다.
## 사용자 리뷰 요청 흐름
구현 중 차단은 active `CODE_REVIEW-local-G05.md``사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 prompt는 금지이며, code-review가 요청의 정당성을 판단하고 필요한 경우에만 `USER_REVIEW.md`를 작성한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/usable-mvp/milestones/product-baseline.md`
- Task ids:
- `responsive-ui`: 기본 테스트 viewport에서 텍스트/버튼 overflow가 없도록 card, badge, toolbar 크기를 안정화한다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-roadmap/current.md`
- `agent-roadmap/phase/usable-mvp/PHASE.md`
- `agent-roadmap/phase/usable-mvp/milestones/product-baseline.md`
- `agent-ops/rules/project/domain/app-shell/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/app-shell-smoke.md`
- `analysis_options.yaml`
- `pubspec.yaml`
- `lib/main.dart`
- `lib/src/app.dart`
- `lib/src/features/app_shell.dart`
- `lib/src/features/builds/builds_page.dart`
- `lib/src/features/devices/devices_page.dart`
- `lib/src/features/console/console_page.dart`
- `lib/src/features/settings/settings_page.dart`
- `lib/src/theme/app_theme.dart`
- `test/widget_test.dart`
### 테스트 환경 규칙
- `test_env=local`.
- `agent-test/local/rules.md`를 읽었다.
- 매칭 profile은 `agent-test/local/app-shell-smoke.md`.
- 필수 검증은 remote Mac runner checkout에서 `flutter analyze``flutter test`.
- 현재 checkout preflight로도 같은 명령을 사용할 수 있지만, 최종 완료 evidence는 remote runner 기준이다.
- `<확인 필요>` 값은 없다.
### 테스트 커버리지 공백
- overflow regression: 기존 `test/widget_test.dart`에는 작은 viewport를 설정하고 shell/toolbar/page를 렌더링하는 테스트가 없다.
- Builds toolbar: `lib/src/features/builds/builds_page.dart:17`-`54`가 고정 `Row`라 좁은 폭에서 입력 2개와 로그인 버튼이 겹칠 수 있다.
- Console toolbar: `lib/src/features/console/console_page.dart:16`-`48`가 fixed `Row`라 필터 입력, segmented control, icon button 조합이 좁은 폭에서 overflow할 수 있다.
- Settings form: `lib/src/features/settings/settings_page.dart:24`-`51`, `74`-`89`가 fixed `Row`라 좁은 폭에서 입력과 버튼이 overflow할 수 있다.
### 심볼 참조
- none. 이름 변경이나 제거 계획은 없다.
### 분할 판단
- split decision policy를 먼저 평가했다.
- 공유 task group은 `agent-task/m-product-baseline/`.
- `01_shell_nav_status`: 선행 shell 구조와 navigation/status 테스트를 고정한다.
- `02+01_responsive_ui`: 이 plan이며, directory 이름 기준으로 predecessor `01_shell_nav_status``complete.log`가 필요하다.
- 현재 확인 시 predecessor `agent-task/m-product-baseline/01_shell_nav_status/complete.log`는 아직 없다. 구현 시작 전 runtime 또는 구현 에이전트는 해당 predecessor completion을 확인해야 한다.
### 범위 결정 근거
- 실제 Jenkins job/token/artifact 동작 구현은 `jenkins-credential`, `artifact-browser` Milestone 소관이므로 제외한다.
- 실제 ADB process/device install/logcat 구현은 `usb-install`, `logcat-console` Milestone 소관이므로 제외한다.
- visual redesign이나 feature completion이 아니라 overflow 없는 placeholder shell 기준선만 다룬다.
### 빌드 등급
- `local-G05`: 여러 placeholder 화면과 widget test를 건드리지만 app-shell UI 안정화로 범위가 제한되고 검증이 `flutter analyze/test`로 결정적이다.
## 구현 체크리스트
- [ ] `agent-task/m-product-baseline/01_shell_nav_status/complete.log`가 존재하는지 확인하고 없으면 이 plan 구현을 시작하지 않는다.
- [ ] top bar, toolbar, card, badge, button layout이 기본 테스트 viewport에서 overflow를 내지 않도록 `AppSokShell`과 placeholder page layout을 안정화한다. 검증: `flutter test`가 overflow exception 없이 통과한다.
- [ ] `test/widget_test.dart`에 작은 viewport smoke test를 추가하고 build/device/console/settings 화면을 순회해 overflow exception이 없음을 검증한다.
- [ ] `dart format lib/src/features/app_shell.dart lib/src/features/builds/builds_page.dart lib/src/features/devices/devices_page.dart lib/src/features/console/console_page.dart lib/src/features/settings/settings_page.dart test/widget_test.dart`를 실행한다.
- [ ] `flutter analyze``flutter test`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
### [RESPONSIVE_UI-1] Overflow-safe shell and placeholder screens
#### 문제
- `lib/src/features/app_shell.dart:151`-`162`의 top bar는 fixed `Row`와 status pill 2개를 사용해 좁은 폭에서 title/status가 밀릴 수 있다.
- `lib/src/features/builds/builds_page.dart:17`-`54`의 toolbar는 `TextField` 2개와 `FilledButton`을 fixed `Row`에 둔다.
- `lib/src/features/console/console_page.dart:16`-`48`의 toolbar는 필터 입력, segmented control, icon button 2개를 fixed `Row`에 둔다.
- `lib/src/features/settings/settings_page.dart:24`-`51`, `74`-`89`의 form row는 입력과 버튼이 좁은 폭에서 줄바꿈되지 않는다.
- `test/widget_test.dart:19`-`35`는 overflow를 잡는 viewport test가 없다.
#### 해결 방법
LayoutBuilder, Wrap, ConstrainedBox, Flexible을 사용해 toolbar와 form row가 좁은 폭에서 자연스럽게 줄바꿈되도록 한다. 버튼은 icon+label이 필요한 곳만 유지하고, compact 영역에서는 icon button 또는 fixed min width로 layout shift를 줄인다.
Before:
```dart
// lib/src/features/builds/builds_page.dart:17
Row(
children: [
Expanded(
flex: 3,
child: TextField(
decoration: InputDecoration(
labelText: 'Jenkins job URL',
```
#### 수정 파일 및 체크리스트
- [ ] `lib/src/features/app_shell.dart`: top bar title/status pill 영역을 overflow-safe하게 만든다.
- [ ] `lib/src/features/builds/builds_page.dart`: toolbar와 build row action 버튼이 좁은 폭에서 overflow 없이 배치되도록 조정한다.
- [ ] `lib/src/features/devices/devices_page.dart`: filter/action row와 tile chip/button row가 안정적인 크기를 유지하는지 확인하고 필요 시 보강한다.
- [ ] `lib/src/features/console/console_page.dart`: filter/level/action toolbar가 줄바꿈 또는 compact 배치되도록 조정한다.
- [ ] `lib/src/features/settings/settings_page.dart`: form row를 좁은 폭에서 세로 배치 또는 wrap으로 전환한다.
- [ ] `test/widget_test.dart`: 작은 viewport smoke test를 추가한다.
#### 테스트 작성
- 작성한다.
- 경로: `test/widget_test.dart`
- 테스트명 후보: `renders shell pages without overflow at compact viewport`
- assertion 목표: `tester.view.physicalSize``devicePixelRatio`를 설정한 뒤 빌드, 디바이스, 콘솔, 설정 화면을 순회하고 `tester.takeException()`이 null임을 확인한다.
#### 중간 검증
```bash
flutter test
```
기대 결과: compact viewport smoke를 포함한 모든 widget test가 통과한다.
## 의존 관계 및 구현 순서
- 이 plan은 directory 이름 `02+01_responsive_ui` 기준으로 `01_shell_nav_status`에 의존한다.
- 구현 시작 전 `agent-task/m-product-baseline/01_shell_nav_status/complete.log` 또는 archive의 같은 predecessor complete log를 확인한다.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `lib/src/features/app_shell.dart` | RESPONSIVE_UI-1 |
| `lib/src/features/builds/builds_page.dart` | RESPONSIVE_UI-1 |
| `lib/src/features/devices/devices_page.dart` | RESPONSIVE_UI-1 |
| `lib/src/features/console/console_page.dart` | RESPONSIVE_UI-1 |
| `lib/src/features/settings/settings_page.dart` | RESPONSIVE_UI-1 |
| `test/widget_test.dart` | RESPONSIVE_UI-1 |
## 최종 검증
```bash
dart format lib/src/features/app_shell.dart lib/src/features/builds/builds_page.dart lib/src/features/devices/devices_page.dart lib/src/features/console/console_page.dart lib/src/features/settings/settings_page.dart test/widget_test.dart
flutter analyze
flutter test
```
Remote Mac runner 최종 evidence:
```bash
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter analyze'
zsh -lc 'cd "$HOME/docker/services/code-server/data/volume/workspace/appsok" && flutter test'
```
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -29,6 +29,7 @@ class AppTheme {
useMaterial3: true,
colorScheme: colorScheme,
scaffoldBackgroundColor: colorScheme.surface,
splashFactory: InkRipple.splashFactory,
fontFamily: 'Apple SD Gothic Neo',
textTheme: const TextTheme(
headlineSmall: TextStyle(fontWeight: FontWeight.w800),

View file

@ -1,8 +1,21 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:appsok/src/app.dart';
import 'package:appsok/src/theme/app_theme.dart';
void main() {
test('keeps the AppSok work app theme baseline', () {
final theme = AppTheme.light();
final colorScheme = theme.colorScheme;
expect(theme.useMaterial3, isTrue);
expect(colorScheme.primary, const Color(0xFF0B6E69));
expect(colorScheme.secondary, const Color(0xFFD66B3D));
expect(colorScheme.tertiary, const Color(0xFF6655A8));
expect(theme.scaffoldBackgroundColor, const Color(0xFFFAFBF7));
});
testWidgets('renders the app shell', (WidgetTester tester) async {
await tester.pumpWidget(const AppSokApp());