Commit graph

66 commits

Author SHA1 Message Date
787bc1416b feat(sync): DataSync-Modul mit getesteter Reconcile-Logik 2026-07-07 15:54:32 +02:00
8459aaed1d chore: lokale data/ (Dev-DB + Backups) ignorieren 2026-07-07 15:52:49 +02:00
97e58903b8 feat(backend): automatisches taegliches SQLite-Online-Backup 2026-07-07 15:50:34 +02:00
45503f03ee feat(backend): GET/PUT /api/state mit Dokument-Persistenz 2026-07-07 15:46:48 +02:00
9714d845bb feat(backend): SQLite-Schicht mit WAL, Dokumenten und Historie 2026-07-07 15:43:30 +02:00
3b0632c4b9 feat(backend): Express-Server liefert statisch + /api/health 2026-07-07 15:40:06 +02:00
4eed9d0c4c refactor(variants): extract shared ineligible/pay/deduct helpers
V1/V2/V3 duplicated the empty-result shape, the paid-shares/bonus math
and the Friday-priority deduction loop. Pull them into ineligibleResult,
payResult and deductInOrder; each variant keeps only its distinct
threshold, eligibility test and deduction slots.

paidShares is now computed uniformly as max(0, classified - deduction);
never-deducted slots carry deduction 0, so the result is byte-identical
(verified against a 13122-case golden master over the full input grid).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:47:57 +02:00
88cc0553f6 refactor(variants): drop unused isWinner flag on variant results
Each variant emitted isWinner:false and the calculator set winner.isWinner
=true, but the UI marks the winner via variantId===winnerId, never the
flag. Only one test read it. Removed from the 6 variant returns, the empty
result, and the calculator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:45:15 +02:00
cb46e8fb04 refactor(calculator): drop unused dutyDetails/totalDuties result fields
No UI reads them - app.js computes its own labels via isQualifyingDay/
getDayTypeLabel when rendering the duty list. Only the test-suite asserted
them; those asserts are removed too. buildDutyDetails goes with them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:43:09 +02:00
bbc8690a0b refactor(image-import): extract resolveEntryName, dedupe resolution
groupEntriesByResolvedEmployee and resolveImports carried an identical
resolvedNames -> ignore/new/assign branch. One helper returning
{resolved, isNew}; callers keep their own null/newEmployee handling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:41:39 +02:00
de2befde7a refactor(app): extract getVacationMapForMonth, dedupe 4x vacation loop
The "loop employees -> getVacationMode -> calculateAllEmployees" block
was copy-pasted in calculateBonuses, generateEmailReport, exportCSV and
exportBonusReport. Collapse to one storage helper. Behaviour identical:
calculateAllEmployees only reads keys present in employeeDuties.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:40:06 +02:00
7efdcbe17b refactor(storage): drop unreachable try/catch in getDutiesForMonth
new Date() and the object spread never throw; the isNaN guard already
drops invalid dates via the .filter(). The inner catch could never fire.
Outer boundary try/catch is kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:38:12 +02:00
91565741a8 refactor(holidays): remove dead getHolidaysForYear
Zero callers across app, calculator, image-import and tests. Holiday
lookup goes through isHoliday/getHolidayName only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:37:36 +02:00
4d8437e508 docs: drop two more false-positive TODO entries
- Same-day duty overwrite: addDuty is keyed per employee+date, so a
  split Saturday duty between two employees creates two independent
  0.5 entries, not a conflict. Not a bug.
- Holiday cutoff 2030: not a current priority, dropped per user call.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 21:08:04 +02:00
9276e8c64d docs: correct TODO.md - tie-breaker was already fixed, not a bug
The eligible-over-ineligible tie-break in calculateMonthlyBonus was a
deliberate fix (commit c733c3e) covered by an explicit test
(test-suite.js:191-203). Flagging it as an open bug in TODO.md was a
misreading of calculator.js against the design spec's simplified
pseudocode; the spec's own test plan (section 12.5) and the actual
test suite confirm the current behavior is correct.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 20:23:13 +02:00
3598a4de9e docs: add TODO.md with known bonus-calculation gaps
Tie-breaker in calculateMonthlyBonus deviates from spec section 5,
same-day duties overwrite instead of summing, and holiday data only
covers 2025-2030.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 19:58:42 +02:00
722f961387 chore: cleanup dead code and duplicated logic from audit
- Remove broken webpack.yml (no package.json/webpack config exists)
- Drop dead RATE_NORMAL/RATE_WEEKEND fields on BonusCalculator; share the
  real rate constants across all three variants in variants.js
