Skip to content

feat: iOS 2단계 — Capacitor 네이티브 랩 (햅틱·Bonjour·배포) - #27

Merged
redsunjin merged 7 commits into
mainfrom
feat/ios-capacitor-wrap
Jul 21, 2026
Merged

feat: iOS 2단계 — Capacitor 네이티브 랩 (햅틱·Bonjour·배포)#27
redsunjin merged 7 commits into
mainfrom
feat/ios-capacitor-wrap

Conversation

@redsunjin

Copy link
Copy Markdown
Owner

Summary

iOS 런칭 트랙 2단계 구현입니다. 스펙: docs/superpowers/specs/2026-07-21-ios-capacitor-wrap-design.md (Apple 개발자 계정 보유 확인에 따라 정식 후속 단계로 진행)

Capacitor 스캐폴드 (SPM)

  • ios/ 플랫폼 커밋 (Capacitor 8.4.2, CocoaPods 없이 SPM 통합), appId kr.selim.maestro
  • 네이티브 웹 빌드 모드: CAPACITOR_BUILD=1 → vite base ./ (웹 빌드 /maestro-coding/ 불변)
  • Info.plist: NSAllowsLocalNetworking(LAN ws://), NSLocalNetworkUsageDescription, NSBonjourServices: _maestro._tcp
  • npm 스크립트: ios:build / ios:open / ios:run

네이티브 통합 (0단계 접점 보정)

  • isNativeShell() 게이트: 네이티브 셸(hostname=localhost)에서 주소 미저장 시 설정 화면 무조건 자동 오픈
  • 햅틱 브릿지: mapPatternToNativePlan() 순수함수(≤10ms LIGHT / ≤25ms MEDIUM / HEAVY)로 기존 vibrate 패턴을 Capacitor Haptics impact 시퀀스로 변환 — 웹 경로·토글·시그니처 불변
  • Bonjour: 서버가 _maestro._tcp mDNS 광고(MAESTRO_MDNS=off로 끔, 실패 무해), 패널에 주변 서버 찾기(발견 → 주소 채움)
    • capacitor-zeroconf 4.0.0은 Package.swift 부재로 SPM 빌드에 네이티브 코드 미포함 확인 → Capacitor.isPluginAvailable('ZeroConf') 런타임 게이트로 노출 제어(미탑재 시 수동 입력 폴백, 플러그인 SPM 지원 시 자동 활성)

문서

  • USER_GUIDE: 네이티브 빌드/실행, 서명, TestFlight 절차, 실기기 수동 검증 체크리스트

Test plan

  • npm run qa — 단위/UI 116 tests + 웹 빌드 PASS
  • npm run test:e2e — 3/3 PASS (웹에서 발견 버튼 부재 어서션 추가)
  • npm run test:server — 56 tests PASS (mDNS on/off 기동 무영향 테스트 추가)
  • xcodebuild -destination 'generic/platform=iOS Simulator' build — BUILD SUCCEEDED
  • 실기기 수동 체크리스트 (USER_GUIDE 참조 — 햅틱 체감, 로컬 네트워크 권한, TestFlight)

🤖 Generated with Claude Code

selimDGAX and others added 7 commits July 21, 2026 15:12
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…time gate)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@redsunjin
redsunjin merged commit 9b3b37a into main Jul 21, 2026
2 checks passed
@redsunjin
redsunjin deleted the feat/ios-capacitor-wrap branch July 21, 2026 06:32

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f00ae164db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread USER_GUIDE.md
### 서버 연결

- 저장된 주소가 없으면 실행 직후 서버 주소 설정 화면이 자동으로 열립니다.
- PC에서 서버가 실행 중이면(`npm run server`, mDNS 광고 기본 켜짐 / `MAESTRO_MDNS=off`로 끔) **주변 서버 찾기**로 자동 발견할 수 있습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Configure the server to listen on the LAN

For a fresh/default setup, this instruction cannot connect an iPad: HOST defaults to 127.0.0.1 in maestro-server.js:52-53 and is used by server.listen at maestro-server.js:3187, so the advertised PC address and the documented manual ws://<PC-IP>:8080 address both target a port that only accepts loopback connections. The native setup needs to instruct users to bind to a LAN interface (for example HOST=0.0.0.0) or provide a native-use configuration that does so.

Useful? React with 👍 / 👎.

Comment thread USER_GUIDE.md

- 저장된 주소가 없으면 실행 직후 서버 주소 설정 화면이 자동으로 열립니다.
- PC에서 서버가 실행 중이면(`npm run server`, mDNS 광고 기본 켜짐 / `MAESTRO_MDNS=off`로 끔) **주변 서버 찾기**로 자동 발견할 수 있습니다.
- 참고: 현재 SPM 빌드에는 ZeroConf 네이티브 플러그인이 포함되지 않아 버튼이 보이지 않을 수 있습니다. 이 경우 `ws://<PC-IP>:8080`을 직접 입력하세요.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Allow the Capacitor origin through the server

When the native app connects, its HTTP API requests originate from the Capacitor WebView (normally capacitor://localhost), but the default allowlist in maestro-server.js:55-60 contains only HTTP Vite origins, and maestro-server.js:1288-1291 rejects every other origin with 403. Consequently the WebSocket connection test may succeed while project, history, agent, and work-session REST requests fail; add the native origin to the applicable allowlist/configuration and document it in this connection flow.

Useful? React with 👍 / 👎.

setSaveError('');
setTestState({ status: 'idle', message: '' });
setDiscovery({ status: 'idle', results: [], message: '' });
clearTimeout(discoveryTimerRef.current);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Stop discovery before cancelling its timer

If the user closes the panel during the eight-second scan, this clears the only timer that calls ZeroConf.unwatch, without stopping the active native watch itself. That watcher can therefore continue delivering callbacks after the panel is closed, and repeated open/scan/close cycles accumulate watches and stale state updates; the close/unmount cleanup should invoke unwatch as well as clear the timer.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants