LunarLog Privacy Policy

Effective Date: September 7, 2026
Last Updated: October 20, 2026 - Section 4 discloses that Apple Health imports on iOS read flow and spotting records (Sections 4 and 10).

LunarLog (“we”, “our”, or “the app”) is a privacy-first menstrual cycle and symptom tracker built for families: an account syncs a profile across a guardian’s own devices and lets it be shared with other guardians — co-parents, caregivers — each with their own role, so sync and multi-guardian collaboration are the product’s priority, not a bolted-on option. We believe that reproductive and menstrual health data is deeply personal and sensitive. LunarLog is architected from the ground up to protect your privacy: your data is protected at rest by each device’s own operating-system encryption (Section 1), nothing you log is uploaded until you sign in, and the app keeps logging, viewing, and predicting even when you have no network connection.

This Privacy Policy explains what information LunarLog processes, how that information is protected, and the choices and rights you have.


1. Core Principles

  • Built For Sync & Family Collaboration: LunarLog’s account (Supabase Auth) is what lets a profile sync across a guardian’s own devices and be shared with other guardians — co-parents and caregivers each get their own role, invitation, and attribution (Section 5). This is the product’s priority and its differentiator, not an add-on; nothing about it changes what data is collected, only that sharing and multi-device sync are what the app is built to do.
  • Protected at Rest: All data stored on your device relies on your operating system’s own at-rest protection (iOS Data Protection / Android device encryption) and is only shown behind device-level biometric or passcode authentication. The browser client is the deliberate exception in the other direction: it keeps nothing at rest — no data copy is ever written to browser storage, and its only browser-stored credential is an HttpOnly refresh cookie no page script can read (Section 6 states the browser posture exactly). On Android, the local database is excluded from cloud backup and device-to-device transfer by declaration (a database backed up off-device would leave the app’s own protections behind). On iOS, the app marks the database file excluded from backup and applies operating-system file protection so it stays unreadable until first device unlock after a restart (matching the session Keychain class) — verified on device before release.
  • No Advertising or Data Brokers: We do not display advertisements, sell your data, monetize your health information, or share data with data brokers or tracking networks.
  • Resilient Offline: The app keeps working without a network — logging, viewing history, and predictions all run from the copy already on your device, and nothing you do offline is blocked or degraded. This is a reliability property, not a requirement to avoid an account: LunarLog does not require an internet connection to be useful in the moment, but syncing and sharing a profile with other guardians does require signing in.
  • Estimates From Your Own Logged Data: LunarLog estimates the timing of the next period from the cycle history you log, computed entirely on your device; a guardian who can see a profile’s cycle data can see its estimates. LunarLog also estimates a fertile window and an ovulation day the same way — a standard calendar-method back-calculation (next predicted period start minus an assumed luteal-phase length) computed entirely on your device from the same logged cycle history, carrying the same reliability tier as the period estimate it is derived from, and covered by the same guardian-visibility and ownership-transfer rules as all other cycle data (Section 5). It is not based on any additional signal you log (temperature, cervical mucus, or test results) and must not be used to prevent pregnancy — it is not birth control, nor a backup to birth control. An earlier version of this policy guaranteed that no fertility feature would ever exist; that guarantee was removed by owner decision in September 2026, and this fertile-window/ovulation estimate is the first feature built under that removal (see the Change History in Section 10). The conceive mode, a per-day conception-likelihood estimate, shipped later in 2026, along with pregnancy, postpartum, and perimenopause modes; each is computed on your device from the same logged history and follows the same guardian-visibility and ownership-transfer rules as the rest of your cycle data.
  • Minimal, Scrubbed Telemetry: Crash and diagnostic reports are strictly scrubbed on your device before transmission to ensure no health data, personal notes, dates, or user identities ever leave your device.

2. Information We Collect and Process

A. Health & Cycle Information (Local & Optional Cloud Sync)

When you log entries in LunarLog, you may record:

  • Dates and timestamps of menstrual cycles.
  • The IANA time zone (e.g. America/New_York) each entry was logged in — used only to derive which calendar day the entry belongs to. Separately, a guardian who turns on caregiver alerts stores their own IANA time zone in their notification preferences, which is what resolves quiet-hours and digest timing; an entry’s zone is never used for that. Each is a coarse location signal (it identifies one of roughly 400 world regions, not a precise location) and is stored and synced under the same rules as the entry itself.
  • Flow intensity levels (an explicit “not bleeding today” note, light, medium, heavy, super heavy).
  • Personal tags and custom notes.
  • Individual tracked symptoms and options (e.g. a specific pain, mood, or body symptom; spotting; a numeric measurement like temperature; an intensity rating) — stored as their own records tied to the day they were logged, the same way flow and tags are, and covered by the same storage and sync rules described here.
  • Import/device provenance: which entries were logged manually versus imported from a source such as Clue, Apple Health, or Health Connect, and an internal key identifying the specific import run — used to label an entry in the app (e.g. “Imported from Clue”) and to avoid creating duplicate entries when the same import is run again. This label is metadata about how an entry was recorded, not a new category of health content, and is covered by the same storage and sync rules as the entry itself.
  • Profile information (display name, sort order, archive status, minor status flag).
  • Same-date merge disclosures: when two guardians log the same date independently and the app merges the two entries, the value that lost the merge (a note’s text, or a flow level) is kept briefly in a disclosure record so the guardian who wrote it can see what happened and recover their text in the app. That record carries the discarded value itself plus which guardians were involved, is visible only to the profile’s guardians, never appears in any notification, and is permanently deleted 30 days after the merge (see Section 7) — the one category here that is intentionally short-lived. A data export you run while a disclosure is still inside that window includes it (your own discarded writing is yours to take with you); once the window has passed, neither the app nor any later export holds it.
  • Shared change history: when an entry changes, the server keeps a short audit record of THAT a change happened — which guardian made it, when, which fields (e.g. “note”, “flow”), and the kind of change (logged, updated, deleted, or discarded by a same-date merge). It deliberately never records what any field SAID: no note text, no tag, no flow level. It is visible only to the profile’s guardians (the same access the entries themselves already grant), and each record is permanently deleted 90 days after the change (see Section 7). It is bookkeeping about your entries, not a second copy of them.
  • Guardian notes: alongside the shared day note, a guardian can add their own dated note about a specific day — one note per guardian per date, attributed to its author, and never merged with another guardian’s note for the same day (two guardians writing about the same date produce two separate notes, both kept). A guardian can edit or remove only their own note. A guardian note is health content and is stored and synced under the same rules as the shared day note, except that it is author-scoped: it is never combined with, or overwritten into, anyone else’s note. It never appears in a notification payload or in a crash report, and it is removed when the profile is deleted, when the account is deleted, and when the guardian who wrote it is revoked from the profile. Every accepted guardian — including the person the note is about (see Section 5) — can read it, and the app states that audience at the point of writing.

Storage: This information is stored directly on your device in a SQLite database protected by your operating system’s at-rest protection (see Section 1). Signing in and enabling cloud sync is what moves it to your account, where it syncs across your own devices and to any guardian the profile is shared with; before you sign in, none of it leaves the device.

B. Account & Authentication Information (Optional)

An account is what makes cross-device sync and sharing a profile with other guardians possible, and creating one remains your choice — a build with no cloud configuration has no account at all. You can log, view, and get predictions in LunarLog without ever creating an account. If you sign in and enable cross-device sync, we process:

  • Email Address: Used for account verification, passwordless sign-in links, and password recovery.
  • Authentication Credentials: Handled securely via Supabase Auth. We support email/password, passwordless magic links, Sign in with Apple, and Google Sign-In.
  • Provider Identifiers: If you authenticate via Apple or Google, we store a cryptographic subject identifier (sub) provided by the identity provider to link your account. We do not access your contacts, external profile files, or social graphs.

Upload Consent: When you sign in on a device that already holds local data, LunarLog asks for your explicit consent before uploading existing records to your account.

C. Support Ticket Information (Optional)

If you use “Send feedback” (Settings, signed-in accounts only), we process:

  • The message you write, your category selection (bug, feature request, support, other), and the reply email address you provide (pre-filled from your account, editable).
  • Diagnostics you approve: app version, build number, OS name and version, device model, active locale, and up to 25 recent in-app navigation/error breadcrumbs — never health data, account identity, or credentials. The app shows you the exact diagnostics payload and lets you turn it off before you submit.
  • An optional screenshot, attached only after an explicit consent step naming the risk that a screenshot of this app usually contains cycle data for a family member.

None of this leaves your device until you tap submit. A ticket you send is visible to the app’s operator team and to you, in the app’s Support history. Submitting a ticket also sends a short alert email to the operator (the ticket id, category, app version, and submission time — not your message, reply email, or attachment). That alert email lives in the operator’s own inbox under that inbox’s own retention, separate from the database record described above — deleting a ticket or your account (see “Support Ticket Retention” in Section 7) removes the database record, not a copy already delivered by email.

D. Technical & Crash Information (Diagnostics)

To maintain app stability and diagnose crashes, LunarLog includes optional telemetry powered by Sentry.

  • Strict Privacy Floor: Before any error or crash report leaves your device, an automated client-side scrubber (lib/observability/scrub.dart) removes all health information, dates, flow levels, notes, tags, profile names, user IDs, device names, auth tokens, and request payloads. A crash report may additionally carry the names of the screens you visited before the crash (e.g. “Settings”, “Feedback”) — never their contents or arguments; an unrecognized or third-party screen name is reported as “unknown” rather than passed through.
  • Native crash reports bypass this on-device scrubber. An Android app freeze, an Android native (NDK) crash, an iOS app hang, or an iOS watchdog termination is assembled and sent by the operating system’s crash-reporting layer, not by this app’s code — it never passes through the scrubber described above. These reports carry device, thread, and stack state, not app content (no note, tag, date, or profile name is ever held in a form a native crash report can capture), and the same server-side scrubbing and IP suppression covers them.
  • Optional performance measurement: if the operator running the app has separately enabled it, LunarLog can also measure how long the app takes to start and how long some in-app operations take. When enabled, this carries operation timings and HTTP status codes — never a URL’s query string, never a request body, and never anything from the allowlist above. This measurement is off by default in every release build.
  • Crash data is anonymous, not linked to your identity or health records, and used solely for bug fixes and app performance.

