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>
3.9 KiB
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(instrings.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)
- Native, not PWA — PWA notification reliability is unacceptable for meds.
- Exact alarms (
USE_EXACT_ALARM), always gated oncanScheduleExactAlarms()with an inexact fallback;setExactAndAllowWhileIdleso Doze doesn't eat doses. - Re-arm every alarm on
BOOT_COMPLETED+MY_PACKAGE_REPLACED(state is wiped then). - Surface a one-time battery-optimisation exemption prompt — biggest cause of dropped reminders on aggressive OEMs.
- No Google Auto Backup (
allowBackup="false", excluded from cloud-backup + transfer). - 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.
- 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. - 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.
- 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