Commit Graph

107 Commits

Author SHA1 Message Date
Daniel Volz 8e2fd0a761 chore: release v1.5.0 (#67)
* chore: release v1.4.0

* feat: timezone-aware locale formatting

- Add TIMEZONE_TO_REGION map for 50+ timezones worldwide
- Combine app language with timezone region (e.g., en + Europe/Berlin → en-DE)
- Fix times displaying in wrong timezone (treated as UTC instead of local)
- Add parseLocalDateTime() to handle ISO strings without UTC conversion
- Users now get regional formatting (24h time, local date format) regardless of app language
- Swedish user with en-SE locale now gets yyyy-mm-dd format and 24h time
- German user with en-DE locale gets dd.mm.yyyy format and 24h time
- Add missing i18n translation key 'lastSent'
- Update all getSystemLocale() calls to pass app language parameter

* chore: release v1.5.0

* fix: timezone-independent test for CI (use 14:00 instead of 22:00)

* fix: make timezone test independent of server timezone
2026-01-23 21:42:57 +01:00
Daniel Volz 8718311876 refactor(frontend): modularize App.tsx into components, pages, hooks, and context (#60)
- Extract App.tsx from 764 lines to ~404 lines
- Create reusable components: MedDetailModal, MobileEditModal, ShareDialog, etc.
- Add AppContext for global state management
- Split pages: DashboardPage, MedicationsPage, SchedulePage, SettingsPage, PlannerPage
- Create custom hooks: useAuth, useMedications, useSettings, useDoses, useSchedule
- Add utility functions in separate modules
- Fix stock status logic (>30 days = green/normal)
- Fix reminder threshold calculation (use reminderDaysBefore not lowStockDays)
- Fix takenBy validation (send [] instead of null)
- Fix datetime format for blister start times (add Z suffix)
- Style 'All OK' status as green/bold

BREAKING: None - all existing functionality preserved
2026-01-22 05:38:34 +01:00
Daniel Volz 89edd74de3 chore: release v1.4.1 (#59)
* chore: release v1.4.0

* chore: release v1.4.1
2026-01-20 19:35:00 +01:00
Copilot 3aa2b608b0 Fix missing Drizzle migrations in production Docker image (#56)
* Initial plan

* fix: Add drizzle migrations folder to production Docker image

Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>
2026-01-20 18:31:28 +01:00
Daniel Volz b68c0b0737 chore: release v1.4.0 (#51) 2026-01-18 15:14:55 +01:00
Daniel Volz 1920b47924 feat: Add About section with version info and update check (#50)
* feat: add About section with version info and update check

- Add About menu item in user dropdown
- Show frontend and backend versions separately
- Add 'Check for Updates' feature using GitHub API
- Compare versions using semver logic
- Cache update check results in sessionStorage (1 hour TTL)
- Link to GitHub repository
- Add i18n translations for EN and DE
- Extend health endpoint to return backend version

* fix: correct i18n interpolation in About modal

- Fix copyright year using dynamic interpolation
- Fix update available message (remove duplicate version placeholder)
- Add download link for available updates
- Change license to GPL-3.0

* fix: correct license to MIT

* chore: sync package.json versions to v1.3.1
2026-01-18 15:12:21 +01:00
Daniel Volz 857b1462e3 fix: include stockAdjustment in export/import (#49)
The stockAdjustment and lastStockCorrectionAt fields were not being
exported or imported, causing stock corrections to be lost when
doing an export/import cycle.

Changes:
- Add stockAdjustment to inventory schema in export validation
- Add lastStockCorrectionAt to medication export schema
- Export both fields when generating export data
- Import both fields when restoring from backup
2026-01-18 14:39:39 +01:00
Daniel Volz 75bb7abebc feat: Stock Correction Modal (#47)
* feat: add stock correction modal with blister-based input

- Add 'Correct Stock' button to medication detail modal
- New modal with Full Blisters + Partial Blister Pills inputs
- Auto-conversion for edge cases (full/negative partial)
- New stockAdjustment field for DB corrections without touching looseTablets
- New lastStockCorrectionAt timestamp to ignore old consumed doses after correction
- Tracking data preserved for future statistics
- Add Drizzle migrations for new columns
- Add translations for en/de

* fix: add stock_adjustment columns to e2e/integration test schemas
2026-01-18 12:53:25 +01:00
Daniel Volz 8d22669bef fix: export/import dismissed doses and person-specific dose IDs (#45)
- Add 'dismissed' field to dose history export/import
- Add 'takenByPerson' field to handle person-suffixed dose IDs (e.g., 5-0-timestamp-Daniel)
- Update parseDoseId() to extract person suffix from dose ID
- Update buildDoseId() to include optional person suffix

This fixes import losing:
1. Which past doses were marked as taken
2. Which doses were dismissed (cleared missed)
3. Person-specific dose tracking for shared schedules
2026-01-18 09:19:23 +01:00
Daniel Volz fb0b3df794 feat: add option to exclude images from export (#44)
- Add 'Include medication images' checkbox in export section
- Default: enabled (full backup with images)
- Disabled: much smaller export (~50 KB instead of several MB)
- Helpful for quick backups or when importing to another instance
2026-01-18 09:12:12 +01:00
Daniel Volz 48ae48a165 fix: increase body size limit for large imports (#43)
- Increase nginx client_max_body_size from 10MB to 50MB
- Add bodyLimit: 50MB to Fastify import route
- Allows importing exports with many base64-encoded images
2026-01-18 09:05:57 +01:00
Daniel Volz a190667320 fix: improve import error handling and add refill_history table migration (#42)
- Add CREATE TABLE IF NOT EXISTS for refill_history in ALTER migrations
- Improve frontend import error handling to show server errors properly
- Parse response as text first to handle non-JSON error responses
2026-01-18 08:55:48 +01:00
Daniel Volz cfdca04df9 fix: handle invalid date values in export route (#41)
Added robust date handling to prevent 'Invalid time value' errors when
exporting dose history and share links. The code now safely handles:
- Date objects that might be invalid
- Timestamps stored as numbers or strings
- Missing or null values

Falls back to current date if conversion fails.
2026-01-18 08:36:17 +01:00
Daniel Volz 42d00dd1c0 fix: add stock_calculation_mode ALTER migration for backward compatibility (#39)
Older production databases were missing the stock_calculation_mode column,
causing 500 errors on /export endpoint. Added migration to add column
with default value 'automatic'.
2026-01-18 08:23:35 +01:00
Daniel Volz 82b2be48cd feat: Add Medication Refill feature with mobile UI improvements (#30)
* feat: Add Medication Refill feature with UI improvements

- Add refill functionality to medications (add packs/loose pills)
- Add refill API endpoint with history tracking
- Add refill section in edit forms (desktop & mobile)
- Add refill modal in medication detail view
- Add refill history display with expand/collapse
- Add schedule lightbox for clicking medication images
- Improve button styling with primary/info/success classes
- Move '+ New entry' button to medication list header
- Lightbox size: 50% desktop, 90% mobile
- Update selectedMed sync after stock changes
- Migrate from schema-sql.ts to Drizzle Kit migrations

* fix: Improve mobile tooltips and refill modal layout

- Center tooltips on screen for mobile devices (fixed position)
- Close tooltips automatically when scrolling on touch devices
- Use click-based tooltip activation instead of hover on mobile
- Fix refill modal buttons to display in two rows on mobile
2026-01-17 20:39:18 +01:00
Daniel Volz 055c0dfe10 feat: Add Clear Missed Doses feature (#28)
- Add dismissed column to dose_tracking table schema
- Add POST /doses/dismiss endpoint for batch dismissing
- Add DELETE /doses/dismiss endpoint to un-dismiss all
- Add frontend dismissedDoses state and missedPastDoseIds useMemo
- Add Clear missed button with confirmation dialog
- Add CSS styles for .past-days-header and .clear-missed-btn
- Add i18n translations for en/de
- Add 5 tests for dismiss endpoints
- Update test schemas with dismissed column

Allows users to acknowledge missed doses without deducting stock.
Closes #28
2026-01-16 21:56:35 +01:00
Daniel Volz ffab9ef4da feat: Add data export/import functionality (#22)
* feat: add data export/import functionality

- Add /export and /import API endpoints with schema-independent JSON format
- Export includes: medications, dose history, settings, share links
- Uses _exportId references for medications, remapped on import
- Images exported as base64 data URLs
- Optional sensitive data inclusion (shoutrrr URLs, etc.)
- Import replaces all existing data with confirmation warning
- Add comprehensive test coverage
- Add English and German translations
- Add frontend UI in Settings page with export/import controls

* fix: correct JSX structure and TypeScript types

- Fix modal placement outside ternary expression in Settings
- Add type assertion for request.body in import route test

* docs: translate copilot-instructions to English

- Add explicit rule that English is the primary language
- Translate all German sections to English
- User may communicate in German, but all project artifacts must be English
2026-01-16 19:59:48 +01:00
Daniel Volz ed707444a2 chore: release v1.1.0 (#19) 2026-01-10 21:29:53 +01:00
Daniel Volz d0a40bde88 feat: Nagging reminders with max limit + ENV defaults for settings (#18)
* ci: prevent duplicate test runs - tests only on PRs, inline tests for builds

* docs: add testing and CI/CD documentation

* security: fix CodeQL vulnerabilities (SSRF, XSS, rate limiting)

- Add URL validation to prevent SSRF attacks on notification endpoints
  - Block private IPs (10.x, 172.16-31.x, 192.168.x, 169.254.x)
  - Block localhost and internal hostnames
  - Only allow HTTP/HTTPS protocols
- Add HTML escaping for medication names in email templates (XSS)
- Add stricter rate limiting for auth routes (5 req/15min for login/register)
- Add SSRF protection tests (405 tests total)

* security: add rate limiting to remaining auth routes

* chore: add CodeQL config to suppress rate-limit false positives

Rate limiting IS implemented via @fastify/rate-limit plugin:
- Global: 100 req/min (index.ts)
- Auth routes: 5-10 req/min via config.rateLimit option

CodeQL doesn't recognize Fastify's plugin-based rate limiting pattern.

* ci: switch to CodeQL Advanced Setup

- Add custom codeql.yml workflow
- Configure to use codeql-config.yml
- Exclude js/missing-rate-limiting rule (false positive)
  Rate limiting is implemented via @fastify/rate-limit plugin

* ci: add explicit permissions to workflows

Fixes CodeQL 'Workflow does not contain permissions' warnings.
Sets minimal 'contents: read' at top level.

* ci: add manual trigger to CodeQL workflow

* ci: add explicit permissions to all workflow jobs

* build(deps): bump esbuild, @vitest/coverage-v8 and vitest in /backend

Bumps [esbuild](https://github.com/evanw/esbuild) to 0.27.2 and updates ancestor dependencies [esbuild](https://github.com/evanw/esbuild), [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest). These dependencies need to be updated together.


Updates `esbuild` from 0.21.5 to 0.27.2
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2024.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.21.5...v0.27.2)

Updates `@vitest/coverage-v8` from 2.1.9 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/coverage-v8)

Updates `vitest` from 2.1.9 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/vitest)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.27.2
  dependency-type: indirect
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.16
  dependency-type: direct:development
- dependency-name: vitest
  dependency-version: 4.0.16
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* docs: add GitHub issue templates

- Bug report template with deployment type, browser info, logs
- Feature request template with affected area, priority
- Config with link to discussions and README
- Optimize test.yml to skip tests for non-code changes

* Initial plan

* Remove database schema duplication by creating shared schema-sql.ts module

Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>

* Refactor frontend date formatting to eliminate duplication

Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>

* docs: Add branch protection warning and PR workflow to instructions

* ci: remove paths filter from test workflow to fix branch protection

* fix: add .js extension to schema-sql imports for ESM compatibility (#15)

* feat: add setting to skip reminders for taken doses

- Add skipRemindersForTakenDoses setting to database schema
- Extend settings API to save and load new setting
- Update intake reminder scheduler to filter taken doses
- Add frontend toggle in settings with i18n (EN/DE)
- Only check doses from today (timezone-aware)
- Update all test schemas with new field
- All 405 tests passing

* feat: add repeat reminders for missed doses

- Add repeatRemindersEnabled and reminderRepeatIntervalMinutes settings
- Refactor intake reminder state from array to object with sendCount tracking
- Update scheduler to send repeated reminders at configurable intervals
- Only remind for today's doses (timezone-aware filtering)
- Add frontend toggle and interval input (5-480 minutes) in settings
- Maintain backward compatibility for old state file format
- Update all test schemas and assertions
- All 406 tests passing

* feat: add nagging reminders with max limit and ENV defaults

- Add maxNaggingReminders setting to limit repeat reminders (1-20)
- Add ENV defaults for all user settings (DEFAULT_*)
- Add ALTER TABLE migrations for backward compatibility
- Add smtpConfigured/shoutrrrConfigured to health endpoint
- Fix Push toggle to allow enabling without existing URL
- Disable skip/repeat toggles when no notifications enabled
- Add Pocket ID button to registration page
- Add getTodaysIntakes() for repeat reminder logic
- Update translations (en/de) for new settings
- Add comprehensive tests for new features

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>
2026-01-10 21:05:44 +01:00
Daniel Volz f41f6df558 fix: add .js extension to schema-sql imports for ESM compatibility (#15) 2026-01-02 15:41:58 +01:00
copilot-swe-agent[bot] 653e9e7fa8 Remove database schema duplication by creating shared schema-sql.ts module
Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>
2026-01-01 12:42:53 +00:00
dependabot[bot] 316d976349 build(deps): bump esbuild, @vitest/coverage-v8 and vitest in /backend
Bumps [esbuild](https://github.com/evanw/esbuild) to 0.27.2 and updates ancestor dependencies [esbuild](https://github.com/evanw/esbuild), [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest). These dependencies need to be updated together.


Updates `esbuild` from 0.21.5 to 0.27.2
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2024.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.21.5...v0.27.2)

Updates `@vitest/coverage-v8` from 2.1.9 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/coverage-v8)

Updates `vitest` from 2.1.9 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/vitest)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.27.2
  dependency-type: indirect
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.16
  dependency-type: direct:development
- dependency-name: vitest
  dependency-version: 4.0.16
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-30 13:54:23 +01:00
Daniel Volz 6b54ecef4f chore: add CodeQL config to suppress rate-limit false positives
Rate limiting IS implemented via @fastify/rate-limit plugin:
- Global: 100 req/min (index.ts)
- Auth routes: 5-10 req/min via config.rateLimit option

CodeQL doesn't recognize Fastify's plugin-based rate limiting pattern.
2025-12-30 12:46:05 +01:00
Daniel Volz b8d5647980 security: add rate limiting to remaining auth routes 2025-12-30 12:42:42 +01:00
Daniel Volz cb1810586d security: fix CodeQL vulnerabilities (SSRF, XSS, rate limiting)
- Add URL validation to prevent SSRF attacks on notification endpoints
  - Block private IPs (10.x, 172.16-31.x, 192.168.x, 169.254.x)
  - Block localhost and internal hostnames
  - Only allow HTTP/HTTPS protocols
- Add HTML escaping for medication names in email templates (XSS)
- Add stricter rate limiting for auth routes (5 req/15min for login/register)
- Add SSRF protection tests (405 tests total)
2025-12-30 11:52:00 +01:00
Daniel Volz ba3ebd27f4 feat: add comprehensive test suite and CI pipeline
- Add 402 unit tests with 61.7% code coverage
- Add Vitest configuration with coverage reporting
- Extract testable utility functions from services
- Create test.yml workflow (runs on PR and push to main)
- Update docker-build.yml to require tests before building
- Add scheduler-utils.ts and server-config.ts for testable code

Test files added:
- auth.test.ts, medications.test.ts, planner.test.ts
- settings.test.ts, doses.test.ts, share.test.ts
- database.test.ts, server.test.ts, services.test.ts
- env.test.ts, translations.test.ts, integration.test.ts
- e2e-routes.test.ts, stock-calculation.test.ts
2025-12-30 11:14:52 +01:00
Daniel Volz fe9310d3d4 feat: update version to 1.0.2 and rename strip terminology to blister in medication and planner routes 2025-12-30 00:07:28 +01:00
Daniel Volz 093aa419af chore: release v1.0.2 2025-12-29 23:55:00 +01:00
Daniel Volz 8132da3c3d feat: update package versions to 1.0.1, improve dose tracking timestamp logic, and enhance release script for signed tags 2025-12-29 23:54:29 +01:00
Daniel Volz 2b59233af2 chore: release v1.0.1 2025-12-29 22:34:52 +01:00
Daniel Volz f341a2aad2 feat: update package versions to 1.0.0 and enhance release script for secondary remote support 2025-12-29 22:33:23 +01:00
Daniel Volz 263033adfd feat: implement dose tracking cleanup on medication start date change 2025-12-29 22:28:18 +01:00
Daniel Volz 85c411ba88 feat: add 'and' operator import for enhanced query capabilities 2025-12-29 20:03:38 +01:00
Daniel Volz 48ee9af536 feat: update dose retrieval to remove 30-day limit and add sharedBy field in share routes 2025-12-29 20:00:25 +01:00
Daniel Volz c378d373d8 feat: enhance dose tracking with takenBy parsing and visual indicators 2025-12-29 19:31:34 +01:00
Daniel Volz 666306b416 Refactor medication model to use blisters and pills instead of strips and tabs
- Updated medication schema to replace stripsPerPack and tabsPerStrip with blistersPerPack and pillsPerBlister.
- Adjusted medication routes to handle new blister and pill structure, including calculations for total pills.
- Modified frontend components to reflect changes in medication data structure and ensure compatibility with new backend logic.
- Updated reminder scheduler and share routes to utilize the new medication model.
- Enhanced Docker configuration for better permissions handling during development.
2025-12-29 19:18:14 +01:00
dependabot[bot] 2bf5ec557f build(deps): bump nodemailer from 6.10.1 to 7.0.11 in /backend
Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 6.10.1 to 7.0.11.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v6.10.1...v7.0.11)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-version: 7.0.11
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-28 21:30:36 +00:00
Daniel Volz 69ca8fd3ba feat: implement per-person dose tracking and update migration process
- Enhanced the database migration process to ensure compatibility with existing production databases, including detailed steps for adding/modifying columns.
- Updated the client-side logic to support tracking doses taken by multiple users, including changes to the data structure and UI components.
- Added new styles for per-person dose tracking to improve user experience and visual clarity.
2025-12-28 19:47:14 +01:00
Daniel Volz 618190d20d feat(i18n): add pill emoji to medication reminder titles for better visibility 2025-12-28 18:27:32 +01:00
Daniel Volz 4a6aab338f feat: migrate taken_by to taken_by_json for multi-person support
- Added `taken_by_json` column to `medications` table to store an array of names.
- Updated migration scripts to convert existing `taken_by` data into JSON format.
- Modified backend routes to handle the new `taken_by_json` structure, including parsing and filtering logic.
- Updated frontend to support multi-value input for "Taken By" using tags.
- Adjusted validation and state management for the new array format in forms.
- Enhanced UI for displaying multiple names and added autocomplete suggestions for input.
- Updated translations for input placeholders to reflect new functionality.
- Added CSS styles for tag input components.
2025-12-28 18:22:32 +01:00
Daniel Volz abffd66e9c feat: add expiration date to share tokens and enhance error handling for expired links 2025-12-28 17:47:49 +01:00
Daniel Volz 0e52a03f7a feat: add stock calculation mode to user settings with automatic and manual options 2025-12-28 15:03:24 +01:00
Daniel Volz 78ee668c8b feat: enhance medication reminder system with improved notifications and user settings updates
- Added new translation keys for empty and low stock notifications in both English and German.
- Implemented user authentication for planner routes and improved user settings loading.
- Separated empty and low stock medications for clearer notifications.
- Enhanced email notifications with detailed alerts for empty and low stock medications.
- Updated user settings in the database when reminders are sent for both intake and stock notifications.
- Improved form validation in the frontend with character limits and error messages.
- Added CSS styles for form validation feedback and character count display.
2025-12-28 14:42:51 +01:00
Daniel Volz 30156ebd60 feat(ui): increase notes character limit to 2000 and add auto-resize functionality for textareas 2025-12-28 13:51:57 +01:00
Daniel Volz f3da765f7c feat(db): add new columns to medications and users tables for enhanced data tracking
feat(oidc): refactor setAuthCookies to use centralized cookie options for consistency
feat(nginx): update configuration to pass cookies through proxy for improved session handling
2025-12-28 02:32:45 +01:00
Daniel Volz 17a535866b feat(oidc): handle missing sub claim in token and redirect with error 2025-12-28 02:15:26 +01:00
Daniel Volz 5ad260a465 feat(auth, oidc): add user avatar URL to auth response and update redirect URLs to use frontend URL 2025-12-28 02:08:34 +01:00
Daniel Volz 3ffdb8a5fe feat(oidc): implement OIDC authentication flow and user management 2025-12-28 01:13:03 +01:00
Daniel Volz bd5c864e84 feat: add user avatar functionality and update related routes
- Implemented avatar upload and deletion in the Auth context.
- Updated UserProfile component to handle avatar display and actions.
- Modified backend routes to return anonymous user ID when auth is disabled.
- Added avatar_url column to users table in the database.
- Enhanced UI for user menu and profile modal to support avatar display.
- Updated translations for new avatar-related strings.
- Improved stock status calculation for medications in the planner.
2025-12-28 00:43:45 +01:00
Daniel Volz cfb8494be3 feat(auth): add 'remember me' functionality and token refresh logic 2025-12-27 21:59:21 +01:00