E. Home-Screen Widget Data (On-Device Only)

If you add the LunarLog home-screen widget (issue #141), the app writes a small, fixed set of facts into an operating-system shared container (an iOS App Group / an Android widget preferences store) that the widget — and only the widget — can read. This container is deliberately outside the encrypted database described in Section 2.A, so what is allowed to cross it is kept to the absolute minimum and documented in the app’s source: a coarse state word (day or “nothing to show”), the current cycle-day count (e.g. “14”), the days-until-next-period countdown when an estimate is active (a relative count, never a date), whether the quick-log button is offered for you on that profile, an opaque random profile identifier (so the button reaches the right profile; never displayed), and the date the counts are anchored to (so the widget can keep its count current between app uses). The widget never displays your profile’s name, a calendar date, a flow level, or any symptom — its default render is deliberately discreet (a bare count on the app’s brand background), because a widget renders on your home screen where the app’s lock screen and app-switcher protections (the opaque cover and Android’s FLAG_SECURE) cannot reach. A widget’s quick-log button never writes on its own: tapping it opens the app, and the “period started today” entry is applied only after you unlock the app, exactly once, through the same write path as logging inside the app. If the profile’s role would not let you log from inside the app (for example, a viewer on a shared profile), the button is not offered and a tap cannot write. Nothing in the widget container ever leaves your device, is synced, or is included in exports.


3. How We Use Your Information

We use the information we process strictly for the following purposes:

  1. Core App Functionality: Enabling you to log, view, and organize cycle records across profiles.
  2. Cross-Device Synchronization (Optional): Mirroring your cycle records across your authorized devices using row-level-secured cloud storage, protected in transit and at rest exactly as described in Section 6 — TLS in transit, Supabase’s own AES-256 infrastructure encryption at rest, never an app-managed cipher.
  3. App Reliability & Security: Diagnosing technical faults and preventing unauthorized access through biometric locks and automated inactivity relocking.

We do not use your information for targeted advertising, marketing communications, automated profiling, or behavioral tracking.


4. Third-Party Service Providers

LunarLog limits third-party integration to essential operational infrastructure:

Service Purpose Data Received Location / Security
Supabase Cloud authentication and database sync (optional) Account email, cycle entries, authentication tokens TLS 1.3 in transit and AES-256 at rest (Supabase’s own infrastructure-level encryption, not an app-managed or end-to-end cipher — Section 6); Row-Level Security enforced
Sentry Crash reporting and error diagnostics Anonymized stack traces, OS version, device architecture, the names of screens visited before a crash, and (only when separately enabled) operation timings (all health/identity data stripped) Client-side scrubbed for app-originated reports; a native crash report (Android NDK/ANR, iOS app hang/watchdog termination) is assembled by the operating system and is instead covered by server-side scrubbing and IP suppression; retained for a maximum of 90 days for debugging
Apple (Sign in with Apple) Optional identity provider on iOS/macOS and in the web client Apple user identifier, relay email address (if selected) Governed by Apple Privacy Policy
Google (Google Sign-In) Optional identity provider Google ID token (email and basic account identifier) Governed by Google Privacy Policy
Resend Transactional support email (an admin alert when you submit a ticket; the admin’s reply email to you) Reply email address and, for the reply you receive, the reply text Governed by Resend’s Privacy Policy
Firebase Cloud Messaging (FCM) Optional remote push alerts to a caregiver when another guardian logs an entry, or when an expected entry hasn’t arrived (only when a guardian turns this on; a build with no push configuration never contacts FCM at all) Your device’s push registration token and the profile’s internal identifier only. Never a note, tag, flow level, date, or profile name - the notification you see on your lock screen is always the same fixed generic text the app’s own local reminders already use Governed by Google Privacy Policy; delivered over Apple/Google’s push infrastructure (APNs on iOS, FCM on Android)

No other third parties receive data from LunarLog.

Data Residency, Hosting Regions, and Geographic Scope: All LunarLog cloud infrastructure and diagnostic telemetry are hosted within the United States:

  • Supabase Cloud Infrastructure: Primary database storage, account authentication, and cloud synchronization for project dleexnnevuuddcgcpztq are hosted on Amazon Web Services (AWS) in the US East (N. Virginia, us-east-1) region.
  • Sentry Error Telemetry: When crash reporting and error diagnostics are enabled, anonymized diagnostic and crash telemetry is transmitted to and processed within Sentry’s United States multi-tenant region (us.sentry.io). All cloud-synchronized user data is stored, processed, and maintained on infrastructure physically located within the United States, regardless of the user’s country of origin, nationality, or device location. Geographic Distribution Scope: In alignment with our operational posture and export compliance filings (see docs/ops/ios-export-compliance.md), LunarLog’s app distribution on the Apple App Store and Google Play is restricted to the United States and Canada.

HIPAA Non-Applicability Notice: LunarLog is a direct-to-consumer software application developed for personal menstrual cycle tracking, family collaboration, and health self-management. LunarLog is not a “covered entity” and is not a “business associate” of any healthcare provider or health plan under the Health Insurance Portability and Accountability Act of 1996 (HIPAA) or its implementing regulations (45 C.F.R. Parts 160 and 164). Information stored on your device or synchronized through LunarLog’s cloud features is not Protected Health Information (PHI) governed by HIPAA rules. Any clinical data exports generated through the app (such as the JSON “Export my data”, FHIR R4 clinical summary bundles, or CSV tabular exports described in Section 7) are user-directed, user-controlled transfers of personal records directly to individuals, clinicians, or health portals chosen entirely by you. Generating an export or handing it to a healthcare provider does not establish a HIPAA business associate relationship or healthcare-provider relationship between LunarLog and that provider or healthcare organization.

On-device health-platform sync (Apple Health / Health Connect) is not an off-device transfer. With your explicit opt-in (Settings, one bound profile), LunarLog can write the period, flow, intermenstrual-bleeding, tracked symptom categories (such as abdominal cramps, headache, bloating, acne, fatigue, nausea, appetite changes, and sleep changes), mood changes (written to Apple Health on iOS as generic ‘Mood Changes’ symptom entries without preserving specific emotional valence), cervical-mucus, ovulation-test, and basal-body-temperature records you log in the app into your device’s own health store — Apple Health on iOS, Health Connect on Android (symptom and mood writes are currently supported on iOS only) — so other health apps you choose can see the same history. On both iOS and Android, LunarLog can also read menstrual flow and intermenstrual-bleeding records from Apple Health or Health Connect, but only when you explicitly start an import (Settings → Health app sync → Import from Apple Health, or Import from Health Connect on Android) and only for the one profile bound to this device: the menstrual-flow and intermenstrual-bleeding records the store returns for the whole available history — read a page at a time, however far back your data goes, not a fixed recent window — are added to that profile’s day entries and spotting observations on this device and labelled as imported from Apple Health or Health Connect, and a value you logged by hand is never overwritten. Intermenstrual-bleeding records are stored as spotting observations, the same shape the app logs spotting in. Samples this app itself wrote are excluded by source filtering — HealthKit’s recording source, Health Connect’s dataOrigin — so syncing out and importing back does not duplicate entries. A basal-body-temperature reading is written only when you logged it yourself (or imported it from another tracker); a reading marked as coming from a wearable or another health platform is never written back and is never merged with a reading you logged by hand. The fertility writes are write-only: LunarLog does not read cervical-mucus, ovulation-test, or basal-body-temperature records back from either platform. Reading starts with an import you run yourself (Settings → Health app sync), and — since September 29, 2026 (issue #993) — once a profile is bound and you have run the first import yourself, the same import pass can also run in the background without a tap: on iOS, Apple Health’s background delivery (a system notification the app registers for) wakes the app when new menstrual data lands in the health store, and on Android a periodic scheduled job checks Health Connect for changes while the app is running in the background. A background pass is the same read, page by page, into the same one bound profile under the same rules: it never prompts and never shows a screen (a background pass runs only when the OS permission is already granted — a revoked or never-granted permission simply stops it), it never writes anything to the health store, it never overwrites a value you logged by hand, and it logs only counts (how many days were imported, skipped, or kept manual), never any health content. Unbinding the profile stops background imports. Apple Health does not tell apps whether read access was allowed, and Health Connect’s own denied-read signal is treated the same way, so an empty result is treated identically to a denied one and is never described as either. The import reads only user-recorded menstrual flow and intermenstrual bleeding. Separately and on iOS only, when you run that import LunarLog also reads Apple’s four computed cycle-deviation types (irregular cycles, infrequent cycles, prolonged periods, and persistent intermenstrual bleeding) over a bounded six-month window and, if any are present, shows them on the overview as a clearly labelled, dismissible second opinion sitting next to — never merged into — lunarlog’s own estimate, because Apple computes them from whatever was logged in Apple Health and may disagree with lunarlog’s history. These four types are read-only, permanently: LunarLog never writes them back, its write surface has no method that accepts one, and LunarLog never writes a predicted or derived value (a next-period prediction, a fertile-window estimate, an ovulation estimate) into the health store (App Store Review guideline 5.1.3). All of this stays on your device: LunarLog does not transmit health data anywhere as part of this feature, and no third party receives it through it. The App Store Connect privacy details and Google Play Data safety declarations that cover the read capability are updated separately (issue #21); the Health disclosure above covers the optional Supabase cloud sync of these entries, which is a separate, independently disclosed flow.

Clinical export is a user-initiated transfer, not collection. The exports described in Section 7 (“Export my data”, JSON; “Export clinical summary”, FHIR; “Export as CSV”, CSV) are built entirely on your device and handed to your operating system’s own share sheet — you pick the destination (AirDrop, Files, email, another app) and only that destination receives a copy. That is a transfer you initiate and control, not a transmission LunarLog performs to a server of ours or a third party’s, and it is not app-side collection of a new data type for store-declaration purposes.


5. Minors’ Privacy & Family Profiles

LunarLog is intended to be operated by a parent, legal guardian, or adult individual.

  • Minimum-Age Policy (13+ to create an account alone; under 13 only through a parent’s invitation): LunarLog is licensed for and intended to be used by individuals aged 13 and older, or by parents and legal guardians creating and managing profiles for household members. An individual aged 13 or older may create an account and use the app directly. An individual under 13 may not sign up on her own; she may use the app on her own device only when a parent or legal guardian has created her profile and invited her to it through the app’s “her own profile” invitation (Section 5, “Her Own Profile”), and accepting that invitation is the record of the parent’s or guardian’s consent for her to use the app. Primary account management or paid services require individuals to be 18 or older. We do not knowingly collect personal data directly from children under 13 without verifiable parental or guardian authorization and supervision. An explicit acknowledgement of this standard is required during onboarding: an operator who arrived on their own acknowledges the 13-or-older statement, while an operator arriving through a parent’s or guardian’s invitation acknowledges that the parent or guardian created the profile and invited her, not that she is 13 or older. When you are signed in, that acknowledgement is recorded on your account — with how you arrived (your own acknowledgement, or a parent’s or guardian’s invitation), when it was made, the app version that made it, and the policy version you acknowledged — included in “Export my data”, and removed when you delete your account; when the policy version changes, you are asked to acknowledge it again.
  • How Minor Status Is Determined: A profile’s minor status is derived from the profile’s birth year when one is present — a profile is a minor until they are 18, and because birth year is a year only with no day or month, the comparison is deliberately conservative, so a profile born late in the year they turn 18 still counts as a minor through that calendar year — and falls back to the stored “this is a minor” flag for a profile with no birth year. It is set by whoever creates or manages the profile, and it gates the minor-specific protections described in this section — most notably the prediction-only sharing refusal below, and the app’s default-hidden symptom and mood tracking categories.
  • Guardian Roles & Read Visibility: While write capabilities are governed by guardian role (a viewer cannot log or edit entries, and only primary guardians or co-parents can edit profile settings), every accepted guardian on a profile — whatever the role, and including a parent who created the profile — reads everything the subject logs (cycle entries, symptoms, observations, tags, and shared notes), with one deliberate exception: a day note the subject herself marked private, which only she can read. That privacy choice is made when the note is written — a note that has already been saved and shared cannot be made private retroactively — and the server enforces it, not only the app: a private note’s text is never sent to a guardian’s device, and the app shows a “Private note” placeholder in its place rather than the note editor.
  • Two-stage custodian model: A profile starts under the adult who created it, who holds both profiles.user_id (the account that can delete the record) and the profile’s primary-guardian membership. That parent can later transfer ownership of a minor’s profile to the minor’s own account once they are ready to hold it themselves. Transferring moves both facts together to the child’s account in a single operation and stamps the profile with when the move happened; every past entry keeps its original “logged by” attribution unchanged, so the record’s history is never rewritten. The parent chooses, at the moment they initiate the transfer, whether they keep logging as a co-manager or drop to read-only; either way the parent’s continued access afterward is an ordinary membership, not custodial control — the child can revoke it at any time, the same way any guardian can be removed from a shared profile. A parent who deletes their own account no longer removes a profile they have transferred away; conversely, if the child later deletes their own account, the profile and its history go with it, exactly as they would for any account holder.
  • Her Own Profile (subject membership): A minor (or any profile subject) can hold her own membership on the profile a parent created, alongside the guardians, without waiting for an ownership transfer. A parent sends a “her own profile” invitation; when she accepts, her device lists the profile under “My profile” — never as a shared profile she merely helps with — and her own logging is attributed to her name in the day sheet and the activity feed, exactly like any guardian’s. The membership grants ordinary logging access (the same permissions as a caregiver: she can log days, but cannot remove a guardian, edit the profile’s details, or delete it — enforced by the server, not just the app), and the guardians already on the profile can still see and log it too, openly and symmetrically, in both directions. This is a labelling and identity fact about the membership, not a new kind of access: the role ladder, every sharing rule in this policy, and the two-stage custodian model above all apply to a subject membership unchanged, and a full ownership transfer (with deletion rights) remains the separate, later decision it always was.
  • No Direct Marketing or Tracking: We do not knowingly collect personal data directly from children under 13 (or under 16 in certain jurisdictions) without parental consent. Minor profiles receive exactly the same protections as adult profiles — the same Row-Level Security, the same TLS-in-transit and AES-256-at-rest infrastructure protection (Section 6, not an app-managed or end-to-end cipher) — and are never shared or analyzed.
  • Guardian Notes Are Visible To The Child: A note a parent or other guardian writes about a minor’s day is not private to the adult who wrote it. Under the owner’s open-and-transparent decision (issue #800), every accepted guardian on the profile can read every guardian note — including the minor herself when she holds an account on her own profile — while only the note’s own author can edit or remove it and only a guardian who can already log entries on the profile can write one (a viewer cannot). The app states that audience on the writing surface itself, not only in this policy. This is deliberately different from a general-purpose private journal: LunarLog does not offer a hidden note about a child.
  • Prediction-Only Sharing Excludes Minors: A profile’s primary guardian can create a prediction-only connection: a single-use code that lets exactly one other LunarLog account see that profile’s estimated period, fertile, ovulation, and PMS days on a read-only calendar — never a logged entry, note, symptom, or flow value, and never guardian access of any kind. The snapshot is computed on the sharing guardian’s own device from the profile’s logged history, uploaded only while the connection is active, and deleted from our servers the moment the connection is revoked or the account or profile is deleted. Because minor profiles are never shared, this connection cannot be created for a minor’s profile, and a code already issued stops working if the profile is marked as a minor’s before it is redeemed — the server refuses both, not just the app. The connection is revocable by either side: the sharer (or the profile’s current primary guardian) can end it, and the recipient can stop receiving it themselves at any time — either action deletes the shared snapshot from our servers immediately.
  • Fertility Data Follows Cycle Data: The fertile-window/ovulation estimate, and any fertility-related data added later, receive no special-case handling of any kind: a guardian who can already see a profile’s cycle data sees that profile’s fertility estimate too, and it transfers with the profile in an ownership transfer exactly like every other entry on it. The same feature set is available on every profile, including minor profiles, with no restriction — an explicit owner decision (September 2026), not a default.

6. Security Protections

We implement rigorous technical safeguards to ensure the security and confidentiality of your data:

  • Device Encryption: The local database relies on your device’s own operating-system-level encryption (iOS Data Protection / Android device encryption), shown to you only after biometric or passcode authentication.
  • Browser Client (Web): app.lunarlog.app runs lunarlog’s web client — a signed-in client over the same backend as the phone apps, built to keep nothing at rest in the browser. No copy of profiles or day entries is ever written to browser storage (no IndexedDB, no localStorage, no cache API use by the app); that rule is enforced by the client’s own build — a lint rule fails any change that touches a browser storage API, and an automated browser test asserts every storage surface stays empty after a full session. The session is the narrowest a browser allows: the access token lives in page memory only and dies with the tab, and the refresh token lives solely in an HttpOnly, Secure, SameSite=Strict cookie that no script running on the page can read, rotated on every use; signing out clears it. A strict Content Security Policy allows only the app’s own code and the Supabase backend — no third-party script loads on the web client at all, which includes crash reporting: error reporting runs on the phone apps only, and the web client sends nothing to Sentry. The server-side authorization model is unchanged: every request carries your session and is governed by Row-Level Security exactly as on a phone, so a browser session reaches only the rows your guardian memberships entitle you to see. Signing in requires an account; the email-link and emailed-code methods additionally require the email delivery setup described in the support pages, so password, Google and Apple are the methods available before that lands. In a browser, Google and Apple sign you in through a redirect to that provider and back, and share the same identity details Section 4 lists for them. The previous Flutter-based web build (retired October 3, 2026) kept an unencrypted browser copy of synced data and its session in browser storage; a browser that used it has that copy and that session cleared automatically on its next visit to app.lunarlog.app, and nothing replaces them.
  • Backup Exclusion: On Android, the local database is excluded from both cloud backup and device-to-device transfer by declaration. On iOS, the app marks the database file excluded from backup and applies file protection so it is unreadable until the first unlock after a restart (matching the session Keychain class) — verified on device before release. The home-screen widget’s shared container (Section 2.E) is marked excluded from backup the same way.
  • Home-Screen Widget Container: The optional home-screen widget reads a small operating-system shared container (Section 2.E) outside the encrypted database. Only the six documented fields above may be written there, the widget’s render is discreet by design, and — because a widget draws on the launcher’s own surface, outside the windows the app-switcher snapshot suppression (an opaque cover plus Android’s FLAG_SECURE) protects — discretion is the privacy control for that surface: the widget never carries content the lock screen itself could not show.
  • Biometric Security: Biometric authentication (Face ID / Touch ID / Android Biometrics) required to unlock the app.
  • Optional In-App PIN: You can additionally require a numeric PIN, set in Settings, as a second lock layer on top of your device credential — useful on a household device also used by someone else. It never replaces the device credential by default; it is an additive layer you opt into. The PIN is never sent to our servers or synced between your devices: only a salted, computationally slow hash of it is kept, in the same device-local secure storage (Keychain/Keystore) as your device credential’s own state, never in the local database and never as part of any export. Repeated wrong guesses are locked out for a period that grows with each additional wrong attempt.
  • Inactivity Timeout: Configurable automatic relocking after inactivity, plus immediate locking upon backgrounding. The one exception is while a sign-in or unlock prompt the app itself opened is on screen: the system reports those the same way it reports you leaving, so locking is deferred for their duration. The app’s contents stay masked throughout, the app relocks as soon as the prompt closes if you have left, and a prompt left open relocks the app after two minutes regardless of the inactivity setting.
  • Screen Obfuscation: App switcher and lock screen previews are masked to prevent unauthorized viewing.
  • Transport Security: All network transmissions use HTTPS with modern TLS (TLS 1.2/1.3) and strong cipher suites.
  • Cloud Storage Encryption (not end-to-end): When cloud sync is enabled, your cycle entries are stored at rest in Supabase’s infrastructure using AES-256 disk encryption — the same platform-level protection any well-run cloud database uses, applied by Supabase, not by an app-managed or end-to-end cipher LunarLog controls. LunarLog does not encrypt entry content client-side before it reaches Supabase: the note, tag, and flow values a guardian with database access could query are readable Postgres columns, protected by Row-Level Security (below) and Supabase’s own infrastructure controls, not by a cipher only your devices hold the key to.
  • Database Row-Level Security: Cloud database tables enforce PostgreSQL Row-Level Security (RLS) ensuring each authenticated user account can only read and write the rows their guardian memberships entitle them to; RLS governs which application queries can return which rows, not who can read the underlying data at the infrastructure or service-role level.

7. Data Export & Retention & Deletion Rights

You have complete control over your data:

  • Export Your Data: From Settings → Your data, “Export my data” saves a JSON file of your profiles and day entries (built entirely from the copy already on your device, so it works fully offline and without a cloud account - it needs only that at least one profile exists on this device) and hands it to your device’s normal share sheet - AirDrop, Files, email, or any app you choose. The file includes every profile and day entry already synced to this device - your own profiles, and, if you are an accepted caregiver or co-parent on someone else’s profile (multi-guardian sharing, Settings → Account), that profile’s entries too, since those are the same records you can already view and log in the app. It never includes sync-protocol internals, another account’s authentication tokens, or credentials. It includes any same-date merge disclosures still inside their 30-day window (see Section 2.A) — a record that has aged past that window is gone from the app and never appears in an export. For a profile you own and share with other guardians, it does include each guardian’s account identifier, role, and status — the same guardian list the app’s Sharing screen already shows you, since that membership list belongs to a profile you own; for a profile shared with you rather than owned by you, the export includes only your own membership row, never a co-guardian’s. When you are signed in and online, the file additionally merges in a section covering your account’s own server-side data - see the Data Portability entry below for what that includes; signed out, or without a network connection, the export still completes using only what is on this device, and the file records that the server step did not run. If you are exporting on a shared or borrowed device, review the file before sharing it further - it reflects everything that account can currently see, not only entries you personally logged. A private day note (Section 5) is never part of a guardian’s export: when the person exporting is not the note’s subject, a note the subject marked private is omitted from the JSON and CSV output (the FHIR and PDF clinical summaries never include note text at all), and the subject’s own export carries it in full.
  • Export a Clinical Summary (FHIR): The same “Your data” section also offers “Export clinical summary (FHIR)” - a separate file, built entirely on-device the same way, in the FHIR R4 clinical-data format some doctors’ offices and patient portals can import directly. It covers one profile’s self-reported cycle and symptom history, coded using standard clinical terminologies (LOINC and SNOMED CT) where a verified mapping exists, and a lunarlog-specific code otherwise - never a guessed clinical code. It carries only that profile’s display name (no email, no account id, no internal identifier of any kind) and is explicitly labeled throughout as self-reported by you or your family, not a clinician’s assessment. This file is shaped like an international clinical-summary standard (the “International Patient Summary”) without claiming full compliance with it, since a few sections that standard expects (allergies, medications) aren’t things this app tracks yet.
  • Export as CSV: The same “Your data” section also offers “Export as CSV” - two spreadsheet-compatible files, a per-cycle cycles table and a day-per-row daily_log table, built entirely on-device like the others. Unlike the JSON and FHIR files, the daily log carries your free-text notes and tags in their own columns, so treat a CSV file with the same care as “Export my data” - and it is subject to the same guardian-lens rule stated above, so a note the subject marked private is omitted whenever the exporter is not the subject. Every field is escaped against spreadsheet formula injection: any text starting with a formula trigger character (=, +, -, @, a tab, or a carriage return) is prefixed and quoted so a spreadsheet shows it as text rather than running it.
  • Export a Clinical Summary (PDF): The same “Your data” section also offers “Export clinical summary (PDF)” - a one-page, on-device summary for a clinician, generated from the same self-reported cycle and symptom data. It carries only the profile’s display name, no internal identifier, and never reads or includes note text.
  • Local Deletion: You can delete individual cycle entries or entire profiles from the app at any time. Deleted records are tombstoned and permanently removed upon sync.
  • Sign Out & Local Wipe: Signing out of your account gives you the option to discard all local database records from that device immediately.
  • Sign Out Everywhere: You can invalidate sessions across all devices from the Account settings.
  • Account & Cloud Deletion: From Settings → Account, “Delete account” immediately and permanently deletes your account: every server row you own (profiles, day entries, settings, your guardian memberships and invitations, the guardian notes you wrote (including any on profiles you do not own; the same removal that happens when a guardian is removed from a profile), your minimum-age acknowledgement record, and the small progress record kept for any bulk import you ran - a source label, row counts, status, and timestamps, no health content), the Supabase account itself (including, if you signed in with Apple, revoking that app’s access via Apple’s own revocation endpoint), and this device’s local data. Your feedback tickets and their reply threads, and any attached screenshots, are also deleted explicitly as part of this same process (see “Support Ticket Retention” below) — not left to happen only as a side effect of the account being removed. The confirmation offers “Export first” so you can save a copy before proceeding. This is not a request queued for later - the server-side rows and the account are normally gone by the time the confirmation completes. The one exception: for an Apple-signed-in account, your data rows are deleted first and then, if Apple cannot confirm the revocation, the account sign-in itself is deliberately left in place rather than deleted with a live Apple grant still attached - the app tells you what happened and lets you retry, which completes the deletion. If any attached screenshot cannot be removed from storage, the same fail-closed rule applies: the deletion stops and is left retryable rather than completing with a screenshot left behind. You can still reach us at will@wjdavis5.net for any deletion the in-app flow does not cover (e.g. if you no longer have access to the device).
  • Support Ticket Retention: Feedback tickets and their reply threads are retained to support ongoing conversations and app improvement; you can request deletion of a ticket at any time by emailing will@wjdavis5.net, and every ticket you own — along with any attached screenshot — is also removed automatically the moment you delete your account (see above): account deletion fails closed rather than completing with a ticket or screenshot left behind. Deleting a single ticket by emailing us (without deleting your whole account) removes the ticket and reply-thread database records themselves; an attached screenshot for that single-ticket case still needs your account to exist at request time so we can delete that file in the same pass, unlike the whole-account path above, which removes the screenshot itself as part of deleting the account. This narrower, request-only gap for a single ticket kept while your account remains open is a tracked improvement, not yet built. A resolved ticket that neither of the above ever cleans up is also aged out automatically after 1 year — see “Server-Side Retention Windows” immediately below.
  • Server-Side Retention Windows: Beyond the rights above, a nightly automated process ages out five narrow categories of server-side record so nothing accumulates forever by default: a content-free caregiver-alert delivery record (which guardian was notified that an entry was logged, never the entry itself) is deleted 30 days after it was sent; a deleted cycle entry’s server-side deletion marker — kept briefly so every one of your other synced devices has a chance to learn the entry was deleted, even one that has not opened the app in a while — is permanently removed 180 days after you deleted it, a window chosen to comfortably exceed how long a device can realistically stay offline before its next sync; a resolved support ticket with no attached screenshot (and its reply thread) is removed 1 year after it was marked resolved, on top of the manual and account-deletion paths described above — a resolved ticket that still has an attachment is left alone by this automatic process specifically because the attachment itself lives in separate storage this process cannot safely reach, and stays covered only by the “Support Ticket Retention” paths above (a request to us, or deleting your account) until it is deleted or its attachment is removed; and a shared per-entry change-history record — showing THAT a guardian’s entry changed, who changed it, when, and which fields, never what they said — is removed 90 days after the change; and a same-date merge disclosure — the record that keeps a note or flow level that lost a merge between two guardians’ entries for one date, so its author can recover it in the app — is removed 30 days after the merge, together with the discarded text it holds. The first four are delivery, sync, and support bookkeeping rather than health content on their own; the fifth is the one deliberate exception, holding a copy of health text for exactly as long as its author needs to see the in-app notice and re-enter it, and no longer. Each is a hard, permanent deletion, not a hidden extension of how long your actual cycle data is retained.

Depending on your jurisdiction (such as the European Economic Area, United Kingdom, California, and other US states), you have the right to:

  • Access: Know what personal data is processed and request a copy.
  • Rectification: Correct inaccurate or incomplete information.
  • Erasure: Request that your personal data be permanently erased (“Right to be Forgotten”).
  • Restrict or Object to Processing: Object to or limit specific processing activities.
  • Data Portability: Receive your data in a structured, commonly used, and machine-readable format - in-app via “Export my data” (Settings → Your data), which produces a JSON file and works whether or not you have a cloud account, and whether or not you are signed in. When you are signed in and online, the file additionally merges your locally stored profiles and day entries with the server’s own record of your account under a server section: your guardian memberships and roles, the invitations and ownership transfers you created or accepted, your notification preferences, your registered devices (with each device’s push token redacted to its last 4 characters), your feedback tickets and their reply threads, your reminder settings, your minimum-age acknowledgement record (when it was made, the app version that made it, and the policy version acknowledged), and the progress record for any bulk import you ran (a source label, row counts, status, and timestamps, no health content). For a profile you share rather than own, that section covers only your own memberships, preferences, and the entries you personally logged - never another guardian’s private data. The export always includes your on-device data - signed in or signed out, online or offline; the server section is included only when you are signed in and that network call succeeds, and the file records which happened (serverIncluded).
  • Withdraw Consent: Withdraw consent for cloud synchronization or error reporting at any time.

To exercise any of these rights, please contact us at will@wjdavis5.net.


9. Apple App Store & Google Play Declarations

In compliance with Apple App Store Guidelines (including Guideline 5.1.1 and PrivacyInfo.xcprivacy) and Google Play Data Safety:

  • Data Used to Track You: None (NSPrivacyTracking: false).
  • Data Linked to You: Email Address (App Functionality — the account email and the optional, free-text support-ticket reply email, which may differ from the account email); Health Information (App Functionality, only when cloud sync is active); Device Push Token (App Functionality, only when a guardian enables caregiver alerts on a build with push configured); Support ticket content — the message and category you write, the diagnostics you approve, the reply thread, and the optional screenshot (App Functionality, only when you submit a feedback ticket; declared as Customer Support, Other Diagnostic Data, and Photos or Videos respectively, all linked to the account).
  • Data Not Linked to You: Crash Data (App Functionality, fully anonymized).
  • On-account records with no separate Apple nutrition category: the minimum-age acknowledgement stored on your account when you are signed in (when it was made, the app version that made it, and the policy version you acknowledged — Section 5) and the authentication credentials and tokens described in Section 2.B are both stored off-device and removed when you delete your account, but Apple’s nutrition labels have no distinct category for either, so neither is answered as a category of its own.
  • The home-screen widget adds no off-device transfer: the widget and its shared container live entirely on your device (Section 2.E); nothing new is collected, linked, or transmitted, so no App Store or Play declaration category changes.
  • On-device health-platform sync adds no off-device transfer: the opt-in Apple Health / Health Connect write of your logged records into the device’s own health store, and the Apple Health / Health Connect import (Section 4) — the pass you start from Settings, and the same prompt-free pass the OS can start in the background once you have opted in — both operate entirely on your device and transmit nothing to LunarLog or any third party. LunarLog never writes a predicted or derived value into the health store; it reads Apple’s four computed cycle-deviation types on iOS as a read-only second opinion and never writes them back (App Store Review guideline 5.1.3). Apple’s background-delivery entitlement (iOS) and Health Connect’s background-read permission (Android) are declared for the import described in Section 4 and for nothing else. The App Store Connect privacy details and Google Play Data safety declarations that describe the read/import capability are updated separately (issue #21).
  • Exports add no off-device transfer and no declared data type: the four exports in Settings → Your data (JSON, CSV, FHIR, and PDF; Section 7) are each built entirely on-device and handed to the operating system’s own share sheet at the user’s direction. The app transmits nothing to LunarLog or any third party for any of them, so no export adds a category to the App Store Connect privacy details or the Google Play Data safety form; a file the user then chooses to send onward is that user’s own transfer, not app-side collection.

10. Changes to this Privacy Policy

We may update this Privacy Policy from time to time to reflect improvements to the app, legal requirements, or architectural changes. The “Last Updated” date at the top of this document will always indicate when changes were made. Substantial changes will be highlighted in app release notes.

Change History

  • October 20, 2026 (Apple Health spotting read disclosed; #1908): Section 4 now discloses that LunarLog can read both menstrual flow and intermenstrual-bleeding records from Apple Health on iOS, matching the Health Connect read on Android. The user-initiated import reads the whole available history for both types into the bound profile (stored as cycle entries and spotting observations, respectively), and background imports keep both types current without prompting or writing. ios/Runner/Info.plist’s NSHealthShareUsageDescription is updated to name intermenstrual bleeding (spotting) and drops the pre-background “Nothing is read automatically” wording (issue #993), and ios/Runner/PrivacyInfo.xcprivacy notes the two read types. No health data leaves your device as part of this feature.
  • October 10, 2026 (mode scope correction): Section 1’s “Estimates From Your Own Logged Data” bullet and the September 7, 2026 entry below said conception and pregnancy features remained outside the product’s scope. They shipped: the conceive mode (a per-day conception-likelihood estimate, issue #204) and the pregnancy, postpartum, and perimenopause modes (issue #188’s mode plan of record). Nothing about what is collected, stored, or shared changed, and the Section 5 rules for fertility data (guardian visibility and ownership transfer) apply to these estimates exactly as they do to the fertile-window estimate.
  • October 4, 2026 (the web client’s sign-in methods, stated correctly): Section 6’s “Browser Client (Web)” bullet said password and “the native Google sign-in” were the web client’s sign-in methods. The web client offers password, Google and Apple, and neither provider’s sign-in is native there: both go through a redirect to the provider and back. Section 4’s Apple row now names the web client alongside iOS/macOS. Nothing about what is collected, stored or shared changed; the earlier text left Apple out and misdescribed the Google flow (issue #1396).
  • October 3, 2026 (the web client at app.lunarlog.app keeps nothing at rest): app.lunarlog.app now runs lunarlog’s React web client instead of the previous Flutter build. The browser posture is now stricter than any earlier web build: no copy of synced data is written to browser storage at all, the access token lives in page memory only, and the refresh token lives in an HttpOnly, SameSite=Strict cookie no page script can read, rotated on every use and cleared on sign-out — Section 6’s web bullet states the full posture. The retired Flutter build kept an unencrypted browser copy of synced data and its session in browser storage; that copy is cleared automatically on a browser’s next visit (a Clear-Site-Data response on the app shell plus a self-unregistering service worker at the old registration path), and nothing replaces it. Crash reporting does not run on the web client (no third-party script loads there at all). No new category of data is collected — this change removes the browser’s stored copy entirely.
  • September 29, 2026 (background health imports gated on your first import): Section 4’s background sentence now names the precondition the code has enforced since the gate shipped (issue #1215; found by the #1221 merge review, issue #1224): a background pass runs only once a user-initiated import has completed for the current binding — you bind a profile, then run the first import yourself from Settings → Health app sync, and only after that pass completes can Apple Health’s background delivery or Android’s scheduled job run the same pass in the background. Until then a background trigger is a silent no-op — no probe, no read, no write — so an observer’s own first fire or a launch-time trigger can never pull the store’s whole history into a profile before the person ever tapped Import. Unbinding or re-binding clears that marker, so the first import (and the consent it represents) always belongs to the current binding. This corrects the ledger in the stricter direction — the shipped behavior is more protective than the earlier sentence implied, since “once a profile is bound” read as if binding alone sufficed — and collects no new data.
  • September 29, 2026 (signed-in browser build — browser error reporting is verified and disclosed): Section 6’s “Signed-In Browser Build (Web)” bullet no longer describes browser crash reporting as unverified and CSP-blocked — that was the pre-#1110 state, and the shipped signed-in web build does not match it. Since issue #1110’s fix, the Sentry SDK’s third-party CDN script stays blocked and the build sends error reports itself: the same scrubbed error envelopes the native builds send, posted from the app’s own code directly to Sentry’s ingest host over the connect-src entries the Content Security Policy already allows. Same data, same on-device scrubbing, same United States region statement, and no third-party script involved in the send. This corrects the ledger in the disclosure direction — a transmission the policy used to deny actually happens, and the bullet now states it (found by the post-merge audit, issue #1187). No new category of data is collected.
  • September 29, 2026 (background health imports — no tap required): Section 4 now discloses that the Apple Health / Health Connect import (issues #217/#458) can run in the background once a profile is bound (issue #993): on iOS, the app registers Apple Health’s background delivery (com.apple.developer.healthkit.background-delivery — a new entitlement entry that also requires the App Store provisioning profile to be regenerated), and on Android, android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND is now declared alongside the existing read permissions and a periodic scheduled job checks Health Connect for changes. What runs in the background is exactly the pass the Settings action runs — the same full-history, page-by-page read into the one bound profile, still excluding records LunarLog itself wrote and still never overwriting a value you logged by hand — with three background-specific properties: it never prompts (it runs only when the OS permission is already granted, so a revoked or never-granted permission simply stops it), it never writes to the health store, and it never shows a screen. The app logs only outcome counts, never health content, and unbinding the profile stops the background imports. Section 9 is updated to name the two background capabilities and that they serve the import and nothing else. No health data leaves your device as part of this feature, and no new category of data is collected. The Google Play Health apps declaration must be re-filed for the new permission before the build ships to any reviewed track (tracked in docs/ops/play-health-declaration.md); the App Store Connect / Google Play declarations remain the operator’s transcription (issue #21).
  • September 26, 2026 (web build boots under its own CSP; noindex; font fallback disclosed): The deployed web client now builds with --no-web-resources-cdn, so Flutter’s CanvasKit engine ships inside the build and resolves locally instead of from www.gstatic.com — a host the strict Content Security Policy blocks and whose blocked fetch had left the page blank (issue #1091). A Roboto face is bundled beside Inter and Fraunces, so the engine’s default family no longer fetches from Google Fonts on a normal boot. The remaining allowance is deliberate and narrow: when text contains a character the bundled faces lack — an emoji, or a non-Latin name — the browser may fetch the needed fallback font file from Google Fonts (fonts.gstatic.com), and Section 6’s “Signed-In Browser Build (Web)” bullet now states it. That request carries the browser’s IP address and never any entry content, and the CSP permits that host only for fonts; the existing statement that no third-party CDN scripts are loaded is unchanged. Separately, the signed-in app is marked noindex (a robots meta tag and an X-Robots-Tag header) and the web manifest sets display: browser, so Chromium does not offer installation — installability stays deferred (issue #1095). No new category of data is collected.
  • September 22, 2026 (under-13 use through a parent’s invitation — the parental-consent record): Section 5’s minimum-age statement is restated (issue #957): 13 or older may create an account and use LunarLog directly; an individual under 13 may use the app on her own device only through an account and profile a parent or legal guardian created and invited her into, using the app’s existing “her own profile” invitation (issue #802’s subject membership). Accepting that invitation is the record of the parent’s or guardian’s consent — the parent created the profile and sent the invite, so the child cannot arrive cold. The onboarding acknowledgement is no longer a flat “I am 13 or older”: an operator arriving through a parent’s invitation acknowledges the parent-initiated invitation instead, and accepting it records parent_invite on the same synced minimum-age acknowledgement row (issue #845). This deliberately reverses the flat 13+ own-signup posture of September 12, 2026 (issue #269) for the invited path only; nothing else in this policy is weakened — minor profiles keep every protection Section 5 already describes, the parent’s own account remains the profile’s custodian until an ownership transfer, and no age is verified or stored from this flow (birth year never gates, issues #269/#802). Store-declaration implications (Apple age rating, Google Play Families / Data safety) are tracked in issue #21’s checklist, not duplicated here.
  • September 22, 2026 (exports honour the private-note lens; CSV and PDF documented): Section 7 now documents the CSV export (issue #469) and the PDF clinical summary (issue #154) alongside JSON and FHIR, and states the guardian-lens rule every export follows: a private day note (Section 5) is never part of a guardian’s export — when the person exporting is not the note’s subject, a note the subject marked private is omitted from the JSON and CSV output, and the FHIR and PDF summaries never include note text at all; the subject’s own export carries it in full. A minor’s profile is exported only by an accepted guardian on that profile (or the subject), with an honest refusal otherwise. Section 9 now records that all four exports are on-device, user-initiated share-sheet transfers that add no new declared data type to the App Store Connect or Google Play forms. No new category of data is collected.
  • September 22, 2026 (privacy-manifest reconciliation): ios/Runner/PrivacyInfo.xcprivacy now declares four data types this policy already disclosed but the manifest omitted (issue #1065): the device push token (Device ID, linked, app functionality) that register_push_device stores through Supabase and FCM/APNs delivers; and the support-ticket content of Section 2.C — the message and category (Customer Support), the operator-approved diagnostics (Other Diagnostic Data), and the optional screenshot (Photos or Videos) — all linked to the account and used only for app functionality. The account email and the support-ticket reply email share the one Email Address declaration. Nothing is newly collected and nothing is weakened: this entry reconciles the manifest and Section 9’s own declaration list with the disclosures Sections 2 and 4 already made, and leaves NSPrivacyTracking false. The App Store Connect and Google Play answers themselves remain the operator’s transcription (issue #21); the issue’s remaining candidates — the provider sub/account id, the per-entry IANA time zone, and the content-free change history — are left for that pass and are not declared as distinct categories here.
  • September 22, 2026 (private day note — the one exception to a guardian’s full read): Section 5’s “Guardian Roles & Read Visibility” bullet now states that every accepted guardian — whatever the role, and including a parent who created the profile — reads everything the subject logs, with one deliberate exception: a day note the subject herself marks private (issue #849, re-scoped by the owner’s 2026-09-20 decision). The privacy choice is made when the note is written: a note may be created private, or marked private while it is still empty, but a note that has already been saved and shared cannot be made private retroactively, and a private flag can never be cleared once set. The server enforces this on every read path, not only in the interface — a private note’s text is masked to null for every non-subject guardian in the sync pull, in the push response, and in the server export — and a guardian device shows a “Private note” placeholder in place of the text and cannot overwrite it. The subject reads her own note in full and it travels with her own “Export my data”. This is a per-note control on the subject’s own day note, not a per-guardian visibility tier; graduated privacy levels for older teenagers remain a separate, future planning effort. No new category of health data is collected.
  • September 21, 2026 (minimum-age acknowledgement recorded on the account): Section 5 now states that the onboarding minimum-age acknowledgement (issue #845) is recorded on your account when you are signed in — with when it was made, the app version that made it, and the policy version you acknowledged — included in “Export my data”, and removed when you delete your account; a change to the policy version asks you to acknowledge it again. It was previously device-local only, so a second signed-in device or a reinstall had no record it happened. No new category of data is collected beyond the acknowledgement fact itself, and no health data is involved.
  • September 21, 2026 (signed-in browser build — the web security posture; epic #831): The web build can now be a first-class signed-in client (behind the operator’s LUNARLOG_WEB_SYNC=true), so this policy states the browser’s storage story explicitly. Section 6 gains a “Signed-In Browser Build (Web)” bullet: a signed-in browser holds the synced profiles and day entries (IndexedDB, no app-managed cipher) and the session’s access/refresh token and PKCE verifier in browser storage that any script on the origin can read, outside any operating-system at-rest protection or biometric gate; the server-side authorization model is unchanged (Row-Level Security still governs every request), the build ships a strict Content Security Policy and cross-origin isolation, and signing out — or the banner’s “Wipe local data” — clears the browser copy. Section 1’s “Protected at Rest” bullet is clarified to name the browser as the deliberate exception. Nothing is weakened: Section 1’s OS-protection language and Section 6’s existing “Cloud Storage Encryption (not end-to-end)” bullet already scoped their guarantees to the on-device and cloud halves, and the browser story is additive disclosure. Epic #831’s non-negotiable is honored in the same change: the banner and the first-run acknowledgement were rewritten so a sync-enabled build never claims it is “not for real data” — it now names what the browser stores and that signing out clears it. Hosting, deploy automation, DNS, PWA/offline, and web auth methods beyond email/password and passwordless email remain deferred.
  • September 21, 2026 (Apple Health computed cycle deviations — read-only insight): Section 4 now discloses that the user-initiated iOS import also reads Apple’s four computed cycle-deviation types (irregular cycles, infrequent cycles, prolonged periods, and persistent intermenstrual bleeding) over a bounded six-month window and, when any are present, shows them on the overview as a clearly labelled, dismissible second opinion next to lunarlog’s own estimate — never merged into it (issue #799, deferred from #217). These are Apple’s own derived values computed from whatever was logged in Apple Health, so they may disagree with lunarlog’s history. They are read-only, permanently: the app never writes them back, the write surface has no method that accepts one, and the four types are absent from every written/shared HealthKit set; App Review guideline 5.1.3 forbids writing derived data into HealthKit. Section 9 is updated to state the read is read-only. The snapshot is a display cache of Apple’s computation on this device and is never synced; no health data leaves your device as part of this feature. The App Store Connect / Google Play declarations that describe the read capability are updated separately (issue #21).
  • September 21, 2026 (full-history health import): The user-initiated import from Apple Health and Health Connect (issues #217/#458) is no longer capped at the last 30 days (issue #992). It reads the whole available history for the one profile bound to this device, a page at a time, stopping when the store has no more data; on Android this is why android.permission.health.READ_HEALTH_DATA_HISTORY is now declared and requested alongside the two menstrual read types (without it Health Connect would return only the 30 days before the permission grant). Nothing else about the read changed: it is still user-initiated only, still into the one bound profile, still excludes records LunarLog itself wrote (dataOrigin / HealthKit source filtering), still never overwrites a value you logged by hand, and background reads (READ_HEALTH_DATA_IN_BACKGROUND) remain undeclared and unavailable. Re-running an import is idempotent — each imported row is keyed to the platform sample it came from — so an interrupted pass can simply be run again. Section 4 and the Play Health apps declaration checklist are updated; the App Store Connect / Google Play declarations remain updated separately (issue #21). No health data leaves your device as part of this feature.
  • September 20, 2026 (home-screen widget): New Section 2.E and a Section 6 bullet disclose the optional home-screen widget (issue #141): the app writes a minimal, documented set of facts (a state word, a cycle-day count, a relative days-until-next count, a quick-log availability flag, an opaque profile identifier, and an anchor date) into an on-device OS shared container outside the encrypted database; the widget renders discreetly — no name, date, flow, or symptom — and its quick-log button opens the app and writes only after the unlock gate, idempotently, and never for a viewer role. Nothing crosses the device, so no store declaration category changes (Section 9).
  • September 20, 2026 (guardian viewer read scope): Section 5 is updated (issues #849, #869) to clarify guardian role semantics: while write capabilities are constrained by role (a viewer cannot log or edit entries, and only primary guardians or co-parents can edit profile settings), all accepted guardians on a profile have full read visibility over logged cycle entries, tags, observations, and notes.
  • September 20, 2026 (minor status determination): Section 5 now states how a profile’s minor status is determined — derived from the profile’s birth year when one is present (a minor is a minor until 18, per #295/#820), falling back to the stored minor flag for a profile with no birth year — and who sets it: whoever creates or manages the profile. Minor status gates the minor-specific protections Section 5 already describes, most notably the prediction-only sharing refusal and the app’s default-hidden symptom and mood tracking categories. No data collection changed; this entry makes the policy state the rule the app already applies.
  • September 20, 2026 (iOS database file protection until first unlock): Section 1’s “Protected at Rest” bullet and Section 6’s “Backup Exclusion” bullet are updated (issue #906) to reflect that the local database and containing directory on iOS use FileProtectionType.completeUntilFirstUserAuthentication rather than FileProtectionType.complete. Under WAL mode, SQLite memory-maps the WAL index file; background tasks (such as background sync or push processing) touching the database while the screen is locked caused pagein bus errors under complete protection. Downgrading to protection until first unlock keeps the database encrypted at rest until the first device unlock after restart, aligning with the class used by the session Keychain (flutter_secure_storage), while preserving app lock, backup exclusion, and offline resilience.
  • September 19, 2026 (HealthKit symptom and mood writes): Section 4 now discloses that tracked symptoms (such as abdominal cramps, headache, bloating, acne, fatigue, nausea, and appetite/sleep changes) and mood tags logged in LunarLog are written on iOS to Apple Health as symptom entries when health platform sync is enabled for the bound profile (issues #238, #916, #917, #918). Mood tags are written to Apple Health as generic ‘Mood Changes’ category samples without preserving specific emotional valence, and symptoms without an explicit severity are recorded with unspecified severity rather than severe. The Health app sync screen in Settings and the HealthKit permission description (NSHealthUpdateUsageDescription) now explicitly describe symptom and mood writes.
  • September 19, 2026 (fertility and basal-body-temperature writes to Apple Health / Health Connect): With the existing one-bound-profile opt-in, LunarLog can now also mirror a logged cervical-mucus observation, an ovulation-test result, and a manually tracked basal-body-temperature (BBT) reading into the device’s own health store (issue #228) — write-only; the app does not read any of these three back. Cervical mucus maps its appearance only (Health Connect’s required sensation field is written as the platform’s “unknown”, since the app has no sensation concept). atypical discharge has no Apple Health equivalent and is deliberately not exported. On Health Connect, an ovulation result of “positive” or “peak” is written as the platform’s positive result, and a Wearable-sourced BBT reading is never written back, so it can never be conflated with a reading you logged by hand. Section 4 now lists the new write types, and the Play Health apps declaration must be re-filed for the three new WRITE_* permissions before any production-track ship (issue #21).
  • September 18, 2026 (guardian notes — a parent’s own note about a child’s day): LunarLog now lets each guardian add their own dated note beside a profile’s shared day note (issue #801) — one note per guardian per date, attributed to its author, never merged with another guardian’s note for the same day, and editable or removable only by the guardian who wrote it. Section 2.A discloses the new record. Section 5 states the visibility rule decided in issue #800: every accepted guardian on the profile can read every guardian note, including the child herself when she holds an account on her own profile, and the app states that audience on the writing surface at the point of writing — a guardian note about a child is deliberately not a private journal. A viewer can read but not write. Guardian notes never appear in a notification payload or a crash report, and they are removed on account deletion, profile deletion, and guardian revocation. No other data collection changed.
  • September 18, 2026 (Health Connect read/import — the Android half of the #781 decision): LunarLog can now import from Health Connect on Android, mirroring the Apple Health read path shipped the same day. This is the owner’s decision recorded in issue #781 (“it’s a cycle-tracking app”), applied to the second platform. The import reads menstrual-flow and intermenstrual-bleeding records — the same two user-recorded types the app already writes — and is user-initiated only: Settings → Health app sync → Import from Health Connect, over a bounded 30-day window, writing into the one profile bound to this device (issue #153). Intermenstrual-bleeding records are stored as spotting observations, the shape the app logs spotting in. Records LunarLog itself wrote are excluded by Health Connect’s dataOrigin, so entries are never re-imported, and a value you logged by hand is never overwritten. Health Connect reports a denied read; like Apple Health’s opacity, that is treated identically to “no data”, and the app never claims to know which occurred. The incremental sync uses Health Connect’s change-token API, with a token-expiry fallback to a fresh bounded read so a long-idle device recovers instead of failing. Full-history and background reads remain undeclared and unavailable. Section 4 now describes the Android read direction, and Section 9 notes that the App Store Connect / Google Play declarations are updated separately (issue #21) — the Play Data safety and Health apps declarations must be updated before any production-track ship. No health data leaves your device as part of this feature.
  • September 18, 2026 (Apple Health read/import — reverses the write-only posture): LunarLog can now import menstrual flow from Apple Health. This is the owner’s decision recorded in issue #781 (“it’s a cycle-tracking app”), and it reverses the write-only commitment this policy stated from September 12, 2026 (and reaffirmed September 17, 2026). The import is user-initiated only — Settings → Health app sync → Import from Apple Health, over a bounded 30-day window — and writes into the one profile bound to this device (issue #153). Samples LunarLog itself wrote are excluded by source filtering, so entries are never re-imported, and a value you logged by hand is never overwritten. Apple Health is opaque about read permission: an empty result is treated identically to a denied read, and the app never claims to know which occurred. The four Apple-computed cycle-deviation types (irregular, infrequent, prolonged, and persistent intermenstrual bleeding) remain read-only and are never requested, read, or written. Section 4 now describes the read direction, and Section 9 notes that the App Store Connect / Google Play declarations are updated separately (issue #21). No health data leaves your device as part of this feature.
  • September 17, 2026 (Apple Health read-permission text restored; no behavior change): Info.plist’s NSHealthShareUsageDescription — Apple’s read-access purpose string, removed on September 12, 2026 by the entry below — has been restored (issue #766). Nothing about what LunarLog does changed: the Apple Health sync is still write-only, HealthKit authorization is still requested with an empty read set, and Section 4’s statement that LunarLog requests no read permission on either health platform remains accurate. The string was restored because App Store Connect rejected a build with ITMS-90683: Apple’s automated check requires the text whenever an app’s entitlements permit read access, which LunarLog’s HealthKit entitlement does, whether or not the app ever reads. The restored text states plainly that LunarLog never reads from Apple Health, rather than inventing a read purpose the app does not have, so the September 12 correction’s substance is preserved. No new category of data is collected, and no health data is read from your device.
  • September 17, 2026 (shared change history): Section 2.A now discloses the change-history record (issue #170): every change to a synced entry leaves a short server-side audit record — which guardian changed it, when, which fields, and the kind of change — that is deliberately content-free (it never records what a note said, which tags were set, or a flow level), is visible only to the profile’s guardians, and is permanently deleted 90 days after the change. Section 7’s “Server-Side Retention Windows” already carried this 90-day window for “a future per-entry change-history record”; that record now exists, so the window applies to it directly. No health content is collected by this record that the entries themselves do not already carry under this policy.
  • September 16, 2026 (same-date merge disclosures): Section 2.A now discloses the merge-disclosure record (issue #130): when two guardians independently log the same date and the entries are merged, the losing note text or flow level is retained — visible only to the profile’s guardians, never in a notification, never in a crash report — so its author sees a quiet in-app notice on that date and can recover their text. Section 7’s “Server-Side Retention Windows” gains this as a fifth aged-out category, deleted permanently 30 days after the merge; it is the one retained window that holds health text, kept only for the recovery window and no longer. “Export my data” carries a disclosure only while it is still inside that window (Sections 2.A and 7), so the file never extends the retention the app itself enforces. No other data collection changed.
  • September 15, 2026 (optional in-app PIN): Section 6 now discloses an optional in-app PIN (issue #271): a second, additive lock layer on top of the device credential, primarily useful on a device also used by someone else, or with no device passcode set at all. Only a salted, computationally slow (PBKDF2) hash of the PIN is ever stored, in the same device-local secure storage (Keychain/Keystore) the device-credential gate already uses — never the PIN itself, never in the local database, never synced to the server, and never included in any export. Repeated wrong guesses are locked out for a period that grows with each additional failure. No new category of data is collected by this change, and the device credential remains the default, recommended gate.
  • September 15, 2026 (server-side retention windows): Section 7 gains a new “Server-Side Retention Windows” bullet (issue #263) disclosing that a nightly automated process now permanently deletes four narrow categories of server-side record once they age past a fixed window: a content-free caregiver-alert delivery record (30 days after it was sent), a deleted cycle entry’s server-side deletion marker (180 days after deletion — long enough for every one of your other devices to learn about the deletion first, even one that has not synced in a while), a resolved support ticket with no attached screenshot and its reply thread (1 year after being marked resolved, on top of the manual and account-deletion deletion paths already described — a resolved ticket that still has an attachment is deliberately left out of this automatic process, since it cannot safely reach the separate storage that attachment lives in), and — for a future per-entry change-history record this app does not yet have — 90 days after a change. No new category of data is collected by this change; it is a maximum-retention backstop on record types (or, for the fourth, a record type not yet built) already disclosed elsewhere in this policy.
  • September 12, 2026 (encryption-claim correction; health-store read permissions removed): Corrected three inaccurate encryption claims (issue #515): Section 3’s cross-device sync bullet, Section 4’s Supabase table row, and Section 5’s minors bullet no longer describe cloud-synced cycle data as “encrypted”/“end-to-end encrypted” in a way that implied an app-managed cipher — LunarLog does not encrypt entry content client-side before it reaches Supabase; note, tag, and flow values are readable Postgres columns protected by TLS in transit, Supabase’s own AES-256-at-rest infrastructure encryption, and Row-Level Security, exactly as Section 6 now states explicitly with a new “Cloud Storage Encryption (not end-to-end)” bullet. Section 7’s “Export Your Data” bullet is corrected to match export_account_data()‘s actual behavior: for a profile you own and share, the export does include each other guardian’s account identifier, role, and status (the same guardian list already visible in the app’s Sharing screen) — it is not true, as previously stated, that the export “never includes other accounts’ identifiers.” Section 4 also now states explicitly that the Apple Health / Health Connect sync is write-only — LunarLog requests no read permission on either platform — matching a fix to AndroidManifest.xml (the unused READ_MENSTRUATION/READ_INTERMENSTRUAL_BLEEDING declarations, never requested by HealthConnectAdapter.kt’s permission set, were removed) and Info.plist (NSHealthShareUsageDescription, Apple’s read-access string, was removed since HealthKit authorization is requested with an empty read set; NSHealthUpdateUsageDescription’s text no longer claims a read capability that does not exist). No new data collection changed; this entry corrects policy text to match code that was already write-only and RLS/infrastructure-encrypted, not end-to-end encrypted.
  • September 12, 2026 (minimum-age policy and onboarding acknowledgement): Section 5 now explicitly states LunarLog’s minimum-age policy (issue #269): LunarLog is intended for individuals aged 13 and older, with primary account management requiring 18+, while parents and guardians may manage profiles for household members. Onboarding now includes an explicit acknowledgement of this standard.
  • September 11, 2026 (data residency, hosting regions, and HIPAA non-applicability): Section 4 now explicitly states LunarLog’s data residency and cloud hosting regions (Supabase Cloud hosted on AWS in us-east-1; Sentry hosted in its US multi-tenant region), confirms that all cloud processing occurs within the United States regardless of user location, and documents the United States and Canada app distribution scope. Section 4 also explicitly clarifies that LunarLog is a direct-to-consumer app, not a HIPAA covered entity or business associate, and that clinical exports are user-initiated transfers that do not establish a HIPAA-governed relationship.
  • September 9, 2026 (prediction-only sharing and minors): Section 5 now discloses the prediction-only connection (issue #151, shipped in #369 without a policy entry) and, with it, the restriction issue #373 adds: a profile’s primary guardian can share that profile’s estimated period, fertile, ovulation, and PMS days — a device-computed snapshot of derived phases, never any logged entry, note, symptom, or flow value — with exactly one other account on a read-only calendar, revocable at any time, with the server-side snapshot deleted the moment the connection ends. This connection is refused for a minor’s profile, both when the code is created and again when it is redeemed (the minor flag can change in between), enforced by the server rather than only hidden in the app. No new category of data is collected; the existing “minor profiles are never shared” commitment is unchanged and now has a concrete enforcement point behind it.
  • September 9, 2026 (health-platform store compliance): Section 4 now states explicitly (issue #254) what the opt-in Apple Health / Health Connect sync already did and did not do: it is an on-device, OS-mediated write of your logged records into the device’s own health store, it transmits nothing off-device and adds no new collected data type for App Store Connect or Play Data safety purposes, and it never writes a predicted or derived value (next-period prediction, fertile-window, ovulation estimate) into the health store — App Store Review guideline 5.1.3. Section 4 also now states separately that the share-sheet exports (JSON, FHIR) are user-initiated transfers to a destination you choose, not app-side collection. The ios/Runner/PrivacyInfo.xcprivacy comment was updated to say the same. No disclosure changed in substance: nothing new is collected, and no third party receives anything new.
  • September 9, 2026: Section 2.A now discloses that each logged entry carries the IANA time zone it was logged in (issue #321, a follow-up from the #180/#319 review): the server already stored this value to derive the entry’s calendar day, but this policy did not previously mention it. The same entry also discloses, for the first time, that a guardian’s own caregiver-alert settings store the guardian’s IANA time zone (used for quiet hours and digest timing — never the entry’s zone). It is a coarse location signal, not a precise one, and is not a new category of data collection — it is metadata about an already-disclosed entry, covered by the same local-first storage and optional-sync rules as the entry itself.
  • September 9, 2026 (flow model): Section 2.A’s flow intensity levels are updated (issue #247): a new “super heavy” level was added, spotting is now recorded as its own tracked symptom rather than a flow level, and an explicit “not bleeding today” note is now distinct from simply not logging a day at all. This is a storage-shape refinement, not a new category of data collected — the same cycle/flow information described here, still local-first, still covered by the same optional-sync and guardian-visibility rules.
  • September 9, 2026 (clinical export): Section 7 now describes “Export clinical summary (FHIR)” (issue #157), a second export format alongside the existing JSON “Export my data”: a FHIR R4 document built entirely on-device, covering the same categories of self-reported cycle and symptom data as the JSON export, coded with standard clinical terminologies where a verified mapping exists. Like the JSON export it needs no cloud account and works fully offline; unlike it, the FHIR file carries only the profile’s display name and no other identifier, by design, since this format is meant to be shareable with a clinician or portal. No new category of data is collected — this is an additional output format for data already disclosed in Section 2.A.
  • September 9, 2026: LunarLog now computes a fertile-window and ovulation estimate (issue #143, following the September 7, 2026 policy removal below): a standard calendar-method back-calculation — estimated ovulation is the next predicted period start minus an assumed 14-day luteal-phase length, and the fertile window is the days immediately around it — computed entirely on your device from the cycle history you already log, with no new data collected and no additional signal (temperature, cervical mucus, test results) used. It carries the same reliability tier as, and is disclosed and protected identically to, the period estimate it is derived from (Section 1, Section 5): available on every profile including minors’, visible to any guardian who can already see that profile’s cycle data, and moved by an ownership transfer the same way. Every place this estimate is shown carries a specific disclaimer that it must not be used to prevent pregnancy and is not birth control.
  • September 9, 2026: Sections 7 and 8 now disclose a small server-side progress record kept for a large bulk import (issue #167, the RPC that makes the Clue-import feature issue #159 laid the groundwork for actually able to complete): a source label, row counts, status, and timestamps, so the app can show progress and resume an interrupted import. No import feature exists yet as of this date. This record carries no health content whatsoever - no symptom, flow, or cycle data - and is treated exactly like every other server-side record already described here: it is included in “Export my data” and removed by “Delete account” along with the rest of your data, and it is never sent over the realtime sync channel.
  • September 9, 2026 (restore from file): Added “Import from file” (issue #140) to the “Your data” section in Settings, the counterpart to “Export my data”: it reads a JSON file this app previously exported, on-device only, and never uploads it anywhere — the file is picked through the operating system’s own file picker (a new, disclosed permission surface: this app can now read a file you explicitly choose), parsed and validated locally, previewed (profile count, entry count, date range, and the merge policy) before anything is written, and then merged into the local store on explicit confirmation. Nothing already on the device is ever deleted or silently overwritten; a colliding entry is merged (tags combined, the heavier flow level kept, an existing note kept) and reported, not replaced. This does not add a new category of data collected — it is a second local read/write path for data this policy already covers.
  • September 9, 2026 (positioning): Reframed this policy’s product framing (issue #122): the opening summary and Core Principles (Section 1) now lead with the account, cross-device sync, and multi-guardian family sharing as the product’s priority, and describe offline operation as a reliability property rather than the product’s identity. No disclosure changed in substance — every fact that was true before (nothing uploads until you sign in, the local store is protected by the OS’s own at-rest protection, an account remains optional and a build with no cloud configuration has none) remains true; only the framing and emphasis changed. Section 2.A’s storage description was also reworded so it no longer reads as describing an app-managed “encrypted SQLite database” independent from Section 1’s OS-at-rest-protection description — the two always meant the same thing and now say so consistently.
  • September 9, 2026: Section 2.A now discloses import/device provenance (issue #159, the foundation for a future Clue/Apple Health/Health Connect import feature): entries and tracked symptoms can carry a label recording where they came from (e.g. “Imported from Clue”) and an internal key used to avoid creating duplicates when the same import is run twice. No import feature exists yet as of this date — this column exists so a future importer has somewhere to write that label — but disclosing it now, rather than only when an importer ships, keeps this policy accurate about what the schema can already record. This is a new disclosed field, not a new category of data collected: it describes how an already-disclosed entry was recorded, the same local-first storage and optional-sync rules apply, and it is never used to identify or contact anyone.
  • September 8, 2026: “Export my data” is now reachable without a cloud account (Issue #222; source B-17): it moved from the sign-in-gated Account section into a new “Your data” section in Settings that shows whenever at least one profile exists on the device, regardless of sign-in state. Signed out, the export still produces the same on-device-only document it always could (serverIncluded: false); signed in, it additionally merges the server-side section described in the Data Portability entry above (Section 8). “Delete account” is unchanged and still lives in the Account section, since account deletion is inherently account-scoped.
  • September 8, 2026: Data Portability (Section 8) now describes the server-side half of “Export my data” (Issue #248): when signed in and online, the exported file merges a server section - guardian memberships/roles, invitations and ownership transfers you created or accepted, notification preferences, registered devices (push token redacted to its last 4 characters), feedback tickets and replies, and reminder settings - into the existing local export, scoped so a shared (non-owned) profile only ever surfaces your own memberships, preferences, and self-authored entries. The local half of export is unaffected and still works fully offline.
  • September 8, 2026 (tracking model foundation): Section 2.A now discloses that individual tracked symptoms and options are stored as their own records tied to the day they were logged (issue #240), alongside flow and tags, rather than only as part of a day’s flow/tag list — this is a storage-shape change, not a new category of data collected: these values are the same kind of cycle/symptom information the app already tracked, still local-first, still covered by the same optional-sync and guardian-visibility rules.
  • September 8, 2026: Account deletion now removes the caller’s feedback-attachment screenshots from storage and deletes feedback tickets (and their reply threads) explicitly, both as fail-closed steps of account deletion itself, rather than the tickets’ removal depending only on a later step (revoking Apple, deleting the Supabase account) that could fail and the screenshots not being removed at all (issues D-24/D-25). Also added the disclosure, in Section 2.C, that submitting a ticket sends a short alert email to the operator with its own retention outside the app’s database, separate from the ticket record itself.
  • September 8, 2026: Strengthened the “Protected at Rest” principle and the “Device Encryption” security protection (issue #244): the local database moved to a directory that receives its own explicit backup handling — on iOS the app now marks the database file excluded from backup and applies the platform’s strongest file-protection class (verified on device before release); on Android the database is excluded from both cloud backup and device-to-device transfer by declaration, alongside its existing backup-off setting.
  • September 7, 2026: Removed the “No Fertility Tracking or Algorithms” Core Principle. The product owner decided (issues #123 and #142) to pursue full parity with a full cycle-tracking product, including ovulation and fertile-window estimation, so this policy no longer guarantees that fertility features will never exist. Those features do not exist in the app as of this date — today the app tracks cycles and flow and estimates the next period — and when they ship, fertility-related data and estimates will follow the same local-first protections and the same guardian-visibility and ownership-transfer rules as all other cycle data (Section 5). Conception and pregnancy features remain outside the product’s scope.
  • September 6, 2026: Added the Firebase Cloud Messaging disclosure for caregiver push alerts.
  • September 3, 2026: Initial policy.

11. Contact Information

If you have any questions, concerns, or requests regarding this Privacy Policy or the handling of your data, please contact:

William Davis (LunarLog Maintainer)
Email: will@wjdavis5.net
Repository: https://github.com/wjdavis5/lunarlog
Issues: https://github.com/wjdavis5/lunarlog/issues
Security Vulnerabilities: SECURITY.md (or email will@wjdavis5.net)