# Data Goblin Plan

This is the high-level development plan for **Data Goblin**, a small personal logging system with a SQLite core and a fast CLI.

## v0.1 Goal

Make `dgob` usable for daily manual logging.

```text
v0.1 = I can use dgob every day instead of my Markdown file.
```

No weather sync, REST API, charts, or markdown import yet.

## v0.1 Scope

### Include

- `dgob version`
- `dgob init`
- `dgob add`
- `dgob symptom`
- `dgob event`
- `dgob coffee`
- `dgob painkiller`
- `dgob today`
- `dgob show DATE`
- `dgob events`
- SQLite schema creation
- simple friendly CLI output

### Exclude For Now

- SMHI weather integration
- blood pressure logging
- REST API
- markdown import
- correlations/statistics
- full TUI
- authentication/users

## v0.1 Database Tables

### `daily_log`

One row per day.

Fields:

- `date`
- `mood`
- `sleep_quality`
- `slept_hours`
- `notes`
- `created_at`
- `updated_at`

### `daily_symptom`

Daily symptom severity values.

Examples:

- `tooth_comfort`
- `headache`
- `jaw_tension`

Fields:

- `id`
- `date`
- `symptom`
- `severity`
- `notes`
- `created_at`

### `event`

Timestamped things that happened.

Examples:

- `coffee +1 cup`
- `painkiller +1 dose`
- `walk 25 min`

Fields:

- `id`
- `timestamp`
- `kind`
- `amount`
- `unit`
- `notes`
- `created_at`

### `schema_version`

Tracks database schema version for future migrations.

## Suggested Commands

### Initialize Database

```sh
dgob init
```

### Add Or Update Daily Log

```sh
dgob add --mood 7 --sleep 6.5 --sleep-quality 6 --notes "jaw annoying"
dgob add --date 2026-05-05 --mood 7
```

### Add Daily Symptom

```sh
dgob symptom tooth_comfort 4
dgob symptom headache 2 --notes "started after lunch"
```

### Add Events

```sh
dgob event coffee
dgob event painkiller
dgob event walk --amount 25 --unit min
```

### Convenience Aliases

```sh
dgob coffee
dgob painkiller
```

### Show Data

```sh
dgob today
dgob show 2026-05-05
dgob events # defaults to today
dgob events --date 2026-05-05
```

## Database Path Priority

Planned lookup order:

1. `--db ./path/to/goblin.db`
2. `DATA_GOBLIN_DB`
3. default path: `~/.local/share/data-goblin/goblin.db`

## Project Structure Idea

```text
src/
  main.odin

  dgob/
    db.odin
    schema.odin
    daily.odin
    symptom.odin
    event.odin
    query.odin
    time.odin
    ui.odin
```

## v0.1 Acceptance Checklist

The following flow should work:

```sh
dgob init

dgob version

dgob add --mood 7 --sleep 6.5 --sleep-quality 6 --notes "jaw annoying"
dgob symptom tooth_comfort 4
dgob coffee
dgob coffee
dgob event walk --amount 25 --unit min

dgob today
dgob show 2026-05-05
dgob events --date 2026-05-05
```

Expected database result:

```text
one daily row
one symptom row
three event rows
```

## Future Milestones

### v0.2 Markdown Import

- Import existing Markdown logs.
- Preserve raw data where parsing is uncertain.
- Report import issues instead of silently discarding data.

### v0.3 Blood Pressure

- Add dedicated blood pressure table.
- Support multiple readings per day.
- Track systolic, diastolic, pulse, posture, arm, and notes.

### v0.4 SMHI Weather Sync

- Fetch daily weather and pressure data from SMHI Open Data (no authentication required, CC BY 4.0).
- Store daily pressure average/min/max.
- Later support hourly observations.

#### SMHI API Notes (researched 2026-05-06)

The old PMP3gv2 API was shut down on 2026-03-31 and returns HTTP 404.
Use the replacement: **SNOW1gv1**.

Endpoint:

```
GET https://opendata-download-metfcst.smhi.se/api/category/snow1g/version/1/geotype/point/lon/{LON}/lat/{LAT}/data.json
```

Key response fields (under `timeSeries[n].data`):

| Field | Unit | Notes |
|---|---|---|
| `air_pressure_at_mean_sea_level` | hPa | Main pressure field |
| `air_temperature` | °C | |
| `relative_humidity` | % | |
| `symbol_code` | integer 1–27 | Weather condition |
| `wind_speed` | m/s | |

- All times in the response are UTC. Time key is `time` (not `validTime` as in the old API).
- Missing values use `9999` as sentinel — filter these out.
- Coordinates in the response are flat `[lon, lat]` (not nested `[[lon, lat]]`).
- Use `referenceTime` from the response body instead of the removed `approvedtime.json` endpoint.
- No hard rate limit, but SMHI's terms ask you to cache responses and avoid redundant fetches.
  A once-daily fetch at sync time is well within acceptable use.
- Fetch once per day; take `timeSeries[0].data.air_pressure_at_mean_sea_level` for near-current pressure.

### v0.5 Summary Views And Export

- Add joined daily summary view.
- Export CSV for external analysis.

### v0.6 Simple Analysis

- Basic stats.
- Simple correlations.
- Pressure delta vs symptom severity.

### v0.7 REST API

- Add thin HTTP API over the same core logic.
- Keep business logic out of the server layer.

### v0.8 Withings Integration

- OAuth authentication against the Withings Public API (no enterprise contract required).
- Store access token and refresh token in a new `integration_config` table.
- Implement token refresh automatically on expiry.
- New command: `dgob withings auth` — opens OAuth URL in browser, captures callback, stores tokens.
- New command: `dgob withings sync` — pulls data since last sync using `lastupdate` cursor.
- Sync cursor stored in `integration_config` to support incremental updates.

#### Data to sync

- **Weight and body composition** (`measure?action=getmeas`) → `measurements` table.
- **Blood pressure and heart rate** (`measure?action=getmeas`) → `measurements` table (feeds into v0.3 data).
- **Sleep summary** (`sleep?action=getsummary`) → sleep fields in `daily_log` (duration, stages, HRV, score).
- **Daily activity** (`measure?action=getactivity`) → `event` rows (steps, calories, distance).

#### Notes

- Withings Public API is free for personal use with no contract.
- OAuth callback can use a local `http://localhost:PORT/callback` for CLI use.
- Available biomarkers depend on which Withings devices you own.
- Rate limit on the free tier: 120 requests per minute, up to 5 000 users.

## Notes

Keep the goblin small at first.

Build the logging habit before building the observatory.