From fb63eea2776f233dd3501225a930fa272a7c9282 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+catomean@users.noreply.github.com> Date: Sat, 29 Aug 2026 11:34:21 +0200 Subject: [PATCH 1/6] chore: add a formatter, matching the style this repo already writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit singleQuote=false was chosen by counting this repo's own imports, not by fleet decree. The fleet is genuinely split and the two repos that already had a .prettierrc disagreed with each other, so there was no standard to restore. Quote style does not cross repo boundaries; having a gate does. Markdown is ignored for now — prettier rewraps prose, which would bury the real diff. Co-Authored-By: Claude Opus 5 --- .prettierignore | 21 +++++++++++++++++++++ .prettierrc | 9 +++++++++ package.json | 9 +++++---- pnpm-lock.yaml | 36 +++++++++++++----------------------- 4 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..1ed5ea51 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,21 @@ +# Build output and vendored trees — formatting these is noise. +node_modules +.next +dist +build +out +coverage +.turbo +.vercel +*.min.js +*.min.css + +# Lockfiles are generated; prettier would rewrite them wholesale. +package-lock.json +pnpm-lock.yaml +yarn.lock + +# Markdown is deliberately out of scope for now. Prettier rewraps prose, which +# is where it is most opinionated and least useful, and it would bury the real +# diff. Remove this line when you want docs formatted too. +*.md diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..a2f11f06 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": true, + "singleQuote": false, + "printWidth": 100, + "tabWidth": 2, + "trailingComma": "all", + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/package.json b/package.json index 3ecb88cf..2caaec21 100644 --- a/package.json +++ b/package.json @@ -34,20 +34,21 @@ "lint": "turbo lint", "test": "turbo test", "type-check": "turbo type-check", - "verify": "pnpm lint && pnpm type-check && pnpm test", + "verify": "npm run format:check && pnpm lint && pnpm type-check && pnpm test", "smoke:production": "tsx scripts/production-smoke.ts", "clean": "turbo clean && rm -rf node_modules", "db:generate": "turbo db:generate", "db:migrate": "turbo db:migrate", "db:studio": "pnpm --filter @kivvi/database db:studio", - "format": "prettier --write \"**/*.{ts,tsx,md,json}\"", - "prepare": "husky" + "format": "prettier --write .", + "prepare": "husky", + "format:check": "prettier --check ." }, "devDependencies": { "@types/node": "^20.11.0", "husky": "^9.1.7", "lint-staged": "^16.3.3", - "prettier": "^3.2.4", + "prettier": "3.9.6", "tsx": "^4.21.0", "turbo": "^2.0.0", "typescript": "^5.3.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8219216c..b245b98d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,8 +31,8 @@ importers: specifier: ^16.3.3 version: 16.3.3 prettier: - specifier: ^3.2.4 - version: 3.8.0 + specifier: 3.9.6 + version: 3.9.6 tsx: specifier: ^4.21.0 version: 4.21.0 @@ -62,7 +62,7 @@ importers: version: 3.2.2(react@18.3.1) '@fleet/ai-forms': specifier: github:catomean/ai-forms#v0.1.0 - version: https://codeload.github.com/catomean/ai-forms/tar.gz/68087895ab9d46d73d03b91ebf5e648b969ebd76(react@18.3.1) + version: git+git@github.com:catomean/ai-forms.git#68087895ab9d46d73d03b91ebf5e648b969ebd76(react@18.3.1) '@kivvi/ai': specifier: workspace:* version: link:../../packages/ai @@ -464,11 +464,11 @@ packages: '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - deprecated: 'Merged into tsx: https://tsx.is' + deprecated: 'Merged into tsx: https://tsx.hirok.io' '@esbuild-kit/esm-loader@2.6.5': resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - deprecated: 'Merged into tsx: https://tsx.is' + deprecated: 'Merged into tsx: https://tsx.hirok.io' '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} @@ -914,15 +914,6 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@fleet/ai-forms@https://codeload.github.com/catomean/ai-forms/tar.gz/68087895ab9d46d73d03b91ebf5e648b969ebd76': - resolution: {tarball: https://codeload.github.com/catomean/ai-forms/tar.gz/68087895ab9d46d73d03b91ebf5e648b969ebd76} - version: 0.1.0 - peerDependencies: - react: '>=18' - peerDependenciesMeta: - react: - optional: true - '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -2429,6 +2420,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} @@ -2980,6 +2972,7 @@ packages: crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained. cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} @@ -3684,12 +3677,12 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -4724,8 +4717,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.0: - resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} engines: {node: '>=14'} hasBin: true @@ -5488,6 +5481,7 @@ packages: uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true vfile-message@4.0.3: @@ -6146,10 +6140,6 @@ snapshots: '@eslint/js@8.57.1': {} - '@fleet/ai-forms@https://codeload.github.com/catomean/ai-forms/tar.gz/68087895ab9d46d73d03b91ebf5e648b969ebd76(react@18.3.1)': - optionalDependencies: - react: 18.3.1 - '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -10296,7 +10286,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.8.0: {} + prettier@3.9.6: {} progress@2.0.3: {} From 6e3cbb357b6cccf73052848bcae815bcb9c057d7 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+catomean@users.noreply.github.com> Date: Sat, 29 Aug 2026 11:38:46 +0200 Subject: [PATCH 2/6] style: format with prettier (759 files) Mechanical. No behaviour change. This SHA is listed in .git-blame-ignore-revs so `git blame` skips it. Co-Authored-By: Claude Opus 5 --- .github/workflows/auto-merge.yml | 6 +- .github/workflows/ci.yml | 22 +- apps/web/app/(auth)/error.tsx | 4 +- apps/web/app/(auth)/forgot-password/page.tsx | 27 +- .../invite/[token]/invite-register-form.tsx | 43 +- apps/web/app/(auth)/invite/[token]/page.tsx | 23 +- apps/web/app/(auth)/join/join-home.tsx | 62 +- apps/web/app/(auth)/login/page.tsx | 41 +- .../register/register-features-panel.tsx | 4 +- .../web/app/(auth)/register/register-form.tsx | 35 +- .../reset-password/reset-password-form.tsx | 73 +- .../accounting/accounts/[code]/page.tsx | 23 +- .../chart-of-accounts/account-form.tsx | 36 +- .../accounting/chart-of-accounts/page.tsx | 31 +- .../chart-of-accounts/toggle-button.tsx | 6 +- .../fiscal-years/[id]/close-buttons.tsx | 18 +- .../accounting/fiscal-years/[id]/loading.tsx | 2 +- .../accounting/fiscal-years/[id]/page.tsx | 37 +- .../accounting/fiscal-years/loading.tsx | 32 +- .../accounting/fiscal-years/new-year-form.tsx | 19 +- .../accounting/fiscal-years/page.tsx | 8 +- .../accounting/journal/[id]/delete-button.tsx | 8 +- .../accounting/journal/[id]/loading.tsx | 2 +- .../accounting/journal/[id]/page.tsx | 57 +- .../journal/journal-entries-table.tsx | 35 +- .../accounting/journal/new/account-picker.tsx | 7 +- .../accounting/journal/new/loading.tsx | 2 +- .../accounting/journal/new/page.tsx | 52 +- .../journal/new/use-journal-entry-form.ts | 24 +- .../(dashboard)/accounting/journal/page.tsx | 30 +- apps/web/app/(dashboard)/accounting/page.tsx | 8 +- .../[bankAccountId]/auto-match-button.tsx | 4 +- .../bank-transactions-table.tsx | 19 +- .../[bankAccountId]/import-transactions.tsx | 44 +- .../banking/[bankAccountId]/loading.tsx | 2 +- .../banking/[bankAccountId]/page.tsx | 56 +- .../banking/[bankAccountId]/parse-bank-csv.ts | 9 +- .../[bankAccountId]/reconcile-button.tsx | 38 +- .../transaction-preview-table.tsx | 46 +- .../(dashboard)/banking/add-account-form.tsx | 25 +- apps/web/app/(dashboard)/banking/page.tsx | 23 +- apps/web/app/(dashboard)/chat/loading.tsx | 6 +- apps/web/app/(dashboard)/chat/page.tsx | 14 +- .../contacts/[id]/address-manager.tsx | 59 +- .../contacts/[id]/contact-detail-sidebar.tsx | 44 +- .../contacts/[id]/contact-donated-items.tsx | 9 +- .../contacts/[id]/contact-donor-impact.tsx | 34 +- .../[id]/contact-recent-documents.tsx | 16 +- .../contacts/[id]/delete-button.tsx | 40 +- .../contacts/[id]/edit/edit-form.tsx | 6 +- .../contacts/[id]/edit/loading.tsx | 2 +- .../app/(dashboard)/contacts/[id]/loading.tsx | 2 +- .../app/(dashboard)/contacts/[id]/page.tsx | 43 +- apps/web/app/(dashboard)/contacts/error.tsx | 4 +- apps/web/app/(dashboard)/contacts/loading.tsx | 5 +- .../app/(dashboard)/contacts/new/loading.tsx | 2 +- .../web/app/(dashboard)/contacts/new/page.tsx | 2 +- apps/web/app/(dashboard)/contacts/page.tsx | 44 +- apps/web/app/(dashboard)/dashboard/charts.tsx | 29 +- .../web/app/(dashboard)/dashboard/loading.tsx | 2 +- apps/web/app/(dashboard)/dashboard/page.tsx | 6 +- .../dashboard/sections/alert-card.tsx | 25 +- .../dashboard/sections/executive-summary.tsx | 19 +- .../dashboard/sections/impact-overview.tsx | 36 +- .../dashboard/sections/inventory-overview.tsx | 37 +- .../sections/onboarding-checklist.tsx | 10 +- .../sections/priority-actions-server.tsx | 5 +- .../dashboard/sections/priority-actions.tsx | 61 +- .../dashboard/sections/quick-actions.tsx | 9 +- .../dashboard/sections/recent-activity.tsx | 20 +- .../sections/revampit-integration-health.tsx | 12 +- .../sections/revampit-workflow-hub.tsx | 8 +- .../dashboard/sections/smart-stats.tsx | 27 +- .../dashboard/sections/welcome-section.tsx | 14 +- .../documents/document-list-table.tsx | 42 +- .../web/app/(dashboard)/documents/loading.tsx | 5 +- apps/web/app/(dashboard)/documents/page.tsx | 20 +- apps/web/app/(dashboard)/error.tsx | 22 +- apps/web/app/(dashboard)/help/page.tsx | 25 +- .../(dashboard)/intake/[id]/labels/page.tsx | 9 +- apps/web/app/(dashboard)/intake/[id]/page.tsx | 38 +- .../intake/[id]/send-receipt-button.tsx | 5 +- .../items/[id]/edit/item-details-fields.tsx | 67 +- .../intake/items/[id]/edit/item-edit-form.tsx | 41 +- .../items/[id]/inventory-item-sidebar.tsx | 25 +- .../(dashboard)/intake/items/[id]/page.tsx | 51 +- .../intake/items/[id]/ricardo-button.tsx | 17 +- .../items/[id]/test/checklist-check-row.tsx | 26 +- .../intake/items/[id]/test/checklist-form.tsx | 52 +- .../intake/items/[id]/test/page.tsx | 18 +- .../items/[id]/test/use-checklist-state.ts | 11 +- .../items/import/inventory-import-panel.tsx | 140 +--- .../intake/items/inventory-filter-pills.tsx | 10 +- .../intake/items/inventory-metrics-grid.tsx | 37 +- .../web/app/(dashboard)/intake/items/page.tsx | 63 +- apps/web/app/(dashboard)/intake/page.tsx | 7 +- .../quick/_components/step-condition.tsx | 14 +- .../quick/_components/step-description.tsx | 12 +- .../intake/quick/_components/step-donor.tsx | 21 +- .../intake/quick/_components/step-photo.tsx | 20 +- .../web/app/(dashboard)/intake/quick/page.tsx | 4 +- .../(dashboard)/intake/repair-queue/page.tsx | 49 +- .../inventory/[warehouseId]/loading.tsx | 2 +- .../inventory/[warehouseId]/page.tsx | 49 +- .../inventory/add-warehouse-form.tsx | 21 +- apps/web/app/(dashboard)/inventory/error.tsx | 4 +- .../inventory/movements/loading.tsx | 5 +- .../(dashboard)/inventory/movements/page.tsx | 82 +-- apps/web/app/(dashboard)/inventory/page.tsx | 16 +- apps/web/app/(dashboard)/layout.tsx | 21 +- .../web/app/(dashboard)/money/banking-tab.tsx | 22 +- apps/web/app/(dashboard)/money/error.tsx | 30 +- apps/web/app/(dashboard)/money/loading.tsx | 5 +- .../app/(dashboard)/money/overview-tab.tsx | 74 +- apps/web/app/(dashboard)/not-found.tsx | 16 +- .../(dashboard)/pos/_components/pos-cart.tsx | 18 +- .../pos/_components/pos-completion-screen.tsx | 10 +- .../pos/_components/pos-payment-panel.tsx | 4 +- .../pos/_components/pos-search.tsx | 8 +- apps/web/app/(dashboard)/pos/page.tsx | 11 +- .../products/[id]/edit/edit-form.tsx | 6 +- .../products/[id]/edit/loading.tsx | 2 +- .../app/(dashboard)/products/[id]/loading.tsx | 2 +- .../app/(dashboard)/products/[id]/page.tsx | 14 +- .../products/[id]/product-detail-main.tsx | 65 +- .../products/[id]/product-detail-sidebar.tsx | 28 +- apps/web/app/(dashboard)/products/error.tsx | 4 +- apps/web/app/(dashboard)/products/loading.tsx | 5 +- .../app/(dashboard)/products/new/loading.tsx | 2 +- .../web/app/(dashboard)/products/new/page.tsx | 2 +- apps/web/app/(dashboard)/products/page.tsx | 27 +- .../products/products-filter-bar.tsx | 19 +- .../(dashboard)/projects/[id]/edit-form.tsx | 61 +- .../app/(dashboard)/projects/[id]/loading.tsx | 2 +- .../app/(dashboard)/projects/[id]/page.tsx | 43 +- .../projects/[id]/project-detail-sidebar.tsx | 35 +- .../[id]/project-linked-documents.tsx | 53 +- apps/web/app/(dashboard)/projects/error.tsx | 30 +- .../app/(dashboard)/projects/new/loading.tsx | 2 +- .../web/app/(dashboard)/projects/new/page.tsx | 54 +- apps/web/app/(dashboard)/projects/page.tsx | 68 +- .../projects/project-table-row.tsx | 11 +- apps/web/app/(dashboard)/purchasing/error.tsx | 4 +- .../web/app/(dashboard)/purchasing/layout.tsx | 6 +- .../purchase-invoices/[id]/edit/loading.tsx | 2 +- .../purchase-invoices/[id]/edit/page.tsx | 4 +- .../purchase-invoices/[id]/loading.tsx | 2 +- .../purchase-invoices/new/loading.tsx | 2 +- .../purchasing/purchase-invoices/new/page.tsx | 2 +- .../purchasing/purchase-invoices/page.tsx | 4 +- .../purchase-orders/[id]/edit/loading.tsx | 2 +- .../purchase-orders/[id]/loading.tsx | 2 +- .../purchase-orders/new/loading.tsx | 2 +- .../purchasing/purchase-orders/new/page.tsx | 2 +- .../repairs/new/repair-intake-form.tsx | 6 +- .../app/(dashboard)/reports/aging/loading.tsx | 2 +- .../app/(dashboard)/reports/aging/page.tsx | 81 +-- .../reports/balance-sheet/loading.tsx | 2 +- .../reports/balance-sheet/page.tsx | 33 +- .../(dashboard)/reports/date-picker-form.tsx | 31 +- .../(dashboard)/reports/date-range-form.tsx | 41 +- apps/web/app/(dashboard)/reports/error.tsx | 4 +- .../app/(dashboard)/reports/export-button.tsx | 38 +- .../app/(dashboard)/reports/health/page.tsx | 45 +- .../(dashboard)/reports/impact/cycle-time.tsx | 4 +- .../reports/impact/destination-breakdown.tsx | 11 +- .../reports/impact/impact-pdf-download.tsx | 7 +- .../reports/impact/monthly-trend.tsx | 22 +- .../app/(dashboard)/reports/impact/page.tsx | 96 +-- .../reports/impact/status-dwell.tsx | 27 +- .../(dashboard)/reports/impact/top-donors.tsx | 16 +- apps/web/app/(dashboard)/reports/page.tsx | 4 +- .../reports/profit-loss/loading.tsx | 2 +- .../(dashboard)/reports/profit-loss/page.tsx | 23 +- .../app/(dashboard)/reports/sales/loading.tsx | 2 +- .../app/(dashboard)/reports/sales/page.tsx | 63 +- .../app/(dashboard)/reports/vat/loading.tsx | 2 +- apps/web/app/(dashboard)/reports/vat/page.tsx | 31 +- .../sales/credit-notes/[id]/edit/loading.tsx | 2 +- .../sales/credit-notes/[id]/loading.tsx | 2 +- .../delivery-notes/[id]/edit/loading.tsx | 2 +- .../sales/delivery-notes/[id]/loading.tsx | 2 +- .../sales/dunning/[id]/loading.tsx | 2 +- .../sales/dunning/dunning-button.tsx | 7 +- .../app/(dashboard)/sales/dunning/loading.tsx | 5 +- .../app/(dashboard)/sales/dunning/page.tsx | 6 +- apps/web/app/(dashboard)/sales/error.tsx | 4 +- .../sales/invoices/[id]/edit/loading.tsx | 2 +- .../sales/invoices/[id]/loading.tsx | 2 +- .../sales/invoices/new/loading.tsx | 2 +- .../(dashboard)/sales/invoices/new/page.tsx | 2 +- apps/web/app/(dashboard)/sales/layout.tsx | 6 +- .../sales/orders/[id]/edit/loading.tsx | 2 +- .../sales/orders/[id]/edit/page.tsx | 7 +- .../(dashboard)/sales/orders/[id]/loading.tsx | 2 +- .../(dashboard)/sales/orders/new/loading.tsx | 2 +- .../app/(dashboard)/sales/orders/new/page.tsx | 2 +- .../sales/quotes/[id]/edit/loading.tsx | 2 +- .../(dashboard)/sales/quotes/[id]/loading.tsx | 2 +- .../(dashboard)/sales/quotes/new/loading.tsx | 2 +- .../app/(dashboard)/sales/quotes/new/page.tsx | 2 +- .../settings/api-tokens/api-tokens-panel.tsx | 44 +- .../settings/api-tokens/loading.tsx | 5 +- .../(dashboard)/settings/api-tokens/page.tsx | 4 +- .../settings/billing/billing-actions.tsx | 28 +- .../(dashboard)/settings/billing/loading.tsx | 2 +- .../app/(dashboard)/settings/billing/page.tsx | 19 +- .../settings/company/ai-config-section.tsx | 33 +- .../settings/company/co2-factors-section.tsx | 6 +- .../company-form-sections/address-section.tsx | 13 +- .../bank-details-section.tsx | 5 +- .../company-info-section.tsx | 13 +- .../document-footer-section.tsx | 5 +- .../preferences-section.tsx | 30 +- .../settings/company/company-form.tsx | 23 +- .../(dashboard)/settings/company/loading.tsx | 2 +- .../settings/company/logo-upload.tsx | 10 +- .../company/organization-profile-section.tsx | 80 +-- .../app/(dashboard)/settings/company/page.tsx | 73 +- .../settings/company/shop-url-section.tsx | 6 +- .../settings/cutover/cutover-panels.tsx | 37 +- .../app/(dashboard)/settings/cutover/page.tsx | 5 +- .../data-repair/data-quality-panel.tsx | 29 +- .../data-repair/data-quality-section.tsx | 12 +- .../data-repair/data-repair-panel.tsx | 75 +- .../data-repair/document-issues-table.tsx | 17 +- .../settings/data-repair/duplicate-group.tsx | 10 +- .../(dashboard)/settings/data-repair/page.tsx | 24 +- .../data-repair/product-issues-table.tsx | 4 +- .../data-repair/repair-card-sections.tsx | 14 +- apps/web/app/(dashboard)/settings/error.tsx | 4 +- .../integration-review-section.tsx | 26 +- .../integrations/operations-section.tsx | 113 +--- .../settings/integrations/page.tsx | 5 +- .../settings/integrations/ricardo-section.tsx | 24 +- .../settings/modules/modules-form.tsx | 19 +- .../app/(dashboard)/settings/modules/page.tsx | 5 +- apps/web/app/(dashboard)/settings/page.tsx | 21 +- .../settings/price-lists/[id]/page.tsx | 6 +- .../settings/price-lists/add-rule-form.tsx | 16 +- .../(dashboard)/settings/price-lists/page.tsx | 6 +- .../settings/price-lists/price-list-form.tsx | 9 +- .../price-lists/price-rules-table.tsx | 12 +- .../settings/profile/avatar-upload.tsx | 19 +- .../settings/profile/change-password-form.tsx | 28 +- .../(dashboard)/settings/profile/loading.tsx | 2 +- .../app/(dashboard)/settings/profile/page.tsx | 10 +- .../settings/profile/profile-form.tsx | 38 +- .../recurring-invoices/[id]/loading.tsx | 2 +- .../settings/recurring-invoices/[id]/page.tsx | 11 +- .../_components/base-order-section.tsx | 19 +- .../_components/notes-section.tsx | 4 +- .../_components/schedule-section.tsx | 42 +- .../email-recipients-section.tsx | 4 +- .../recurring-invoices/new/loading.tsx | 2 +- .../settings/recurring-invoices/new/page.tsx | 5 +- .../settings/recurring-invoices/page.tsx | 8 +- .../recurring-config-form.tsx | 5 +- .../recurring-config-row.tsx | 28 +- .../settings/repair-import/page.tsx | 8 +- .../repair-import/product-import-panel.tsx | 48 +- .../repair-import/repair-import-form.tsx | 176 ++--- .../settings/sequences/loading.tsx | 7 +- .../(dashboard)/settings/sequences/page.tsx | 9 +- .../settings/sequences/sequence-row.tsx | 16 +- .../app/(dashboard)/settings/team/loading.tsx | 5 +- .../app/(dashboard)/settings/team/page.tsx | 52 +- .../(dashboard)/settings/team/role-badge.tsx | 8 +- .../settings/team/team-invitations-list.tsx | 10 +- .../_components/webhook-create-form.tsx | 37 +- .../_components/webhook-endpoint-card.tsx | 18 +- .../webhooks/webhook-delivery-log.tsx | 47 +- .../settings/webhooks/webhooks-panel.tsx | 26 +- apps/web/app/(landing)/about/page.tsx | 40 +- .../app/(landing)/circular-economy/page.tsx | 88 +-- .../app/(landing)/contact/_contact-form.tsx | 31 +- apps/web/app/(landing)/contact/page.tsx | 4 +- apps/web/app/(landing)/datenschutz/page.tsx | 53 +- apps/web/app/(landing)/faq/page.tsx | 12 +- .../app/(landing)/for/brockenhaeuser/page.tsx | 37 +- .../(landing)/for/it-refurbishers/page.tsx | 37 +- .../app/(landing)/for/repair-cafes/page.tsx | 45 +- apps/web/app/(landing)/for/vintage/page.tsx | 31 +- apps/web/app/(landing)/how-it-works/page.tsx | 58 +- apps/web/app/(landing)/impressum/page.tsx | 25 +- .../app/(landing)/knowledge/[slug]/page.tsx | 19 +- apps/web/app/(landing)/knowledge/page.tsx | 32 +- apps/web/app/(landing)/landing-ai-section.tsx | 18 +- .../(landing)/landing-deployment-section.tsx | 4 +- .../(landing)/landing-scenarios-section.tsx | 8 +- apps/web/app/(landing)/layout.tsx | 6 +- apps/web/app/(landing)/opengraph-image.tsx | 4 +- .../app/(landing)/orgs/[slug]/apply-form.tsx | 16 +- apps/web/app/(landing)/orgs/[slug]/page.tsx | 46 +- apps/web/app/(landing)/orgs/page.tsx | 24 +- apps/web/app/(landing)/page.tsx | 53 +- .../app/(landing)/pricing/opengraph-image.tsx | 6 +- apps/web/app/(landing)/pricing/page.tsx | 80 +-- apps/web/app/(landing)/roadmap/page.tsx | 80 +-- .../web/app/(landing)/roadmap/roadmap-data.ts | 23 +- apps/web/app/(landing)/why-kivvi/page.tsx | 35 +- .../(onboarding)/components/ColumnMapper.tsx | 35 +- .../(onboarding)/components/CsvUploader.tsx | 16 +- .../components/ImportCategoryList.tsx | 16 +- .../components/ImportChoiceScreen.tsx | 16 +- .../(onboarding)/components/ImportPreview.tsx | 16 +- .../components/ImportProgress.tsx | 14 +- .../components/OnboardingShell.tsx | 10 +- .../components/StepBusinessConfig.tsx | 52 +- .../components/StepCompanyInfo.tsx | 34 +- .../components/StepDataImport.tsx | 92 +-- .../app/(onboarding)/onboarding/layout.tsx | 6 +- apps/web/app/(onboarding)/onboarding/page.tsx | 19 +- apps/web/app/actions/accounting.ts | 79 +-- apps/web/app/actions/action-factory.ts | 4 +- apps/web/app/actions/ai-extract.ts | 19 +- apps/web/app/actions/api-tokens.ts | 16 +- apps/web/app/actions/auth.ts | 25 +- apps/web/app/actions/banking.ts | 52 +- apps/web/app/actions/billing.ts | 18 +- apps/web/app/actions/bulk-import.ts | 203 ++---- apps/web/app/actions/bulk-operations.ts | 127 +--- apps/web/app/actions/contact.ts | 28 +- apps/web/app/actions/contacts.ts | 39 +- apps/web/app/actions/csv-export.ts | 11 +- apps/web/app/actions/cutover.ts | 9 +- apps/web/app/actions/dashboard-preferences.ts | 24 +- apps/web/app/actions/data-quality.ts | 35 +- apps/web/app/actions/data-repair.ts | 21 +- apps/web/app/actions/documents.ts | 137 +--- apps/web/app/actions/dunning.ts | 10 +- apps/web/app/actions/email.ts | 83 +-- apps/web/app/actions/integrations.ts | 308 +++------ apps/web/app/actions/inventory-items.ts | 176 ++--- apps/web/app/actions/inventory.ts | 70 +- apps/web/app/actions/invitations.ts | 36 +- apps/web/app/actions/memberships.ts | 51 +- apps/web/app/actions/onboarding.ts | 122 +--- apps/web/app/actions/parse-form-data.ts | 2 +- apps/web/app/actions/participation.ts | 41 +- apps/web/app/actions/password-reset.ts | 33 +- apps/web/app/actions/pricing.ts | 49 +- apps/web/app/actions/products.ts | 16 +- apps/web/app/actions/projects.ts | 31 +- apps/web/app/actions/recurring-invoices.ts | 29 +- apps/web/app/actions/reports.ts | 49 +- apps/web/app/actions/search.ts | 3 +- apps/web/app/actions/settings.ts | 81 +-- apps/web/app/actions/shop.ts | 19 +- apps/web/app/actions/utils.ts | 11 +- .../app/actions/utils/revalidate-documents.ts | 5 +- apps/web/app/actions/webhooks.ts | 40 +- apps/web/app/api/auth/[...nextauth]/route.ts | 2 +- apps/web/app/api/chat/route.ts | 89 +-- apps/web/app/api/cron/dunning/route.ts | 15 +- .../app/api/cron/recurring-invoices/route.ts | 20 +- .../documents/[id]/delivery-note-pdf/route.ts | 25 +- apps/web/app/api/documents/[id]/pdf/route.ts | 35 +- .../app/api/documents/[id]/quote-pdf/route.ts | 25 +- apps/web/app/api/export/[entity]/route.ts | 15 +- apps/web/app/api/export/full/route.ts | 55 +- apps/web/app/api/intake/[id]/receipt/route.ts | 25 +- .../items/[id]/erasure-certificate/route.ts | 23 +- apps/web/app/api/reports/impact-pdf/route.ts | 38 +- apps/web/app/api/v1/contacts/[id]/route.ts | 23 +- apps/web/app/api/v1/contacts/route.ts | 3 +- .../api/v1/documents/[id]/payments/route.ts | 19 +- apps/web/app/api/v1/documents/[id]/route.ts | 37 +- apps/web/app/api/v1/documents/route.ts | 26 +- .../[id]/repair-labor-invoice/route.ts | 21 +- .../app/api/v1/inventory-items/[id]/route.ts | 30 +- apps/web/app/api/v1/inventory-items/route.ts | 9 +- .../api/v1/marketplace/agency-sales/route.ts | 16 +- .../app/api/v1/marketplace/payouts/route.ts | 16 +- apps/web/app/api/v1/products/[id]/route.ts | 23 +- apps/web/app/api/v1/products/route.ts | 3 +- .../v1/repair-orders/[id]/advance/route.ts | 20 +- .../v1/repair-orders/[id]/finalize/route.ts | 8 +- .../v1/repair-orders/[id]/subsidy/route.ts | 20 +- apps/web/app/api/v1/repair-orders/route.ts | 24 +- apps/web/app/api/v1/services/sales/route.ts | 24 +- apps/web/app/api/webhooks/ricardo/route.ts | 17 +- apps/web/app/api/webhooks/stripe/route.ts | 95 ++- apps/web/app/globals.css | 301 +++++---- apps/web/app/layout.tsx | 9 +- apps/web/app/not-found.tsx | 4 +- .../app/shop/[slug]/[itemId]/inquiry-form.tsx | 12 +- apps/web/app/shop/[slug]/[itemId]/page.tsx | 18 +- apps/web/app/shop/[slug]/page.tsx | 21 +- apps/web/app/shop/layout.tsx | 6 +- apps/web/app/sitemap.ts | 5 +- apps/web/components/back-button.tsx | 6 +- apps/web/components/breadcrumb.tsx | 16 +- apps/web/components/bulk-action-toolbar.tsx | 6 +- apps/web/components/bulk-confirm-dialog.tsx | 12 +- apps/web/components/bulk-result-banner.tsx | 27 +- .../web/components/chat-widget/chat-input.tsx | 14 +- .../components/chat-widget/chat-messages.tsx | 28 +- .../components/chat-widget/chat-widget.tsx | 15 +- .../command-bar/action-preview-card.tsx | 8 +- .../command-bar/ai-response-panel.tsx | 29 +- apps/web/components/command-palette.tsx | 28 +- .../contacts/contact-export-button.tsx | 5 +- .../contact-form-sections/address-section.tsx | 11 +- .../advanced-sections.tsx | 57 +- .../contact-form-sections/basic-section.tsx | 21 +- apps/web/components/contacts/contact-form.tsx | 31 +- .../components/contacts/contact-picker.tsx | 17 +- .../contacts/contact-quick-actions.tsx | 5 +- .../components/contacts/contact-table-row.tsx | 26 +- .../contacts/quick-create-modal.tsx | 22 +- .../contacts/selectable-contact-table.tsx | 27 +- apps/web/components/copy-button.tsx | 14 +- apps/web/components/csv-export-button.tsx | 6 +- .../components/documents/doc-type-sub-nav.tsx | 3 +- .../components/documents/document-actions.tsx | 10 +- .../documents/document-bulk-actions.tsx | 37 +- .../documents/document-contact-dates-card.tsx | 23 +- .../components/documents/document-delete.tsx | 20 +- .../documents/document-detail-main-column.tsx | 65 +- .../documents/document-detail-sidebar.tsx | 78 +-- .../components/documents/document-detail.tsx | 48 +- .../components/documents/document-form.tsx | 63 +- .../components/documents/document-list.tsx | 47 +- .../documents/document-summary-panel.tsx | 5 +- .../documents/edit-document-form.tsx | 37 +- .../documents/edit-document-page.tsx | 16 +- .../documents/edit-document-summary.tsx | 5 +- .../documents/edit-line-items-table.tsx | 34 +- .../documents/intake-bulk-review.tsx | 45 +- .../documents/intake-quick-entry.tsx | 27 +- .../documents/line-items-editor.tsx | 21 +- .../web/components/documents/payment-form.tsx | 41 +- .../documents/product-search-input.tsx | 43 +- .../documents/selectable-document-table.tsx | 39 +- .../documents/send-and-mark-button.tsx | 11 +- .../documents/send-email-dialog.tsx | 5 +- .../documents/sortable-line-item.tsx | 61 +- .../web/components/documents/status-badge.tsx | 22 +- .../documents/taler-payment-panel.tsx | 8 +- .../dunning/selectable-dunning-table.tsx | 31 +- apps/web/components/error-boundary.tsx | 24 +- apps/web/components/feature-hint.tsx | 7 +- apps/web/components/header.tsx | 76 +-- .../components/inventory/erasure-section.tsx | 12 +- .../inventory/item-batch-toolbar.tsx | 41 +- .../inventory/item-checklist-display.tsx | 24 +- apps/web/components/inventory/item-label.tsx | 20 +- .../inventory/item-photo-upload.tsx | 10 +- .../inventory/item-pricing-card.tsx | 40 +- .../inventory/item-specs-editor.tsx | 16 +- .../components/inventory/item-timeline.tsx | 56 +- .../inventory/movement-form/index.tsx | 42 +- .../movement-form/product-picker.tsx | 15 +- .../inventory/repair-labor-billing.tsx | 18 +- .../inventory/repair-parts-section/index.tsx | 5 +- .../repair-part-add-form.tsx | 25 +- .../repair-parts-list.tsx | 27 +- .../inventory/repair-queue-assign-button.tsx | 4 +- .../inventory/selectable-item-list.tsx | 16 +- .../components/keyboard-shortcuts-help.tsx | 22 +- apps/web/components/kivvi-logo.tsx | 8 +- .../landing/landing-cta-section.tsx | 11 +- .../web/components/landing/landing-footer.tsx | 3 +- .../web/components/landing/landing-header.tsx | 4 +- apps/web/components/landing/landing-nav.tsx | 19 +- apps/web/components/landing/vertical-card.tsx | 13 +- apps/web/components/landing/vertical-icons.ts | 5 +- apps/web/components/language-switcher.tsx | 43 +- apps/web/components/model-selector.tsx | 90 ++- apps/web/components/money/stat-cards.tsx | 22 +- apps/web/components/page-header.tsx | 8 +- apps/web/components/pagination.tsx | 7 +- .../products/product-export-button.tsx | 5 +- .../product-form-sections/basic-section.tsx | 19 +- .../inventory-section.tsx | 5 +- .../product-form-sections/pricing-section.tsx | 28 +- .../visibility-section.tsx | 4 +- apps/web/components/products/product-form.tsx | 17 +- .../components/products/product-table-row.tsx | 25 +- .../products/selectable-product-table.tsx | 23 +- apps/web/components/recent-items-dropdown.tsx | 18 +- .../web/components/section-error-boundary.tsx | 8 +- apps/web/components/session-provider.tsx | 6 +- .../components/settings-subpage-header.tsx | 8 +- apps/web/components/sidebar.tsx | 31 +- .../components/sidebar/company-switcher.tsx | 29 +- apps/web/components/sidebar/nav-link.tsx | 21 +- .../skeletons/detail-page-skeleton.tsx | 2 +- .../skeletons/document-list-skeleton.tsx | 5 +- .../skeletons/form-page-skeleton.tsx | 2 +- .../skeletons/report-page-skeleton.tsx | 2 +- apps/web/components/sortable-header.tsx | 8 +- apps/web/components/status-badge.tsx | 12 +- apps/web/components/theme-provider.tsx | 8 +- apps/web/components/theme-toggle.tsx | 8 +- apps/web/components/ui/ai-form-bar.tsx | 6 +- apps/web/components/ui/button.tsx | 19 +- apps/web/components/ui/char-count-input.tsx | 18 +- .../web/components/ui/char-count-textarea.tsx | 18 +- apps/web/components/ui/dropdown-menu.tsx | 8 +- apps/web/components/ui/form-field.tsx | 31 +- apps/web/components/ui/image-upload.tsx | 4 +- apps/web/components/ui/skeleton.tsx | 14 +- apps/web/e2e/auth.setup.ts | 23 +- apps/web/e2e/auth.spec.ts | 50 +- apps/web/e2e/contacts.spec.ts | 68 +- apps/web/e2e/global-teardown.ts | 14 +- apps/web/e2e/helpers.ts | 35 +- apps/web/e2e/import-demo-capture.spec.ts | 14 +- apps/web/e2e/intake.spec.ts | 19 +- apps/web/e2e/invoices.spec.ts | 54 +- apps/web/e2e/navigation.spec.ts | 8 +- apps/web/hooks/use-chat-widget.tsx | 24 +- apps/web/hooks/use-chat.ts | 29 +- apps/web/hooks/use-command-bar-ai.ts | 10 +- apps/web/hooks/use-command-palette.ts | 99 ++- apps/web/hooks/use-document-form.ts | 15 +- apps/web/hooks/use-focus-trap.ts | 6 +- apps/web/hooks/use-keyboard-shortcuts.ts | 21 +- apps/web/hooks/use-model-selection.ts | 3 +- apps/web/hooks/use-popover.ts | 5 +- apps/web/hooks/use-recent-items.ts | 16 +- apps/web/hooks/use-selection.ts | 8 +- apps/web/i18n/request.ts | 18 +- apps/web/i18n/types.ts | 4 +- apps/web/lib/ai-form-binding.ts | 10 +- apps/web/lib/ai/call-provider.ts | 17 +- apps/web/lib/api-auth.ts | 4 +- apps/web/lib/api-handler.ts | 13 +- apps/web/lib/api-idempotency.ts | 11 +- apps/web/lib/auth.ts | 9 +- .../web/lib/config/__tests__/ai-forms.test.ts | 7 +- apps/web/lib/config/command-palette-items.ts | 5 +- apps/web/lib/config/contact-types.ts | 4 +- apps/web/lib/config/currencies.ts | 2 +- apps/web/lib/config/dashboard-config.ts | 7 +- apps/web/lib/config/document-types.ts | 57 +- apps/web/lib/config/inventory-items.ts | 36 +- apps/web/lib/config/inventory.ts | 4 +- apps/web/lib/config/journal.ts | 2 +- apps/web/lib/config/locales.ts | 18 +- apps/web/lib/config/products.ts | 4 +- apps/web/lib/config/site.ts | 6 +- apps/web/lib/config/units.ts | 14 +- apps/web/lib/config/vat-rates.ts | 2 +- apps/web/lib/content/knowledge.ts | 9 +- apps/web/lib/csv-utils.ts | 4 +- apps/web/lib/db.ts | 4 +- apps/web/lib/email/transporter.ts | 6 +- apps/web/lib/env.ts | 14 +- apps/web/lib/integration-secrets.ts | 28 +- apps/web/lib/logger.ts | 10 +- apps/web/lib/pdf/build-pdf-data.ts | 5 +- apps/web/lib/rate-limit.ts | 5 +- apps/web/lib/render-document-detail-page.tsx | 5 +- apps/web/lib/ricardo-client.ts | 25 +- apps/web/lib/stripe.ts | 6 +- apps/web/lib/taler-client.ts | 68 +- apps/web/lib/utils.ts | 3 +- apps/web/middleware.ts | 33 +- apps/web/next.config.js | 44 +- apps/web/sentry.client.config.ts | 4 +- docker-compose.yml | 2 +- docs/openapi.yaml | 587 ++++++++-------- .../ai/src/__tests__/free-first-chain.test.ts | 12 +- .../ai/src/__tests__/tool-registry.test.ts | 4 +- .../ai/src/__tests__/tool-schemas.test.ts | 75 +- packages/ai/src/audit.ts | 41 +- packages/ai/src/context.ts | 5 +- packages/ai/src/engine.ts | 21 +- packages/ai/src/index.ts | 12 +- packages/ai/src/permissions.ts | 62 +- packages/ai/src/prompts.ts | 5 +- packages/ai/src/providers/anthropic.ts | 16 +- packages/ai/src/providers/index.ts | 20 +- packages/ai/src/providers/ollama.ts | 73 +- .../ai/src/providers/openai-compatible.ts | 102 +-- .../ai/src/tools/bulk-update-item-status.ts | 20 +- packages/ai/src/tools/classify-payment.ts | 22 +- packages/ai/src/tools/convert-document.ts | 69 +- packages/ai/src/tools/create-contact.ts | 15 +- packages/ai/src/tools/create-document.ts | 51 +- packages/ai/src/tools/create-journal-entry.ts | 37 +- packages/ai/src/tools/create-price-list.ts | 13 +- packages/ai/src/tools/create-price-rule.ts | 23 +- packages/ai/src/tools/create-product.ts | 9 +- .../src/tools/find-uninvoiced-repair-labor.ts | 4 +- packages/ai/src/tools/get-account-balances.ts | 7 +- packages/ai/src/tools/get-bank-summary.ts | 34 +- packages/ai/src/tools/get-customer-details.ts | 9 +- .../ai/src/tools/get-dashboard-summary.ts | 19 +- .../ai/src/tools/get-financial-summary.ts | 6 +- .../ai/src/tools/get-inventory-dashboard.ts | 3 +- packages/ai/src/tools/get-invoice-details.ts | 67 +- packages/ai/src/tools/get-item-details.ts | 24 +- packages/ai/src/tools/get-price-lists.ts | 14 +- packages/ai/src/tools/get-project-details.ts | 33 +- .../ai/src/tools/get-recurring-invoices.ts | 4 +- packages/ai/src/tools/get-report.ts | 69 +- packages/ai/src/tools/get-stock-levels.ts | 29 +- packages/ai/src/tools/index.ts | 5 +- .../ai/src/tools/intake-inventory-item.ts | 41 +- .../ai/src/tools/list-overdue-invoices.ts | 29 +- packages/ai/src/tools/prepare-document.ts | 36 +- packages/ai/src/tools/process-dunning.ts | 3 +- .../ai/src/tools/reconcile-transaction.ts | 13 +- packages/ai/src/tools/record-checklist.ts | 13 +- packages/ai/src/tools/record-data-erasure.ts | 13 +- packages/ai/src/tools/record-payment.ts | 10 +- packages/ai/src/tools/record-repair-part.ts | 24 +- packages/ai/src/tools/record-repair.ts | 27 +- .../ai/src/tools/resolve-product-price.ts | 31 +- .../ai/src/tools/return-inventory-item.ts | 9 +- packages/ai/src/tools/search-customers.ts | 10 +- packages/ai/src/tools/search-inventory.ts | 19 +- packages/ai/src/tools/search-invoices.ts | 64 +- packages/ai/src/tools/search-products.ts | 42 +- packages/ai/src/tools/search-projects.ts | 32 +- packages/ai/src/tools/search-repair-orders.ts | 19 +- packages/ai/src/tools/update-contact.ts | 13 +- .../ai/src/tools/update-document-status.ts | 6 +- .../ai/src/tools/update-inventory-item.ts | 56 +- packages/ai/src/tools/update-item-status.ts | 43 +- packages/ai/src/tools/update-product.ts | 26 +- packages/ai/src/tools/utils.ts | 21 +- packages/ai/src/types.ts | 15 +- .../__tests__/accounting-integration.test.ts | 56 +- .../core/src/__tests__/accounting.test.ts | 24 +- packages/core/src/__tests__/banking.test.ts | 284 ++++---- packages/core/src/__tests__/billing.test.ts | 4 +- .../__tests__/business-health-metrics.test.ts | 6 +- .../src/__tests__/business-snapshot.test.ts | 6 +- .../src/__tests__/calculate-totals.test.ts | 24 +- .../core/src/__tests__/camt-parser.test.ts | 212 +++--- .../src/__tests__/checklist-templates.test.ts | 34 +- .../core/src/__tests__/co2-factors.test.ts | 10 +- .../__tests__/consignment-accounting.test.ts | 80 +-- packages/core/src/__tests__/cutover.test.ts | 16 +- .../__tests__/dashboard-stats-change.test.ts | 6 +- .../core/src/__tests__/data-quality.test.ts | 40 +- .../__tests__/document-conversions.test.ts | 29 +- packages/core/src/__tests__/documents.test.ts | 15 +- .../__tests__/domain-webhook-emission.test.ts | 33 +- packages/core/src/__tests__/dunning.test.ts | 83 +-- packages/core/src/__tests__/email.test.ts | 16 +- .../src/__tests__/erasure-certificate.test.ts | 34 +- .../core/src/__tests__/idempotency.test.ts | 38 +- packages/core/src/__tests__/impact.test.ts | 81 +-- .../src/__tests__/import-mappings.test.ts | 393 ++++++----- .../core/src/__tests__/integrations.test.ts | 8 +- .../src/__tests__/inventory-dashboard.test.ts | 6 +- .../src/__tests__/inventory-import.test.ts | 50 +- .../__tests__/inventory-integration.test.ts | 21 +- .../src/__tests__/inventory-items.test.ts | 4 +- .../inventory-transfer-stock.test.ts | 39 +- .../core/src/__tests__/invitations.test.ts | 124 ++-- .../marketplace-agency-accounting.test.ts | 15 +- .../core/src/__tests__/memberships.test.ts | 128 ++-- packages/core/src/__tests__/modules.test.ts | 25 +- .../core/src/__tests__/onboarding.test.ts | 5 +- .../core/src/__tests__/pdf-generation.test.ts | 52 +- packages/core/src/__tests__/pricing.test.ts | 51 +- .../purchase-invoice-integration.test.ts | 54 +- .../core/src/__tests__/qr-reference.test.ts | 57 +- .../src/__tests__/recent-activity.test.ts | 10 +- .../record-payment-atomicity.test.ts | 15 +- .../src/__tests__/recurring-invoices.test.ts | 262 +++---- .../__tests__/repair-labor-invoice.test.ts | 17 +- packages/core/src/__tests__/repairs.test.ts | 12 +- packages/core/src/__tests__/reports.test.ts | 42 +- .../src/__tests__/revenue-leakage.test.ts | 6 +- .../core/src/__tests__/service-sales.test.ts | 22 +- .../src/__tests__/tenant-isolation.test.ts | 21 +- .../warehouse-single-default.test.ts | 23 +- .../__tests__/workflow-suggestions.test.ts | 9 +- .../core/src/config/checklist-templates.ts | 17 +- .../core/src/config/document-constants.ts | 7 +- packages/core/src/config/item-status-sets.ts | 13 +- packages/core/src/config/item-transitions.ts | 5 +- packages/core/src/config/modules.ts | 8 +- .../core/src/config/pipeline-thresholds.ts | 4 +- packages/core/src/config/product.ts | 10 +- packages/core/src/config/project.ts | 7 +- packages/core/src/config/vat-rates.ts | 16 +- .../core/src/domain/accounting-integration.ts | 97 +-- packages/core/src/domain/accounting.ts | 186 +---- packages/core/src/domain/banking.ts | 115 +--- packages/core/src/domain/business-snapshot.ts | 116 ++-- packages/core/src/domain/camt-parser.ts | 27 +- packages/core/src/domain/companies.ts | 5 +- packages/core/src/domain/contacts.ts | 124 +--- packages/core/src/domain/cost-centers.ts | 9 +- packages/core/src/domain/cutover.ts | 3 +- .../core/src/domain/dashboard-activity.ts | 12 +- packages/core/src/domain/dashboard-alerts.ts | 42 +- .../core/src/domain/dashboard-bootstrap.ts | 47 +- .../core/src/domain/dashboard-preferences.ts | 27 +- packages/core/src/domain/dashboard-stats.ts | 50 +- .../core/src/domain/dashboard-workflow.ts | 22 +- packages/core/src/domain/dashboard.ts | 5 +- packages/core/src/domain/data-quality.ts | 92 +-- packages/core/src/domain/data-repair.ts | 36 +- .../core/src/domain/document-conversions.ts | 19 +- packages/core/src/domain/documents.ts | 265 ++------ packages/core/src/domain/dunning.ts | 60 +- packages/core/src/domain/email.ts | 50 +- .../core/src/domain/erasure-certificate.ts | 41 +- packages/core/src/domain/funds.ts | 25 +- packages/core/src/domain/idempotency.ts | 27 +- packages/core/src/domain/impact-pdf.ts | 127 +--- packages/core/src/domain/impact.ts | 76 +-- packages/core/src/domain/import-bulk.ts | 129 +--- packages/core/src/domain/import-mappings.ts | 28 +- .../core/src/domain/intake-integration.ts | 8 +- .../core/src/domain/integration-health.ts | 79 +-- packages/core/src/domain/integrations.ts | 24 +- .../core/src/domain/inventory-dashboard.ts | 34 +- packages/core/src/domain/inventory-import.ts | 35 +- .../core/src/domain/inventory-integration.ts | 31 +- packages/core/src/domain/inventory-items.ts | 239 ++----- packages/core/src/domain/inventory.ts | 112 +-- packages/core/src/domain/invitations.ts | 42 +- packages/core/src/domain/ledger-hash.ts | 4 +- packages/core/src/domain/memberships.ts | 93 +-- packages/core/src/domain/nav-badges.ts | 91 +-- packages/core/src/domain/number-sequences.ts | 31 +- packages/core/src/domain/onboarding.ts | 5 +- packages/core/src/domain/participation.ts | 22 +- .../core/src/domain/payment-classification.ts | 21 +- packages/core/src/domain/pdf-generation.ts | 186 ++--- packages/core/src/domain/permissions.ts | 5 +- packages/core/src/domain/posting-groups.ts | 39 +- packages/core/src/domain/pricing.ts | 21 +- packages/core/src/domain/products.ts | 106 +-- packages/core/src/domain/projects.ts | 26 +- .../domain/purchase-invoice-integration.ts | 11 +- .../core/src/domain/recurring-invoices.ts | 61 +- packages/core/src/domain/repairs.ts | 68 +- packages/core/src/domain/reports.ts | 88 +-- packages/core/src/domain/revenue-leakage.ts | 13 +- packages/core/src/domain/ricardo.ts | 33 +- packages/core/src/domain/sample-data.ts | 11 +- packages/core/src/domain/service-sales.ts | 43 +- packages/core/src/domain/webhooks.ts | 52 +- packages/core/src/utils/format.ts | 6 +- packages/core/src/utils/overdue.ts | 14 +- packages/core/vitest.config.ts | 6 +- packages/database/drizzle.config.ts | 10 +- packages/database/src/enums.ts | 74 +- packages/database/src/index.ts | 4 +- packages/database/src/schema.ts | 638 ++++++------------ scripts/cleanup-import-data.ts | 168 ++--- scripts/fix-line-items.ts | 167 +++-- scripts/get-company-id.ts | 14 +- scripts/import-kivitendo.ts | 373 +++++----- scripts/production-smoke.ts | 16 +- scripts/set-org-profile.ts | 196 +++--- scripts/validate-kivitendo-csvs.ts | 152 +++-- 759 files changed, 7451 insertions(+), 16572 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 29dcf889..f814320c 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -19,10 +19,10 @@ name: Auto-merge on: workflow_run: - workflows: ['CI'] + workflows: ["CI"] types: [completed] schedule: - - cron: '*/10 * * * *' + - cron: "*/10 * * * *" workflow_dispatch: {} # Declared on the CALLER as well as inside the reusable workflow: a called @@ -46,4 +46,4 @@ jobs: # SPACE-separated: the sweep word-splits this. A comma would become one # bogus token, every dispatch would fail, and the only symptom would be # that nothing deploys — while the sweep still reported success. - rearm_workflows: 'ci.yml deploy.yml' + rearm_workflows: "ci.yml deploy.yml" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d317155f..d47f2f13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,17 +5,17 @@ on: push: branches: [main] paths-ignore: - - '**.md' - - 'docs/**' - - 'LICENSE' - - '.vscode/**' + - "**.md" + - "docs/**" + - "LICENSE" + - ".vscode/**" pull_request: branches: [main] paths-ignore: - - '**.md' - - 'docs/**' - - 'LICENSE' - - '.vscode/**' + - "**.md" + - "docs/**" + - "LICENSE" + - ".vscode/**" # Cancel in-progress runs on new pushes to the same PR concurrency: @@ -23,8 +23,8 @@ concurrency: cancel-in-progress: true env: - NODE_VERSION: '20' - PNPM_VERSION: '9' + NODE_VERSION: "20" + PNPM_VERSION: "9" jobs: ci: @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - cache: 'pnpm' + cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/apps/web/app/(auth)/error.tsx b/apps/web/app/(auth)/error.tsx index 1c620004..07fdb4bb 100644 --- a/apps/web/app/(auth)/error.tsx +++ b/apps/web/app/(auth)/error.tsx @@ -25,9 +25,7 @@ export default function AuthError({

{t("errorTitle")}

-

- {t("errorDescription")} -

+

{t("errorDescription")}

-

- {t("checkYourEmail")} -

-

- {t("resetEmailSent")} -

+

{t("checkYourEmail")}

+

{t("resetEmailSent")}

) : ( <> -

- {t("resetPassword")} -

-

- {t("resetPasswordSubtitle")} -

+

{t("resetPassword")}

+

{t("resetPasswordSubtitle")}

{error && (
- +
-
{error && ( -
- {error} -
+
{error}
)}
-
-
-
diff --git a/apps/web/app/(auth)/invite/[token]/page.tsx b/apps/web/app/(auth)/invite/[token]/page.tsx index 98c76b3f..df2e9556 100644 --- a/apps/web/app/(auth)/invite/[token]/page.tsx +++ b/apps/web/app/(auth)/invite/[token]/page.tsx @@ -6,10 +6,7 @@ import { useRouter } from "next/navigation"; import Link from "next/link"; import { Loader2, Building2, CheckCircle2, XCircle, Clock } from "lucide-react"; import { useTranslations } from "next-intl"; -import { - getInvitationDetailsAction, - acceptInvitationAction, -} from "@/app/actions/invitations"; +import { getInvitationDetailsAction, acceptInvitationAction } from "@/app/actions/invitations"; import { registerAndAcceptInviteAction } from "@/app/actions/auth"; import type { InvitationWithCompany } from "@kivvi/core/src/domain/invitations"; import { InviteRegisterForm } from "./invite-register-form"; @@ -20,18 +17,12 @@ interface InvitePageProps { export default function InvitePage({ params }: InvitePageProps) { const { token } = params; - const { - data: session, - status: sessionStatus, - update: updateSession, - } = useSession(); + const { data: session, status: sessionStatus, update: updateSession } = useSession(); const router = useRouter(); const t = useTranslations("team"); const tc = useTranslations("common"); - const [invitation, setInvitation] = useState( - null, - ); + const [invitation, setInvitation] = useState(null); const [loading, setLoading] = useState(true); const [accepting, setAccepting] = useState(false); const [error, setError] = useState(""); @@ -221,17 +212,13 @@ export default function InvitePage({ params }: InvitePageProps) {

{t("roleAssignment", { - role: invitation - ? tc(`permissionPresetLabel.${invitation.permissionPreset}`) - : "", + role: invitation ? tc(`permissionPresetLabel.${invitation.permissionPreset}`) : "", })}

{error && ( -
- {error} -
+
{error}
)} @@ -98,26 +81,16 @@ export function JoinHome({
{user.avatarBase64 ? ( // eslint-disable-next-line @next/next/no-img-element - + ) : ( )}

{title}

-

- {description} -

-

- {user.name || user.email} -

-

- {user.email} -

+

{description}

+

{user.name || user.email}

+

{user.email}

@@ -127,9 +100,7 @@ export function JoinHome({

{t("profileTitle")}

-

- {t("profileDesc")} -

+

{t("profileDesc")}

{t("pendingInvites")} {pendingInvites.length === 0 ? ( -

- {t("waitingDesc")} -

+

{t("waitingDesc")}

) : (
{pendingInvites.map((invite) => ( @@ -204,14 +173,9 @@ export function JoinHome({

- +
))} @@ -224,9 +188,7 @@ export function JoinHome({

{t("discoveryTitle")}

-

- {t("discoveryDesc")} -

+

{t("discoveryDesc")}

diff --git a/apps/web/app/(auth)/login/page.tsx b/apps/web/app/(auth)/login/page.tsx index eae5a5ef..182581b4 100644 --- a/apps/web/app/(auth)/login/page.tsx +++ b/apps/web/app/(auth)/login/page.tsx @@ -71,11 +71,7 @@ function LoginForm() { {error && (
- +
- - + {t("forgotPassword")}
@@ -133,24 +123,14 @@ function LoginForm() { onClick={() => setShowPassword(!showPassword)} className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground transition-colors hover:text-foreground" tabIndex={-1} - aria-label={ - showPassword ? t("hidePassword") : t("showPassword") - } + aria-label={showPassword ? t("hidePassword") : t("showPassword")} > - {showPassword ? ( - - ) : ( - - )} + {showPassword ? : }
- @@ -158,10 +138,7 @@ function LoginForm() {
{t("noAccount")}{" "} - + {t("createAccount")}
@@ -186,9 +163,7 @@ function LoginForm() { {/* Right side - Brand & Features */}
-

- {t("businessOnAutopilot")} -

+

{t("businessOnAutopilot")}

{t("heroSubtitle")}

    diff --git a/apps/web/app/(auth)/register/register-features-panel.tsx b/apps/web/app/(auth)/register/register-features-panel.tsx index 96b5b72a..e09f602b 100644 --- a/apps/web/app/(auth)/register/register-features-panel.tsx +++ b/apps/web/app/(auth)/register/register-features-panel.tsx @@ -19,9 +19,7 @@ export function RegisterFeaturesPanel() { return (
    -

    - {t("businessOnAutopilot")} -

    +

    {t("businessOnAutopilot")}

    {t("heroSubtitle")}

      diff --git a/apps/web/app/(auth)/register/register-form.tsx b/apps/web/app/(auth)/register/register-form.tsx index cc73f7a4..f203ec90 100644 --- a/apps/web/app/(auth)/register/register-form.tsx +++ b/apps/web/app/(auth)/register/register-form.tsx @@ -130,11 +130,7 @@ export function RegisterForm({ prefillEmail, callbackUrl }: RegisterFormProps) { {error && (
      - + -

      - {t("companyNameHint")} -

      +

      {t("companyNameHint")}

      )}
    @@ -207,10 +198,7 @@ export function RegisterForm({ prefillEmail, callbackUrl }: RegisterFormProps) {
    -
-

- {t("passwordResetSuccess")} -

-

- {t("passwordResetSuccessMessage")} -

+

{t("passwordResetSuccess")}

+

{t("passwordResetSuccessMessage")}

) : ( <> -

- {t("resetYourPassword")} -

-

- {t("enterNewPassword")} -

+

{t("resetYourPassword")}

+

{t("enterNewPassword")}

{error && (
- +
-
-