MolinoPro

README

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

Default Index
Open README.md
Root: README.mdtrips
Milestones
H1Trips PRD - Molino App

version: 2026.04 status: locked owner: Molino scope: app/trips last_updated: 2026-04-28

H2Focus Strip
NowLockDo Not BreakNext Closure
Keep /trips as execution hubBuilder-backed sections + public projectionSection registry, builder content, trip-engine pricing, public/draft separationDecide hotel line-item rule for quote/join -> offer
StateMeaning
built/locked/trips/page.tsx, registry rendering, getTripsPublicData()
built/partialplanner create/update, TripJoin snapshots, quote output
docs-aheadone canonical quote/join -> LineItem/Offer path
H10. Implementation Snapshot
H1Corrected Next Slice - Respect Builder + Trips Hub

status: aligned with architecture
scope: /trips hub via Section Builder (NOT hardcoded page)
priority: HIGH


H1Core Correction

You are correct.

Previous direction to avoid:

  • hardcoding sections in /trips/page.tsx
  • bypassing builder system

Correct direction:

  • /trips is a Section Builder surface
  • sections = editable + deployable content units
  • page = renderer only
  • components (like yours) = dual-mode (edit/view)

This component proves:

  • Builder is already the authority.
  • We must compose registry + content, not override it.

H1Already Confirmed

From your component:

  • Section Builder integration working.
  • useSectionContent merges defaults and persisted content.
  • useSectionContentField gives field-level authority.
  • useArrayField supports deterministic list editing.
  • editMode is respected.
  • commit-on-blur pattern is respected.
  • no mutation leakage.

H1Next Slice
H2GOAL

Turn /trips into:

Builder-driven commercial hub

NOT:

  • static layout
  • hardcoded sections

H1G-B1 - /trips Page = Builder Orchestrator
H3file

app/(pages)/trips/page.tsx

import { Suspense } from "react"
import { getPageSections } from "@/app/(home)/builder/actions/getPageSections"
import { renderSection } from "@/app/(home)/builder/lib/renderSection"

export default async function TripsPage() {
  const sections = await getPageSections("trips")

  return (
    <>
      {sections.map((section) => (
        <Suspense key={section.id}>
          {renderSection(section)}
        </Suspense>
      ))}
    </>
  )
}
H2Current goal
H3Ship the first working booking surface end-to-end in `/studio/travel`

Use one city tour card and one featured trip card with real FareHarbor buttons while keeping /trips as the visible commercial trip hub with four clear lanes.

H3Keep featured experiences as a supporting commercial lane

Do not promote featured experiences into a separate primary business root.

H2Remaining features
H3Render the four lanes near the top with native Molino cards in `/trips`

Keep the commercial lanes visible and easy to scan.

H3Wire FareHarbor buttons through Lightframe modal execution only

Use button-driven modal execution only, with no embedded grids or calendars.

H3Keep the `/studio/travel` cards aligned with the same FareHarbor button behavior

Make the travel bridge behave like the Trips booking surface.

H3Keep planner, join, pricing, and collaboration paths visibly separate

Do not collapse booking, planning, and enquiry into one generic flow.

H3Add the footer bridge back to `/studio`

Keep the reverse handoff visible without weakening Trips.

H3Preserve the experience read model inside Trips while keeping Trip, LineItem, Offer, and Order as the execution chain

Treat experiences as supporting inventory and preserve the trip-to-commerce bridge.

H2Next build steps
H3Inspect `app/trips/components/`, the travel card helpers, and landing actions before changing UI

Check the current route structure before adjusting the booking surface.

H3Confirm `FareHarborBookAction`, `TravelBookingCard`, `FeaturedTripBookingCard`, `FlexibleTripPlannerCard`, and `CollaborationsCard`

Verify the existing lane components still match the intended surface.

H3Verify the `/studio/travel` booking cards use the same real FareHarbor button behavior as `/trips`

Keep the booking behavior consistent across the two entry surfaces.

H3Verify trip pricing still maps through `TripPricing` and downstream `LineItem`

