med-det-samme/CLAUDE.md
Ole-Morten Duesund 7256c49112 Project skeleton: Gradle 9.4.1 wrapper, AGP 9.2.1, Compose, manifest with reminder permission set
Milestone 1 of the build brief. Version catalog pins verified against
Maven Central / Google Maven on 2026-06-10; Kotlin held at 2.3.10 to
match AGP 9.2's bundled KGP (built-in Kotlin) because KSP has no
Kotlin 2.4 release yet. compileSdk 37 (forced by core-ktx 1.19),
targetSdk 35 per brief. allowBackup=false + full dataExtractionRules
opt-out; own encrypted backup comes in milestone 5.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 13:31:39 +02:00

3.9 KiB

«Med det samme» — Claude Code project memory

Local-first Android medication reminder. My personal MyTherapy replacement: no ads, no account, no analytics, no cloud service of yours. Single user, single device. Reminders are the entire point — reliability beats polish wherever they trade off. The name says the brief: nag me to take the dose now.

  • Package / applicationId: no.naiv.meddetsamme
  • Display name: Med det samme (in strings.xml, referenced from the manifest)
  • minSdk 26, targetSdk 35, JVM 17, Kotlin + Compose (Material3)
  • Stack: Room (+KSP), WorkManager, OkHttp, security-crypto, kotlinx-serialization. Gradle Kotlin DSL + version catalog. No AWS SDK, no DI framework.

Working agreement

  • Senior dev, Linux host. Be concise; explain why for non-obvious choices in a line or two (XAI, not essays). 24h clocks everywhere.
  • Never claim it builds without running the build. Verify; don't assert.
  • Verify current stable library versions yourself before bumping — don't trust memory.
  • Smallest change that works. No speculative abstraction.
  • Ask before anything irreversible (schema migrations, data deletion).
  • This is a medication app: wrong schedule/dose math is a real harm. Keep schedule logic pure and unit-tested before anything depends on it.

Decisions — don't relitigate (flag and wait if you think one's wrong)

  1. Native, not PWA — PWA notification reliability is unacceptable for meds.
  2. Exact alarms (USE_EXACT_ALARM), always gated on canScheduleExactAlarms() with an inexact fallback; setExactAndAllowWhileIdle so Doze doesn't eat doses.
  3. Re-arm every alarm on BOOT_COMPLETED + MY_PACKAGE_REPLACED (state is wiped then).
  4. Surface a one-time battery-optimisation exemption prompt — biggest cause of dropped reminders on aggressive OEMs.
  5. No Google Auto Backup (allowBackup="false", excluded from cloud-backup + transfer).
  6. Own backup: versioned JSON → encrypted → S3-compatible PUT to self-hosted Garage, path-style, hand-rolled SigV4. One serializer for export, import, and auto-backup.
  7. Crypto target is age (passphrase/scrypt) so backups are age -d-decryptable and never lock me into this app. JCE AES-GCM is the baseline behind an interface; verify age against the age test vectors before trusting it.
  8. FEST, not Felleskatalogen, and not as a live API: its open Rekvirent extract is a SOAP/WCF M30 XML dump. The phone reads a slim pre-flattened JSON synced from my server (that job lives outside this repo) and does autocomplete offline.
  9. Refill is derived from inventory + consumption. Prescription renewal (rxExpiryEpochDay, refillsRemaining) is tracked separately from stock.

Load-bearing — change with care

  • The reminder subsystem is the reliability core. After any change, re-verify: alarms re-arm on boot/update, escalation cancels on Taken, the next occurrence is always armed, Taken decrements inventory.
  • Escalation contract: due dose → PENDING log + notify, re-nag every 10 min (cap ~6 / ~1 h) until Taken or Snooze; Snooze pushes the next nag 15 min and stays PENDING.
  • The S3 SigV4 signer: if a PUT fails it's almost always clock skew or a non-path-style endpoint, not the maths. Don't "fix" the signer first.
  • The schedule engine is pure — add tests here before touching the math.

Out of scope — don't add without asking

Caregiver/"Team" alerts, multi-profile, Health Connect, streaks/gamification, injection-site tracking, symptom/mood diary. (Modelling "trackable" generically is fine if cheap; build no diary UI.)

Commands

  • Build debug: ./gradlew assembleDebug
  • Unit tests: ./gradlew test
  • Lint: ./gradlew lint