MolinoPro

20260418_FastProductionSAP_MLV

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

Default Index
Open README.md
Root: README.mdframework
Milestones
H1📘 MOLINO — FAST PROJECTION ARCHITECTURE (LOCKED — MLV)

H10. SYSTEM IDENTITY

System = Deterministic Core + Projection Engine

  • Prisma (DB) → single source of truth
  • Entities → canonical business objects
  • Document → projection + orchestration surface
  • Folio → deterministic renderer
  • Actions → only mutation authority
  • Projection Engine → external outputs (Google Workspace)

H11. GLOBAL EXECUTION MODEL (SIMPLIFIED)

Truth (Prisma) ↓ Document (projection) ↓ Folio (render) ↓ User / AI Intent ↓ Actions (persist) ↓ Revalidate ↓ Projection (optional) ↓ External Systems (Docs / Calendar / Sheets)


H12. CORE PRINCIPLE (LOCKED)

Compute once → project everywhere

  • All logic happens in Next.js
  • External systems receive ready-to-render payloads
  • No logic outside core system

H13. DOCUMENT SYSTEM (MINIMAL)
H23.1 ROLE
  • projection surface
  • working buffer
  • UI interaction layer

NOT:

  • not canonical truth
  • not responsible for business logic

H23.2 OUTPUT RESPONSIBILITY

Document can trigger:

  • Google Docs export
  • Calendar generation
  • Reports (Sheets / CSV)

H14. ENTITY CORE (UNCHANGED)

Entities:

  • Project
  • Trip
  • Offer
  • Order
  • LineItem (core connector)

H24.1 LINE ITEM (CRITICAL)
LineItem {
  label
  quantity
  unitPrice
  total
}

Used across:
	•	documents
	•	offers
	•	reports
	•	exports

⸻

5. ACTION SYSTEM (LOCKED)

Location:

app/(entity)/actions/

Rules:
	•	ONLY Prisma writes
	•	ONLY mutation authority
	•	ALWAYS revalidate

⸻

6. PROJECTION ENGINE (NEW CORE LAYER)

⸻

6.1 ROLE

Projection Engine = external output adapter
	•	transforms internal data → external systems
	•	stateless
	•	reusable across entities

⸻

6.2 STRUCTURE

computeBundle(entity, id)
    ↓
projectEntity(bundle)
    ↓
External Systems


⸻

6.3 OUTPUT BUNDLE (CANONICAL)

type OutputBundle = {
  meta: {
    entity: string;
    entityId: string;
    title: string;
  };

  document?: DocumentPayload;
  calendar?: CalendarPayload[];
  tabular?: TabularPayload;
  email?: EmailPayload;
};


⸻

7. OUTPUT STRUCTURES (LOCKED)

⸻

7.1 DOCUMENT

Narrative

type DocumentPayload = {
  title: string;
  blocks: { type: string; content: string }[];
};


⸻

With Line Items

type DocumentWithLineItems = {
  title: string;
  header: Record<string, string>;
  lineItems: LineItem[];
  totals?: { total: number };
};


⸻

7.2 CALENDAR

type CalendarPayload = {
  title: string;
  start: string;
  end: string;
  location?: string;
  meta?: Record<string, string>;
};


⸻

7.3 TABULAR (CSV / SHEETS)

type TabularPayload = {
  columns: string[];
  rows: (string | number)[][];
};


⸻

7.4 EMAIL

type EmailPayload = {
  to: string;
  subject: string;
  body: string;
};


⸻

8. PROJECTION FUNCTIONS

⸻

8.1 ENTRY POINT

export async function projectEntity(entity: string, id: string) {
  const bundle = await computeBundle(entity, id);

  if (bundle.document) await projectToDocs(bundle.document);
  if (bundle.calendar) await projectToCalendar(bundle.calendar);
  if (bundle.tabular) await projectToSheets(bundle.tabular);
  if (bundle.email) await sendEmail(bundle.email);
}


⸻

8.2 RULE
	•	ONE button
	•	ONE action
	•	MULTIPLE outputs

⸻

9. APPS SCRIPT LAYER (LOCKED)

⸻

9.1 ROLE

Apps Script = stateless printer
	•	no logic
	•	no computation
	•	no iteration

⸻

9.2 ENDPOINTS

POST /gas/print/doc
POST /gas/print/calendar
POST /gas/print/sheet
POST /gas/print/email


⸻

9.3 CONTRACT

Input:

{
  title,
  data
}

Output:

{
  success: true,
  url
}


⸻

10. USER EXPERIENCE (SIMPLIFIED)

⸻

10.1 UNIVERSAL ACTION

Every entity:

[ Export ]

Optional:

Export →
  • Doc
  • Calendar
  • Sheet


⸻

10.2 USER DOES NOT SEE
	•	APIs
	•	Apps Script
	•	data formats
	•	integration logic

⸻

11. MINIMAL ENTITY MAPPING

Entity	Outputs
Trip	Doc + Calendar
Offer	Doc + Sheet
Order	Doc + Email
Document	Doc
LineItems	Sheet + CSV


⸻

12. CSV EXPORT (LOCAL)

function toCSV(payload: TabularPayload) {
  return [
    payload.columns.join(","),
    ...payload.rows.map(r => r.join(","))
  ].join("\n");
}


⸻

13. PERFORMANCE MODEL

⸻

13.1 NEXT.JS
	•	computes everything
	•	formats everything
	•	resolves titles
	•	prepares payload

⸻

13.2 APPS SCRIPT
	•	receives payload
	•	renders output
	•	returns link

