//Confirmed development stage , the trip is now represented and controlled from the document interface, and integrated with lineItems, the trip also has its own route already working and in construction,
//app/(pages)/documents2/actions/GOALS-AHEAD.txt
Below is a full canonical module specification, describing: • the Document system • Offer/Order/Invoice pipeline • LineItem model extensions • Bound vs Local modes • The LineItemEditor + Document section roles • The Pricing Engine integrations (Trip → Package, Product → Package, Experience → Package) • Where the next module begins (Trip Logic)
This becomes your official reference doc, ready to copy/paste into a fresh conversation.
⸻
📦 CANONICAL SPEC: “Documents v2 + Offers + LineItem Engine”
You can copy/paste the following block as the source of truth into any new conversation:
⸻
🧩 Module: DOCUMENT ENGINE v2 — Unified Offers / Orders / Invoices / Notes
This module defines how documents, offers, line items, and pricing packages interface inside the system.
⸻
- Project Documents
A ProjectDocument is a JSON-driven editable document that can be rendered with different templates: • note2 • offer • proforma • invoice • firmorder • custom
Each template defines:
{ key, label, emoji, requireExplicitEdit, defaultData, renderView(data), renderEditor(data, update) }
These templates are registered inside:
app/(pages)/documents2/components/DocRegistryComponents.tsx
⸻
- Document Data Model (JSON inside projectDocument.data)
All templates share a core pattern:
{ title: string, description?: string, clientName?: string,
meta: { currency?: string, [k: string]: any }
// For line-item-aware documents: offerId?: number | null offerMode?: "local" | "bound"
lineItemsDraft?: LineItem[] }
The key concept:
offerMode • "local" → document stores its own draft line items • "bound" → document reflects real Offer line items, always live
⸻
- LineItems (DB Model)
Line items are the atomic billing rows stored in the database.
Extended model includes:
unitType: string? // e.g. per_person, per_day, per_night, per_transfer, package, etc. unitLabel: string? // e.g. "person", "night", "km", "package" meta: Json? // breakdown / pricing logic / source metadata
A line item always represents a resolved price. It is never “raw trip data” or “raw product data”.
⸻
- Document Line Item Section (“DocSection_LineItems”)
The core UI for editing/viewing document-side line items.
This component is responsible for: • Showing local line items OR showing bound offer line items • Providing UI to: • Bind a document to an offer • Detach a document from an offer • Passing edits up to document data (when in local mode)
Bound mode = read-only except via the Offer editor.
⸻
- Offer Document Template (DocTemplate_Offer)
Implements two modes: 1. Local (pre-offer) Document keeps draft line items and may create/attach an Offer. 2. Bound-to-offer Document fetches canonical offer line items using getOfferWithLineItems(offerId) Editor modifies them via updateOfferLineItemsFromEditor.
This template is the “manager” of the document ↔ offer relationship.
⸻
- Server Actions (backend integration)
getOfferWithLineItems(offerId)
Returns live items + computed totals.
createOfferFromDocument(documentId)
Takes local draft line items from a document → creates a new Offer with real line items → binds document to the offer.
bindDocumentToOffer(documentId, offerId)
Attaches a document to an existing offer → document becomes “bound”.
detachDocumentFromOffer(documentId)
Copies current canonical offer line items into the document as draft items → switches back to local mode.
updateOfferLineItemsFromEditor(offerId, items[])
The offer’s canonical editing API for line items.
⸻
- Order / Invoice Relationship to Offers
Offer → Order
When an offer becomes an order: • line items are copied (not referenced) • order totals are computed once • order may modify quantities independently without affecting the offer
Order → Invoice
Invoice also receives a copy of resolved line items, but may adjust: • delivered quantities • payment state • due amounts
There is no re-pricing inside orders or invoices. Only Offer runs pricing transforms.
⸻
- The Pricing Engine (NEW MODULE)
This is where the next conversation begins.
A universal transformer layer generates normalized line item packages from domain entities:
Trip → LineItemPackage Product → LineItemPackage Experience → LineItemPackage
Where a LineItemPackage looks like:
{ packageTotal: number defaultUnitType: string defaultUnitLabel: string
rows: [ { title: string qty: number unitType: string unitLabel: string unitPrice: number meta?: any } ] }
Representation rules • Offer may choose between: • Single-row package • Multi-row detailed breakdown • Order always uses detailed breakdown (logistics-level detail) • Invoice uses order breakdown but adjusts delivered qty
Source selection UI
LineItemEditor supports selecting:
sourceType: "trip" | "product" | "experience" | "custom" sourceId: number
Then calls:
resolvePricing(sourceType, sourceId, context)
Context includes things like group size, dates, cities, participants, etc.
⸻
🏁 END OF SPEC MODULE
Copy/paste the entire block above into a new conversation.
⸻
🎉 NEXT STEP
When you’re ready, simply start a new conversation with:
“Let’s begin the Trip Pricing Engine (computeTripPricing). Here is the first piece of the trip model…”
Then paste whichever version of your trip logic you want me to base the unified engine on (Apps Script / Spreadsheet / NestJS / NextJS).
I’ll: • Extract the core rules • Normalize the breakdown categories • Build the canonical pricing engine • Make it compatible with LineItemPackage generation • Ensure it integrates cleanly into Offer → Order → Invoice pipeline