docs(ios): 同步 0.2.x 实况文档与规划记录
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
# iOS Native IPA Foundation Implementation Plan
|
||||
|
||||
> **状态:Task 1 - Task 6 已全部完成(2026-09-14,0.2.1 build 6)。**
|
||||
>
|
||||
> 执行时有两处偏离本计划的规定,现行事实以 [docs/ios-native.md](../../ios-native.md) 为准:
|
||||
>
|
||||
> - **持久化不用 GRDB/SQLite**。计划里的 `instances`、`instance_tags`、`device_groups`、
|
||||
> `connection_logs` 等表改为四个沙盒 JSON 文件:`instances.json`、`instance-groups.json`、
|
||||
> `credentials.json`、`log-center.json`,仓储与修订冲突语义保持不变。
|
||||
> - **实例密码不进 Keychain**。TrollStore 环境下 Keychain 读写不稳定,改用应用沙盒内的
|
||||
> `credentials.json`,配合只存在于进程内存的会话 Cookie。
|
||||
>
|
||||
> 计划末尾提到的后续五份计划(消息、通知、操作与审计、日志与维护、设备模块、备份兼容)不再单独
|
||||
> 编写:消息与日志已随 0.2.x 落地,通知、操作审计、维护与备份按产品决策移除或暂缓。
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Build the native iOS foundation that can compile into an unsigned `MultiSimAdmin.ipa`, persist instances locally, connect safely to SimAdmin upstreams, and render the first fleet workbench.
|
||||
@@ -39,7 +52,7 @@ This is the first of six executable plans. Later plans cover messages, notificat
|
||||
- Produces: SwiftUI entry `MultiSimAdminApp`.
|
||||
- Produces: `scripts/build-ios-ipa.sh`, used by every later UI task.
|
||||
|
||||
- [ ] **Step 1: Write the metadata test**
|
||||
- [x] **Step 1: Write the metadata test**
|
||||
|
||||
Create `apps/ios/Tests/MultiSimAdminTests/AppMetadataTests.swift`:
|
||||
|
||||
@@ -58,7 +71,7 @@ final class AppMetadataTests: XCTestCase {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the test and verify it fails**
|
||||
- [x] **Step 2: Run the test and verify it fails**
|
||||
|
||||
Run from repo root:
|
||||
|
||||
@@ -68,7 +81,7 @@ cd apps/ios && swift test --filter AppMetadataTests
|
||||
|
||||
Expected: failure because `MultiSimAdmin` and `AppMetadata` do not yet exist.
|
||||
|
||||
- [ ] **Step 3: Create the package and minimal app**
|
||||
- [x] **Step 3: Create the package and minimal app**
|
||||
|
||||
Create `apps/ios/Package.swift`:
|
||||
|
||||
@@ -166,7 +179,7 @@ Create `apps/ios/Sources/MultiSimAdmin/Resources/Info.plist`:
|
||||
</plist>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run the test and verify it passes**
|
||||
- [x] **Step 4: Run the test and verify it passes**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter AppMetadataTests
|
||||
@@ -174,7 +187,7 @@ cd apps/ios && swift test --filter AppMetadataTests
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 5: Create the IPA builder**
|
||||
- [x] **Step 5: Create the IPA builder**
|
||||
|
||||
Create `scripts/build-ios-ipa.sh`:
|
||||
|
||||
@@ -217,7 +230,7 @@ git add apps/ios scripts/build-ios-ipa.sh
|
||||
git commit -m "feat(ios): add native app foundation"
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Verify clean IPA build**
|
||||
- [x] **Step 6: Verify clean IPA build**
|
||||
|
||||
```bash
|
||||
scripts/build-ios-ipa.sh
|
||||
@@ -242,7 +255,7 @@ Expected: ARM64 Mach-O executable, valid ZIP, and printed SHA-256.
|
||||
- Produces: `AITheme` with named colors and control dimensions.
|
||||
- Produces: `AIButtonStyle(kind:size:)`, `AICard`, `AITag`, and `AIBrandBar`.
|
||||
|
||||
- [ ] **Step 1: Write the token test**
|
||||
- [x] **Step 1: Write the token test**
|
||||
|
||||
```swift
|
||||
import SwiftUI
|
||||
@@ -270,7 +283,7 @@ final class AIThemeTests: XCTestCase {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the test and verify it fails**
|
||||
- [x] **Step 2: Run the test and verify it fails**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter AIThemeTests
|
||||
@@ -278,7 +291,7 @@ cd apps/ios && swift test --filter AIThemeTests
|
||||
|
||||
Expected: FAIL because `AITheme` is undefined.
|
||||
|
||||
- [ ] **Step 3: Implement theme, buttons, cards, and brand bar**
|
||||
- [x] **Step 3: Implement theme, buttons, cards, and brand bar**
|
||||
|
||||
Create `apps/ios/Sources/MultiSimAdmin/Theme/AITheme.swift`:
|
||||
|
||||
@@ -410,7 +423,7 @@ struct MultiSimAdminApp: App {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests and IPA build**
|
||||
- [x] **Step 4: Run tests and IPA build**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test
|
||||
@@ -419,7 +432,7 @@ cd ../.. && scripts/build-ios-ipa.sh
|
||||
|
||||
Expected: all tests PASS and the IPA is regenerated.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
- [x] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add apps/ios
|
||||
@@ -440,7 +453,7 @@ git commit -m "feat(ios): add shared design system"
|
||||
- Consumes: GRDB `DatabaseQueue`.
|
||||
- Produces: `Instance`, `InstanceInput`, `InstancePatch`, `InstanceQuery`, `InstanceRepository`.
|
||||
|
||||
- [ ] **Step 1: Write repository tests**
|
||||
- [x] **Step 1: Write repository tests**
|
||||
|
||||
Create `apps/ios/Tests/MultiSimAdminTests/InstanceRepositoryTests.swift`:
|
||||
|
||||
@@ -513,7 +526,7 @@ final class InstanceRepositoryTests: XCTestCase {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests and verify failure**
|
||||
- [x] **Step 2: Run tests and verify failure**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter InstanceRepositoryTests
|
||||
@@ -521,7 +534,7 @@ cd apps/ios && swift test --filter InstanceRepositoryTests
|
||||
|
||||
Expected: FAIL because the persistence types are undefined.
|
||||
|
||||
- [ ] **Step 3: Define models and migration**
|
||||
- [x] **Step 3: Define models and migration**
|
||||
|
||||
Create `apps/ios/Sources/MultiSimAdmin/Models/InstanceModels.swift`:
|
||||
|
||||
@@ -857,7 +870,7 @@ private struct InstanceRow: Codable, FetchableRecord, MutablePersistableRecord {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run repository tests**
|
||||
- [x] **Step 4: Run repository tests**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter InstanceRepositoryTests
|
||||
@@ -865,7 +878,7 @@ cd apps/ios && swift test --filter InstanceRepositoryTests
|
||||
|
||||
Expected: PASS. If GRDB column mapping fails, fix only the mapping code, not the public interface.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
- [x] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add apps/ios
|
||||
@@ -885,7 +898,7 @@ git commit -m "feat(ios): add instance persistence"
|
||||
- Produces: `UpstreamRoute`, `UpstreamResponse`, `UpstreamError`, `SimAdminClient`.
|
||||
- Produces: `func send(_ route: UpstreamRoute, baseURL: URL, cookie: String?) async throws -> UpstreamResponse`.
|
||||
|
||||
- [ ] **Step 1: Write route and client tests**
|
||||
- [x] **Step 1: Write route and client tests**
|
||||
|
||||
```swift
|
||||
import XCTest
|
||||
@@ -916,7 +929,7 @@ final class UpstreamClientTests: XCTestCase {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the tests and verify failure**
|
||||
- [x] **Step 2: Run the tests and verify failure**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter UpstreamClientTests
|
||||
@@ -924,7 +937,7 @@ cd apps/ios && swift test --filter UpstreamClientTests
|
||||
|
||||
Expected: FAIL because upstream types are undefined.
|
||||
|
||||
- [ ] **Step 3: Implement routes and client**
|
||||
- [x] **Step 3: Implement routes and client**
|
||||
|
||||
Create `apps/ios/Sources/MultiSimAdmin/Upstream/UpstreamRoute.swift`:
|
||||
|
||||
@@ -1062,7 +1075,7 @@ public struct SimAdminClient: Sendable {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests and commit**
|
||||
- [x] **Step 4: Run tests and commit**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test
|
||||
@@ -1086,7 +1099,7 @@ Expected: all tests PASS.
|
||||
- Consumes: `SimAdminClient`, `InstanceRepository`.
|
||||
- Produces: `actor InstanceSessionStore`; protocol `CredentialStore`; `ConnectionProbe.test(_ instance:)`.
|
||||
|
||||
- [ ] **Step 1: Write connection probe test**
|
||||
- [x] **Step 1: Write connection probe test**
|
||||
|
||||
```swift
|
||||
import Foundation
|
||||
@@ -1126,7 +1139,7 @@ final class ConnectionProbeTests: XCTestCase {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the test and verify failure**
|
||||
- [x] **Step 2: Run the test and verify failure**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter ConnectionProbeTests
|
||||
@@ -1134,7 +1147,7 @@ cd apps/ios && swift test --filter ConnectionProbeTests
|
||||
|
||||
Expected: FAIL because the probe and client protocol are undefined.
|
||||
|
||||
- [ ] **Step 3: Implement session, credentials, probe, and client protocol**
|
||||
- [x] **Step 3: Implement session, credentials, probe, and client protocol**
|
||||
|
||||
Create `apps/ios/Sources/MultiSimAdmin/Upstream/InstanceSessionStore.swift`:
|
||||
|
||||
@@ -1271,7 +1284,7 @@ public struct ConnectionProbe: Sendable {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests and commit**
|
||||
- [x] **Step 4: Run tests and commit**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test
|
||||
@@ -1296,7 +1309,7 @@ Expected: all tests PASS.
|
||||
- Consumes: `InstanceRepository`, `ConnectionProbe`, `CredentialStore`.
|
||||
- Produces: `@MainActor final class FleetViewModel` with `refresh()`, `add(_:)`, `update(_:)`, and `delete(_ ids: [UUID])`.
|
||||
|
||||
- [ ] **Step 1: Write fleet view model test**
|
||||
- [x] **Step 1: Write fleet view model test**
|
||||
|
||||
```swift
|
||||
import XCTest
|
||||
@@ -1325,7 +1338,7 @@ final class FleetViewModelTests: XCTestCase {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the test and verify failure**
|
||||
- [x] **Step 2: Run the test and verify failure**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test --filter FleetViewModelTests
|
||||
@@ -1333,7 +1346,7 @@ cd apps/ios && swift test --filter FleetViewModelTests
|
||||
|
||||
Expected: FAIL because the fleet model and test doubles are undefined.
|
||||
|
||||
- [ ] **Step 3: Implement view model and SwiftUI screens**
|
||||
- [x] **Step 3: Implement view model and SwiftUI screens**
|
||||
|
||||
Create `apps/ios/Sources/MultiSimAdmin/Features/Fleet/FleetViewModel.swift`:
|
||||
|
||||
@@ -1425,7 +1438,7 @@ Create `apps/ios/Sources/MultiSimAdmin/Features/Fleet/FleetView.swift` with a `N
|
||||
|
||||
Create `apps/ios/Sources/MultiSimAdmin/Features/Fleet/InstanceFormView.swift` with validated fields for name, origin, tags, group, and optional password. The Save button uses `AIButtonStyle(kind: .primary)` and calls `model.add(_:)`.
|
||||
|
||||
- [ ] **Step 4: Add in-memory test doubles**
|
||||
- [x] **Step 4: Add in-memory test doubles**
|
||||
|
||||
Append to `apps/ios/Tests/MultiSimAdminTests/FleetViewModelTests.swift`:
|
||||
|
||||
@@ -1466,7 +1479,7 @@ struct MemoryInstanceRepository: InstanceRepository {
|
||||
|
||||
Then adapt the test to `let repository = MemoryInstanceRepository()`.
|
||||
|
||||
- [ ] **Step 5: Run tests, build IPA, and commit**
|
||||
- [x] **Step 5: Run tests, build IPA, and commit**
|
||||
|
||||
```bash
|
||||
cd apps/ios && swift test
|
||||
@@ -1487,4 +1500,3 @@ Expected: all tests PASS and the IPA contains the fleet UI.
|
||||
4. **Logs and maintenance plan**: runtime/connection logs, diagnostics, retention, cleanup, optimize, manual backups.
|
||||
5. **Device modules plan**: overview, cellular, SIM, calls, eSIM, WiFi Calling, device network, OTA, configuration, and per-instance panels.
|
||||
6. **Organization and compatibility plan**: groups, tags, identities, discovery, database import, component backup compatibility, and release audit.
|
||||
|
||||
|
||||
@@ -2,6 +2,25 @@
|
||||
|
||||
日期:2026-09-08
|
||||
|
||||
> **实现修订(2026-09-14,0.2.1 build 6)**
|
||||
>
|
||||
> 本文是改写启动时的设计稿,保留作为历史背景。以下决策在实现过程中被推翻,现行事实以
|
||||
> [docs/ios-native.md](../../ios-native.md) 为准,正文中的旧描述不再单独改写:
|
||||
>
|
||||
> - 底部导航为**节点、消息、设置**三个入口,不是本文的五个 Tab。
|
||||
> - **应用内通知中心整体移除**:通知依赖常驻进程转发,应用关闭后无法工作,因此通道、规则、
|
||||
> 投递队列、手动投递均不实现。
|
||||
> - **日志中心不是独立 Tab**,收纳在「设置 → 本地数据」内。
|
||||
> - **不使用 iOS Keychain**:TrollStore 环境下 Keychain 读写不稳定,实例密码改存应用沙盒
|
||||
> `Documents/credentials.json`,仅内存持有会话 Cookie。
|
||||
> - **不使用 GRDB/SQLite**:本地数据改为四个 JSON 文件(`instances.json`、
|
||||
> `instance-groups.json`、`credentials.json`、`log-center.json`),不引入第三方依赖。
|
||||
> - **操作目录、任务、审计、维护、备份、恢复未实现**:iPhone 前台场景不承载高风险写操作与
|
||||
> 调度型能力,本文对应章节按未落地处理。
|
||||
> - 设备模块落地为 6 个只读分区(设备、SIM、蜂窝网络、系统资源、CPU、连接状态)加短信读写,
|
||||
> 本文列出的通话、eSIM、OTA、WiFi Calling、自动化历史未纳入当前版本。
|
||||
> - 配色从「浅灰画布 + 青绿主按钮」改为深墨蓝与金色的品牌对,浅色用中性冷灰画布,主操作为蓝色。
|
||||
|
||||
## 目标
|
||||
|
||||
把 multi-simadmin 的管理能力改写为独立 iPhone 应用,而不是为现有 Web 服务做一个远程客户端或 WebView 壳。应用面向 iOS 16+ 和 TrollStore 安装环境,构建流程产出未签名 IPA;Apple 证书、开发者账号、TestFlight 和上架签名不在本项目范围内。
|
||||
|
||||
Reference in New Issue
Block a user