- Simplify getEmptyResult() to build allResults via .map instead of
  three manual spreads
- Replace 5 duplicated German month-name arrays and 2 weekday-name
  arrays in app.js with a shared monthName()/WEEKDAY_NAMES helper;
  drop the now-redundant getMonthName() method
- Reuse existing .modal/.modal-backdrop/.modal-content CSS classes in
  generateEmailReport() instead of hand-rolled inline styles
- Delegate ImageImporter.classify() to the shared classify() in
  variants.js instead of a duplicated copy
- Unify ad hoc YYYY-MM-DD formatting in app.js to use the existing
  HolidayProvider.formatDate() helper

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 19:23:14 +02:00
a6be57e964 chore: remove enterprise standards adoption boilerplate
Multi-tenant deploy policies, container/Quadlet hardening rules, and
ADR/SOP templates don't fit a single-maintainer static-site app with
one Dockerfile and no container orchestration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 19:11:33 +02:00
5d8f7759d9 Merge pull request 'chore: adopt engineering standard v1.0.0' (#1) from chore/adopt-standards-v1.0.0 into main
Some checks failed
NodeJS with Webpack / build (22.x) (push) Has been cancelled
ci / standards-gate (push) Has been cancelled
NodeJS with Webpack / build (18.x) (push) Has been cancelled
NodeJS with Webpack / build (20.x) (push) Has been cancelled
2026-07-05 18:49:09 +02:00
9c0dc7b4e1 chore: adopt engineering standard v1.0.0
Some checks failed
ci / standards-gate (pull_request) Has been cancelled
NodeJS with Webpack / build (18.x) (pull_request) Has been cancelled
NodeJS with Webpack / build (20.x) (pull_request) Has been cancelled
NodeJS with Webpack / build (22.x) (pull_request) Has been cancelled
Adopt the org engineering standard (its-consulting/standards @ v1.0.0).

Adds baseline governance/CI/policy files rendered from the standard's
templates and pins .standards-version=1.0.0. Vendored OPA/Rego policies
under .standards/policies/ so CI runs the gate locally (no cross-repo dep).
Placeholders ({{ORG}}/{{REPO}}/{{OWNER_HANDLE}}/{{MAINTAINER_EMAIL}}) filled in.
Existing files that differ were left untouched by the adopter.

Automated rollout. Files created: 16.
2026-07-01 19:32:52 +02:00
262be954bb chore: remove implementation plans for shipped features
The bild-import and bonus-varianten plans were step-by-step build guides
consumed during implementation. Both features are merged and live.
Design specs in docs/specs/ stay for reference.
2026-05-12 19:36:22 +02:00
a92bf00d38 docs: replace Railway deployment section with Hetzner setup
Live URL, server details, container/network setup, Caddy block, and
update procedure for the self-hosted deployment.
2026-05-12 19:16:05 +02:00
9a26d8b9ef Merge feature/bonus-varianten: 3 variants + vacation + date-stepper
Conflicts resolved:
- sw.js: bumped CACHE_NAME to dienstplan-pro-v4 (was v3 + v2). Both
  variants.js and image-import.js are in ASSETS.
- storage.js: kept STORAGE_KEY_DUTIES + STORAGE_KEY_VACATION (Feature B)
  alongside STORAGE_KEY_OPENROUTER_KEY/MODEL + DEFAULT_MODEL (Feature A).
- styles.css: appended Feature B variants/vacation/date-stepper rules
  after Feature A modal/key rules; both blocks coexist.
2026-05-12 18:45:31 +02:00
408c30b4e3 Merge feature/bild-import: Bild->Dienste import via OpenRouter Vision 2026-05-12 18:42:48 +02:00
f69a36f2f0 fix(app): expose app instance on window so image-import.js init finds it
`let app` at top level does not create a window property, so the
DOMContentLoaded handler in image-import.js found window.app undefined
and never instantiated window.imageImporter. Clicking the Bild-Import
button then showed the 'Bild-Import nicht verfuegbar' toast.

Set window.app explicitly after construction.
2026-05-12 18:41:07 +02:00
c733c3ed02 fix(calculator): prefer eligible variant over ineligible at bonus-tie
Winner-picker used strict > with lowest-variantId tie-break, which made
V1 (ineligible) win over V3 (eligible) when all variants produced bonus=0
on Sa+So-only duties. Now ties prefer the eligible variant, keeping the
lowest-variantId rule as a sub-tie-breaker.
2026-05-12 18:36:24 +02:00
49b3b53878 chore(pwa): bump cache to v2, include variants.js, evict old caches 2026-05-12 18:27:24 +02:00
016ce93979 feat: add date-stepper buttons (Feature C) clamped to selected month 2026-05-12 18:27:06 +02:00
ba219ce0eb docs: settings info-box explains V1/V2/V3, auto-select, vacation mode 2026-05-12 18:25:39 +02:00
2e05067ce0 chore(pwa): bump cache to v3, precache image-import.js, evict old caches on activate 2026-05-12 18:25:16 +02:00
1407696adb refactor: CSV/HTML/email exports read winner.* from new variants shape 2026-05-12 18:25:07 +02:00
7839fd67d7 test(image-import): pin error-toast strings for HTTP/parse/network errors 2026-05-12 18:24:45 +02:00
e3a8ae2d7b feat(settings): add Bild-Import (KI) section with key management and model picker 2026-05-12 18:24:21 +02:00
3b6283ced1 feat(image-import): add resolveImports (pure) and commitImport persisting duties via DataStorage 2026-05-12 18:23:27 +02:00
15bf520bc1 feat: result card shows winner banner, all-variants details, vacation toggle 2026-05-12 18:23:11 +02:00
801757b92c feat(image-import): add renderPreview + Stage 3 grouping, unknowns, slot badges, remove-row 2026-05-12 18:22:37 +02:00
c43675478b feat(image-import): add runRecognition pipeline (compress, call, parse, dedupe, match) + Stage 2 cancel 2026-05-12 18:22:07 +02:00
34e9e67f6d feat: pass vacationMap from storage to calculateAllEmployees 2026-05-12 18:22:06 +02:00
6c536995b6 feat(image-import): add modal markup, CSS, and Stage 1 file/drop/camera wiring 2026-05-12 18:21:46 +02:00
68f35d3e3d feat: add dienstplan_vacation key + getVacationMode/setVacationMode + export/import 2026-05-12 18:21:31 +02:00
b8dd1ad150 feat(image-import): add openImportDialog entry point with API-key prompt and stage helpers 2026-05-12 18:20:42 +02:00
7154edde86 feat(image-import): wire open-image-import-btn + card-header layout 2026-05-12 18:20:11 +02:00
b921592f7e test: migrate Berechnung + Edge-Case tests to new variants result shape 2026-05-12 00:17:04 +02:00
20f63e07cd feat(image-import): add normalizeName, matchNames (exact+fuzzy), classify slot helper 2026-05-12 00:16:27 +02:00
773c286236 feat(image-import): add inline levenshtein distance helper 2026-05-12 00:15:39 +02:00
bc1d92937c refactor: BonusCalculator runs all 3 variants and picks winner 2026-05-12 00:15:38 +02:00
93e6b32fe9 feat(image-import): add parseResponse with fence-stripping and schema validation 2026-05-12 00:15:15 +02:00
f7153a5e53 feat: implement variant2 (1 sa + 2 weekday) 2026-05-12 00:14:50 +02:00
60e71d4a57 feat(image-import): add callVisionAPI with OpenRouter fetch + typed HTTP errors 2026-05-12 00:14:38 +02:00
591a2773cc feat: implement variant1 (1 fr+so + 3 weekday, fr-priority) 2026-05-12 00:14:21 +02:00