Commit Graph
54 Commits
Author SHA1 Message Date
willemjan bd66d3dacd Fix CI: downgrade artifact actions to v3 for Gitea Actions compatibility
CI/CD / test (push) Successful in 41s
CI/CD / sonarqube (push) Successful in 34s
CI/CD / build-and-scan (push) Successful in 1m56s
CI/CD / deploy (push) Successful in 17s
upload-artifact@v4/download-artifact@v4 use the newer Artifact API v2,
which Gitea's act_runner doesn't support yet (GHESNotSupportedError).
v3 uses the older, Gitea-compatible API.
2026-09-05 23:03:16 +02:00
willemjan 47050bf031 Merge pull request 'Feature/insulin profile' (#37) from feature/insulin-profile into main
CI/CD / test (push) Failing after 51s
CI/CD / sonarqube (push) Skipped
CI/CD / build-and-scan (push) Skipped
CI/CD / deploy (push) Skipped
Reviewed-on: #37
2026-09-05 20:58:07 +00:00
willemjan de0ecebce5 Merge pull request 'Feature/treatment overlays' (#36) from feature/treatment-overlays into feature/insulin-profile
willemjan/glucose-dashboard/pipeline/head This commit looks good
Reviewed-on: #36
2026-09-05 20:57:52 +00:00
willemjan caf28046cb Merge pull request 'Feature/pdf report redesign' (#35) from feature/pdf-report-redesign into feature/treatment-overlays
willemjan/glucose-dashboard/pipeline/head This commit looks good
Reviewed-on: #35
2026-09-05 20:56:48 +00:00
willemjan a4d29e85a8 Merge pull request 'Add CI test-coverage gate at 80%' (#34) from feature/ci-coverage-gate into feature/pdf-report-redesign
willemjan/glucose-dashboard/pipeline/head This commit looks good
Reviewed-on: #34
2026-09-05 20:56:20 +00:00
willemjan 7f4377329a Add CI test-coverage gate at 80%, backfill remaining logic-module gaps
willemjan/glucose-dashboard/pipeline/head This commit looks good
pytest-cov + pyproject.toml [tool.coverage.*] measure reporting.py,
nightscout_client.py, data_processing.py, pdf_export.py, profile_data.py,
ui_common.py, and auth.py; app.py and pages/*.py are omitted (thin
Streamlit UI scripts, not meaningfully unit-testable without a running
Streamlit session — the handful of similarly UI-coupled functions left
in ui_common.py/auth.py are marked "# pragma: no cover" with the same
rationale, since the logic they call into is already fully tested).

The Gitea Actions test job now runs with --cov and fails the build
below 80%; the coverage XML is uploaded as a build artifact and fed
into the SonarQube scan (closing the gap flagged in
homelab-cicd-werkinstructie.md). Backfilled a few missing branches
(get_colors() theme fallback, secondary-y-axis overlay traces) to reach
98% on the measured modules — comfortable headroom above the 80% gate.

Builds on #29/#30/#31.
2026-09-05 22:52:29 +02:00
willemjan c617f4e41b Merge pull request 'Feature/insulin profile' (#33) from feature/insulin-profile into main
CI/CD / test (push) Successful in 17s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Successful in 42s
CI/CD / deploy (push) Successful in 3s
Reviewed-on: #33
2026-09-05 20:47:43 +00:00
willemjan a10a4c0414 Merge pull request 'Feature/treatment overlays' (#32) from feature/treatment-overlays into feature/insulin-profile
Reviewed-on: #32
2026-09-05 20:47:10 +00:00
willemjan a3d89c4d21 Merge pull request 'Redesign PDF report: landscape pages, headers/footers, icon, daily stats' (#31) from feature/pdf-report-redesign into feature/treatment-overlays
Reviewed-on: #31
2026-09-05 20:45:16 +00:00
willemjan 1376101212 Merge pull request 'Add basal/bolus/carb/target overlays to Live and Dagoverzicht charts' (#30) from feature/treatment-overlays into feature/insulin-profile
Reviewed-on: #30
2026-09-05 20:44:26 +00:00
willemjan f2c3f97b1f Redesign the PDF report: landscape pages, headers/footers, icon, daily stats
Every report section now gets its own landscape A4 page (or, for
Dagoverzicht, one page per day) via a GlucoseReportPDF(FPDF) subclass
with a real header (section title, report version, insulin/pump/sensor
type from new REPORT_* env vars) and footer (page number, generation
timestamp, Nightscout link) on every page, plus an original SVG icon
in the header — inspired by the LibreView AGP report.

New "Insulineprofiel" PDF section mirrors the dashboard page (basal
bar chart, ISF/carb-ratio segments, DIA). Each Dagoverzicht day now
draws the same basal/bolus/carb/target overlays as the interactive
charts (matplotlib port of the Plotly helpers from #30) plus a new
per-day stats block (reporting.daily_stats: avg/min/max glucose,
total/basal/bolus/SMB insulin, hypo/hyper counts and durations).

Builds on #29 (profile data) and #30 (overlay logic/colors).
2026-09-05 22:44:14 +02:00
willemjan d33516e2a1 Avoid pandas Timedelta(days=1) deprecation warning
pd.Timedelta(days=1) triggers a DeprecationWarning about NumPy's
"generic" timedelta unit in this pandas version; pd.Timedelta(1, unit="D")
is equivalent and warning-free.
2026-09-05 22:38:07 +02:00
willemjan c54dcf616a Add basal/bolus/carb/target overlays to the Live and Dagoverzicht charts
willemjan/glucose-dashboard/pipeline/pr-feature/insulin-profile This commit looks good
Overlay the full insulin picture onto the interactive glucose charts:
basal rate as a semi-transparent step-area (profile schedule overridden
by active temp basal), bolus doses as size-scaled dots split into
food/correction/SMB categories (food and correction labeled with units,
SMB left unlabeled), carbs as bars, and the pump's target glucose as a
line — each with its own color, alpha, and legend entry. Shared trace-
building helpers live in ui_common.py so both pages (and the PDF report
in a follow-up PR) render identically.

Builds on the pump profile work in #29 (profile_data.py, load_profile()).
2026-09-05 22:30:10 +02:00
willemjan 6004f76d76 Merge pull request 'Add pump profile fetching and Insulineprofiel page' (#29) from feature/insulin-profile into main
CI/CD / test (push) Successful in 51s
CI/CD / sonarqube (push) Successful in 24s
CI/CD / build-and-scan (push) Successful in 2m9s
CI/CD / deploy (push) Successful in 22s
willemjan/glucose-dashboard/pipeline/head This commit looks good
Reviewed-on: #29
2026-09-05 19:43:58 +00:00
willemjan 79249958c2 Add pump profile fetching and Insulineprofiel page
willemjan/glucose-dashboard/pipeline/head This commit looks good
Fetch and parse the latest-used Nightscout profile (basal schedule, ISF,
carb ratio, DIA, targets) and show it as a new dashboard page: a list of
basal/ISF/carb-ratio segments plus a bar chart of basal rate by hour of
day. This is the data foundation for treatment overlays on the glucose
charts and the redesigned PDF report in follow-up PRs.
2026-09-05 21:37:17 +02:00
willemjan 8641022219 Merge pull request 'test jenkins' (#28) from dev into main
CI/CD / test (push) Successful in 9s
CI/CD / sonarqube (push) Successful in 22s
CI/CD / build-and-scan (push) Successful in 1m56s
willemjan/glucose-dashboard/pipeline/head Something is wrong with the build of this commit
CI/CD / deploy (push) Successful in 16s
Reviewed-on: #28
2026-08-10 21:20:28 +00:00
willemjan e08f269855 test jenkins
willemjan/glucose-dashboard/pipeline/head Something is wrong with the build of this commit
2026-08-10 23:19:27 +02:00
willemjan db3204ab58 Merge pull request 'Show estimated HbA1c in mmol/mol (IFCC) alongside % (#25)' (#27) from dev into main
CI/CD / test (push) Successful in 9s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Successful in 49s
CI/CD / deploy (push) Successful in 3s
2026-08-01 21:13:00 +00:00
willemjan b8e01fa8c9 Show estimated HbA1c in mmol/mol (IFCC) alongside the % value
Dutch lab results conventionally report HbA1c in mmol/mol rather than
DCCT/NGSP %. Adds gmi_mmol_per_mol() using the standard IFCC conversion
(Hoelzel et al. 2004) and shows it next to the existing % value on the
Samenvatting page and in the PDF summary.

Closes gitea #25.
2026-08-01 23:12:43 +02:00
willemjan 25c3fe6730 Merge pull request 'GMI trend: daily scatter + rolling average + linear trend/CI (#19)' (#26) from dev into main
CI/CD / test (push) Successful in 10s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Successful in 43s
CI/CD / deploy (push) Successful in 2s
2026-08-01 20:58:12 +00:00
willemjan 374ead70e5 Replace monthly GMI bar chart with daily scatter + rolling avg + linear trend/CI
Adds daily_gmi() and gmi_trend(): per-day GMI as scatter points, a 7-day
rolling average line, and a linear regression trend line with a 95%
confidence band (normal approximation, no scipy dependency, consistent
with the existing preference for a lean container image).

Recomputed from the already-fetched period data on each page load; the
existing 1-hour Streamlit cache on load_range_data() already avoids
repeated Nightscout calls for the same period, so no separate storage
layer is needed at the current max. 90-day report window.

Closes gitea #19.
2026-08-01 22:57:54 +02:00
willemjan d637ad39e4 Merge pull request 'Fix bolus/basal insulin categorization: split SMB from manual corrections (#20)' (#24) from dev into main
CI/CD / test (push) Successful in 9s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Successful in 40s
CI/CD / deploy (push) Successful in 3s
2026-08-01 20:53:10 +00:00
willemjan 9e11dd8d73 Fix bolus/basal insulin categorization: split SMB from manual corrections, add basal calc
AndroidAPS records an automatic SMB micro-bolus as eventType "Correction
Bolus" with type "SMB", not as its own eventType. bolus_stats() was
grouping by eventType alone, so every SMB was silently counted as a manual
correction bolus. Verified against production data: 100% of "Correction
Bolus" treatments over 90 days were actually type=SMB.

Also adds basal_stats(), computing delivered basal directly from Temp
Basal treatments (rate x duration) without needing the pump profile.

Closes gitea #20.
2026-08-01 22:52:54 +02:00
willemjan 5addd6a49b Merge pull request 'Add TIR bar/threshold lines, Dagoverzicht + hypo/hyper Level-1 charts to PDF (#14, #15, #16, #17, #18)' (#23) from dev into main
CI/CD / test (push) Successful in 9s
CI/CD / sonarqube (push) Successful in 23s
CI/CD / build-and-scan (push) Successful in 42s
CI/CD / deploy (push) Successful in 3s
2026-08-01 20:48:51 +00:00
willemjan 441bb84212 Add TIR bar/threshold lines, Dagoverzicht charts, and hypo/hyper Level-1 charts to PDF export
Closes gitea #14 (PDF part), #15 (PDF part), #16, #17, #18.
2026-08-01 22:33:45 +02:00
willemjan 95f006078f Merge pull request 'Add clinical threshold lines + TIR stacked bar chart (#14, #15)' (#22) from dev into main
CI/CD / test (push) Successful in 7s
CI/CD / sonarqube (push) Successful in 21s
CI/CD / build-and-scan (push) Successful in 41s
CI/CD / deploy (push) Successful in 2s
2026-08-01 20:28:23 +00:00
willemjan 00fb81b283 Add clinical threshold lines to AGP/Dagoverzicht charts, TIR stacked bar to Samenvatting
Closes gitea #14, #15.
2026-08-01 22:26:26 +02:00
willemjan 4bb9251d7d Merge pull request 'Fix treatments API pagination cursor field (created_at, not date)' (#21) from dev into main
CI/CD / test (push) Successful in 8s
CI/CD / sonarqube (push) Successful in 19s
CI/CD / build-and-scan (push) Successful in 41s
CI/CD / deploy (push) Successful in 3s
2026-08-01 19:43:40 +00:00
willemjan 699848b479 fix: treatments endpoint needs a created_at cursor, not date
Investigated the "only ~4 days of treatments" report via direct
MongoDB access (issue #13): the collection has 123k+ documents, no
capping, no TTL index — the full year of history is in the database.

The actual cause: /api/v1/treatments.json filters/sorts on the string
field `created_at`, not the numeric `date` field /api/v1/entries uses.
Paginating with find[date][$lte] (or no filter at all) silently caps
treatments to an internal ~4-day window even though every document has
a valid `date` field; find[created_at][$lte] correctly walks back
through the full history.

_paginated_get() now takes an explicit cursor_field per endpoint and
always sends the cursor from the first request (never omitted), so
that hidden default window can't trigger. Verified against the real
instance: a 92-day treatments fetch now returns 39,403 rows (was ~700).
2026-08-01 21:43:08 +02:00
willemjan 6c6b175a28 Merge pull request 'Fix multi-day Nightscout fetch truncation + data-completeness warnings' (#12) from dev into main
CI/CD / test (push) Successful in 7s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Successful in 41s
CI/CD / deploy (push) Successful in 3s
2026-07-31 12:22:10 +00:00
willemjan 55883480c0 docs: record FR1 findings and add profile-tuning design spec
requirements-profile-tuning.md: document the LXC 102/107 investigation
outcome (LXC 102's houthacker/nightscout-autotune image already solves
both the analysis and NS-upload directions) and resolve the two open
questions this depended on.

design-profile-tuning.md: full design spec for the separate
glucose-profile-tuning app/service, reviewed and approved.
2026-07-31 14:21:46 +02:00
willemjan 29d20ca441 fix: Nightscout API silently truncated multi-day fetches to ~3-4 days
_entries_since/_treatments_since requested a single page via `count`,
but Nightscout's /api/v1/entries and /api/v1/treatments ignore a large
`count` and cap the response around ~1150/~700 documents regardless of
how far back the requested period goes. Every report page relying on
fetch_entries_range/fetch_treatments_range (7/14/30/90-day selectors)
was silently only getting the most recent ~3-4 days, no matter the
selected period.

Fixed by paginating with `find[date][$lte]` cursors in a new
_paginated_get(), walking back until the requested `since` boundary is
reached or the server returns a short/empty page (= genuinely no more
data, confirmed by manually paginating against the real instance:
entries go back 50+ days, treatments only ~4 days on this install).

Also added reporting.completeness_warning(), shared by the interactive
pages (via ui_common.render_completeness_warning) and the PDF export,
that distinguishes "a structural gap at the start of the period" (data
wasn't fetched/available) from "scattered gaps below the clinical AGP
coverage threshold" (Danne et al. 2017) — the previous single generic
"X% sensor coverage" message read as a CGM/sensor problem even when
the real cause was this fetch bug.
2026-07-31 14:21:35 +02:00
willemjan c39646ceaa Merge pull request 'PDF export (FR10) - completes reporting requirements' (#10) from dev into main
CI/CD / test (push) Successful in 11s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Successful in 1m58s
CI/CD / deploy (push) Successful in 14s
2026-07-26 19:11:06 +00:00
willemjanandClaude Sonnet 5 fe6a471f17 add PDF export (FR10)
pdf_export.py builds a PDF report (summary stats, AGP chart, hypo/hyper
event summaries) via fpdf2 + matplotlib rather than plotly's kaleido, to
avoid bundling a Chromium build into the image just for this. The Export
page lets the user pick which sections to include and a date range, then
download the result to send to the hospital team.

This completes all ten functional requirements in
docs/requirements-reporting.md.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-26 21:10:46 +02:00
willemjan 52c9284f85 Merge pull request 'Trends page: GMI trend, weekday pattern, bolus, site-age (FR7, FR8)' (#9) from dev into main
CI/CD / test (push) Successful in 6s
CI/CD / sonarqube (push) Successful in 18s
CI/CD / build-and-scan (push) Successful in 40s
CI/CD / deploy (push) Successful in 4s
2026-07-26 19:06:24 +00:00
willemjanandClaude Sonnet 5 9929f44daa add Trends page: GMI trend, overnight/daytime, weekday pattern, bolus, site-age (FR7, FR8)
reporting.py gains overnight_daytime_split, day_of_week_pattern,
bolus_stats, and site_interval_stats. The last two are explicitly scoped
to bolus-only insulin (no basal reconstruction) since that needs the
Nightscout profile, which is the separate profile-tuning feature's
territory — documented as a caveat in both the UI and the design doc.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-26 21:06:06 +02:00
willemjan 419508dd5e Merge pull request 'Dagoverzicht + Hypo/Hyper Events pages (FR4, FR5, FR6)' (#8) from dev into main
CI/CD / test (push) Successful in 5s
CI/CD / sonarqube (push) Successful in 17s
CI/CD / build-and-scan (push) Successful in 44s
CI/CD / deploy (push) Successful in 3s
2026-07-26 18:13:56 +00:00
willemjanandClaude Sonnet 5 04c5f521fe add Dagoverzicht, Hypo Events, and Hyper Events pages (FR4, FR5, FR6)
Dagoverzicht stacks one glucose trace per calendar day (small multiples
via a shared 0-24h x-axis). The two event pages share a new
render_event_level() helper in ui_common.py so Level 1/Level 2 hypo and
hyper are rendered identically: count/avg/longest/events-per-week
metrics, a time-of-day histogram, and a table of individual events.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-26 20:13:38 +02:00
willemjan 689452cf4c Merge pull request 'Samenvatting + AGP Profiel pages (FR2, FR3, FR9)' (#7) from dev into main
CI/CD / test (push) Successful in 6s
CI/CD / sonarqube (push) Successful in 22s
CI/CD / build-and-scan (push) Successful in 47s
CI/CD / deploy (push) Successful in 3s
2026-07-26 18:09:41 +00:00
willemjanandClaude Sonnet 5 1207ff536f add Samenvatting and AGP Profiel pages (FR2, FR3, FR9)
Wires reporting.py's stats into two new pages: a summary panel (data
completeness, GMI, %CV, 5-band time-in-range vs. consensus targets) and
the standard AGP percentile chart (5th-95th and 25th-75th bands plus
median, aggregated by time-of-day across the selected period).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-26 20:09:25 +02:00
willemjan e600d6cf7d Merge pull request 'Reporting foundation: multipage nav, auth gate, date-range fetch' (#6) from dev into main
CI/CD / test (push) Successful in 6s
CI/CD / sonarqube (push) Successful in 17s
CI/CD / build-and-scan (push) Successful in 38s
CI/CD / deploy (push) Successful in 3s
2026-07-26 18:01:15 +00:00
willemjanandClaude Sonnet 5 3ef9a7666a add reporting foundation: multipage nav, auth gate, date-range fetch
First increment of the clinical reporting feature (see
docs/requirements-reporting.md and docs/design-reporting.md): moves the
existing live view to pages/1_Live.py, adds a password gate since the
dashboard URL will be shared with the diabetes team, adds
fetch_entries_range/fetch_treatments_range for multi-day report queries,
and adds reporting.py with the core clinical calculations (GMI, %CV,
5-band time-in-range, hypo/hyper event detection per the Battelino et al.
2019 persistence rule). No report pages wired up yet — that's next.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-26 20:00:48 +02:00
willemjan 10aa315e40 Merge pull request 'Pin trivy-action to last docker-based release' (#5) from dev into main
CI/CD / test (push) Successful in 6s
CI/CD / sonarqube (push) Successful in 19s
CI/CD / build-and-scan (push) Successful in 57s
CI/CD / deploy (push) Successful in 19s
2026-07-26 12:54:59 +00:00
willemjanandClaude Sonnet 5 7379f6be8c pin trivy-action to the last docker-based release
@master resolves to a version that installs Trivy via a nested
setup-trivy composite action, which does an actions/checkout against
github.com with a token. On Gitea's act_runner that fails with "Input
required and not supplied: token" even when the token is explicitly
set to an empty string (act_runner doesn't distinguish empty from
unset). v0.26.0 introduced that composite/setup-trivy split; v0.25.0
is the last release that ships as a self-contained Docker image with
Trivy already baked in, so it needs no token at all.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-26 14:54:43 +02:00
willemjan e3443e9f9f Merge pull request 'Fix registry hostname (duckdns) and Trivy github auth' (#4) from dev into main
CI/CD / test (push) Successful in 6s
CI/CD / sonarqube (push) Successful in 20s
CI/CD / build-and-scan (push) Failing after 10s
CI/CD / deploy (push) Skipped
2026-07-25 20:05:33 +00:00
willemjanandClaude Sonnet 5 e0d6b79e68 use the working duckdns hostname for the registry, fix trivy github auth
gitea.zb.local resolves but is plain HTTP, which Docker refuses as a
registry without daemon-level insecure-registry config. gitea.zb.lan
resolves but nothing answers there yet (proxy not configured for it).
gitea.zb-kw.duckdns.org is confirmed reachable end-to-end over HTTPS,
including the registry v2 API, from both the runner and the deploy
target, so use that consistently. Also fix aquasecurity/trivy-action's
token-setup-trivy input, which defaults to gitea.token and gets
rejected by github.com when it tries to clone the install script.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-25 22:02:53 +02:00
willemjan d6107515c0 updated sonarqube scan action version 2026-07-25 21:22:18 +02:00
willemjan 274d27c5bc Merge pull request 'Fix pytest module discovery in CI' (#3) from dev into main
CI/CD / test (push) Successful in 5s
CI/CD / sonarqube (push) Successful in 1m17s
CI/CD / build-and-scan (push) Failing after 4m37s
CI/CD / deploy (push) Skipped
2026-07-25 19:12:20 +00:00
willemjanandClaude Sonnet 5 566a817365 fix pytest module discovery in CI
CI invokes the pytest console script directly (pytest tests/ -v), which
unlike `python -m pytest` does not add the repo root to sys.path. That
broke imports of the top-level data_processing/nightscout_client
modules from the test files. Add pythonpath = ["."] so it works
regardless of invocation style.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-25 21:09:48 +02:00
willemjan f17e4f6c39 Merge pull request 'Nightscout-koppeling + CI/CD-fixes' (#2) from dev into main
CI/CD / test (push) Failing after 49s
CI/CD / sonarqube (push) Skipped
CI/CD / build-and-scan (push) Skipped
CI/CD / deploy (push) Skipped
2026-07-25 07:30:10 +00:00
willemjanandClaude Sonnet 5 e805dc9194 fix registry hostname and load .env automatically
gitea.thuis.local doesn't resolve on this network; the real internal
Gitea hostname is gitea.zb.local. Also load .env via python-dotenv so
the app works the same under PowerShell as bash, and add .dockerignore
so .env never ends up baked into the image.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-25 09:29:43 +02:00
willemjan 60735de445 added getting data from nightscout 2026-07-25 08:54:08 +02:00
willemjan c02110a82b first commit 2026-07-24 07:49:59 +02:00
willemjan edb261ee5c Initial commit 2026-07-23 14:38:33 +00:00