# 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.