Skip to content

Commit 5193cb9

Browse files
committed
docs: add comprehensive README with build, test, and run instructions
Covers prerequisites, Android/iOS build steps, simulator launch, test commands, tech stack overview, project structure, phase roadmap, API client regeneration, and contributing guidelines.
1 parent e2690e1 commit 5193cb9

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed

README.md

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# MyFAQ.app
2+
3+
Native iOS and Android client for [phpMyFAQ](https://www.phpmyfaq.de),
4+
built with Kotlin Multiplatform, SwiftUI, and Jetpack Compose.
5+
6+
**Status: Phase 0 (foundations)**. The apps display a placeholder
7+
screen that proves the shared module, API client, encrypted database,
8+
and secure storage are wired end-to-end. No user-visible features yet
9+
-- those land in Phase 1.
10+
11+
- Website: [myfaq.app](https://myfaq.app)
12+
- phpMyFAQ minimum version: **4.2.0**
13+
- Business model: freemium (read + offline free forever; writes behind
14+
Pro unlock in Phase 3)
15+
16+
---
17+
18+
## Prerequisites
19+
20+
| Tool | Minimum | Install |
21+
|-------------------|-----------|----------------------------------------------|
22+
| JDK | 17+ | `brew install openjdk` or [Temurin](https://adoptium.net) |
23+
| Android SDK | API 35 | [Android Studio](https://developer.android.com/studio) or `sdkmanager` |
24+
| Xcode | 15.0 | Mac App Store (macOS only) |
25+
| XcodeGen | latest | `brew install xcodegen` |
26+
| Git | 2.x | pre-installed on macOS |
27+
28+
Run the bootstrap checker:
29+
30+
```bash
31+
mobile/scripts/bootstrap.sh
32+
```
33+
34+
### Android SDK quick setup (without Android Studio)
35+
36+
```bash
37+
brew install --cask android-commandlinetools
38+
sdkmanager "platforms;android-35" "build-tools;35.0.0"
39+
echo "sdk.dir=$HOME/Library/Android/sdk" > mobile/local.properties
40+
```
41+
42+
### Xcode first-launch setup
43+
44+
If you see `xcodebuild` errors about `IDESimulatorFoundation`:
45+
46+
```bash
47+
sudo xcodebuild -runFirstLaunch
48+
sudo xcodebuild -license accept
49+
```
50+
51+
---
52+
53+
## Repository layout
54+
55+
```
56+
phpMyFAQ/MyFAQ
57+
├── plans/ Planning docs (source of truth)
58+
│ ├── mobile-app-plan.md Architecture & feature plan
59+
│ └── phase-0-foundations.md Phase 0 detailed execution plan
60+
├── docs/mobile/ Technical docs
61+
│ ├── architecture.md Module diagram & boundaries
62+
│ ├── build.md Build reference
63+
│ └── phase-0-handoff.md Pinned versions & decisions
64+
├── .github/workflows/ CI/CD
65+
│ ├── mobile-ci.yml Lint + test + debug builds
66+
│ ├── mobile-openapi-sync.yml API client regeneration
67+
│ └── mobile-release.yml Signed release (Phase 1)
68+
└── mobile/ Source tree (Gradle root)
69+
├── shared/ Kotlin Multiplatform module
70+
│ ├── src/commonMain/ Business logic, API, DB, DI
71+
│ ├── src/androidMain/ Android platform actuals
72+
│ ├── src/iosMain/ iOS platform actuals
73+
│ └── src/commonTest/ Shared tests
74+
├── androidApp/ Jetpack Compose host
75+
├── iosApp/ SwiftUI host (XcodeGen)
76+
├── spec/openapi/ Pinned phpMyFAQ API spec
77+
└── scripts/ Dev tooling
78+
```
79+
80+
---
81+
82+
## Building & running
83+
84+
### Android
85+
86+
```bash
87+
cd mobile
88+
./gradlew :androidApp:assembleDebug
89+
```
90+
91+
The debug APK lands at
92+
`mobile/androidApp/build/outputs/apk/debug/androidApp-debug.apk`.
93+
94+
Install on a connected device or emulator:
95+
96+
```bash
97+
adb install androidApp/build/outputs/apk/debug/androidApp-debug.apk
98+
```
99+
100+
Or open `mobile/` as a project in Android Studio and run from the IDE.
101+
102+
### iOS
103+
104+
```bash
105+
# 1. Build the shared KMP framework
106+
cd mobile
107+
./gradlew :shared:assembleSharedDebugXCFramework
108+
109+
# 2. Generate the Xcode project (one-time, re-run after project.yml changes)
110+
cd iosApp
111+
xcodegen generate
112+
113+
# 3a. Open in Xcode and run (Cmd+R)
114+
open iosApp.xcodeproj
115+
116+
# 3b. Or build from CLI
117+
xcodebuild \
118+
-project iosApp.xcodeproj \
119+
-scheme iosApp \
120+
-configuration Debug \
121+
-destination 'platform=iOS Simulator,name=iPhone 16' \
122+
CODE_SIGNING_ALLOWED=NO \
123+
build
124+
```
125+
126+
To run on a simulator from CLI after building:
127+
128+
```bash
129+
xcrun simctl boot "iPhone 16" 2>/dev/null
130+
xcrun simctl install booted \
131+
build/Build/Products/Debug-iphonesimulator/iosApp.app
132+
xcrun simctl launch booted app.myfaq.ios
133+
```
134+
135+
> **Note:** After changing shared Kotlin code, rebuild the
136+
> XCFramework (step 1) before rebuilding in Xcode. The pre-build
137+
> script in `project.yml` does this automatically but adds build
138+
> time. For faster iteration, disable it in Xcode's Build Phases
139+
> and run the Gradle task manually.
140+
141+
---
142+
143+
## Running tests
144+
145+
```bash
146+
cd mobile
147+
148+
# Shared module tests (JVM — fast, no device/simulator needed)
149+
./gradlew :shared:testDebugUnitTest
150+
151+
# Shared module iOS tests (requires macOS + Xcode)
152+
./gradlew :shared:iosSimulatorArm64Test
153+
154+
# All shared tests
155+
./gradlew :shared:allTests
156+
```
157+
158+
### What the tests cover (Phase 0)
159+
160+
| Test file | What it validates |
161+
|-----------|-------------------|
162+
| `MyFaqApiTest` | `/meta` deserialization, unknown-key tolerance, MetaLoader rendering |
163+
| `EntitlementsTest` | `Entitlements.isPro()` always returns `false` |
164+
| `SecureStoreContract` | Round-trip put/get/remove/clear (abstract; run by platform tests) |
165+
166+
---
167+
168+
## Tech stack
169+
170+
| Layer | Technology |
171+
|-------|-----------|
172+
| Shared logic | Kotlin Multiplatform |
173+
| Android UI | Jetpack Compose, Material 3 |
174+
| iOS UI | SwiftUI |
175+
| HTTP | Ktor (MockEngine in Phase 0; OkHttp/Darwin in Phase 1) |
176+
| Serialization | kotlinx.serialization |
177+
| Database | SQLDelight + SQLCipher (Android) / Data Protection (iOS) |
178+
| Secure storage | EncryptedSharedPreferences (Android) / Keychain (iOS) |
179+
| DI | Koin |
180+
| API codegen | openapi-generator (Kotlin multiplatform target) |
181+
182+
### Pinned versions
183+
184+
See [`mobile/gradle/libs.versions.toml`](mobile/gradle/libs.versions.toml)
185+
for the single source of truth. Key versions:
186+
187+
- Kotlin **2.1.20**, Gradle **9.4.1**, AGP **8.10.0**
188+
- Ktor **3.0.3**, SQLDelight **2.0.2**, Koin **4.0.0**
189+
- Android min SDK **26**, iOS **16.0**
190+
191+
---
192+
193+
## Regenerating the API client
194+
195+
The Kotlin API client is generated from the pinned phpMyFAQ OpenAPI
196+
spec at `mobile/spec/openapi/v3.2.yaml`. To update:
197+
198+
```bash
199+
# Download the spec from a phpMyFAQ release
200+
curl -fsSL \
201+
https://raw.githubusercontent.com/thorsten/phpMyFAQ/4.2.0/docs/openapi.yaml \
202+
-o mobile/spec/openapi/v3.2.yaml
203+
204+
# Regenerate (requires openapi-generator-cli or Docker)
205+
mobile/scripts/generate-api-client.sh
206+
```
207+
208+
Or trigger the `mobile-openapi-sync` GitHub Actions workflow.
209+
210+
---
211+
212+
## Project structure (shared module)
213+
214+
```
215+
shared/src/commonMain/kotlin/app/myfaq/shared/
216+
├── api/
217+
│ ├── MyFaqApi.kt Interface + impl (Phase 0: /meta only)
218+
│ ├── MetaLoader.kt Callback facade for platform UI
219+
│ ├── HttpClientFactory.kt MockEngine wiring (Phase 0)
220+
│ └── dto/Meta.kt /meta response DTO
221+
├── data/
222+
│ └── DatabaseFactory.kt Encrypted DB creation + passphrase mgmt
223+
├── di/
224+
│ └── SharedModule.kt Koin modules + initKoin()
225+
├── domain/
226+
│ └── Instance.kt Instance + AuthMode domain models
227+
├── entitlements/
228+
│ └── Entitlements.kt Pro gate facade + expect object
229+
└── platform/
230+
├── SecureStore.kt expect class (put/get/remove/clear)
231+
└── DatabaseDriverFactory.kt expect class (create with passphrase)
232+
```
233+
234+
---
235+
236+
## Phase roadmap
237+
238+
| Phase | What ships | Status |
239+
|-------|-----------|--------|
240+
| **0** | KMP scaffold, CI, encrypted DB, secure storage, Entitlements stub | **current** |
241+
| **1** | Workspaces, categories, FAQ list/detail, server search, paywall shell | planned |
242+
| **2** | Offline: SQLite + FTS5, background sync, attachments (public v1.0.0) | planned |
243+
| **3** | Pro: StoreKit 2 + Play Billing, login/OAuth2, ask/comment/rate (v2.0.0) | planned |
244+
| **4** | Accessibility, localization, telemetry scrub | planned |
245+
| **5** | Widgets, watch app, iPad split-view, push notifications | planned |
246+
247+
See [`plans/mobile-app-plan.md`](plans/mobile-app-plan.md) for the
248+
full architecture plan and
249+
[`plans/phase-0-foundations.md`](plans/phase-0-foundations.md) for
250+
Phase 0 details.
251+
252+
---
253+
254+
## Contributing
255+
256+
1. Check out the repo and run `mobile/scripts/bootstrap.sh`
257+
2. Make changes under `mobile/`
258+
3. Run `cd mobile && ./gradlew :shared:allTests` before pushing
259+
4. CI runs on every push to `main` and on PRs (path-filtered to
260+
`mobile/**`)
261+
262+
### Code style
263+
264+
- Kotlin: enforced by ktlint + detekt (run via `./gradlew ktlintCheck detekt`)
265+
- Swift: swiftlint (configured in CI)
266+
- Commit messages: [Conventional Commits](https://www.conventionalcommits.org/)
267+
268+
---
269+
270+
## License
271+
272+
[Mozilla Public License 2.0](LICENSE)

0 commit comments

Comments
 (0)