6.6 KiB
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.mdbeside 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, 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 and the boundary guard in
../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 — 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 |