# 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 |
