# 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` §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`/`targetSdk` 36, `minSdk` 26 | Play requires API 36 for new apps and updates from **2026-08-31** | ## 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 |