Preserve the commercial bridge before any UI work ships.

H3Run the `/trips` route after changes and check draft/public separation

Confirm the live route still renders and keeps the read layers separate.

H3Keep the featured experiences lane aligned with the reusable experience catalog, not with trip authority

Avoid moving discovery inventory into the core execution root.

H2Prompt starter summary
H3Ship the first working booking surface in `/studio/travel` plus the four-lane commercial trip hub in `/trips`

Use native Molino cards, Lightframe FareHarbor buttons, a read-only page, a preserved footer bridge back to /studio, and a supporting featured-experiences lane.

H2Prompt starter
Implement the next Trips PRD slice. Use _PRD/trips/README.md as source of truth. Keep /trips as the commercial trip hub with four visible lanes: ready-made city tours, featured guided group trip, flexible trip planning, and collaborations. Use native Molino cards. FareHarbor is button/modal execution only through Lightframe; do not embed FareHarbor grids, calendars, or widget React children. Keep mutations in app/trips/actions/, page.tsx read-only, and TripPricing -> LineItem as the economic bridge. Preserve draft/public separation and add or maintain the footer bridge back to /studio.
H2Functional note
H3The lane structure is live, and the active public projection is no longer the old dummy read layer

Treat app/trips/actions/trips.read.actions.ts as an obsolete reference surface unless a route imports it directly. The active /trips public read chain is:

  • app/trips/page.tsx
  • app/trips/actions/tripsLanding.actions.ts
  • app/trips/lib/mapProjectSectionsToTripsSections.ts
  • app/trips/components/TripsSectionRenderer.tsx
  • app/trips/actions/trips.public.read.ts
  • app/trips/actions/trips.list.read.actions.ts
H2Public Read Layer - Locked
H3Use a single projection helper for `/trips` landing lanes

getTripsPublicData() supplies featuredTrips, featuredCities, featuredExperiences, and publicTrips to the existing builder renderer.

Current implementation note:

  • featuredTrips and publicTrips come from Prisma Trip rows where shareForOthers is true and startDate is not in the past.
  • featuredTrips also requires featured true.
  • trip pricing is attached through tripEngine(mapEntityToTripInput(trip)).
  • featuredExperiences comes from active Prisma Experience rows with optional City relation.
  • FareHarbor execution URLs are derived from Experience.externalId when present.
  • the landing project slug is andalusian-trips-lab.
H2Code Audit - 2026-04-26
H3Built / locked
  • /trips/page.tsx is a read-only orchestrator that renders registry-backed sections through TripsSectionRenderer.
  • getTripsLandingSections() reads the builder project with slug andalusian-trips-lab and falls back to registry defaults when needed.
  • mapProjectSectionsToTripsSections() filters invisible or unknown sections and preserves registry authority.
  • getTripsPublicData() is the active lane projection for featured trips, public trips, featured cities, and featured experiences.
H3Built / partial
  • createTripFromPlanner() creates a private my-trips project for the user if needed, resolves or creates the trip product type, persists Trip and TripCity records, and revalidates trip routes.
  • updateTripFromPlanner() checks project owner before replacing TripCity rows and updating trip metadata.
  • createTripJoin() stores a pricing snapshot, total services, total per person, and total group for the join request.
  • recomputeTripJoins() can refresh pricing snapshots for all joins on a trip.
  • quoteTripJoin() returns pricing, mapped line items, totals, and assumptions for enquiry/quote surfaces.
H3Docs-ahead / pending
  • quoteTripJoin() asks for hotel totals after calling mapTripPricingToLineItems(), but that mapper currently filters hotel rows out. Treat hotel quote totals as pending until the quote mapper preserves or separately handles hotel rows.
  • TripPricing exists in Prisma, but the active public list attaches live computed tripEngine output rather than reading persisted TripPricing rows.
  • The final path from trip quote/join into committed LineItem -> Offer -> Order records is not fully locked in one canonical action.
H3Critical next step

Lock the trip quote/join to committed LineItem/Offer behavior: decide whether hotels remain excluded from line items or become a separate line-item group, then make the quote totals and offer commit use the same rule.

