docs: codify audit rules in CLAUDE.md + README + audit records

CLAUDE.md: new "2026-06-09 audit" enforced-rules section (mandatory coercion
helpers, deterministic id-tiebreak ordering, $queryRaw FOR-UPDATE locking
discipline, uniqueness-in-transaction, guard reads, Rules-of-Hooks, seed prod
guard), lint/typecheck/format commands, and the app_test/.env.test testing
section with the hard-throw guard.

README rewritten from the placeholder stub (setup/run/build/test/gates/migrations).

REVIEW.md / REVIEW_FINDINGS.md / REVIEW_FIXES.md: the full audit record — 277
files reviewed, ~362 findings, every one fixed and verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-09 06:45:37 +02:00
parent 519edce373
commit b4f859ea6e
5 changed files with 3220 additions and 5 deletions

View File

@@ -76,9 +76,14 @@ npm run build:client # vite build → dist-client/
npm start # node dist/server.js
# Tests
npm test # vitest run (single pass)
npm test # vitest run (single pass) — runs against the app_test DB via .env.test
npm run test:watch # vitest watch
# Quality gates
npm run typecheck # tsc -b --noEmit (also type-checks the tests via tsconfig.test.json)
npm run lint # eslint . — react-hooks/rules-of-hooks is an ERROR; keep at 0 errors
npm run format # prettier --write .
# Database
npx prisma migrate dev # Create migration from schema changes + apply to dev
npx prisma migrate dev --name <descriptive_name> # Named migration
@@ -239,11 +244,13 @@ if ("error" in body) return error(reply, body.error, 400);
## Testing
Tests live in `src/__tests__/`. They use Vitest + Supertest against a real test database (`.env.test`).
Tests live in `src/__tests__/`. They use Vitest + Supertest against a **real, throwaway test database** (`app_test`).
- The suite spans 17 files / 195 tests — auth, numbering, warehouse, plan, invoices, exchange-rates, schema coercion, NAS file manager, env, manual-create, AI/Odin (conversation CRUD, isolation, auto-title, cascade, budget), received-invoices VAT. Server-side only (no component tests yet).
- **Isolated test DB (`app_test`):** the suite MUTATES a real MySQL DB, so it runs against `app_test` (NOT dev `app`), configured in **`.env.test`** (gitignored). `src/__tests__/setup.ts` **hard-throws** if `DATABASE_URL` doesn't name a `*test*` database — a stray URL can never corrupt dev/prod data. To (re)create it: `CREATE DATABASE app_test;` → copy `.env` to `.env.test` with the DB name swapped + `ANTHROPIC_API_KEY=` blanked → `DATABASE_URL=<app_test-url> npx prisma migrate deploy``DATABASE_URL=<app_test-url> npx tsx prisma/seed.ts`.
- The suite spans 18 files / 247 tests — auth (incl. happy-path login/refresh-rotation), numbering, warehouse (incl. FIFO oldest-first), plan, invoices, exchange-rates, schema coercion, NAS file manager, env, manual-create, AI/Odin, received-invoices VAT. Server-side only (no component tests yet).
- Tests are now **type-checked** by `tsc -b` (via `tsconfig.test.json`) — keep them compiling.
- Use `buildApp()` helper to spin up the Fastify instance for tests.
- Tests use `vitest.config.ts` with `environment: 'node'` and 15s timeout.
- Tests use `vitest.config.ts` with `environment: 'node'` and 15s timeout; `fileParallelism: false` (serialized) to avoid `number_sequences` deadlocks.
- **Do not mock Prisma** — tests hit a real database to catch schema/query bugs.
When adding new features, add tests in `src/__tests__/`. Name test files `<feature>.test.ts`.
@@ -302,7 +309,7 @@ The admin frontend is **fully on Material UI v7** (Emotion). The old ~7,100 line
- **Theme is single-source:** `src/context/ThemeContext.tsx` owns the `<html data-theme>` attribute + the View-Transitions cross-fade, and persists under MUI's **`mui-mode`** localStorage key (the same key MUI reads on mount). Do NOT add a second theme key — that desyncs page vs toggle on refresh.
- **Dialogs** lock `<html>` via `useDialogScrollLock` (MUI only locks `<body>`, and `html{overflow-x:hidden}` makes `<html>` the scroller); Modal/ConfirmDialog freeze title/label/loading through the close fade so nothing flashes. Login renders OUTSIDE AppShell.
**Gates every change:** `npx tsc -b --noEmit` (NOT `-p tsconfig.json` — a vacuous solution file that checks nothing), `npm run build`, `npx vitest run`.
**Gates every change:** `npx tsc -b --noEmit` (NOT `-p tsconfig.json` — a vacuous solution file that checks nothing), `npm run build`, `npx vitest run`, `npm run lint`. The solution `tsconfig.json` now references `tsconfig.test.json` too, so `tsc -b` **type-checks the test files** (previously skipped). ESLint (flat config in `eslint.config.mjs`) enforces `react-hooks/rules-of-hooks` as an **error** — that rule catches the "hook after an early `return`" bug class; keep `npm run lint` at zero errors (warnings are advisory). Prettier config is `.prettierrc.json` (`npm run format`).
---
@@ -445,6 +452,40 @@ audit found and fixed the deviations. Full report: `docs/codebase-audit-2026-06-
- **Attendance/leave** writes `@db.Date` at **local noon** (`new Date(y, m, d, 12, 0, 0)`).
- **Frontend "today" / date-string round-trips:** use `utils/date.ts` `localDateStr` (server) / `normalizeDateStr` (client). **Never** use `new Date().toISOString().split("T")[0]` for "today" — it's the UTC date and is a day early during the late-evening Prague window.
## Conventions (enforced — added by the 2026-06-09 full audit)
The 2026-06-09 file-by-file audit traced most bugs to a handful of patterns. These are now rules — `npm run lint` + `tsc -b` (which now type-checks tests) catch some automatically.
**Zod validation — shared coercion helpers are MANDATORY**
- All numeric/boolean/date/email form fields MUST use the helpers in **`src/schemas/common.ts`**: `numberFromForm`, `numberInRange(min,max)`, `nonNegativeNumberFromForm`, `positiveNumberFromForm`, `intIdFromForm`, `nullableNumberFromForm`/`nullableIntIdFromForm`, `booleanFromForm`, `isoDateString`, `timeString`, `emailOrEmpty`.
- **NEVER** the raw `z.union([z.number(), z.string()]).transform(Number)` idiom — it silently yields `NaN` that flows into Prisma/business math (this was the single biggest bug class). FK ids → `intIdFromForm`/`nullableIntIdFromForm`; quantities/prices → `nonNegative`/`positive`; bounded values (VAT `0100`, month `112`) → `numberInRange`.
- `isoDateString`/`timeString` are **lenient** (they strip a trailing time/seconds component) because an edit form re-submits a `@db.Date` that the `toJSON` override serialised as `"YYYY-MM-DDT00:00:00"`. Use them for date/time fields, not a bare regex.
- An optional email a form may submit as `""`**`emailOrEmpty.nullish()`** (a bare `.email()` 400s the whole form, blocking unrelated saves).
**Deterministic ordering — always tiebreak a timestamp sort with `id`**
- `created_at`/`received_at` are **second-precision** (`@db.Timestamp(0)`/`DateTime(0)`), so `orderBy: { created_at: "desc" }` alone is non-deterministic for same-second rows. ALWAYS add `{ id: "desc" }` (or `asc`) as the secondary sort. (Bit `plan.service.resolveCell`/`resolveGrid` and warehouse FIFO `selectFifoBatches`.)
**Concurrency — locking discipline for stock / balance / sequence mutations**
- Any service op that read-modify-writes shared rows (stock, batches, reservations, balances, number sequences) MUST: run inside a `prisma.$transaction`; take the row lock with `SELECT … FOR UPDATE` via **`tx.$queryRaw`** (NOT `$executeRaw` — it does not reliably hold the lock); and lock rows in one global **ascending-id order** (parent → items → batches) so concurrent paths can't deadlock. See `warehouse.service.ts` `lockParentRow`/`lockRowsForUpdate` and `attendance.service.ts` `lockUserRow`.
- **Uniqueness checks** (username/email/document number) go INSIDE the create transaction (re-check immediately before insert) and catch `P2002` → 409. A pre-transaction check is a TOCTOU race that surfaces as a 500.
**Permissions — guard reads, not just writes**
- GET list/detail endpoints need a `requirePermission`/`requireAnyPermission` guard, NOT bare `requireAuth` (bare-auth reads leak data to any logged-in user). Role-management writes are admin-only and re-checked (no privilege escalation; no creating/rewriting the `admin` role).
**Frontend — Rules of Hooks (lint-enforced) + no UTC-today**
- ALL hooks (`useState`, `useApiMutation`, `useMemo`, …) run BEFORE any early `return` (the `<Forbidden/>`/`<Navigate/>` permission guard goes AFTER every hook). `eslint.config.mjs` sets `react-hooks/rules-of-hooks` to **error**`npm run lint` must stay at 0 errors. This was a systemic crash bug across ~14 pages.
- Mutations invalidate the **broad domain key**; a mutation that writes via raw `apiFetch` must still `invalidateQueries` the domain it touched (several dashboard widgets were missing this).
**Safety**
- `prisma/seed.ts` **refuses to run when `APP_ENV=production`** (it wipes/reseeds permissions). Never seed prod.
- Every catch logs (never silently swallow) — the NAS managers were the worst offenders.
---
## Known Issues & Gotchas

73
README.md Normal file
View File

@@ -0,0 +1,73 @@
# boha-app-ts
Internal business-management system for a Czech company (attendance, invoicing,
leave/trips, projects, vehicles, warehouse, HR) — a TypeScript/Node.js rewrite
of the legacy PHP app. User-facing text is Czech by design.
> For full architecture, conventions, and gotchas, see **[CLAUDE.md](./CLAUDE.md)**.
## Stack
- **Backend:** Fastify 5 · Prisma 6 → MySQL · Zod 4 · JWT (HS256) + TOTP 2FA
- **Frontend:** React 18 · Vite · Material UI v7 (Emotion) · TanStack Query — an
SPA in `src/admin/`, served by the same Fastify process (Vite middleware in
dev, static files in prod)
- **Other:** Puppeteer (PDF) · nodemailer · node-cron · `@anthropic-ai/sdk` (the
admins-only "Odin" assistant)
## Prerequisites
- Node.js (LTS) and a MySQL database
- Copy `.env.example``.env` and fill in the **required** vars (`DATABASE_URL`,
`JWT_SECRET`, `TOTP_ENCRYPTION_KEY` — generate the keys with `openssl rand -hex 32`)
## Setup
```bash
npm install
npx prisma generate
npx prisma migrate dev # apply migrations to your dev DB
npx prisma db seed # optional: dev-only sample data (NEVER on prod)
```
## Develop
```bash
npm run dev:server # API (tsx watch) on http://127.0.0.1:3050
npm run dev:client # Vite dev server (manage separately)
```
## Build & run
```bash
npm run build # tsc server → dist/ + vite client → dist-client/
npm start # node dist/server.js
```
## Test
```bash
npm test # vitest run — hits a real test DB (.env.test); no Prisma mocks
```
## Quality gates
Before committing, all of these must pass:
```bash
npx tsc -b --noEmit # typecheck (NOT `tsc -p tsconfig.json`)
npm run build
npx vitest run
npm run lint # ESLint (incl. react-hooks) — see eslint.config.js
```
## Database migrations
Every schema/data change is a tracked Prisma migration — **never** `prisma db push`
or raw SQL on production. Stop the dev server before running `prisma migrate dev`.
See CLAUDE.md → _Database Migrations_ for the full workflow and the production
deploy/hotfix process.
## License
ISC

386
REVIEW.md Normal file
View File

@@ -0,0 +1,386 @@
# Codebase Audit — REVIEW.md
**Date:** 2026-06-08
**Scope:** entire repository (tracked source/config files via `git ls-files`)
**Method:** file-by-file review. Source of truth for progress — re-read before continuing after any compaction.
**Total files to review:** 277
---
## .claude/hooks/
- [x] .claude/hooks/block-env.js
- [x] .claude/hooks/format-on-save.js
## .claude/
- [x] .claude/settings.json
- [x] .claude/settings.local.json
## ./
- [x] .env.example
- [x] CLAUDE.md
- [x] boneyard.config.json
- [x] index.html
- [x] package.json
## prisma/
- [x] prisma/schema.prisma
- [x] prisma/seed.ts
## scripts/
- [x] scripts/migrate-received-invoices-to-nas.ts
- [x] scripts/rotate-totp-key.ts
## src/
- [x] src/App.tsx
## src/__tests__/
- [x] src/__tests__/ai.test.ts
- [x] src/__tests__/auth.service.test.ts
- [x] src/__tests__/auth.test.ts
- [x] src/__tests__/customers.schema.test.ts
- [x] src/__tests__/env.test.ts
- [x] src/__tests__/exchange-rates.test.ts
- [x] src/__tests__/helpers.ts
- [x] src/__tests__/invoices.service.test.ts
- [x] src/__tests__/manual-create.test.ts
- [x] src/__tests__/nas-file-manager.test.ts
- [x] src/__tests__/nas-project-folder.test.ts
- [x] src/__tests__/numbering.test.ts
- [x] src/__tests__/plan.test.ts
- [x] src/__tests__/planAuditDescription.test.ts
- [x] src/__tests__/planCategory.test.ts
- [x] src/__tests__/received-invoices-vat.test.ts
- [x] src/__tests__/schema-nan.test.ts
- [x] src/__tests__/setup.ts
- [x] src/__tests__/warehouse.test.ts
## src/admin/
- [x] src/admin/AdminApp.tsx
- [x] src/admin/GlobalStyles.tsx
## src/admin/components/
- [x] src/admin/components/AlertContainer.tsx
- [x] src/admin/components/AttendanceShiftTable.tsx
- [x] src/admin/components/BulkAttendanceModal.tsx
- [x] src/admin/components/BulkPlanModal.tsx
- [x] src/admin/components/ErrorBoundary.tsx
- [x] src/admin/components/Forbidden.tsx
- [x] src/admin/components/OrderConfirmationModal.tsx
- [x] src/admin/components/PlanCategoriesModal.tsx
- [x] src/admin/components/PlanCellModal.tsx
- [x] src/admin/components/PlanGrid.tsx
- [x] src/admin/components/PlanRangeChips.tsx
- [x] src/admin/components/ProjectFileManager.tsx
- [x] src/admin/components/RichEditor.tsx
- [x] src/admin/components/ShiftFormModal.tsx
- [x] src/admin/components/ShortcutsHelp.tsx
## src/admin/components/dashboard/
- [x] src/admin/components/dashboard/DashActivityFeed.tsx
- [x] src/admin/components/dashboard/DashAttendanceToday.tsx
- [x] src/admin/components/dashboard/DashKpiCards.tsx
- [x] src/admin/components/dashboard/DashProfile.tsx
- [x] src/admin/components/dashboard/DashQuickActions.tsx
- [x] src/admin/components/dashboard/DashSessions.tsx
- [x] src/admin/components/dashboard/DashTodayPlan.tsx
## src/admin/components/odin/
- [x] src/admin/components/odin/InvoiceReviewCard.tsx
- [x] src/admin/components/odin/OdinChat.tsx
- [x] src/admin/components/odin/OdinComposer.tsx
- [x] src/admin/components/odin/OdinMark.tsx
- [x] src/admin/components/odin/OdinSidebar.tsx
- [x] src/admin/components/odin/OdinThread.tsx
- [x] src/admin/components/odin/types.ts
## src/admin/components/warehouse/
- [x] src/admin/components/warehouse/ItemPicker.tsx
- [x] src/admin/components/warehouse/ReservationPicker.tsx
## src/admin/context/
- [x] src/admin/context/AlertContext.tsx
- [x] src/admin/context/AuthContext.tsx
## src/admin/hooks/
- [x] src/admin/hooks/useAttendanceAdmin.ts
- [x] src/admin/hooks/useDebounce.ts
- [x] src/admin/hooks/useModalLock.ts
- [x] src/admin/hooks/usePaginatedQuery.ts
- [x] src/admin/hooks/usePlanWork.ts
- [x] src/admin/hooks/useReducedMotion.ts
- [x] src/admin/hooks/useTableSort.ts
## src/admin/lib/
- [x] src/admin/lib/apiAdapter.ts
- [x] src/admin/lib/entityTypeLabels.ts
## src/admin/lib/queries/
- [x] src/admin/lib/queries/ai.ts
- [x] src/admin/lib/queries/attendance.ts
- [x] src/admin/lib/queries/auditLog.ts
- [x] src/admin/lib/queries/common.ts
- [x] src/admin/lib/queries/dashboard.ts
- [x] src/admin/lib/queries/invoices.ts
- [x] src/admin/lib/queries/leave.ts
- [x] src/admin/lib/queries/mutations.ts
- [x] src/admin/lib/queries/offers.ts
- [x] src/admin/lib/queries/orders.ts
- [x] src/admin/lib/queries/plan.ts
- [x] src/admin/lib/queries/projects.ts
- [x] src/admin/lib/queries/settings.ts
- [x] src/admin/lib/queries/trips.ts
- [x] src/admin/lib/queries/users.ts
- [x] src/admin/lib/queries/vehicles.ts
- [x] src/admin/lib/queries/warehouse.ts
## src/admin/lib/
- [x] src/admin/lib/queryClient.ts
## src/admin/pages/
- [x] src/admin/pages/Attendance.tsx
- [x] src/admin/pages/AttendanceAdmin.tsx
- [x] src/admin/pages/AttendanceBalances.tsx
- [x] src/admin/pages/AttendanceCreate.tsx
- [x] src/admin/pages/AttendanceHistory.tsx
- [x] src/admin/pages/AttendanceLocation.tsx
- [x] src/admin/pages/AuditLog.tsx
- [x] src/admin/pages/CompanySettings.tsx
- [x] src/admin/pages/Dashboard.tsx
- [x] src/admin/pages/InvoiceDetail.tsx
- [x] src/admin/pages/Invoices.tsx
- [x] src/admin/pages/LeaveApproval.tsx
- [x] src/admin/pages/LeaveRequests.tsx
- [x] src/admin/pages/Login.tsx
- [x] src/admin/pages/NotFound.tsx
- [x] src/admin/pages/Odin.tsx
- [x] src/admin/pages/OfferDetail.tsx
- [x] src/admin/pages/Offers.tsx
- [x] src/admin/pages/OffersCustomers.tsx
- [x] src/admin/pages/OffersTemplates.tsx
- [x] src/admin/pages/OrderDetail.tsx
- [x] src/admin/pages/Orders.tsx
- [x] src/admin/pages/PlanWork.tsx
- [x] src/admin/pages/ProjectDetail.tsx
- [x] src/admin/pages/Projects.tsx
- [x] src/admin/pages/ReceivedInvoices.tsx
- [x] src/admin/pages/Settings.tsx
- [x] src/admin/pages/Trips.tsx
- [x] src/admin/pages/TripsAdmin.tsx
- [x] src/admin/pages/TripsHistory.tsx
- [x] src/admin/pages/UiKit.tsx
- [x] src/admin/pages/Users.tsx
- [x] src/admin/pages/Vehicles.tsx
- [x] src/admin/pages/Warehouse.tsx
- [x] src/admin/pages/WarehouseCategories.tsx
- [x] src/admin/pages/WarehouseInventory.tsx
- [x] src/admin/pages/WarehouseInventoryDetail.tsx
- [x] src/admin/pages/WarehouseInventoryForm.tsx
- [x] src/admin/pages/WarehouseIssueDetail.tsx
- [x] src/admin/pages/WarehouseIssueForm.tsx
- [x] src/admin/pages/WarehouseIssues.tsx
- [x] src/admin/pages/WarehouseItemDetail.tsx
- [x] src/admin/pages/WarehouseItems.tsx
- [x] src/admin/pages/WarehouseLocations.tsx
- [x] src/admin/pages/WarehouseReceiptDetail.tsx
- [x] src/admin/pages/WarehouseReceiptForm.tsx
- [x] src/admin/pages/WarehouseReceipts.tsx
- [x] src/admin/pages/WarehouseReports.tsx
- [x] src/admin/pages/WarehouseReservations.tsx
- [x] src/admin/pages/WarehouseSuppliers.tsx
## src/admin/
- [x] src/admin/theme.test.ts
- [x] src/admin/theme.ts
## src/admin/ui/
- [x] src/admin/ui/Alert.tsx
- [x] src/admin/ui/AppShell.tsx
- [x] src/admin/ui/Button.tsx
- [x] src/admin/ui/Card.tsx
- [x] src/admin/ui/Checkbox.tsx
- [x] src/admin/ui/ConfirmDialog.tsx
- [x] src/admin/ui/DataTable.tsx
- [x] src/admin/ui/DateField.tsx
- [x] src/admin/ui/EmptyState.tsx
- [x] src/admin/ui/Field.tsx
- [x] src/admin/ui/FileUpload.tsx
- [x] src/admin/ui/FilterBar.tsx
- [x] src/admin/ui/LoadingState.tsx
- [x] src/admin/ui/Modal.tsx
- [x] src/admin/ui/MonthField.tsx
- [x] src/admin/ui/MuiProvider.tsx
- [x] src/admin/ui/PageEnter.tsx
- [x] src/admin/ui/PageHeader.tsx
- [x] src/admin/ui/Pagination.tsx
- [x] src/admin/ui/ProgressBar.tsx
- [x] src/admin/ui/RichText.tsx
- [x] src/admin/ui/Select.tsx
- [x] src/admin/ui/SidebarNav.tsx
- [x] src/admin/ui/StatCard.tsx
- [x] src/admin/ui/StatusChip.tsx
- [x] src/admin/ui/Tabs.tsx
- [x] src/admin/ui/TextField.tsx
- [x] src/admin/ui/ThemeToggle.tsx
- [x] src/admin/ui/TimeField.tsx
- [x] src/admin/ui/index.ts
- [x] src/admin/ui/navData.tsx
- [x] src/admin/ui/useDialogScrollLock.ts
## src/admin/utils/
- [x] src/admin/utils/api.ts
- [x] src/admin/utils/attendanceHelpers.ts
- [x] src/admin/utils/dashboardHelpers.ts
- [x] src/admin/utils/formatters.ts
## src/config/
- [x] src/config/database.ts
- [x] src/config/env.ts
## src/context/
- [x] src/context/ThemeContext.tsx
## src/
- [x] src/main.tsx
## src/middleware/
- [x] src/middleware/auth.ts
- [x] src/middleware/security.ts
## src/routes/admin/
- [x] src/routes/admin/ai.ts
- [x] src/routes/admin/attendance.ts
- [x] src/routes/admin/audit-log.ts
- [x] src/routes/admin/auth.ts
- [x] src/routes/admin/bank-accounts.ts
- [x] src/routes/admin/company-settings.ts
- [x] src/routes/admin/customers.ts
- [x] src/routes/admin/dashboard.ts
- [x] src/routes/admin/invoices-pdf.ts
- [x] src/routes/admin/invoices.ts
- [x] src/routes/admin/leave-requests.ts
- [x] src/routes/admin/offers-pdf.ts
- [x] src/routes/admin/orders-pdf.ts
- [x] src/routes/admin/orders.ts
- [x] src/routes/admin/plan.ts
- [x] src/routes/admin/profile.ts
- [x] src/routes/admin/project-files.ts
- [x] src/routes/admin/projects.ts
- [x] src/routes/admin/quotations.ts
- [x] src/routes/admin/received-invoices.ts
- [x] src/routes/admin/roles.ts
- [x] src/routes/admin/scope-templates.ts
- [x] src/routes/admin/sessions.ts
- [x] src/routes/admin/totp.ts
- [x] src/routes/admin/trips.ts
- [x] src/routes/admin/users.ts
- [x] src/routes/admin/vehicles.ts
- [x] src/routes/admin/warehouse.ts
## src/schemas/
- [x] src/schemas/ai.schema.ts
- [x] src/schemas/attendance.schema.ts
- [x] src/schemas/auth.schema.ts
- [x] src/schemas/bank-accounts.schema.ts
- [x] src/schemas/common.ts
- [x] src/schemas/customers.schema.ts
- [x] src/schemas/invoices.schema.ts
- [x] src/schemas/leave-requests.schema.ts
- [x] src/schemas/offers.schema.ts
- [x] src/schemas/orders.schema.ts
- [x] src/schemas/plan.schema.ts
- [x] src/schemas/planCategory.schema.ts
- [x] src/schemas/profile.schema.ts
- [x] src/schemas/projects.schema.ts
- [x] src/schemas/received-invoices.schema.ts
- [x] src/schemas/roles.schema.ts
- [x] src/schemas/scope-templates.schema.ts
- [x] src/schemas/settings.schema.ts
- [x] src/schemas/trips.schema.ts
- [x] src/schemas/users.schema.ts
- [x] src/schemas/vehicles.schema.ts
- [x] src/schemas/warehouse.schema.ts
## src/
- [x] src/server.ts
## src/services/
- [x] src/services/ai.service.ts
- [x] src/services/attendance.service.ts
- [x] src/services/audit.ts
- [x] src/services/auth.ts
- [x] src/services/exchange-rates.ts
- [x] src/services/invoice-alerts.ts
- [x] src/services/invoices.service.ts
- [x] src/services/leave-notification.ts
- [x] src/services/mailer.ts
- [x] src/services/nas-file-manager.ts
- [x] src/services/nas-financials-manager.ts
- [x] src/services/nas-offers-manager.ts
- [x] src/services/numbering.service.ts
- [x] src/services/offers.service.ts
- [x] src/services/orders.service.ts
- [x] src/services/plan.service.ts
- [x] src/services/planCategory.service.ts
- [x] src/services/projects.service.ts
- [x] src/services/system-settings.ts
- [x] src/services/users.service.ts
- [x] src/services/warehouse.service.ts
## src/types/
- [x] src/types/fastify.d.ts
- [x] src/types/index.ts
## src/utils/
- [x] src/utils/czech-holidays.ts
- [x] src/utils/date.ts
- [x] src/utils/encryption.ts
- [x] src/utils/html-to-pdf.ts
- [x] src/utils/pagination.ts
- [x] src/utils/planAuditDescription.ts
- [x] src/utils/response.ts
- [x] src/utils/totp.ts
## src/
- [x] src/vite-env.d.ts
## ./
- [x] tsconfig.app.json
- [x] tsconfig.json
- [x] tsconfig.server.json
- [x] vite.config.ts
- [x] vitest.config.ts

1330
REVIEW_FINDINGS.md Normal file

File diff suppressed because it is too large Load Diff

1385
REVIEW_FIXES.md Normal file

File diff suppressed because it is too large Load Diff