@@ -8,7 +8,7 @@ with multi-instance support and full offline browsing.
88- ** Domain** : < https://myfaq.app > (owned by the phpMyFAQ project)
99- ** Business model** : freemium. All read and offline features are free
1010 forever. Write features (ask a question, post a comment, rate, register)
11- are gated behind a paid Pro unlock introduced in a later release (see
11+ are gated behind a paid Pro unlocked introduced in a later release (see
1212 "Monetization and freemium gating" below).
1313
1414This is a planning document, not a commitment. Phases, milestones, and tech
@@ -21,7 +21,7 @@ choices should be revisited before any implementation work begins.
2121- Native iOS and Android apps, branded MyFAQ.app, that read any phpMyFAQ
2222 4.2+ instance via its public ` v3.2 ` REST API, and (in a later paid
2323 release) write to it.
24- - Multi-instance support: a single install of the app can register and
24+ - Multi-instance support: a single installation of the app can register and
2525 switch between several phpMyFAQ installations, similar to how a mail
2626 app manages multiple accounts.
2727- Full offline browsing of cached categories, FAQs, tags, news, glossary,
@@ -45,7 +45,7 @@ choices should be revisited before any implementation work begins.
4545
4646## Platforms and tech stack
4747
48- MyFAQ.app uses ** Kotlin Multiplatform (KMP) with native UI on each
48+ MyFAQ.app uses ** Kotlin Multiplatform (KMP) with a native UI on each
4949platform** . This decision is final for v1.
5050
5151- ** Shared module (Kotlin Multiplatform)** : networking, models, database,
@@ -56,7 +56,7 @@ platform**. This decision is final for v1.
5656- ** Android UI** : Jetpack Compose.
5757- ** Rationale** : one copy of the API client, cache layer, and sync logic;
5858 native look and feel on both platforms; no JavaScript runtime on
59- device; straightforward path to watchOS and Wear OS later if desired.
59+ a device; straightforward path to watchOS and Wear OS later if desired.
6060
6161### Shared libraries
6262
@@ -157,8 +157,8 @@ updated_at timestamp
157157 ` https://host/api/v3.2 ` and rejects ` http:// ` outside of a dev build.
1581582 . The app calls ` GET /api/v3.2/meta ` for the bootstrap payload
159159 (version, title, language, available languages, enabled features,
160- logo URL, OAuth discovery metadata). On success it shows a
161- confirmation sheet with the detected title and version. On failure
160+ logo URL, OAuth discovery metadata). On success, it shows a
161+ confirmation sheet with the detected title and version. On failure,
162162 it shows a precise diagnostic (DNS, TLS, HTTP status, JSON shape).
163163 The legacy ` GET /version ` + ` /title ` + ` /language ` fan-out is kept
164164 only as a fallback for instances that do not yet expose ` /meta ` .
@@ -173,12 +173,12 @@ updated_at timestamp
173173 version, last sync timestamp, and an online status dot.
174174- Tapping an instance sets it as the active context; all data-bound
175175 screens scope their queries by ` instance_id ` .
176- - Long- press opens rename, re-authenticate, clear cache, and delete.
176+ - Long press opens rename, re-authenticate, clear cache, and delete.
177177- QR-code add: scan a QR that encodes ` {base_url, token?} ` — useful for
178178 enterprise rollouts.
179179- Deep-link handler for the custom scheme ` myfaq://add?url=...&token=... `
180180 and universal links under ` https://myfaq.app/add?url=... ` , so any
181- phpMyFAQ web install can offer an "Open in MyFAQ.app" button on the
181+ phpMyFAQ web installation can offer an "Open in MyFAQ.app" button on the
182182 admin landing page.
183183
184184## Authentication
@@ -201,7 +201,7 @@ existing surface:
201201 supports personalized content and rate-limit exemptions.
2022024 . ** OAuth2** — the existing ` /oauth/authorize ` plus ` /oauth/token `
203203 endpoints with PKCE. This is the preferred mode for multi-user
204- corporate installs .
204+ corporate installations .
205205
206206A biometric gate (Face ID or fingerprint) is required to unlock any
207207instance whose auth mode is not ` NONE ` . The gate unlocks the Keychain or
@@ -233,7 +233,7 @@ pending_writes (id, instance_id, kind, payload_json, created,
233233
234234### Cache policy
235235
236- - Default TTL per resource: categories 24 hours, FAQs 6 hours, news 1
236+ - Default TTL per resource: categories are 24 hours, FAQs 6 hours, news 1
237237 hour, search results 10 minutes, attachments until cache eviction.
238238- Honor HTTP ` ETag ` / ` If-None-Match ` when the server sends them; fall
239239 back to ` Last-Modified ` ; fall back to a client-side ` fetched_at + ttl `
@@ -265,7 +265,7 @@ typical FAQ sizes). This is tracked as a server-side feature request
265265
266266### Sync triggers
267267
268- - App launch, if the last sync is older than 15 minutes.
268+ - App launches if the last sync is older than 15 minutes.
269269- Pull-to-refresh on any list screen.
270270- Instance switch.
271271- Background: every 6 hours on both platforms via WorkManager /
@@ -296,7 +296,7 @@ Only relevant once the Pro write release ships:
296296
297297- All writes go through ` pending_writes ` first and are replayed once the
298298 instance is reachable.
299- - A failed write keeps its original payload, increments ` attempts ` , and
299+ - A failed writing keeps its original payload, increments ` attempts ` , and
300300 shows a persistent banner in the affected screen until resolved or
301301 dismissed.
302302
@@ -338,7 +338,7 @@ The mobile app is a mobile-first adaptation of the existing web UI:
338338
339339### Theming
340340
341- - Match phpMyFAQ's Bootstrap look lightly, but defer to platform norms:
341+ - Match phpMyFAQ's Bootstrap looks light but defers to platform norms:
342342 iOS uses SF Symbols for navigation icons and Android uses Material 3.
343343- Do not ship the phpMyFAQ CSS bundle inside the WebView. Use a tuned
344344 minimal stylesheet that respects system dark mode.
@@ -377,14 +377,14 @@ phpMyFAQ community rather than only read it.
377377- Theming, language override, biometric protection of per-instance
378378 secrets
379379
380- ### What requires a Pro unlock
380+ ### What requires a Pro unlocked
381381
382382- User session login and OAuth2 sign-in
383383- ` POST /api/v3.2/question ` — ask a new question
384- - ` POST /api/v3.2/register ` — create a user on a phpMyFAQ install
384+ - ` POST /api/v3.2/register ` — create a user on a phpMyFAQ installation
385385- FAQ rating submission
386386- Comment posting
387- - The offline write queue (` pending_writes ` ) and the retry banner
387+ - The offline writing queue (` pending_writes ` ) and the retry banner
388388- Any future write endpoint added to the public API
389389
390390### Entitlement storage and enforcement
@@ -417,7 +417,7 @@ plan supports either SKU existing in isolation or both together.
417417
418418- Apple requires that any external purchase path (e.g., buying Pro on
419419 myfaq.app with a credit card) either is not mentioned at all in the
420- iOS build, or goes through StoreKit External Purchase Link Entitlement
420+ iOS build or goes through StoreKit External Purchase Link Entitlement
421421 for eligible regions. Simplest path for v1: in-app purchase only.
422422- Google Play permits alternative billing in some regions, but the v1
423423 build uses Google Play Billing only.
@@ -447,19 +447,19 @@ plan supports either SKU existing in isolation or both together.
447447- ** Signing** : iOS via an App Store Connect API key stored in GitHub
448448 encrypted secrets. Android via the Play Publisher API, with the
449449 upload key rotated through Play App Signing.
450- - ** Distribution** : Apple App Store, Google Play, plus a sideload APK
450+ - ** Distribution** : Apple App Store, Google Play, plus a sideloaded APK
451451 published on GitHub Releases and signed with the project release key
452- (see ` release.md ` section 13). The sideload APK must include the
453- billing library stub but hide Pro upsells — sideload users never see
454- a broken purchase button, they see a "managed by Play" notice.
452+ (see ` release.md ` section 13). The sideloaded APK must include the
453+ billing library stub, but hide Pro upsells — sideload users never see
454+ a broken purchase button; they see a "managed by Play" notice.
455455- ** Crash-free budget** : block a release if crash-free sessions drop
456456 below 99.5% during staged rollout.
457457
458458## Testing strategy
459459
460460- ** Unit tests** (shared module): HTTP mapping, cache invalidation, sync
461461 state machine, and search ranking. Run against a recorded set of JSON
462- fixtures captured from a real phpMyFAQ dev install .
462+ fixtures captured from a real phpMyFAQ dev installation .
463463- ** Contract tests** : replay the committed OpenAPI specification against
464464 the client with schemathesis-style fuzzing to catch drift.
465465- ** End-to-end** : a dockerized phpMyFAQ running in CI (the existing
@@ -509,7 +509,7 @@ Detailed plan: [`phase-0-foundations.md`](phase-0-foundations.md).
509509
510510- Repository and CI skeleton.
511511- KMP module scaffolding, SwiftUI and Compose shells.
512- - Generated API client from the committed OpenAPI spec.
512+ - Generated an API client from the committed OpenAPI spec.
513513- Instance model, Keychain / Keystore wrappers, encrypted database.
514514- ` Entitlements ` facade stub (always returns ` false ` — real
515515 implementation lands in Phase 3).
0 commit comments