prisma / @prisma/client 6.19.2 -> 7.8.0; added @prisma/adapter-mariadb 7.8.0 and
mariadb 3.5.2 (the runtime driver).
Prisma 7 breaking changes handled (verified via Prisma's own tooling — the
official upgrade-guide summary had hallucinated package names, so I confirmed
everything against `prisma validate`/`generate` and the installed type defs):
- The Rust query engine is removed; the runtime connection is now made through a
driver adapter. src/config/database.ts wires PrismaMariaDb, parsing
DATABASE_URL into an explicit mariadb pool config so the literal `@` in our
password (which a naive connection-string parser mishandles) is correct.
- datasource `url` is no longer allowed in schema.prisma -> moved to a new
prisma.config.ts (schema + datasource.url + migrations.seed). Prisma 7 no
longer auto-loads .env, so the config does `import "dotenv/config"`.
- The deprecated package.json#prisma seed config was removed (now in the config).
- seed.ts and the two maintenance scripts now use the shared adapter-wired client.
The legacy `prisma-client-js` generator STILL works under v7 (generates to
@prisma/client as before), so NO import-path changes were needed across the 16
@prisma/client import sites — switching to the new prisma-client/output generator
is not required for us. No prisma.$use() middleware exists. Node 24 / TS 5.9
exceed the v7 minimums (20.19 / 5.4).
No migrations were run (your DBs are untouched); removing datasource.url is a
config change, not DDL, so this phase needs no new migration.
Gates: tsc 0 | build 0 | vitest 247/247 against app_test (proves the mariadb
adapter works at runtime, incl. raw SELECT...FOR UPDATE locking and Decimal/VAT)
| eslint 0 errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
react / react-dom 18.3.1 -> 19.2.7; @types/react 18.3.31 -> 19.2.17;
@types/react-dom 18.3.7 -> 19.2.3 (latest stable 19.2.x).
Only breaking change hitting our code: React 19 removed the no-arg useRef<T>()
overload. AppShell's logoutTimer -> useRef<T | undefined>(undefined) — the same
transform the official `types-react-codemod preset-19` (useRef-required-initial)
applies. No other preset-19 transforms were relevant (already on createRoot; no
ReactDOM.render, string refs, propTypes/defaultProps on function components).
No Next.js / RSC in this project (it's a Vite SPA served by Fastify), so those
React 19 concerns don't apply here. MUI v7, framer-motion 12, TanStack Query 5,
react-router-dom 6 and react-quill-new all installed cleanly against React 19
(no peer-dependency conflicts).
Gates: tsc 0 | build 0 | vitest 247/247 | eslint 0 errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Assign one project/category to many employees over a date range in one
action. "Hromadné přiřazení" on /plan-work: employee checklist +
include-weekends toggle, mirrors the single-create form. Creates range
entries grouped by contiguous eligible days per employee (weekends-off →
per-work-week chunks); per-day cap skips days already at 3; 92-day range
cap. Reuses createEntry; summary audit + result counts. No migration.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A plan cell now holds up to 3 records: additive assignments + day
exceptions, via the layered entries/overrides model (no migration).
resolveCell/resolveGrid return arrays; cap enforced per layer on create;
grid renders up to 3 stacked; cell editor is a day panel (list/add/edit,
layer-aware add); dashboard "today" card shows up to 3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The order delete modal sends { delete_files }, but the route ignored the
body and deleteOrder never touched the NAS — so the project folder of an
order-spawned project always stayed on the share (the only way to delete
such a project is via its order, since deleteProject blocks order-linked
projects). Project delete (standalone projects) already worked.
- orders route: read delete_files from the body, pass to deleteOrder.
- orders.service deleteOrder(id, deleteFiles): select project_number and,
after the DB transaction commits, best-effort deleteProjectFolder for
each linked project when the flag is set. Non-fatal; idempotent.
- tests: NasFileManager.deleteProjectFolder coverage — removes by number
prefix, no-op when absent, false when not mounted (158 -> 161 tests).
Bump version to 2.0.4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Manual project creation already creates the 02_PROJEKTY/<number>_<name>
folder (projects.service.createProject). Projects created from an order —
both from an accepted offer (createOrderFromQuotation) and a manual
offer-less order (createOrder) — did not, so they had no NAS folder until
a user opened the project and clicked "create folder" or uploaded a file.
- orders.service: best-effort, non-fatal createProjectFolder after each
project-creating transaction commits (mirrors createProject; gated on
isConfigured(), logs on failure, never rolls back the order).
- projects.service: log when the existing auto-create returns false
(was silently discarded — CLAUDE.md known-issue #4).
- nas-file-manager: optional constructor basePath seam for tests.
- tests: NasFileManager.createProjectFolder coverage — naming, idempotency,
Czech diacritics, empty name, not-mounted (152 -> 158 tests).
Bump version to 2.0.3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New "Vaše dnešní zařazení" dashboard card: shows the logged-in user's
work-plan entry for today (category + project/site + note, multi-day
range badge), with a muted empty state.
No DB migrations. tsc -b --noEmit, npm run build, vitest 152/152 clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UI consistency pass on top of v2.0.0:
- Colored button text unified to white on all filled controls (both
themes); darker dark-mode fills so white stays legible.
- Icon badges unified via a shared iconBadgeSx (solid tile + white glyph).
- Detail-page header action buttons stack one-per-row on mobile.
- Dropped the duplicate "Zrušit" in the plan view-cell modal.
No DB migrations. tsc -b --noEmit, npm run build, vitest 152/152 clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Major release. The admin frontend is now entirely on Material UI v7:
every page and shared component migrated off ~7,100 lines of hand-written
CSS, and all five custom stylesheets (base/variables/plan/attendance/
offers) eliminated — global styles live in a theme-aware MUI <GlobalStyles>,
widgets (Quill, Leaflet, planner grid) in scoped styled() wrappers, and the
only remaining CSS imports are the two third-party libraries.
Also includes the post-migration polish: consistent page-entrance motion,
unified filters, mobile card layouts, readable status row tints, white-glyph
icon badges, single-key theme persistence, and the offer-page fixes
(heartbeat 401 handling, expires_in token lifetime, duplicate-key + motion
deprecation).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Install @mui/material@^7, @emotion/react@^11, @emotion/styled@^11,
@mui/x-date-pickers@^8 as production dependencies. Downgrade
@types/react and @types/react-dom from ^19 to ^18.3 to match the
React 18.3.1 runtime. tsc --noEmit and vite build:client both pass
cleanly with no new errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Combines the undeployed v1.9.7 (compact 2-up filter bars) with the date-field
unification (all date fields via AdminDatePicker + mode-aware placeholder).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Supersedes the undeployed v1.9.5: adds the mobile tab-bar scroll fix and
combobox touch-target fixes on top of the Phase 1+2 responsive rules.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Manual standalone project creation (shared numbering pool, with tracking:
collision-safe, release-on-delete, audit, Samostatný/Z objednávky badge) and
manual order creation without an offer (header form, optional linked project,
price line item, PO PDF upload mirroring the from-offer flow). Re-adds the
projects.create permission via migration + seed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mobile work-plan (Plán prací) responsive fixes — desktop unchanged:
- Toolbar stacks into clean full-width rows on ≤640px (nav group,
centered range label, full-width segmented view toggle, full-width
category button); drops the fixed 230px label min-width and the
margin-left:auto that made the toolbar ragged on phones.
- Grid scroll container: 100dvh-based max-height, momentum scroll, and
overscroll containment so a fling does not bounce the whole page.
- ≤480px tightens columns (date col 72px via the colgroup <col>, person
cols 132px) so ~2 people are comfortably visible at 360–390px.
- Touch (@media hover:none): faint persistent + on empty editable
cells, since the hover-reveal add hint never fires on a phone.
Dev: `npm run dev` (backend) now listens on 3050 instead of 3000 to
avoid colliding with other local apps; CLAUDE.md dev-port note updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add created_at to offer create/update schemas so user-selected date is stored instead of always defaulting to now()
- Translate payment method in invoice PDF based on language (Příkazem → Bank transfer, etc.)
- Add order_date and cnb_rate translation keys, replace hardcoded inline strings
- Remove duplicate has_order filter from offers backend route
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove exchange_rate and exchange_rate_date from quotations (schema, service, PDF, form)
- Add item_description field to invoice_items (schema, migration, service, form, PDF)
- Add offer status/customer/order filters with tab-based UI
- Clean up offer statuses to active/ordered/invalidated
- Allow invalidate action for non-ordered offers (not just expired)
- Add fade animations on offers and invoices table data changes
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- New settings.system permission with migration (idempotent INSERT)
- requireAnyPermission helper for route guards accepting multiple perms
- Move document numbering + currency/VAT cards from system tab to CompanySettings
- Rename security tab to roles, add canManageSystem alongside canManageCompany
- TOTP required endpoint and system-info now use settings.system
- Roles list now includes user_count
- Sidebar Settings link includes settings.system
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Change attendance idx_attendance_user_date from unique to index (allow multiple shifts per day)
- Reset migrations to single baseline init migration
- Add seed script with admin user (admin/admin)
- Update CLAUDE.md with migration workflow documentation
- Various frontend fixes (queries, pages, hooks)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace Quill editor.format() with direct DOM style manipulation to
avoid getSelection(true) calls that steal focus and scroll the page
to the sections area on mount.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AttendanceAdmin sends ?year=YYYY&month=M (separate params), but the
route handler assumed month was always in "YYYY-MM" format. When
query.month was just "4", the split produced NaN for month and 4 for
year, causing the service to skip the month filter entirely.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fix items table description column width on mobile (was ~82px, now ~260px)
- Activate unused offers-items-table CSS class in OfferDetail form
- Save all form fields to localStorage draft (language, VAT, exchange rate were missing)
- Use DRAFT_KEY constant in loadOfferDraft, add error logging
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The frontend sends month as "YYYY-MM" but the route handler was passing
it through Number() which parsed only the year portion, causing the
service to ignore the month filter entirely.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace hand-coded skeleton CSS/JSX with boneyard-js auto-generated bones
- Remove skeleton.css and @keyframes shimmer from base.css
- Add <Skeleton> wrappers with fixtures to all 25+ page components
- Generate 20 bone captures via boneyard CLI (CDP auth-gated capture)
- Refactor data fetching from useEffect+useState to TanStack Query
- Extract query hooks into src/admin/lib/queries/ and apiAdapter
- Add usePaginatedQuery hook replacing useApiCall/useListData
- Fix parseFloat || 0 anti-pattern in OfferDetail and OffersTemplates inputs
- Fix customer_id mandatory validation on offer creation
- Fix leave-requests comma-separated status filter (Prisma enum in: [])
- Add cross-entity cache invalidation for orders/offers/invoices/projects
- Make rate limits configurable via env vars (RATE_LIMIT_MAX, RATE_LIMIT_REFRESH, etc.)
- Add boneyard.config.json with routes and breakpoints
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove ProjectCreate page, POST /projects endpoint, and next-number endpoint
- Projects can only be created through orders (shared numbering sequence)
- Remove dead CreateProjectSchema and createProject service function
- Delete 'order' row from number_sequences (unused; code uses 'shared')
- Smart sequence release: decrement last_number only when deleting the highest number
- Fix received-invoices stats referencing non-existent is_deleted and amount_czk columns
- Update deploy instructions in CLAUDE.md (npm install, prisma migrate deploy)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove ref-mirror useEffect in AuthContext (cachedUserRef already written at mutation sites)
- Replace useEffect slide direction in ReceivedInvoices with render-time computation
- Fix Login.tsx useEffect dependency array (mount-only alert should have [] deps)
- Move "project created" alert to navigation source in ProjectCreate, remove useEffect in ProjectDetail
- Move companySettings defaults into fetch callbacks in InvoiceDetail and OfferDetail
- Replace due_date useEffect with useMemo in InvoiceDetail
- Capture initial snapshots from API data instead of useEffect in InvoiceDetail, OfferDetail, OrderDetail
- Replace localStorage draft useEffect with lazy useState initializer in OfferDetail
- Fix attendance dropdown to filter by attendance.record permission only
- Fix clock-out 404 on update-address (remove departure_time filter for departure action)
- Fix received-invoices stats endpoint referencing non-existent is_deleted and amount_czk columns
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- feat: manual VAT override in order confirmation modal
- feat: order confirmation PDF respects user-selected applyVat toggle
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- feat: order confirmation PDF generation with VAT support
- feat: order confirmation modal with custom item editing
- fix: attendance negative duration clamping and switchProject timing
- fix: Quill editor locked to Tahoma 14px, PDF heading sizes
- fix: invoice/offer PDF font consistency (Tahoma enforcement)
- fix: invoice alert cron improvements
- fix: NAS financials manager edge cases
- refactor: numbering service with unique sequence constraints
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>