You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A locked spec/decision for each of seven roadmap fronts standing between Technikpool's current state and a polished v1: asset label generation, a Flutter check-in/check-out companion app, a UI consistency pass, DGUV inspection due-date tracking, offer/invoice document generation, product-image & manufacturer-logo handling (with background removal/crop), and org visual identity (a color + short avatar label per org, used to identify the owning org at a glance in the calendar, device lists, and elsewhere). "Done" for this map means every front has enough decided — data model, workflow, architecture, UI approach — that implementation can start without further design discussion. This map does not build the features; it charts the way to specs ready for handoff.
Notes
Stack: SvelteKit + Svelte 5 + Prisma 7/Postgres + Better-Auth, per this repo's CLAUDE.md. Remote functions in src/lib/remote/*.remote.ts.
Grounding already done while charting (don't re-derive): no DGUV/inspection fields on Asset today; no Offer/Invoice models; the existing delivery-note route is a packing-list-style print view off Production data, not a persisted document; Product.imageUrl is a plain pasted URL (no upload, no storage backend, no image processing lib in package.json); Manufacturer has no logo field; a check-in/check-out flow already exists server-side (src/lib/remote/checkout.remote.ts — scanAsset, checkoutAssets, keyed by assetTag) and is used today by a browser page at src/routes/checkout/+page.svelte. The Flutter app front is about giving this existing logic a mobile-native surface, not inventing new business logic from scratch.
This map is plan-only by default (no execution override): tickets resolve to decisions/specs, not shipped code, except wayfinder:task tickets which may do concrete unblocking work.
The /grilling, /domain-modeling, /research, and /prototype companion skills referenced by the Wayfinder skill are not installed in this repo (only wayfinder itself is, per skills-lock.json). Sessions should conduct grilling/prototyping conversationally in their place, one question at a time, and use a plain subagent for research tickets in place of a dedicated /research skill.
Tracker: GitHub Issues on RuegerEvents/technikpool. Sub-issue and blocking relationships are wired via GitHub's native addSubIssue / addBlockedBy GraphQL mutations (visible in the issue's sidebar).
Prototype full-page production device-list editor — resolved via iterated prototype (artifact): a full, fluid-width page (not a div-replacement) with three panes — category quick-filter (left), available devices with search/org/location filters (center), booked-for-this-production (right, grouped by category). Rows use a − count + quantity stepper (not a single add button) since multiple identical units can be needed — this moves the underlying model from per-Asset add/remove to per-Product-quantity, with the system auto-assigning specific Asset records. The right pane is never filtered by the center pane's controls — it always shows the full booking, plus a summary strip of the orgs/locations represented. Reached via a "Manage equipment" link from the production detail page, replacing the current inline add-panel.
DGUV inspection due-date data model & overdue visibility — Organization.defaultInspectionIntervalMonths is copied onto Asset.inspectionIntervalMonths at creation (a snapshot, not a live reference — later org-default changes don't retroactively affect existing assets, and the per-asset value stays individually editable). A new dedicated Inspection model (not reusing AssetTransaction) records assetId, performedAt, result (plain string, e.g. "PASSED"/"FAILED"), notes, inspectorName (free text — the certifying inspector is typically external, not an app user). Asset.nextInspectionDue is a materialized field kept in sync for fast overdue queries; assets with no interval set are excluded from tracking. Overdue status surfaces via a dashboard stat tile and a dedicated report page — no asset-list column for now.
Prototype the image upload/crop/background-removal UI flow — resolved via an interactive prototype (artifact, reviewed and approved): fixed 1:1 square crop for both product photos and manufacturer logos (no aspect choice), defaulting to a square bounding the photo's longer side so the whole image fits uncropped, with the resize handle able to expand past the photo's edges (transparent padding) or shrink for a tighter crop. Flow: upload → crop → background removal (adjustable strength, prototype uses a rough corner-color threshold standing in for the real @imgly/background-removal from Research: background-removal approaches for product/logo photos #11). Covers both Product.imageUrl and a new (not-yet-schemad) Manufacturer logo field; uploads go through the storage backend from File storage backend for uploaded images #10.
Org visual identity: color + two-letter avatar prefix — new Organization.color (hex, @unique) and Organization.avatarLabel (exactly 2 uppercase letters, @unique) fields; assetIdPrefix can't double as the label (it's numeric-only, 3 digits). Always manually set by an org owner/admin (no auto-generation), required on createOrg/editable via updateOrg following the assetIdPrefix pattern. Existing orgs get a one-off backfill script assigning temporary unique values before the fields go not-null; owners edit to real values afterward. This ticket covers data model + org-settings input only — Calendar devices-mode is the queued first consuming surface.
Label content, code type, and print mechanism — resolved by the already-shipped sticker sheet generator (/stickers, hand-tested and confirmed by the user): Data Matrix code via bwip-js encoding a payload template keyed to Asset.assetTag's prefix+number scheme, server-rendered PDF sheets (not browser print, not dedicated label-printer/ZPL), sized for precut sticker paper or flag/cable-tail labels; a single range-based generator page covers both single and bulk printing (no per-asset print button, no bulk-select-from-created-assets flow).
Research: background-removal approaches for product/logo photos — default to client-side @imgly/background-removal (in-browser WASM, ~40MB model, no per-call cost, photos never leave the device); self-hosted rembg (u2net/isnet, CPU) as an optional server-side fallback if quality falls short; hosted APIs (remove.bg, ~$0.20–0.27/image) ruled out as a default. Flags a licensing trap: rembg's higher-quality bria-rmbg backend is CC BY-NC 4.0 (non-commercial only) — avoid unless a commercial license is bought.
Research: German legal requirements for offer/invoice documents — invoices cannot stay purely computed like delivery-note; §14(4) UStG unique-numbering and GoBD immutability require a persisted, uniquely-numbered Invoice record with a fixed content snapshot at issuance. Offers (Angebote) are not tax documents and carry no such requirement — can stay a purely computed print view. Also flags the 2027/2028 German e-invoicing mandate as a second reason invoices need structured, persisted data.
File storage backend for uploaded images — self-hosted, S3-compatible object storage (RustFS recommended, coded against the generic S3 API so it stays swappable); uploads proxy through a new SvelteKit +server.ts endpoint (client sends the already-cropped/bg-removed image as multipart/form-data; server holds credentials and does the PUT), not a presigned direct-to-storage flow.
Offer/invoice data model & generation workflow — pricing lives on Asset (net purchase price + optional purchase date), multiplied by an org-configurable default percentage per Category to derive a daily rate, then by production day count; both the rate and day count are overridable per document, plus one overall discount (% or €). Orgs get an isKleinunternehmer flag — prices always stored net, shown as gross to Kleinunternehmer orgs on entry. Both Offer and Invoice are persisted, copyable entities (copy-to-new-customer, copy-to-invoice as a snapshot conversion), revising the earlier assumption that offers could stay a purely computed print view.
Not yet specified
Flutter app: concrete screen designs and offline-sync architecture — waits on the workflow ticket resolving what the app must do before shape can be prototyped.
Offers/invoices: PDF/document template, branding, and legal footer content — no visual spec given yet.
Out of scope
A real billing/accounting module for offers & invoices (pricing history, sent/accepted/paid status tracking) — user chose document generation only, off existing production data, no payment tracking.
Active reminders/notifications (email/push) for overdue DGUV inspections — user chose passive overdue visibility (dashboard/list surfacing) only, not an alerting system.
Destination
A locked spec/decision for each of seven roadmap fronts standing between Technikpool's current state and a polished v1: asset label generation, a Flutter check-in/check-out companion app, a UI consistency pass, DGUV inspection due-date tracking, offer/invoice document generation, product-image & manufacturer-logo handling (with background removal/crop), and org visual identity (a color + short avatar label per org, used to identify the owning org at a glance in the calendar, device lists, and elsewhere). "Done" for this map means every front has enough decided — data model, workflow, architecture, UI approach — that implementation can start without further design discussion. This map does not build the features; it charts the way to specs ready for handoff.
Notes
src/lib/remote/*.remote.ts.Assettoday; noOffer/Invoicemodels; the existingdelivery-noteroute is a packing-list-style print view offProductiondata, not a persisted document;Product.imageUrlis a plain pasted URL (no upload, no storage backend, no image processing lib inpackage.json);Manufacturerhas no logo field; a check-in/check-out flow already exists server-side (src/lib/remote/checkout.remote.ts—scanAsset,checkoutAssets, keyed byassetTag) and is used today by a browser page atsrc/routes/checkout/+page.svelte. The Flutter app front is about giving this existing logic a mobile-native surface, not inventing new business logic from scratch.wayfinder:tasktickets which may do concrete unblocking work./grilling,/domain-modeling,/research, and/prototypecompanion skills referenced by the Wayfinder skill are not installed in this repo (onlywayfinderitself is, perskills-lock.json). Sessions should conduct grilling/prototyping conversationally in their place, one question at a time, and use a plain subagent for research tickets in place of a dedicated/researchskill.RuegerEvents/technikpool. Sub-issue and blocking relationships are wired via GitHub's nativeaddSubIssue/addBlockedByGraphQL mutations (visible in the issue's sidebar).Decisions so far
− count +quantity stepper (not a single add button) since multiple identical units can be needed — this moves the underlying model from per-Assetadd/remove to per-Product-quantity, with the system auto-assigning specificAssetrecords. The right pane is never filtered by the center pane's controls — it always shows the full booking, plus a summary strip of the orgs/locations represented. Reached via a "Manage equipment" link from the production detail page, replacing the current inline add-panel.Organization.defaultInspectionIntervalMonthsis copied ontoAsset.inspectionIntervalMonthsat creation (a snapshot, not a live reference — later org-default changes don't retroactively affect existing assets, and the per-asset value stays individually editable). A new dedicatedInspectionmodel (not reusingAssetTransaction) recordsassetId,performedAt,result(plain string, e.g."PASSED"/"FAILED"),notes,inspectorName(free text — the certifying inspector is typically external, not an app user).Asset.nextInspectionDueis a materialized field kept in sync for fast overdue queries; assets with no interval set are excluded from tracking. Overdue status surfaces via a dashboard stat tile and a dedicated report page — no asset-list column for now.@imgly/background-removalfrom Research: background-removal approaches for product/logo photos #11). Covers bothProduct.imageUrland a new (not-yet-schemad)Manufacturerlogo field; uploads go through the storage backend from File storage backend for uploaded images #10.assets-mode rows (unfiltered by default), org filter state lives in a URL query param, and each asset row's org name gets prefixed with a small colored badge showing the org's 2-letteravatarLabelon itscolor. This is the landed UI-polish reference pattern (merged from Prototype a canonical reference page for the UI polish baseline #6): the badge component and filter-checklist pattern become the baseline other pages are measured against. Unblocked Prototype full-page production device-list editor.Organization.color(hex,@unique) andOrganization.avatarLabel(exactly 2 uppercase letters,@unique) fields;assetIdPrefixcan't double as the label (it's numeric-only, 3 digits). Always manually set by an org owner/admin (no auto-generation), required oncreateOrg/editable viaupdateOrgfollowing theassetIdPrefixpattern. Existing orgs get a one-off backfill script assigning temporary unique values before the fields go not-null; owners edit to real values afterward. This ticket covers data model + org-settings input only — Calendar devices-mode is the queued first consuming surface./stickers, hand-tested and confirmed by the user): Data Matrix code viabwip-jsencoding a payload template keyed toAsset.assetTag's prefix+number scheme, server-rendered PDF sheets (not browser print, not dedicated label-printer/ZPL), sized for precut sticker paper or flag/cable-tail labels; a single range-based generator page covers both single and bulk printing (no per-asset print button, no bulk-select-from-created-assets flow).@imgly/background-removal(in-browser WASM, ~40MB model, no per-call cost, photos never leave the device); self-hostedrembg(u2net/isnet, CPU) as an optional server-side fallback if quality falls short; hosted APIs (remove.bg, ~$0.20–0.27/image) ruled out as a default. Flags a licensing trap: rembg's higher-qualitybria-rmbgbackend is CC BY-NC 4.0 (non-commercial only) — avoid unless a commercial license is bought.delivery-note; §14(4) UStG unique-numbering and GoBD immutability require a persisted, uniquely-numberedInvoicerecord with a fixed content snapshot at issuance. Offers (Angebote) are not tax documents and carry no such requirement — can stay a purely computed print view. Also flags the 2027/2028 German e-invoicing mandate as a second reason invoices need structured, persisted data.+server.tsendpoint (client sends the already-cropped/bg-removed image asmultipart/form-data; server holds credentials and does thePUT), not a presigned direct-to-storage flow.Asset(net purchase price + optional purchase date), multiplied by an org-configurable default percentage perCategoryto derive a daily rate, then by production day count; both the rate and day count are overridable per document, plus one overall discount (% or €). Orgs get anisKleinunternehmerflag — prices always stored net, shown as gross to Kleinunternehmer orgs on entry. BothOfferandInvoiceare persisted, copyable entities (copy-to-new-customer, copy-to-invoice as a snapshot conversion), revising the earlier assumption that offers could stay a purely computed print view.Not yet specified
Out of scope