MolinoPro

SKILL_document-engine

Master Codebase Guidebook
Markdown + HTML Dev-Docs Renderer - Frontend Client Module

Default Index
Open README.md
Root: README.mddocument
Milestones
H1SKILL: Document Engine (Virtual Instrument)

Module: Document System Status: Active / Stable enough for continued work Part of: MASTER_SKILL.md — Chapter 4 See also: ./mlv-document-one_akill.md, ./GOALS-AHEAD.md


H2Identity

The Virtual Document Instrument is an in-app entity — not a file, not a Google Doc.

It is:

  • An internal application entity, editable in the web app
  • Rendered through Folio (pagination + wagons)
  • Used as orchestration surface (triggers real operations)
  • Used as projection surface (reflects entity state)
  • Used as commercial instrument (offers, proposals, letters)
  • A trigger surface for exports and workflows

It is NOT:

  • A Google Doc
  • A DOCX file
  • The canonical truth for trips, offers, orders, or payments

H2Document Templates Registry
// app/(pages)/documents2/components/DocRegistryComponents.tsx

Templates:
  note2       → free-form notes
  offer       → commercial offer (local or bound to Offer entity)
  proforma    → pre-invoice
  invoice     → final invoice
  firmorder   → confirmed order document
  trip-offer-v1 → trip commercial proposal (primary)
  custom      → open template

Each template shape:

{
  key: string,
  label: string,
  emoji: string,
  requireExplicitEdit: boolean,
  defaultData: Record<string, any>,
  renderView(data): JSX.Element,
  renderEditor(data, update): JSX.Element
}

H2Document Data Model

All templates share a core JSON structure stored in projectDocument.data:

{
  title: string,
  description?: string,
  clientName?: string,
  meta: { currency?: string, [k: string]: any },

  // Offer linking:
  offerId?: number | null,
  offerMode?: "local" | "bound",

  // Line items (local mode):
  lineItemsDraft?: LineItem[],

  // Trip section (trip-offer-v1):
  tripSection?: {
    kind: "trip",
    tripData: TripDraftData
  },

  // Content sections:
  contentSections?: Array<{
    id: string,
    type: "text",
    role: "letter-intro" | "itinerary" | "cta" | string,
    content: string
  }>,

  // CTA:
  ctaSection?: {
    enabled: boolean,
    type: "whatsapp" | "email" | "link",
    phone?: string,
    text: string
  }
}

H2Offer Mode Rules

"local" mode:

  • Document stores its own draft line items in lineItemsDraft
  • User can freely edit line items
  • Can trigger createOfferFromDocument() to promote to a real Offer

"bound" mode:

  • Document reflects real Offer line items via getOfferWithLineItems(offerId)
  • Line items are read-only in the document
  • Editing happens through the Offer editor → updateOfferLineItemsFromEditor()
  • Can detach with detachDocumentFromOffer() → copies canonical items into local mode

H2Document Actions Reference
// Offer linkage
getOfferWithLineItems(offerId)
  → { items: LineItem[], totals: { subtotal, tax, total } }

createOfferFromDocument(documentId)
  → creates Offer from local draft items → binds document → returns { offerId }

bindDocumentToOffer(documentId, offerId)
  → attaches document to existing offer → switches to bound mode

detachDocumentFromOffer(documentId)
  → copies canonical offer items into document draft → switches to local mode

updateOfferLineItemsFromEditor(offerId, items[])
  → canonical editing API for bound offer line items

// Trip integration
commitTripFromDocument({ documentId, tripDraft })
  → persists TripDraftData as real Trip entity → returns { tripId }

syncTripLineItems({ tripId, items })
  → upserts line items by (tripId, key) → deletes orphaned items

populateTripOfferFromTrip({ trip, pricing, client })
  → deterministic doc generation → fills contentSections

H2Intent Flag Pattern (Command-Driven)

DocSection_TripBuilder emits intents, never side effects:

// Button in TripBuilder:
onChange?.({
  ...section,
  tripData: {
    ...trip,
    _requestCommitTrip: true, // persist trip to DB
    _requestInsertIntoLineItems: true, // insert line items
    _requestOverwriteTripLineItems: true, // overwrite line items
    _requestPopulateTripOffer: true, // fill document content sections
  },
});

Documents2Canvas.handleTripSectionChange is the only coordination point:

  • Reads intent flags
  • Calls the appropriate server action
  • Queues save with flag reset to false
  • Returns early after handling

H2Document Lifecycle
Status-driven (never deleted):
  Draft → Proposed → Confirmed

Only Orders are permanent records.
Documents, Offers, Trips are revisable.
Revisions create new versions, not silent overwrites.

H2Folio (Render Layer)
rawBlocks (input)
    ↓ normalize
FlowUnits
    ↓ paginate (layout only)
wagons (render units per page)
    ↓
DOM output

Invariants:

  • Deterministic IDs across renders
  • Pagination is layout only — never business logic
  • Pure transforms — no side effects in render pipeline

H2What this is NOT
  • Not a Google Doc editor
  • Not the source of truth for business entities
  • Not responsible for payment, booking, or order truth
  • Not a file system

This skill is Chapter 4 of MASTER_SKILL.md. See also: ./GOALS-AHEAD.md for full Document Engine v2 + Offer/Order spec.