Products: dimensions are mm — unit notice + plausibility check with 'Convert to mm' on the form and the grid; storage-usage BI dimension check card (details)
Products: label weight fields as kg (same unit policy as the mm dimensions) (details)
Leads: logo + website screenshot stored on the lead once (AD_Image / offer_conditions.visuals) and reused by every offer (details)
Storage usage: merchant/warehouse/month/invoiced/product filters (SelectBox) + current m³ list per product with €/day and €/month; mobile product: camera photo capture into the Strapi gallery; dashboard calls card: show call time (details)
Android app 1.0.73 (versionCode 74): photo capture on the product page (details)
Mobile product: in-page camera (getUserMedia, back camera) for product photos instead of the file-chooser capture; Capture section with equal EAN / Foto buttons (details)
Mobile product: capture buttons pause the scanner focus monitor on pointerdown (lost taps); camera start timeout + Systemkamera fallback; EAN overlay closes via one helper (details)
Android app version bump (release script) (details)
Quote PDF: return base-price note shortened to acceptance, customer identification, system entry, putaway (DE/EN) (details)
Price sheet PDF: country flags in the EU / non-EU / Warenpost tables and country surcharge rows (details)
Order sources: Adobe Commerce brand tile (Adobe A on red) + OTTO red-on-white in MarketplaceIcon; sales-orders source column draws brand tiles for amazon/ebay/otto/shopify/shopware/etsy/kaufland/zalando/adobe-commerce instead of hardcoded images (details)
Price sheet: keep disabled services listed (resolve returns all services; unchecked service vanished and stayed hidden via localStorage), sticky country/service search in the matrix (German DHL names, / focuses, Esc clears, per-section counts), internal row notes no longer printed on the merchant PDF (details)
Contract/AGB: carrier cases under LogYou's shipping contract (Nachforschungsauftrag, damage/loss claims, address/delivery clarifications, complaints) billed by time at the hourly rate (contract Versandkosten DE/EN + offer footnote); AGB § 13.6 Schwundtoleranz 1 % → 0,5 % p. a. (only place it is defined, contract placeholder default aligned) (details)
Quote: three configurable fulfillment plans (Start / Wachstum / Premium with name, price, description, feature list, per-plan 'im PDF' flag) edited as cards in the modal and printed as brand cards under the monthly costs; selected plan drives the Servicepauschale for forecast/contract; legacy saved fee maps onto Start (details)
Quote plans editor: taller description (3 rows) and feature (7 rows) textareas so the default texts show without scrolling (details)
Quote PDF: plan cards as one equal-height table that replaces the monthly fee row; selected plan marked 'Empfohlen' instead of 'Ihr Plan' (details)
Quote plans: no selection — the first plan ticked 'im PDF' supplies the Servicepauschale (chip on its card), PDF shows the plans without any highlight (details)
Quote PDF: plan cards with spacing (white gap columns in the equal-height table), orange accent bar, navy header with orange price, feature list below (details)
Lead page: the two offer buttons sit in one labelled 'Angebot' group and are named Fulfillment-Angebot / LogShip-Angebot (toolbar icon titles aligned) (details)
Lead page offer group: buttons read Fulfillment / LogShip-Cloud, 'Angebot' caption darker, bolder and slightly larger (details)
Leads + users: KI-Konsole readable bubbles and "Als E-Mail senden" hand-off, AD_User.FullName, Nuxt UI user pages, lead fixes
- KI-Konsole: explicit bubble text colours (global `*` colour rule made the user bubble unreadable); new "Als E-Mail senden" on assistant turns extracts subject/body and opens the lead mail composer on top, pre-filled and editable (composer `draft` prop, templateKey 'ai-chat', signature/footer as usual) - AD_User.FullName: used for the staff mail signature (fallback Name), carried in the logship_user cookie, written by store/update (update only when the key is sent), field on /create/user and /edit/user-:id - User pages rebuilt on Nuxt UI (hero with avatar/badges, UTabs, card groups, USwitch with track fix); edit page now reads/writes IsAddMailTextAutomatically correctly - Dashboard "Neueste Leads": expired leads (LeadStatus E) no longer listed - /create/lead: company name, website and AiScore were dropped on the initial save (client + store route) - Recipes: console hand-off, REST cache reset for new columns, USwitch gap
Theme: text colour inherits again (drop color on the universal selector), readable hero/dark surfaces system-wide
The universal `* { color: var(--theme-text-primary) }` in public/css/styles.css painted every element without its own colour dark, so text inside navy hero cards, chat bubbles and dark badges was unreadable. Colour now cascades from html/body; form controls keep the explicit theme colour, buttons inherit. User page: ext. badge and card titles get explicit colours (Bulma strong colour on dark cards).
Sales orders grid: LATERAL view + two-step paging, totals route, external links for all marketplaces
- v_orders_summary rewritten as LEFT JOIN LATERAL (applied on prod 2026-10-27); DDL now versioned in reference/sql with backup/apply/restore scripts (node + pg, .env PG_* keys, PG tunnel on dev) - summary.post.ts: step 1 ids-only page (cheap deep $skip), step 2 rows by id in step-1 order; shared query builder server/utils/orders/summaryQuery.ts; single-flight per identical block, no row cache - totals moved to orders/ag-grid/summary-totals.post.ts (60 s cache + single-flight), page calls it debounced on grid ready / switch / column filter / card reload; blocks never wait for it - AgGridServer: cacheBlockSize / maxBlocksInCache props + filterChanged emit (orders page uses 100/20) - SSE stream seeds globalLastOrderId from the newest order on a fresh process (no replay of old orders + push notifications after a PM2 restart) - fix: external reference links for Shopware, Shopify, Amazon and JTL were dead on the list — $select on the view only carried plentyone_order_id; all marketplace id columns AgMarketplaceLink.vue uses are selected now
Orders: manual customs (CN23) tax note on the order popup and the order edit form
- "Zoll (CN23): Steuer bereits abgeführt (IOSS/OSS)" block (paid via / amount / currency / scheme / code) writes the same sentence the eBay import writes as the FIRST line of C_Order.Description — "Tax of {amount} {currency} has been paid via {paidVia} ({scheme}) with Code: {code}" — which the DHL customs routes forward as CN23 exportDescription; other Description text is kept below it - composables/useCustomsTaxNote.ts (build/parse/apply, tolerant to codes with spaces and the " | ** Voided" suffix) + components/sales/CustomsTaxNoteFields.vue (floating-label layout, preview with 80-char counter) - shown only for DHL-Paket shippers (isCustomsTaxNoteShipper — single place to extend for DPD); popup strips the note when the shipper leaves DHL, edit form hides without touching the Description; editable on completed orders - quick-add.post.ts now sends description; DHL customs routes collapse whitespace before the 80-char cut - translations en/de/es/ne, recipe in .claude/rules/fulfillment/commissioning.md
Offers: editable article name + description for the monthly fee line in the quote PDF
- pricing.monthlyFeeLabel (default "Start") and pricing.monthlyFeeNote (default "Der komplette Fulfillment-Kern für Ihren Einstieg.") — two text inputs next to the €/M. field in QuoteModal.vue - quotePdf.ts prints them in the "Monatliche Kosten" row; empty label falls back to "Servicepauschale", legacy offers without the keys keep the old "inkl. …" subtext, an explicitly emptied note prints nothing - applySavedQuoteConditions keeps both strings verbatim (fillNonEmpty would re-apply the default) - translations en/de/es, recipe note in .claude/rules/offers/pdf-generation.md
Build: bundle tslib into the Nitro server bundle (500 on full reload of /bi/shipping-performance)
Left external, the amcharts "exporting" plugin's bare `import 'tslib'` survived into .output, Nitro's tracer copied only tslib.js / tslib.es6.mjs, and Node resolved the ESM import to the missing modules/index.js (package exports "import" → "node"): "Cannot find module …/node_modules/tslib/modules/index.js" on every SSR render of the page, while client-side navigation worked. nitro.externals.inline: ['tslib'] bundles it; verified by importing the built chunk in Node. vite.ssr.noExternal has no effect on this builder. Recipe note incl. the custom-buildDir gotcha (Nitro esbuild "symbol R already declared").
Leads: explicit offer buttons (Fulfillment-Angebot / LogShip Cloud / Vertrag), no remembered offer type
The hero "Angebot" button reopened the last-used offer type (per-lead localStorage) and the second button flipped its meaning accordingly, so "Angebot" opened the LogShip Cloud offer once that had been used on the lead. Each button now names its type and always opens exactly that modal; the in-modal type switch stays.
Offers: make offer, Rahmenvertrag and AGB consistent (customer contradiction list) + barcode / pick clauses
Contract (contractTexts DE+EN, contractPdf): - term: contract starts with signature, operational start = first goods receipt, integration/setup free, running fees only from the operational start (was: integration could start billing while pricing said "no costs until first goods receipt") - pricing: "Basispreis pro Versandauftrag", shipment counts at status "versendet", explicit pick inclusion ({pickInclusion} = quote.pricing.qtyPickfree) and a definition of "Pick" (base unit or packaging unit with own barcode), NEW "Wareneingang" item driven by the offer ({inboundPricing} = quote.inbound.mode: included / hourly / custom) with the included scope and the on-request count check, returns scope defined once (SLA item now refers to it; blocked stock + photos, customer decides refunds), carrier tariff pass-through, no packaging costs for pre-packed goods, nominal storage dimensions, service fee named like the offer, annex 1 validity note - NEW clause "Barcodes & Artikelkennzeichnung": scannable code per sales unit, relabelling by time + material, no liability / no 13.6 tolerance when the customer waives relabelling - {noticeAgbNote} whenever noticeMonths differs from the AGB's 3-month fallback - ContractModal: "Angebot vom (Anlage 1)" mirrors the attached offer's date, select "Wareneingang (lt. Angebot)" - Annex 1: a newer saved quote wins over a stale sent PDF; regenerated offer keeps cut-off + validity
Offer PDF (quotePdf DE+EN): base price per Versandauftrag with "Picks nicht enthalten / inkl. n Picks", pick definition footnote, goods receipt = Packstückkontrolle (count per SKU on request), returns scope subtext, storage nominal dimensions, packaging only by consumption; flyer + modal hint aligned.
AGB seed (agbDefault.ts): Pick / Versandauftrag definitions, B2C limit 31,5 kg + Sperrgut, barcode rule + pallet 120×80×150 = offer pallet space, shrinkage only in 13.6, returns scope, payment = contract, notice period follows the contract. Recipe section "Offer ↔ contract ↔ AGB consistency".
- app/components/mobile/Header.vue + StepGuide.vue: every /mobile/* page now starts with a sticky Nuxt UI header and a Zebra-style pictogram step guide driven by one `stepGuide` computed per page (commission, digital-picking, fix-locator-owner, generate-shipments, inventory, locator-articles/-labels, movement, picklist, print-labels, product, receive, reconditioning, return, tasks); shared DigitalPicklist overlay gets the compact `.dp-guide` variant; mobile-theme.css + ReturnLabelPrinterPicker adjusted - android: versionCode 73 / 1.0.72 ("Enhance Styling and new Icon Explanation") - server/utils/ticketAutoClose.ts + plugins/ticket-auto-close.ts + requests/[id]/auto-close.post.ts: merchant-action tickets idle for TICKET_AUTOCLOSE_DAYS (10) are completed with an [Auto-Close] note and a merchant mail (6 h timer on PM2 instance 0, off on nuxt dev, dry-run endpoint for staff) - notifications: action-notification / push-task-status pass the acting user; stream.get.ts and pushNotifier skip the actor; orgRoleAccessCache fix for roles with org 0; notificationBus tweaks - recipes: mobile/capacitor-app-build.md (page skeleton), requests/tickets.md (auto-close, who gets toast/push/mail); reference: Hive contract PDF (template ancestor), scanner.png
Products: dimensions are mm — unit notice + plausibility check with 'Convert to mm' on the form and the grid; storage-usage BI dimension check card
Storage rent (m³) is billed from L×W×H×stock; cm/m entries were billed 1 000× too little (wonderhome 2026-10). analyzeDimensions() is the single check used by ProductForm, the products grid (highlighted cells + warning toast with a convert action after an inline edit) and the new dimension-check route/card on /materials/storage-usage.
Leads: logo + website screenshot stored on the lead once (AD_Image / offer_conditions.visuals) and reused by every offer
Lead hero: upload/replace/remove logo, capture the website screenshot; quote modals (fulfillment + LogShip Cloud) take both from the prefill, persist what they capture/upload on the lead and show 'am Lead gespeichert'.
Storage usage: merchant/warehouse/month/invoiced/product filters (SelectBox) + current m³ list per product with €/day and €/month; mobile product: camera photo capture into the Strapi gallery; dashboard calls card: show call time
Mobile product: in-page camera (getUserMedia, back camera) for product photos instead of the file-chooser capture; Capture section with equal EAN / Foto buttons
Mobile product: capture buttons pause the scanner focus monitor on pointerdown (lost taps); camera start timeout + Systemkamera fallback; EAN overlay closes via one helper
Price sheet PDF: country flags in the EU / non-EU / Warenpost tables and country surcharge rows
public/flags SVGs bundled as Nitro server asset assets:flags, rasterised once per process with sharp (flagImages.ts, 36 px PNG, 1 px border, fixed-width flag column so names align); smoke script mocks the flags storage; recipe note in carrier-rates.md.
Order sources: Adobe Commerce brand tile (Adobe A on red) + OTTO red-on-white in MarketplaceIcon; sales-orders source column draws brand tiles for amazon/ebay/otto/shopify/shopware/etsy/kaufland/zalando/adobe-commerce instead of hardcoded images
Price sheet: keep disabled services listed (resolve returns all services; unchecked service vanished and stayed hidden via localStorage), sticky country/service search in the matrix (German DHL names, / focuses, Esc clears, per-section counts), internal row notes no longer printed on the merchant PDF
Contract/AGB: carrier cases under LogYou's shipping contract (Nachforschungsauftrag, damage/loss claims, address/delivery clarifications, complaints) billed by time at the hourly rate (contract Versandkosten DE/EN + offer footnote); AGB § 13.6 Schwundtoleranz 1 % → 0,5 % p. a. (only place it is defined, contract placeholder default aligned)
Quote: three configurable fulfillment plans (Start / Wachstum / Premium with name, price, description, feature list, per-plan 'im PDF' flag) edited as cards in the modal and printed as brand cards under the monthly costs; selected plan drives the Servicepauschale for forecast/contract; legacy saved fee maps onto Start