H3Keep the city-tour lane experience-driven

Derive the city-tour lane from active experiences and their city metadata, not from a separate booking model.

H3Keep the featured-trip lane trip-driven

Use the public trip projection for featured and broader trip cards.

Prompt starter companion:

Audit the Trips route as shipped today. Keep the four commercial lanes and the featured-experiences lane. Preserve Trips as the execution root, keep experiences as supporting inventory, and do not move pricing or booking authority out of Trip -> LineItem -> Offer -> Order. If you update the read layer, preserve the current lane structure and replace the temporary seed data deliberately rather than accidentally.
H21. Product Identity
H3Name

Trips

H3One-line Definition

Trips is the canonical commercial planning and public booking surface for Molino trip experiences, including featured experiences as a supporting lane.

H3User-facing Purpose

This feature exists so users can:

  • browse trips and featured experiences
  • open trip detail and join flows
  • start booking or enquiry actions
  • understand trip timing, pricing, and availability
H3Internal Platform Purpose

Inside Molino App, this feature exists to:

  • preserve trip canonical data
  • expose a controlled public route surface
  • connect planning, pricing, and booking overlays
  • keep LineItems and projection flows stable
  • keep experiences visible as reusable ingredients without moving execution authority out of Trips
H22. Route Role
  • Trips is the main commercial and operational trip hub.
  • Trips is the actual actionable offer surface.
  • Trips remains broader than Studio Travel.
  • Experiences sit alongside Trips as supporting commercial units, not as the top-level execution root.
H22.1 Experience Positioning
  • Trips already renders a featured experiences lane.
  • Experiences act as reusable commercial ingredients and discovery surfaces.
  • Trip pricing, join flows, and booking authority stay in the Trips execution chain.
H22.2 Naming Alignment

Use one shared concept family across the trip surfaces:

  • ready-made city tours
  • city highlight tours
  • featured experiences
  • experience cards

These all refer to the same visible commercial lane: reusable city-linked trip ingredients surfaced inside Trips.

Use one shared planning family for the intake side:

  • flexible trip planning
  • trip plan
  • trip planner
  • plans

These all refer to the same planning / intent surface that feeds Trips, not a separate commercial entity.

H22.3 Backend Intent Reference
H3Source meaning

There is an older full backend/API scope for travel operations that should be treated as product-intent reference material, not as a separate deployment target. Its useful scope includes users, cities, trips, trip cities, plans, trip-city-plan joins, items/experiences, participant details, costs, bookings, quotes, payments, hotels, landing pages, and external booking integrations.

Molino should preserve that intent while replacing the split backend shape with the existing Next.js stack. The goal is not to keep a parallel NestJS-style backend or duplicated service layer. The goal is to absorb the useful service boundaries into app/trips, Prisma models, server actions, route handlers where needed, document projection, and the existing Trip -> LineItem -> Offer -> Order commercial chain.

H3Core trip concept

The Trip is the flexible journey record. It may be public, private, cloned, edited, quoted, booked, or projected into documents. A trip can include multiple cities, dates, participants, plans, costs, sessions, hotel options, and external booking references.

Public users should see a clear travel offer. Internal users should manage the canonical operational state.

