WFDASH-WEBAPP/APP_CAPABILITIES.md
SJCoetz 7a68cafe35 chore: add logos, opencode config and build assets
This commit includes the temporary Next.js build cache files, public brand
logos, and project configuration added in this change.
2026-07-27 08:21:20 +02:00

17 KiB

WFDASH — Westcott Fasteners Dashboard

Overview

WFDASH is a Next.js (App Router) + PocketBase application for Westcott Fasteners, a fastener supply business. It manages the complete quote-to-cash lifecycle for industrial fastener orders — from inbound RFQ emails through pricing, supplier procurement, collection, delivery, and invoicing.

The system is operator-centric, built for the office team who process dozens of quotes and orders daily. It replaces manual spreadsheet/email workflows with structured pipelines, real-time dashboards, and automation via n8n workflows.


Core Domains

1. Quotes Pipeline (/quotes, /sprint)

Inbound RFQ → Processing → Approval → Send → Follow-up

Feature Description
Email Intake n8n webhook receives inbound RFQ emails, extracts items via AI, creates quotes in PocketBase. Idempotent on Message-ID.
Sprint (/sprint) Item-level work queue. Operators claim individual line items (30-min soft TTL), price them, and save — the item then drops off the list. Replaces "claim whole quote" bottleneck.
Categories Admin-managed categories (JEI, TOOLS, FASTENERS, OIL, HUSQVARNA, UNKNOWN) with brand/supplier/keyword match rules. Items auto-bucket or land in UNKNOWN for review.
AI Pricing n8n AI agent reads supplier price lists, matches SKUs, writes cost_price + selling_price with pricing_source="ai" or "catalogue". Operator reviews before saving.
Quote Statuses new → claimed → processed → approval_pending → approved → emailed → complete (also rejected, problem, cancelled, mail_failed, follow_up)
Approvals Dedicated /quotes/approvals page for quotes needing sign-off.
PDF Generation Branded quote PDFs (CNL / ISHERWOOD letterhead) with supplier authorization letters.
Email Send Modal with CC/BCC, custom subject/body, attachment picker. Status flips to sending → n8n sends via SMTP → callback records emailed or mail_failed. Retry supported.
Follow-ups Per-quote follow_up_due date; dashboard widget flags overdue.
Customer Replies Inbound replies tracked via quote_replies collection; shows "Replied" chip on quote row.
Templates Reusable quote scaffolding; "Create from template" spawns a real quote.

2. Orders (/orders, /orders/new, /orders/[id])

Quote → Order → Line Items → Delivery → Invoice

Feature Description
Create from Quote One-click converts a quote to an order, copying all line items. Atomic order number generation (ORD-YYYY-MM-NNN) via server-side counter — continues sequence across month boundaries, concurrency-safe.
Order List Collapsible cards grouped by item status tabs: New, Processing, Collection Pool, Collected, Delivered, Cancelled. Search spans order #, company, customer, item description, or price.
Item Status Lifecycle pending → processed → po_generated → collection_pool → assigned → collected → stock_verified → picking → ready_delivery → delivered (terminal). Also ready_invoice, invoiced, stock_booked, cancelled.
Quote Matching Auto-links order to quote via exact match on quote_number / reference / RFQ / external_number. Suggests a "potential quote" when fuzzy.
Repair Orders is_repair_order flag for non-standard jobs.

3. Operations / Collection (/collection-pool, /collection-map, /collection-confirm)

Supplier Collection → Driver Assignment → Confirmation

Page Purpose
Collection Pool Supplier-grouped view of items in collection_pool or assigned status. Per-row "Assign driver" + per-supplier bulk assign. Shows PO #, supplier, age, ready-for-collection flag.
Collection Map Leaflet map with supplier markers clustered by proximity. Click a cluster → see items → assign driver inline.
Collection Confirm Driver-facing (mobile) — scan/confirm collection, marks items collected.

4. Invoicing (/invoicing)

Delivery Note → QuickBooks Invoice → Print

