H1Commercial PRD - Molino App
version: 2026.04
status: active
owner: Molino
scope: Offer / Order / LineItem
last_updated: 2026-04-26
H2Focus Strip
| Now | Lock | Do Not Break | Next Closure |
|---|---|---|---|
| Commercial snapshot path | Offer -> Order clone, not mutation | LineItem totals, tax, meta, source links | Add/designate canonical createOrderFromOfferSnapshot() |
| State | Meaning |
|---|---|
| built/locked | pure computeLineItem(), LineItem CRUD/clone, offer line item reads |
| built/partial | offer CRUD, order CRUD, document-to-order bridge |
| docs-ahead | immutable order snapshot and single conversion action |
H10. Implementation Snapshot
H2Current goal
H3Keep Commercial as the downstream economic boundary
Keep it focused on offers, orders, and committed line items.
H3Support the new `/studio/travel` and `/trips` booking surface
Do this without moving pricing authority into UI or document layers.
H2Remaining features
H3Preserve stable line-item totals after pricing commit
Keep committed totals stable.
H3Keep offer snapshots distinct from confirmed order snapshots
Maintain a clean proposal-to-confirmation boundary.
H3Make projection output read from canonical commercial data
Avoid presentational recomputation.
H3Prevent UI components and documents from recomputing economic totals independently
Keep pricing authority in server-side helpers.
H2Next build steps
H3Inspect `app/orders/actions/`, `orderFromOffer.ts`, and `mapTripPricingToLineItems.ts`
Confirm the current commercial bridge before editing.
H3Verify Offer -> Order conversion preserves snapshot data
Keep the snapshot handoff explicit.
H3Check revalidation after commercial mutations
Make sure the route state refreshes correctly.
H3Test projection output against canonical line items
Confirm the output still matches the source data.
H3Confirm the booking surface still lands in Offer, Order, and LineItem records rather than UI-side totals
Keep the booking surface anchored in the commercial record.
H2Prompt starter summary
H3Treat LineItem as economic truth
Snapshot Offers and Orders in server-side helpers, and keep pricing and revalidation logic out of UI components while the new booking surface is validated in /studio/travel and /trips.
H2Prompt starter
Implement the next Commercial PRD slice. Use _PRD/trips/transactions/README.md as source of truth. Treat LineItem as economic truth once committed. Offers snapshot proposed commercial terms; Orders snapshot confirmed terms. Keep pricing calculations in server-side helpers/actions and do not duplicate totals in UI components, documents, or projection outputs. Inspect app/orders/actions/, orderFromOffer.ts, product projection helpers, and app/trips/lib/mapTripPricingToLineItems.ts before editing. Revalidate relevant routes after mutations.
H21. Product Identity
H3Name
Commercial
H3One-line Definition
Commercial is Molino's downstream economic system for offers, orders, and line items.
H3User-facing Purpose
This feature exists so users can:
- receive structured commercial proposals
- confirm or review order snapshots
- understand pricing and line-item composition
- preserve a clear record of commercial terms
H3Internal Platform Purpose
Inside Molino App, this feature exists to:
- preserve economic truth after pricing is committed
- keep offers and orders as immutable snapshots where appropriate
- connect Trip and Document outputs to transactional records
- avoid recalculating totals in projection layers
H22. Scope
H3In Scope
- entities:
Offer,Order,LineItem - related models:
Trip,TripPricing,Document,Product - actions:
app/orders/actions/, offer/order projection helpers, order creation from offer - behaviors: snapshotting, revalidation, projection, conversion from proposal to confirmed order
H3Out of Scope
- client-side pricing authority
- duplicate economic calculations in UI components
- replacing the canonical pricing layer with presentation logic
H23. Authority Model
- pricing calculations belong to server-side helpers and actions
- line items are the economic record once committed
- offers snapshot commercial terms
- orders snapshot confirmed terms
- projection surfaces must not invent totals independently
H24. Current Implementation Surface
app/orders/actions/projectOrders.tsapp/orders/actions/orderFromOffer.tsapp/orders/types/order.types.tsapp/products/actions/projectProducts.tsapp/trips/lib/mapTripPricingToLineItems.ts- Prisma models in
prisma/schema.prisma
H24.1 Current Code Reality
LineItemcan attach toProduct,Trip,Experience,ProjectDocument,ProjectAsset,Offer, andOrder.Offerowns editable commercial snapshots and has relatedLineItem,ProjectDocument,Order, andTripJoinrecords.Orderis the downstream locked transaction surface and stores optionalsnapshotdata plus order-owned line items.TripJoinstores a frozen pricing snapshot at join time and may bridge to anOfferorOrder.TripPricingexists as a persisted pricing record, while the active trip public list currently attaches live computed pricing through the trip engine before mapping cards.- Documents can reference offers, orders, and line items, but they must render commercial truth rather than recompute it.
H24.2 Code Audit - 2026-04-26
H3Built / locked
app/lineitems/lib/computeLineItem.tsis a pure client/server-safe normalizer with no Prisma or server engine calls.app/lineitems/actions/lineItems.tsowns persisted line-item create, update, delete, clone, and bulk update operations.cloneLineItems()copies source line items into a new parent while preserving totals, tax, display mode, group key, and serialized meta.addTripItemsToOffer()creates offer-owned trip line items from a server-built package and keeps FareHarbor/UI/pricing meta on the line item.
H3Built / partial
getOfferWithLineItems()reads offer-owned line items and normalizes meta into a typed boundary shape.projectOffers.tssupports offer CRUD and includes line items, documents, orders, and contact metadata in read helpers.projectOrders.tssupports order CRUD, but does not yet own a full snapshot conversion contract.documentToOrder()creates an order from a document-bound offer and copies line items into order-owned rows.
H3Docs-ahead / pending
confirmOffer()is explicitly marked legacy and should not be treated as the canonical conversion path because it mutates existing line items from offer to order.documentToOrder()copies offer line items, but currently recomputestotal,taxRate, andtaxTotalinstead of preserving the committed offer line-item economics exactly.orderFromOffer.tsis a pure mapper over an olderOfferObjectshape and is not the current locked Prisma conversion path.- Offer and order snapshots exist in schema shape, but the app still needs one named canonical action for Offer -> Order that clones rather than mutates or recomputes.
H3Critical next step
Create or designate one canonical createOrderFromOfferSnapshot() action that:
- reads offer line items through
getOfferWithLineItems() - creates an order with an explicit snapshot payload
- clones line items to
parentType: "order"while preserving totals and meta - marks or links the source offer without moving its line items
- revalidates
/offers/[offerId],/orders/[orderId], and any document route that projects the order
H25. Acceptance Criteria
- line-item totals stay stable after commit
- offer and order snapshots remain distinct
- commercial flows revalidate correctly after mutation
- projection output matches canonical data
H26. Locked Summary
Commercial is Molino's pricing and transaction boundary. It captures the finalized economic record and must remain separate from presentational recomputation.