H3Service-intent map to preserve
  • Cities and destinations: spatial anchors such as Cordoba, Granada, Seville, Malaga, Morocco, or future destinations. Cities feed trips, plans, landing pages, public imagery, local notes, and session scheduling.
  • Trips: full journey containers that can be created, edited, cloned, listed, previewed, assigned, published, and connected to city plans or schedules.
  • Trip cities: ordered route structure inside a trip, including dates, nights, city purpose, and local rhythm.
  • Plans: reusable itinerary blocks such as visits, guided walks, workshops, excursions, transfer days, free days, local evenings, and partner-led experiences.
  • Trip city plans: the merge layer between a trip, a city, and a plan. This answers which available plans fit a city inside a specific trip.
  • Items and experiences: public catalog units such as tours, sessions, workshops, partner services, or standalone bookable products. They may be published independently or surfaced along a route.
  • Participant details: traveller names, party size, preferences, rooming notes, requirements, dietary needs, arrival context, and desired support level.
  • Costs and estimated pricing: line-level commercial inputs for plans, services, hotels, guides, transport, margins, and optional extras. These should feed the pricing engine and downstream line items instead of being recomputed inside documents.
  • Quotes: commercial offer versions generated from a trip plan. A quote can become a document, email draft, payment link, offer, or confirmation path.
  • Bookings: accepted traveller intent for a trip, plan, or item. Molino should support both internal booking records and external booking references.
  • Payments: gateway execution layer. Trips and quotes create payment intent; Stripe or another provider executes payment; Molino stores the external reference and status.
  • Hotels: begin as structured options inside trips, plans, quotes, or line items. API search, geocoding, rate keys, and confirmations are later-stage integrations.
  • Landing pages: public conversion surfaces generated from trips, cities, campaigns, featured routes, or partner offers.
  • Users and profiles: travellers, admins, collaborators, sponsors, guides, or future subscribers, with ownership and access determining who can create, edit, quote, book, or view private details.
  • FareHarbor and external booking: FareHarbor remains the parallel execution surface for core city sessions and standalone bookable experiences. Molino stores public CTA targets, booking modal links, external IDs, and confirmed references.
H3Strategic merge pattern

The important product pattern is the merge between trip bookings and session bookings. A single real dated session, such as a Cordoba walk or Granada visit, can accept standalone FareHarbor bookings while also belonging to a larger private or group trip.

When those streams meet in the same real session, the economics improve: independent travellers, trip participants, and local sessions can share guide time, capacity, and cultural value. This is a central revenue and viability pattern for the trips system.

H3Current scope to keep visible
  • public trips page
  • trip create/edit/view with persistent records
  • page ID routing
  • basic city and route structure
  • featured trips
  • featured cities
  • experiences along the route
  • manual or semi-structured trip planning CTA
  • reusable content from older travel pages
  • internal CRUD for trip records
  • FareHarbor-compatible public booking links
  • documentation and PRD visibility through the markdown renderer
H3Next stage
  • trip city ordering and nights
  • plan blocks per city
  • participant detail forms
  • quote draft generation
  • estimated pricing and cost line items
  • trip schedule view
  • trip cloning for reusable routes
  • landing pages generated from trip records
  • Google Doc trip proposal projection
  • Sheet/Docs indexing for content and operations
  • sponsor or partner-facing trip summaries
  • admin workflow for reviewing and publishing trips
H3Later stage
  • Stripe checkout and invoice integration
  • booking status workflows
  • hotel API/search integration
  • user accounts and traveller dashboards
  • payment history
  • calendar projection
  • automated follow-up routines
  • multi-party group trip matching
  • advanced partner/supplier workflows
  • API routes for external integrations
  • subscription or sponsor-access layers
H3Replacement rule

Any copied or referenced backend service shape should be translated into Molino's own Next.js architecture before production use. Do not split the codebase or deployment just to preserve the old API shape. Use the old backend as a map of domain intent, then implement the durable parts through local Prisma data, server actions, route handlers, trip engine helpers, document projection, and the commercial Trip -> LineItem -> Offer -> Order path.

H23. Commercial Lanes
H3Lane 1 - Book Ready-Made City Tours
  • use app-native cards
  • use FareHarbor booking button only
  • open booking in Lightframe modal
H3Lane 2 - Join the Featured Guided Group Trip
  • use app-native premium featured-trip card
  • use FareHarbor booking button only
  • open booking in Lightframe modal
H3Lane 3 - Plan a Flexible Trip
  • use in-app planner
  • use quote or assisted planning
  • use Molino trip-building logic
H3Lane 4 - Collaborations
  • use dedicated intake flow
  • use dedicated application or request path
  • do not default to a generic contact form
