113 lines
6.6 KiB
Markdown
113 lines
6.6 KiB
Markdown
# Privacy: Period Tracker — Project Plan
|
|
|
|
```
|
|
Status: Current
|
|
Owner: _null
|
|
Last reviewed: 2026-08-18
|
|
Governs: scope, audience, and what this project deliberately is not
|
|
Review trigger: Any change of scope, audience, or platform; anything added to or
|
|
removed from the "deliberately not" list below
|
|
```
|
|
|
|
> The vision. The **milestones in this repository's issue tracker** hold the
|
|
> sequence of work; this holds what the work is *for*.
|
|
>
|
|
> The full specification — prediction requirements, screen-by-screen UX, copy,
|
|
> data model, monetization, compliance — is
|
|
> [`PRODUCT_PLAN.md`](PRODUCT_PLAN.md) beside this file. This document is the
|
|
> short argument; that one is the detail, and it is not summarised here because
|
|
> two copies of one specification disagree the first time either is edited.
|
|
|
|
## What this is
|
|
|
|
A private Android period tracker whose one job is to predict a user's next
|
|
period well. It learns the individual's cycle from confirmed dates, produces a
|
|
most-likely date with an honest window and a confidence label, estimates
|
|
ovulation and the fertile window from that, and asks discreetly whether the
|
|
period started — using both the *yes* and the *not yet* to improve the next
|
|
forecast. Everything core works offline, without an account.
|
|
|
|
## Who it is for
|
|
|
|
Someone who wants to know when their period is coming and does not want a
|
|
wellness platform. They have probably used a tracker that predicted a generic
|
|
28-day cycle at them for a year, and one that put their fertility data somewhere
|
|
they could not see. The product's two promises answer exactly those two
|
|
experiences: **it learns your cycle**, and **we never sell your data**.
|
|
|
|
Not "everyone who menstruates". A person who wants community, articles,
|
|
pregnancy mode or a symptom encyclopedia is better served elsewhere, and
|
|
building for them is what turns this into the app it exists to not be.
|
|
|
|
## What it is deliberately not
|
|
|
|
Every "not" here is a decision that stops being re-litigated. From
|
|
[`PRODUCT_PLAN.md` §5](PRODUCT_PLAN.md), and it is the most useful list in this
|
|
repository:
|
|
|
|
- not a social network, community or forum
|
|
- not a pregnancy tracker — no pregnancy mode in V1
|
|
- not an AI chatbot
|
|
- not a wellness article feed
|
|
- not a diet or exercise tracker
|
|
- not a horoscope or lunar-phase app
|
|
- not a shop
|
|
- not a partner-account or sex-diary product
|
|
- not a large mood/symptom library
|
|
- not a supplements funnel
|
|
- not a diagnostic tool, and **not contraception** — fertility output is an
|
|
estimate and says so wherever it appears
|
|
- not an app that makes free users worse at the thing it is for
|
|
|
|
Two of those are harder rules than the rest. **Prediction quality is never a
|
|
paid feature**, and **health data never reaches the advertising subsystem** —
|
|
see [`PRODUCT_PLAN.md` §33 and §34](PRODUCT_PLAN.md) and the boundary guard in
|
|
[`../architecture/README.md`](../architecture/README.md).
|
|
|
|
## Stack and platform
|
|
|
|
Verified against the official sources on 2026-08-18, not inherited from the
|
|
specification's own version numbers — which the specification itself asks for.
|
|
|
|
| Concern | Choice | Why |
|
|
| --- | --- | --- |
|
|
| Language | Kotlin 2.4.10 | Android is Kotlin-first; null safety and data classes suit a model built out of dates |
|
|
| UI | Jetpack Compose, Compose BOM 2026.08.00 | Android is Compose-first; XML layouts are the legacy path |
|
|
| Design system | Material 3 (1.4.0) | dynamic colour, dark mode and accessible contrast without hand-rolling any of it |
|
|
| Build | Gradle 9.7.0, AGP 9.3.1, Kotlin DSL | version catalog in `gradle/libs.versions.toml` |
|
|
| Local structured data | Room 2.8.4 | cycle history is structured, must survive updates, and needs migrations that can be tested |
|
|
| Preferences | DataStore 1.2.1 | typed, async, no SharedPreferences main-thread surprises |
|
|
| Background work | WorkManager 2.11.2 | reminders must survive process death; **no exact-alarm permission** — a period reminder does not need alarm-clock precision |
|
|
| DI | Hilt 2.60.1 | wired at the skeleton stage; retrofitting DI across modules later is the expensive order |
|
|
| Prediction engine | pure Kotlin JVM module | testable without an emulator, which is the only way it gets the test coverage §50 asks for |
|
|
| Target | `compileSdk` 37, `targetSdk` 36, `minSdk` 26 | current AndroidX requires compiling against 37; `targetSdk` 36 is Play's floor for new apps and updates from **2026-08-31**, and raising it opts the app into runtime behaviour changes, which is a tested decision rather than a build fix |
|
|
|
|
## Success looks like
|
|
|
|
Observable, from [`PRODUCT_PLAN.md` §60](PRODUCT_PLAN.md) — the primary metrics
|
|
are about the forecast, not about engagement:
|
|
|
|
- mean absolute next-period prediction error, falling as confirmed cycles accrue
|
|
- share of predictions within ±1 and ±2 days
|
|
- measurable accuracy improvement at 3, 6 and 12 confirmed cycles
|
|
- a user with a stable 35-day cycle is never predicted at 28
|
|
|
|
And one qualitative test that decides the rest: **a first-time user enters their
|
|
last period and immediately sees a forecast they believe.**
|
|
|
|
Deliberately not optimised for: time in app, ads viewed, feed engagement. A good
|
|
period tracker helps in seconds and gets out of the way.
|
|
|
|
## Known risks
|
|
|
|
Written now, while it is still cheap to be honest.
|
|
|
|
| Risk | What it would look like | What is done about it |
|
|
| --- | --- | --- |
|
|
| The engine falls back to a global average | a 35-day user predicted at 28 — the specification calls this a core product defect | the acceptance tests in §51 are written before the engine, and run in a module with no Android dependency so they always run |
|
|
| Confidence becomes decoration | "High" shown because there is a lot of data rather than because the data agrees | confidence is derived from variability and historical error, and §15's two worked examples are test cases |
|
|
| Health data leaks into ad requests | a cycle-state string in an ad extra, or an ads SDK initialised with user properties | a module-boundary guard: `ads` may not depend on the cycle database or the prediction domain, and the guard is proved to fail before it is trusted |
|
|
| A notification exposes cycle state on a lock screen | Discreet mode showing the private text publicly | notification privacy modes are a QA pass of their own, tested at every mode |
|
|
| Play health-app policy changes before launch | a submission rejected on Data Safety or a medical-claim reading | policy verified immediately before submission, never from memory; the target API deadline is already in the table above |
|
|
| A keystore or Play service-account JSON gets committed | a signing key in the history, which deleting the file does not undo | `scripts/secrets.sh` runs before every commit; `local.properties`, `*.jks` and `*.keystore` are ignored from the first commit |
|