Feature Description
To Invoice Tab Orders grouped by order number where at least one item is ready_invoice. Per-line qty/price overrides for the QB payload.
QuickBooks Integration Modal picks QB company (CNL / ISHERWOOD), searches QB customers via n8n webhook, builds invoice payload, POSTs to n8n → QB. Returns PDF URL stored on order_items.qb_invoice_pdf.
Delivery Notes Parallel flow: mark lines delivery_note status, auto-generates DN{YYMMDD}NN number. Same line editor (include/exclude, qty/price override).
Invoiced Tab Two sections: Today's Unprinted (grouped by invoice #, print badges) + All Invoiced (searchable history). Print tracking (printedAt, printedBy, printCount) stored in order_item_details.print JSON.
PDF Print Server-rendered React-PDF → streamed back. One-click print for single or bulk (today's batch).

5. Stock Management (/stock, /stock/[id], /stock-orders)

Inventory → Surplus Booking → Stock Orders → Ledger

Feature Description
Stock Items SKU, name, unit, location, current_qty, min_qty, supplier. Status badge: OK / Low / Critical / Inactive.
Stock Ledger Immutable append-only ledger (stock_ledger) with signed change_qty and reason (purchase_surplus, stock_order, customer_fulfillment, adjustment, return). current_qty denormalized for fast reads.
Surplus Booking When a supplier delivers more than ordered, operator splits the line: customer qty → order, surplus qty → stock. Creates stock_ledger entry (reason=purchase_surplus) + links order_item.surplus_qty + stock_booked_from.
Stock Orders (v2) Pure stock replenishment: SP-YYYYMMDDNN number, multi-line, status draft → sent → received → cancelled. Receive flow books ledger + updates current_qty per line.
Fulfilment from Stock /api/v1/stock/fulfill — books out qty from stock for a customer order, creates ledger entry (reason=customer_fulfillment).

6. Pricelist / Catalogue (/pricelist)

Raw Uploads → AI Extraction → Structured Catalogue

Tab Purpose
Raw Uploads Drag-drop PDF/CSV/TXT/images (≤50 MB). Optional supplier link, status, free-text notes for AI (e.g. "Brand is JEI. Apply 30% markup. ZAR excl. VAT."). Upload creates raw_price_list row; n8n workflow picks up, extracts, writes to price_list.
Catalogue Searchable price_list table: SKU, normalised SKU, description, category, brand, supplier, cost/selling/markup, stock_qty, rich specifications JSON (diameter, length, material, synonyms). search_text column enables fuzzy/synonym search.

7. Purchase Orders (embedded in Orders flow)

PO Generation → Email → Supplier Reply Tracking

  • Created from order items grouped by supplier.
  • Versioned PDFs stored on purchase_orders.documents array + documents_history.
  • Email modal (to/cc/bcc, HTML+text body, attachment picker) → n8n sends → callback records email_message_id, last_reply_at, supplier_reply_preview.
  • Stale PO detection (purchase-orders/stale endpoint).

8. Delivery Notes (/delivery-notes)

Generated from delivered order items

  • Auto-numbered DN{YYMMDD}NN.
  • Status: draft → ready → delivered → cancelled.
  • Linked to order + company + customer.
  • Printable PDF (shares invoice print pipeline).

9. Repairs (/repairs)

Lightweight repair job tracker

  • Repair number auto-generated.
  • Status: new → assessing → quoted → approved → in_progress → completed → cancelled.
  • Links to customer / company / order (optional).
  • Item description + fault description + notes.

10. Companies / Customers / Suppliers (/companies, /customers, /suppliers)

Master data management

  • Companies: name, address, email, tel, VAT, reg number, geo-coordinates (for map).
  • Customers: name, emails (primary/alt/buyer), company relation, rep (user), delivery coordinates, description.
  • Suppliers: name, email, number, address, supply_tags (for category matching), coordinates, closing time.

11. Dashboard (/dashboard)

Real-time KPIs & Charts

Widget Data
KPI Cards Customers, Active Quotes, Orders This Month, Revenue (sparkline per card)
Concentric Rings Quote pipeline depth (New / Claimed / Approved / Processed)
Orders Trend New vs Fulfilled (8 weeks, stacked bars)
Status Mix Quote distribution (progress bars)
Growth Trends Customers vs Orders (12 weeks, area chart)
Approval Rate Radial gauge (Approved / Active)
Activity Pulse Multi-line (Customers / Quotes / Orders velocity)
Quote Pipeline Donut chart (all non-template quotes)
Top Customers Horizontal bars by quote volume
Follow-ups Due Clickable cards → quote detail

Real-time: PocketBase subscriptions on customers, quotes, orders → auto-refresh.


12. Settings (/settings)

  • Theme picker (light/dark/system) with CSS variables.
  • Developer identity switcher (for local multi-user testing).

Automation & Integrations (n8n)

Workflow Trigger Action
Email Intake Inbound email (IMAP/webhook) Parse → AI extract items → Create quote + items + attachments
Quote Outbound Quote status = sending Render PDF → SMTP send → Callback recordSendOutcome
Supplier RFQ Sprint bulk "Email suppliers" Group by supplier → Send RFQ → Track outbound_message_id
Supplier Reply Monitor Inbound email with In-Reply-To matching PO/quote Update supplier_replied_at, supplier_reply_count
Price List Ingest New raw_price_list row AI extract → Write price_list rows → Update log_summary
QuickBooks Invoice Invoicing modal submit Build QB payload → QB API → Return PDF URL
PO Stale Alert Scheduled Find POs without reply > N days → Notify

Technical Architecture

Layer Technology
Frontend Next.js 15 (App Router), React 19, TypeScript, Tailwind CSS
Backend PocketBase (Go) — auth, real-time, file storage, admin UI
Automation n8n (self-hosted) — workflows, AI agents, webhooks
Charts Custom SVG (no Chart.js/Recharts) — sparklines, bars, donuts, radial, area, concentric
PDF @react-pdf/renderer (server-side in API routes)
Maps Leaflet + OpenStreetMap
Auth PocketBase auth (email/password), cookie-based session via middleware
Real-time PocketBase subscribe("*", callback) on collections
API Next.js Route Handlers (/api/v1/...) + PocketBase SDK (server)

Key Design Patterns

  1. Item-Level Workflows — Not quote/order level. Sprint, Collection Pool, Invoicing all operate on order_items / quote_items rows.
  2. Optimistic UI + Real-time — Local state updates immediately; PB subscriptions reconcile.
  3. Server-Side Number Generation — Atomic counters (quote_counters, order_counters) prevent collisions.
  4. Idempotency — Email intake dedups on Message-ID; quote/PO sends record outbound Message-ID for bounce matching.
  5. Human-in-the-Loop AI — AI writes pricing_source="ai" + zero prices; operator must claim, review, save.
  6. JSON Audit Fields — order_item_details, quote_item.pricing_notes, print metadata stored as JSON on the row — no extra collections for append-only logs.
  7. Per-User Color Coding — claimed_by / rep → deterministic hue (OKLCH) for row tinting + avatar chips.
  8. Working-Day SLA — isOlderThanWorkingDays() excludes weekends; dashboard ages quotes in working days.

Data Model Highlights (PocketBase Collections)

Collection Purpose
quotes Quote header (number, customer, company, status, email thread, PDF, follow-up)
quote_items Line items (description, qty, cost/sell/markup, supplier, claim_status, pricing_source, category)
quote_attachments Inbound RFQ files + generated PDFs + outbound attachments
quote_replies Customer email replies (thread)
orders Order header (number, company, customer, quote link, rep, invoiced flag)
order_items Line items (status lifecycle, supplier, PO link, in_stock, surplus_qty, pricing audit)
purchase_orders Supplier POs (versioned PDFs, email payload, supplier replies)
collection_pool Driver assignment queue (links order_item + supplier + driver)
stock_items Inventory master (SKU, qty, min, location, supplier)
stock_ledger Immutable movements (signed qty, reason, reference)
stock_purchases Stock replenishment orders
price_list Structured catalogue (AI-extracted)
raw_price_list Uploaded supplier files awaiting extraction
categories Admin-managed buckets for sprint (match_brands, match_supplier_tags, match_keywords)
delivery_notes Delivery note header
delivery_note_items Line items on delivery note
repairs Repair jobs
companies / customers / suppliers Master data
users (auth) Operators + drivers

Pages / Routes Summary

Route Purpose
/dashboard KPI dashboard
/quotes Quote list (tabs: New, Claimed, Pending Approval, Completed, Email Failed, Problem, All, Templates)
/quotes/[id] Quote detail (items, pricing, PDF, email, approvals)
/quotes/[id]/process Sprint-style item processing for a single quote
/quotes/approvals Approval queue
/sprint Global item-level pricing queue (by category)
/orders Order list (item-status tabs)
/orders/new Create order (from quote or blank)
/orders/[id] Order detail (items, status transitions, PO, delivery, invoice)
/orders/assign Legacy driver assign (hidden from nav)
/invoicing To Invoice / Invoiced (QB + delivery notes + print)
/collection-pool Supplier collection queue + bulk assign
/collection-map Map view of suppliers
/collection-confirm Mobile driver confirmation
/stock Stock list + low-stock filter
/stock/[id] Stock detail + ledger + adjustments
/stock-orders Stock replenishment orders
/pricelist Raw uploads + Catalogue tabs
/suppliers Supplier CRUD
/companies Company CRUD
/customers Customer CRUD
/repairs Repair job tracker
/delivery-notes Delivery note list
/settings Theme, dev identity

API Endpoints (Key)

Endpoint Method Purpose
/api/v1/quotes/[id]/pdf GET Render quote PDF
/api/v1/quotes/[id]/send-email POST Validate + queue outbound send
/api/v1/quotes/[id]/retry-email POST Retry failed send
/api/v1/quotes/[id]/create-from-template POST Spawn quote from template
/api/v1/orders/from-quote POST Convert quote → order
/api/v1/order-items/[id]/status PATCH Transition item status
/api/v1/invoicing/customers GET/POST QB customer search/create
/api/v1/stock/items GET/POST Stock CRUD
/api/v1/stock/items/[id]/adjust POST Manual qty adjustment + ledger
/api/v1/stock/fulfill POST Book out stock for customer order
/api/v1/stock/surplus-book POST Book surplus from collection
/api/v1/stock/purchases GET/POST Stock orders CRUD
/api/v1/stock/purchases/[id]/receive POST Receive stock order lines
/api/v1/sprint/items/[id]/claim POST Race-safe 30-min claim
/api/v1/sprint/items/[id]/attachments/upload POST Upload pricing proof
/api/v1/purchase-orders/[id]/send-email POST Send PO to supplier
/api/v1/purchase-orders/[id]/pdf GET Render PO PDF
/api/v1/files/[collection]/[recordId]/[filename] GET Stream PocketBase file

Deployment Notes

  • PocketBase runs separately (Docker/binary). App connects via NEXT_PUBLIC_POCKETBASE_URL.
  • n8n runs separately; webhooks configured in n8n point to /api/v1/... routes.
  • Files served via PocketBase /api/files/... — proxied through Next.js route for auth if needed.
  • Environment: NEXT_PUBLIC_POCKETBASE_URL, POCKETBASE_ADMIN_EMAIL, POCKETBASE_ADMIN_PASSWORD (for server SDK).

Summary

WFDASH is a complete operational ERP for a fastener distributor, covering:

  1. Quote intake (email → AI → structured quote)
  2. Item-level pricing (Sprint claim/price/save)
  3. Order management (quote → order → multi-status item lifecycle)
  4. Supplier procurement (PO generation, email, reply tracking)
  5. Collection logistics (pool → map → driver assign → confirm)
  6. Inventory (stock items, ledger, surplus booking, stock orders)
  7. Invoicing (delivery notes + QuickBooks + PDF print)
  8. Catalogue (raw uploads → AI extraction → searchable price list)
  9. Repairs (lightweight job tracker)
  10. Real-time dashboard (KPIs, charts, follow-ups)

Built for speed, auditability, and operator ergonomics — every screen is a work queue, not a CRUD form.