bitpill 0.3.3

A personal medication management TUI application built in Rust.
Documentation
# BitPill — Product Overview

BitPill is a medication management TUI application. Users register medications
and receive reminders at scheduled times.

> **Note:** Only the TUI is released. REST API is WIP.

---

## Project Structure

```
src/
├── domain/                    # Pure business logic (no I/O)
│   ├── entities/             # Medication, DoseRecord
│   ├── value_objects/        # Dosage, MedicationId, ScheduledTime, etc.
│   └── errors.rs             # Domain errors
│
├── application/              # Use-case orchestration
│   ├── dtos/                 # Request/Response DTOs
│   │   ├── requests.rs       # All request structs
│   │   └── responses.rs      # All response structs
│   ├── ports/                # Port traits
│   │   ├── inbound/          # Use-case ports (CreateMedicationPort, etc.)
│   │   ├── outbound/         # Repository/trait ports
│   │   └── fakes/            # Test doubles
│   ├── services/             # Use-case implementations
│   └── errors.rs             # Application errors
│
├── infrastructure/           # Concrete implementations
│   ├── clock/               # SystemClock
│   ├── notifications/       # ConsoleNotificationAdapter
│   ├── persistence/         # JSON repositories
│   └── container.rs         # Composition root
│
└── presentation/
    └── tui/                 # ratatui UI (this is what's released)
        ├── app.rs           # App state, event loop
        ├── presenters/      # Screen renderers
        ├── handlers/        # Event handlers
        ├── components/      # Reusable widgets
        └── templates/       # Layout templates
```

---

## Product Flow

```
┌─────────────────────────────────────────────────────────────────┐
│  1. User registers a medication                                 │
│     name: "Aspirin", dosage: 500 mg, times: [08:00, 20:00]     │
│                          │                                      │
│                          ▼                                      │
│  2. Medication is validated and persisted                       │
│     CreateMedicationService → MedicationRepository              │
│                          │                                      │
│                          ▼                                      │
│  3. At each scheduled time, a notification is dispatched        │
│     (timer / scheduler triggers for every ScheduledTime)        │
│                          │                                      │
│                          ▼                                      │
│  4. User takes the dose and confirms it                         │
│     MarkDoseTakenService → DoseRecordRepository                 │
│                          │                                      │
│                          ▼                                      │
│  5. DoseRecord is updated: taken_at = now                       │
└─────────────────────────────────────────────────────────────────┘
```

---

## Key Use Cases

### Register a Medication (`CreateMedicationService`)

1. Presentation collects: name, dosage in mg, list of (hour, minute) pairs.
2. Service validates each input via domain value objects.
3. A `Medication` aggregate root is created with a unique ID.
4. The medication is saved via `MedicationRepository`.
5. The saved `Medication` is returned to the caller.

**Error paths**
- Empty/whitespace name → `DomainError::EmptyMedicationName`
- Zero dosage → `DomainError::InvalidDosage`
- Invalid time (hour ≥ 24 or minute ≥ 60) → `DomainError::InvalidScheduledTime`
- Storage failure → `CreateMedicationError::Repository`

---

### Mark a Dose as Taken (`MarkDoseTakenService`)

Triggered when the user confirms they have taken a dose (e.g. after a notification).

1. A `DoseRecordId` and the actual `taken_at` timestamp are provided.
2. The service loads the `DoseRecord` from `DoseRecordRepository`.
3. `DoseRecord::mark_taken(taken_at)` is called — enforces single-take invariant.
4. The updated record is persisted.

**Error paths**
- Record not found → `MarkDoseTakenError::NotFound`
- Already taken → `MarkDoseTakenError::Domain(DoseAlreadyTaken)`
- Storage failure → `MarkDoseTakenError::Repository`

---

## Document Index

| File | Doc |
|---|---|
| `src/domain/errors.rs` | [domain/errors.md]domain/errors.md |
| `src/domain/entities/medication.rs` | [domain/entities/medication.md]domain/entities/medication.md |
| `src/domain/entities/dose_record.rs` | [domain/entities/dose_record.md]domain/entities/dose_record.md |
| `src/domain/value_objects/dosage.rs` | [domain/value_objects/dosage.md]domain/value_objects/dosage.md |
| `src/domain/value_objects/medication_name.rs` | [domain/value_objects/medication_name.md]domain/value_objects/medication_name.md |
| `src/domain/value_objects/medication_id.rs` | [domain/value_objects/medication_id.md]domain/value_objects/medication_id.md |
| `src/domain/value_objects/dose_record_id.rs` | [domain/value_objects/dose_record_id.md]domain/value_objects/dose_record_id.md |
| `src/domain/value_objects/scheduled_time.rs` | [domain/value_objects/scheduled_time.md]domain/value_objects/scheduled_time.md |
| `src/application/ports/clock_port.rs` | [application/ports/clock_port.md]application/ports/clock_port.md |
| `src/application/ports/notification_port.rs` | [application/ports/notification_port.md]application/ports/notification_port.md |
| `src/application/ports/medication_repository.rs` | [application/ports/medication_repository.md]application/ports/medication_repository.md |
| `src/application/ports/dose_record_repository.rs` | [application/ports/dose_record_repository.md]application/ports/dose_record_repository.md |
| `src/application/services/create_medication_service.rs` | [application/services/create_medication_service.md]application/services/create_medication_service.md |
| `src/application/services/mark_dose_taken_service.rs` | [application/services/mark_dose_taken_service.md]application/services/mark_dose_taken_service.md |
| `src/application/services/schedule_dose_service.rs` | [application/services/schedule_dose_service.md]application/services/schedule_dose_service.md |
| `src/infrastructure/container.rs` | [infrastructure/container.md]infrastructure/container.md |
| `src/infrastructure/clock/system_clock.rs` | [infrastructure/clock.md]infrastructure/clock.md |
| `src/infrastructure/notifications/console_notification_adapter.rs` | [infrastructure/notifications.md]infrastructure/notifications.md |