Folder Structure
This document maps the real folder layout of Tours so you can quickly locate any piece of code. The trees below reflect the actual repository — a single Next.js 16 App Router application (there is no separate server project).
Repository Root
tours-web/
├── src/ # All application code (see below)
├── scripts/ # DB init/seed scripts + add-on & OpenAPI tooling (tsx / node)
├── docs/ # Buyer docs + add-on packages (docs/add-ons)
├── public/ # Static assets (favicon, manifest, images)
├── migrations/ # Legacy SQL snapshots (schema is created by ensure*Schema functions)
├── prisma/ # Prisma schema kept for tooling only (runtime uses raw SQL)
├── translations/ # Exported i18n catalogs
├── middleware wiring # src/middleware.ts (see below)
├── next.config.ts # Next.js config (image domains, etc.)
├── tailwind.config.ts # Tailwind CSS config
├── tsconfig.json # TypeScript config (@/* path alias → src/*)
├── vercel.json # Vercel deployment config
├── package.json # Scripts: dev/build, db:init, db:seed:*, addons:*, gen:openapi
└── .env / .env.production # DATABASE_URL, JWT_SECRET, SECRET_KEY, R2_*, …
src/ Overview
src/
├── app/ # Next.js App Router: pages + route handlers (the API)
├── core/ # Reusable framework: contracts + registries (channels/plugins/payments/adapters)
├── product/ # Add-ons (63) + GENERATED aggregation indexes + booking/master schema
├── lib/ # DB client, schema (*-schema.ts), auth, r2, secrets, queries, helpers
├── components/ # Shared React UI (admin, tour, booking, dashboard, form, ui, data-table, …)
├── views/ # Page-level view components for the public site
├── services/ # Client-side data/service helpers
├── hooks/ # Reusable React hooks
├── context/ # React context providers
├── config/ # App configuration constants
├── constants/ # Static constant data
├── data/ # Static/seed data sets
├── assets/ # Bundled assets imported by components
├── types/ # Shared TypeScript types
├── utils/ # Generic utilities (e.g. cn())
├── generated/ # Generated artifacts (Prisma client output — not hand-edited)
├── docs/ # In-app documentation (content/*.md — these files)
└── middleware.ts # Next.js middleware (edge request handling)
src/app — Route Groups
App Router folders wrapped in parentheses are route groups (they organise code
without appearing in the URL). Dynamic segments use [param].
src/app/
├── layout.tsx # Root layout (fonts, providers, global shell)
├── (site)/ # PUBLIC site + storefront → /
│ ├── page.tsx # Home
│ ├── [slug]/ # CMS pages by slug
│ ├── tours/ # Catalog + tour detail
│ ├── booking/ # Booking / checkout flow
│ ├── blogs/ gallery/ faq/ about/ contact/ how-it-works/ enquiry/ careers/ ai-tools/
│ ├── r/ x/ # Referral + short-link redirects
│ └── privacy-policy/ terms-and-conditions/ cookie-policy/ refund-policy/ …
├── (auth)/ # Traveler/operator account auth → /login, /register, …
│ ├── login/ register/ forgot-password/ reset-password/ verify-email/
├── admin/ # ADMIN → /admin/*
│ ├── login/ # Admin login (outside the panel group)
│ └── (panel)/ # Authenticated admin shell + pages
│ ├── dashboard/ tours/ bookings/ customers/ operators/ reviews/
│ ├── blogs/ pages/ gallery/ testimonials/ hero-slider/ faqs/ media/
│ ├── inclusions/ extras/ master-data/ coupons/ calendar/ calendars/ leads/
│ ├── marketing/ partners/ apps/ builder/ theme-builder/ why-choose-us/ settings/ …
├── customer/ # TRAVELER (customer) portal → /customer/*
│ └── (app)/ # Authenticated traveler shell + pages
│ ├── dashboard/ bookings/ wishlist/ reviews/ payments/
│ ├── messages/ notifications/ support/ settings/
├── operator/ # OPERATOR (seller) portal → /operator/*
│ ├── (app)/ # Authenticated operator shell + pages
│ │ ├── dashboard/ tours/ reservations/ calendar/ reviews/
│ │ ├── insights/ payouts/ billing/ inbox/ settings/
│ ├── [slug]/ # Public operator profile
│ └── become/ # Operator onboarding / sign-up
├── influencer/ # INFLUENCER portal → /influencer/*
│ ├── (auth)/ # login / forgot-password / reset-password / otp
│ └── (app)/ # dashboard, tours, bookings, commission, payouts,
│ # referral-links, analytics, marketing-materials, ai-chat, …
├── install/ # First-run setup wizard → /install
├── docs/ # In-app buyer docs → /docs/[version]
├── api-docs/ # OpenAPI (Scalar) viewer → /api-docs (admin-gated)
├── files/ # File proxy → /files/[...key]
├── ref/ # Influencer referral entry → /ref/[username]
└── api/ # HTTP API (route handlers — the backend)
├── v1/ # Versioned resource handlers (see below)
├── install/ # Installer endpoints
├── license/ # License activation / status
└── openapi.json/ # OpenAPI document (admin-gated)
src/app/api — The API
Every route.ts is an endpoint; there are roughly 300 of them. The versioned surface
lives under src/app/api/v1 with one folder per resource:
api/v1/
├── admin/ # Admin-only resource handlers (tours, bookings, customers, settings, …)
├── portal/ # Traveler auth + account endpoints
├── customer/ # Traveler portal data (bookings, wishlist, reviews, …)
├── operator/ # Operator portal endpoints (tours, departures, reservations, payouts, …)
├── influencer/ # Influencer portal endpoints
├── tours/ destinations/ inclusions/ extras/ coupons/ # Catalog + commerce
├── bookings/ booking-settings/ # Booking + checkout
├── blogs/ pages/ faqs/ gallery/ hero-sliders/ testimonials/ # CMS
├── reviews/ analytics/ track/ # Reviews + metrics
├── chat/ chatbot/ livechat/ calendar-config/ captcha/ video/ # Integration channels
├── countries/ currencies/ languages/ locations/ brand/ i18n/ # Reference data
├── forms/ app-version/ plugins/ cron/ ical/ ext/ # Misc + automation
src/core — Reusable Framework
Stable contracts and registries the app reads at runtime. Add-ons plug into these.
src/core/
├── channels/ registry.ts → CHANNELS, types.ts (ChannelDef/ProviderDef)
├── plugins/ registry.ts → FEATURES, types.ts → FeaturePlugin, hooks.ts (events)
├── payments/ registry.ts → PAYMENT_DRIVERS, types.ts, drivers/{cod,bank,paypal}.ts
├── adapters/ client.ts / server.ts → clientAdapters()/serverAdapters()
├── email/ video/ calendar/ captcha/ social/ chatbot/ messaging/ realtime/
├── analytics/ script-channel/ # adapter contracts per channel kind
├── install/ setup wizard + DB provisioning helpers
├── admin/ dashboard/ wishlist/ # shared admin/portal building blocks
src/product — Add-ons & Domain Schema
The 63 built-in add-ons, the domain schema for tours/bookings, plus the generated aggregation indexes.
src/product/
├── booking/schema.ts # ensureBookingSchema(): listings (tours), units (departures),
│ # bookings, booking_payments/extras/notes/emails, coupons,
│ # listing_reviews, seasons, unit_rates, extras, ical_feeds
├── master/schema.ts # master_items, listing_master_items, listing_nearby_places
├── addons/ # add-on packages, one folder each
│ ├── announcements/ # Feature add-on: addon.json, index.ts, schema.ts, *.tsx
│ ├── audit-logs/ webhooks/ digest/ maps/ api/ …
│ ├── payments-mollie/ # Provider add-on: channel + payment driver
│ ├── payments-paystack/ email-sendgrid/ analytics-clarity/ chatbot-anthropic/ …
│ └── index.ts # [GENERATED] ADDON_CHANNELS
├── features/index.ts # [GENERATED] ADDON_FEATURES
├── adapters-server/index.ts # [GENERATED] ADDON_SERVER_ADAPTERS (by kind)
└── adapters-client/index.ts # [GENERATED] ADDON_CLIENT_ADAPTERS (by kind)
Generated Add-on Indexes
The four index.ts files above are produced by scripts/bundle-addons.mjs and
must not be edited by hand. The script scans every addons/<id>/addon.json, then:
- emits
ADDON_CHANNELS(channel/provider add-ons → merged into coreCHANNELS), - emits
ADDON_FEATURES(add-ons flagged as features → exposed asFEATURES), - emits
ADDON_SERVER_ADAPTERSandADDON_CLIENT_ADAPTERS, grouped by kind (payment,email,sms,chatbot,captcha,analytics,calendar,video,livechat, …).
A companion scripts/gen-addon-catalog.mjs reads the same manifests to produce the
add-on catalog under docs/add-ons. Re-run them via npm run addons:bundle and
npm run addons:catalog.
src/lib — Core Library
src/lib/
├── db.ts # Neon/postgres.js client + sql tagged template + rawSql()
├── vendor-schema.ts # Commerce/store/users/settings ensure*Schema() functions
├── auth-schema.ts leads-schema.ts # Admin auth + leads schema (booking/master
│ # schema lives in src/product/*/schema.ts)
├── operators.ts # hosts table + getOperatorId() / commission + earnings/payouts
├── influencers.ts # Influencer accounts + referral/commission helpers
├── auth.ts # Admin JWT (jose, HS256) + admin_token cookie
├── customer-auth.ts # Traveler/operator JWT + member_session cookie + OTP
├── secrets.ts # AES-256-GCM encrypt/decrypt of stored credentials
├── r2.ts # Cloudflare R2 / S3 upload, presign, delete, public URL
├── public-id.ts # ensurePublicId() — non-sequential public ids
├── api-helpers.ts # ok() / err() / serverErr() JSON responses
├── require-permission.ts route-permissions.ts permissions-catalog.ts # RBAC
├── license/ # index.ts, license client, addons (RS256 offline verify)
├── booking/ document/ builder/ hero/ menu/ blocks/ ai/ seeds/ # subdomains
├── image.ts r2.ts mailer.ts i18n.ts locations.ts payments.ts …
scripts — Provisioning & Tooling
| Script | npm command | Purpose |
|---|---|---|
init-db.ts |
(part of db:init) |
Create base/CMS tables + seed admin user + default pages |
init-core.ts |
(part of db:init) |
Provision core/auth/vendor + Tours business schema (ensure*) |
seed-*.ts |
db:seed:core, … |
Demo/test data (tours, operators, travelers, reviews, hero…) |
bundle-addons.mjs |
addons:bundle |
Regenerate the four product index files |
gen-addon-catalog.mjs |
addons:catalog |
Regenerate the add-on catalog under docs/add-ons |
gen-openapi.ts |
gen:openapi |
Regenerate the OpenAPI spec from the route handlers |
reset-template.ts |
db:reset |
Reset the template database |
npm run db:init chains init-db.ts → init-core.ts, fully provisioning a fresh
database by calling the same ensure*Schema() functions the API routes use at request
time.
© CreativeCape Solutions · creative-cape.com · support@creative-cape.com