⸻

13.3 RESULT
	•	fast
	•	predictable
	•	scalable

⸻

14. DEVELOPMENT PLAN (FAST TRACK)

⸻

DAY 1
	•	projectToDocs
	•	computeBundle (Trip minimal)

✔ Google Doc output

⸻

DAY 2
	•	projectToCalendar
	•	projectToSheets

✔ full projection system

⸻

DAY 3
	•	wire entities
	•	add UI buttons

✔ usable system

⸻

15. RULES (CRITICAL)

⸻

	•	no logic in Apps Script
	•	no Google as source of truth
	•	no duplicate computation
	•	no multi-step UI

⸻

16. FINAL MODEL

Entity
↓
computeBundle
↓
projectEntity
↓
Apps Script
↓
Google Workspace


⸻

17. FINAL LOCK

You are building:

A fast projection engine over a deterministic system

⸻

18. SUCCESS CRITERIA

✔ click → doc generated
✔ trip → calendar generated
✔ offer → sheet generated
✔ one action works everywhere

⸻

19. FINAL PRINCIPLE

Simplicity over completeness
Projection over duplication
Integration over invention

⸻

🚀 NEXT

→ implement computeBundle(trip)
→ implement /gas/print/doc
→ connect button

STOP. Do not expand until loop works.

✔️ Short Answer

Your schema is already 90% compatible with the Projection Engine.

You do NOT need a redesign.
You only need to add a thin “projection metadata layer” + optional output tracking.

⸻

🟣 1. WHAT YOU ALREADY HAVE (ALIGNED)

You already cover:

✔ Entities (Trip, Offer, Order, LineItem)
✔ Document system (ProjectDocument, DocumentPage)
✔ Calendar (CalendarEvent)
✔ Deliverables (generic output container)
✔ Assets (external integration hooks possible)

→ This is already a full ERP core

⸻

🟢 2. WHAT IS MISSING (MINIMAL ADDITIONS)

You need ONLY 2 additions

⸻

A. Projection Metadata (LIGHTWEIGHT)

Add a universal tracking layer:

model Projection {
  id         String   @id @default(cuid())

  entity     String   // "trip" | "offer" | etc
  entityId   String

  type       String   // "doc" | "calendar" | "sheet" | "email"

  externalId String?  // Google Doc ID, Event ID, Sheet ID
  externalUrl String?

  status     String   @default("created") // created | updated | failed

  payload    Json?    // snapshot of what was sent

  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  @@index([entity, entityId])
  @@index([type])
}


⸻

WHY THIS MATTERS

Enables:
	•	re-sync
	•	updates
	•	debugging
	•	audit trail
	•	multi-output tracking

⸻

B. OPTIONAL: ExternalRef (LIGHTER ALTERNATIVE)

If you want even simpler:

model ExternalRef {
  id        String   @id @default(cuid())
  entity    String
  entityId  String
  key       String   // "docId", "calendarEventId"
  value     String

  createdAt DateTime @default(now())

  @@index([entity, entityId])
}


⸻

🟡 3. NO CHANGES NEEDED (IMPORTANT)

DO NOT modify:
	•	Trip
	•	Offer
	•	Order
	•	LineItem
	•	Document
	•	Deliverable

They already support projection.

⸻

🔵 4. HOW YOUR CURRENT MODELS MAP TO OUTPUTS

Output	Current Model
Docs	ProjectDocument / Deliverable
Calendar	CalendarEvent
Sheets	(derived, no model needed)
CSV	(derived, no model needed)
Email	(no persistence needed initially)


⸻

🟠 5. MINIMAL INTEGRATION (HOW IT FITS)

⸻

Example: Trip → Calendar

// Action
projectTripToCalendar(tripId)

Flow:

Trip
↓
computeBundle
↓
create CalendarEvent (optional local)
↓
call GAS
↓
store Projection


⸻

Example: Offer → Document

Offer
↓
LineItems
↓
computeBundle
↓
projectToDocs
↓
store Projection


⸻

🔴 6. WHAT YOU SHOULD NOT ADD

❌ No “GoogleDoc” model
❌ No “SheetModel”
❌ No duplication of outputs
❌ No schema for CSV

Reason:

Outputs are projections, not entities

⸻

🟣 7. OPTIONAL (ADVANCED BUT CLEAN)

Attach projection to Deliverable

You already have:

model Deliverable {
  ...
  data Json
}

You can store:

{
  "docUrl": "...",
  "calendarIds": ["..."],
  "sheetUrl": "..."
}

→ No schema change needed

⸻

🟢 8. FINAL MINIMAL ADDITION SET

REQUIRED

+ model Projection

OPTIONAL

+ model ExternalRef


⸻

⚡ 9. RESULTING SYSTEM (UPDATED)

Entity (Trip / Offer)
    ↓
computeBundle (Next.js)
    ↓
projectEntity
    ↓
Apps Script
    ↓
Google Workspace
    ↓
Projection (stored)


⸻

🧠 10. STRATEGIC IMPACT

With this small addition:

You now have:

✔ full audit trail
✔ sync capability
✔ multi-output system
✔ extensible integrations
✔ production-grade architecture

⸻

✅ FINAL VERDICT
	•	Your schema is already correct and sufficient
	•	Only 1 small model (Projection) completes the system
	•	No restructuring required
	•	You are already operating at ERP + Integration layer level

⸻

🚀 NEXT STEP

Add:

model Projection { ... }

Then implement:

projectEntity("trip", tripId)

→ Store result in Projection

That completes the loop.