- parseInt(month/year) now passes radix 10 consistently.
- minGap eligibility guards null/undefined (c.minGapDays != null && > 0).
- The corrupt-localStorage load and the createEmployee catch now console.warn
instead of swallowing the error silently.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New js/utils.js exports toISO, monthPrefix, getWeekday, formatDateDE and
buildNameMap. algorithm.js, calendar.js, excel.js and history.js now import
these instead of re-implementing ISO construction, weekday math, DD.MM.YYYY
formatting and the id→name map inline. Adds tests/utils.test.mjs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- saveState is now debounced (~400ms) to coalesce rapid changes; a pending
write is flushed on beforeunload and on visibilitychange→hidden so the last
change is never lost.
- The SheetJS <script> gets defer so it no longer blocks initial parse; the
typeof XLSX guard already covers any not-yet-available case.
Verified headless: app loads without JS/CSP errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extracts the day-cell construction into a self-contained makeDayCell(d). Slot
changes and holiday/closure toggles now replace just that one cell
(cell.replaceWith) plus update export-button visibility, instead of rebuilding
the entire month grid and re-attaching every listener on each interaction.
Structural changes (month/year/slot-count) still do a full render.
Faithful extraction; verified headless that the page loads without JS errors
and tests pass. Interactive render coverage to follow in the test-layer issue.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- generatePlan computes a histCount Map once; scoreCandidate now does an O(1)
lookup instead of filtering the whole history per candidate per day.
- minGap eligibility finds the latest prior date in a single pass instead of
spreading history+monthAssignments into a new array and sorting it.
Behaviour is unchanged (all algorithm tests pass).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README gains a "Datenschutz & Speicherung" section: local single-user tool,
unencrypted localStorage, avoid shared devices, export JSON to back up.
- Comments the generateId Math.random fallback as a non-crypto last resort,
acceptable for local employee ids.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds sanitizeCell(): cell values starting with = + - @ or a control char are
prefixed with an apostrophe so spreadsheets render them as literal text
instead of executing them as formulas. Applied to the names column.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
removeEmployee now also filters the deleted employee's history entries, so
no orphaned "(unbekannt)" rows remain. Adds a test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
saveState now logs a console.warn on failure and alerts the user once per
session (storage full/unavailable) so they can export their data and avoid
silent data loss.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- loadFromJSON and the localStorage startup load now run employees through
normalizeEmployees(): fills missing constraints, drops unusable rows,
de-duplicates ids, and discards invalid vacation ranges — preventing
later crashes (e.g. c.neverDays on undefined) and same-day double-books.
- Excel import is wrapped in try/catch with a typeof XLSX guard and user
feedback; the Excel export button gets the same guard.
- createEmployee reuses the shared defaultConstraints() factory.
Adds normalizeEmployees tests (defaults, dropping, dedup, vacations) and a
loadFromJSON normalization test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
generatePlan gains a preAssigned parameter: manual entries occupy slots,
count toward eligibility (maxPerMonth/minGap) and are never double-booked;
only the remaining slots per day are auto-filled. The generate handler now
keeps manual:true entries for the month instead of wiping them.
Adds tests for slot occupation, fully-manual days, and maxPerMonth counting.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
currentYear now initializes to the current year and the year selector
offers a rolling range (this year -1 to +2) so plans can be created
for years other than 2026.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Move inline style.cssText to semantic classes (cal-legend, cal-header-cell,
cal-day-tag-label, cal-btn-row) in calendar.js
- Buttons "FT"/"BU" → "Feiertag"/"Betriebsurl." for clarity
- Decorative turntable/mixer SVG header art in index.html
- style.css build-out for the new classes
- Initial README content
- Dev port 3000 → 3001
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>