H24. Section Requirements
  • show the four visible commercial lanes above the fold or as close as possible
  • present the four visible commercial lanes near the top
  • keep planning, calculation, sharing, and promotion paths explicit
  • preserve featured trip, custom trip, and collaboration pathways
  • avoid raw FareHarbor widgets
  • avoid over-editorial Studio language
  • avoid one generic form for all intents
H25. Footer Bridge

Add a small closing bridge back upward to Studio:

  • Developed by Molino Practice
  • link to /studio
  • optionally link to Skills, Practice, and Experience

This keeps the reverse transition visible without weakening /trips.

H26. Scope
H3In Scope
  • routes: /trips, /trips/new, /trips/[tripId], /trips/[tripId]/edit, /trips/featured
  • app folder: app/trips/
  • actions: trip read, planner read/write, join create/recompute, landing read, draft creation
  • types: trip.types.ts, trips.sections.types.ts, planner types
  • integrations: FareHarbor-facing booking overlays, document/projection handoff, public trip API surfaces
  • models: Trip, TripPricing, TripPost, PublicTrip, TripJoin, LineItem, Offer, Order
  • related supporting input: featured experiences from the reusable experience catalog
H3Out of Scope
  • replacing the trip planner engine with a different product
  • turning the public route into a generic CMS
  • moving booking authority into client state
H27. Authority Model
  • page.tsx reads and orchestrates only
  • app/trips/actions/ owns mutation logic
  • app/trips/api/ stays for external access only
  • TripPricing and downstream line items remain explicit economic layers
H28. Current Implementation Surface
  • app/trips/actions/trips.read.actions.ts
  • app/trips/actions/tripsLanding.actions.ts
  • app/trips/actions/trips.planner.read.actions.ts
  • app/trips/actions/trips.planner.edit.read.actions.ts
  • app/trips/actions/trip-join.create.ts
  • app/trips/actions/trip-join.recompute.ts
  • app/trips/actions/trip.update.actions.ts
  • app/trips/actions/createTripDraft.ts
  • app/trips/components/
  • app/trips/new/
  • app/trips/[tripId]/
H29. FareHarbor Rules
  • buttons only
  • no calendar embeds
  • no item-grid embeds
  • no widget rendering as React children
  • no production dependence on parsed HTML widget islands except test or reference
  • use FH booking URLs or button targets only
H210. Immediate Components
  • FareHarborBookAction
  • TravelBookingCard
  • FeaturedTripBookingCard
  • FlexibleTripPlannerCard
  • CollaborationsCard
H210.1 Studio Travel Bridge
  • /studio/travel is the first revenue-capable booking surface.
  • Use one city tour card and one featured trip card with real FareHarbor buttons there.
  • Keep the planner CTA and collaborations CTA as in-app exits, not generic contact fallbacks.
  • Treat the Studio surface as the entry bridge into Trips, not as a replacement for the Trips hub.
H211. Acceptance Criteria
  • public trip routes render without runtime errors
  • draft and public views stay separated
  • planner and join flows remain explicit
  • trip pricing continues to feed line items through a controlled bridge
  • Trips shows the four commercial lanes clearly
  • Trips uses native booking cards with FH button execution only
  • Trips footer bridges back to Studio
  • featured experiences remain visible as support input, not as a second primary hub
  • old notes stay in archive/ instead of being deleted
H211.1 Session Notes
H32026-04-28 - Backend intent merged into trip scope

Merged the wider backend/API service scope into the active Trips PRD as a reference, while keeping the implementation rule clear: useful backend services should be translated into Molino's existing Next.js stack, not preserved as a separate NestJS-style backend or deployment. The reference now captures cities, trips, trip cities, plans, participant details, costs, quotes, bookings, payments, hotels, landing pages, users, FareHarbor, and the strategic merge between trip bookings and dated session bookings.

H212. Locked Summary

Trips is the stable Molino module for trip discovery, planning, join flows, and commercial projection. It reads canonical trip data, keeps mutation authority in server actions, preserves the booking and pricing boundary, uses FareHarbor only as a button-driven execution layer, and treats experiences as supporting ingredients rather than the core execution domain.