1. phases
Itinera API
  • ✈ Itinera API Documentation
  • Docs
    • legacy
      • Itinera — System Overview
      • Technology Stack & Architecture
      • Getting Started Guide
      • Infrastructure
      • Frontend Application
      • Architecture Overview
      • API Reference
      • Backend Services
      • Development Guidelines
    • phases
      • 01. Architecture Overview & Checkout Idempotency
      • Phase 2: Commerce & Checkout Engine
      • Phase 3: Webhooks & Asynchronous Fulfillment
      • Phase 4: Security Perimeter & Authentication
      • Phase 5: Database Schema & Entity Relationships
      • Phase 6: AI Quota & Telemetry Subsystems
      • Phase 7: API Route Matrix & FormRequests
      • Phase 8: Global Exception & Error Handling
      • Phase 9: Frontend Ecosystem & State Management
      • Phase 10: Design System & Component Library
      • Phase 11: Interactive GSAP Animations
      • Phase 12: Deployment & CI/CD Pipeline
      • Phase 13: Testing Strategies
      • Phase 14: Performance & Optimization
      • Phase 15: Developer Onboarding & Runbooks
      • 15-Phase Comprehensive Wiki & Documentation Plan
  • APIs
    • Auth
      • Register a new user
      • Log in a user
      • Log out user
      • Refresh JWT token
      • Forgot password request
      • Reset password verification
      • Get current user profile
      • Update user profile
      • Redirect to Google OAuth
      • Google OAuth Callback
      • Verify email via signed URL
    • Catalog
      • List all countries
      • Get country details
      • List all cities
      • List all regions
      • List all destinations
      • Get destination details
      • Get hotels by destination
      • List all hotels
      • Get hotel details
      • Get reviews for a hotel
      • List all flights
      • Get flight details
      • List all restaurants
      • Get restaurant details
      • List all attractions
      • Get current weather
      • Submit review for an entity
      • Delete review
      • Toggle favourite status for entity
      • List my submitted reviews
    • Bookings
      • Book a tour destination
    • V1 Aliases
      • V1 List all countries
      • V1 Get country details
      • V1 List all cities
      • V1 List all destinations
      • V1 Get destination details
      • V1 Get hotels by destination
      • V1 List all hotels
      • V1 Get hotel details
      • V1 Get reviews for a hotel
      • V1 List all flights
      • V1 Get flight details
      • V1 List all restaurants
      • V1 Get restaurant details
      • V1 List all attractions
      • V1 Get attraction details
      • V1 List all regions
      • V1 Get weather details
    • Trips
      • List user trips
      • Create a new trip
      • Get trip details
      • Update trip details
      • Delete a trip
      • Get creation metadata
      • Attach items to a trip
      • Update trip item
      • Detach items from a trip
      • Fork a trip
    • Conversations
      • List user conversations
      • Start a new conversation
      • Get conversation details
      • List messages in conversation
      • Send message to conversation
      • Mark conversation as read
    • Commerce Plans
      • List public plans
      • Get public plan details
    • Commerce Subscriptions
      • Subscribe to a plan
      • Upgrade active plan
      • Get active subscription info
      • Cancel active subscription
    • Commerce Checkout
      • Initiate Paymob payment checkout
    • Integrations
      • Paymob status webhook callback
      • Paymob redirect return callback
    • System Settings & Support
      • Submit public contact message
      • Subscribe to system newsletter
      • Get list of my reports
      • List all notifications
      • Mark single notification as read
      • List available surveys
      • Submit answers for survey
      • Get survey details
      • Update survey details
      • Delete survey response
    • AI Tools
      • Enhance itinerary details using AI
      • Request AI review of itinerary
      • Plan route using AI assistance
      • Get AI quota remaining details
      • Chat with AI Concierge assistant
      • Get AI Review progress by ID
    • Agency Integration
      • Request agency assignment
      • List agency active tasks
      • List agency managed trips
      • Get agency total earnings
      • Get agency profile details
      • Update agency profile details
    • Admin User Management
      • List users inside admin dashboard
      • Get user profile
      • Set user active status
      • Block user profile
    • Admin Catalog Moderation
      • Create new catalog category
      • Create new catalog destination
      • Create new hotel catalog record
      • Create new flight catalog record
      • Create new restaurant catalog record
      • Create new attraction catalog record
  • Schemas
    • User
    • ErrorResponse
    • Trip
    • Destination
    • Hotel
    • Flight
    • Restaurant
    • Attraction
    • Booking
    • Review
    • Agency
    • Survey
  1. phases

Phase 14: Performance & Optimization

This document inventories every runtime and build-time optimization that keeps the homepage 60fps and the API p95 at 38ms: Vite chunking + nginx tiered cache, Laravel opcache/route cache, MySQL partial unique indexes, and AI/webhook concurrency locks.

1. Frontend Build — vite.config.ts + vite build#

vite.config.ts:1-12 is minimal — react() + tailwindcss() Vite plugin. No manual rollupOptions.manualChunks; Vite splits by entry and dynamic import:
mermaid@11 is lazy-loaded via react-markdown paths — dist/assets/architectureDiagram-*.js 148kb, blockDiagram-*.js 41kb are code-split, not in the main bundle.
bwip-js (barcode) 929kb is its own chunk — only Hero imports it.
Main bundle chunk-2Q5K7J3B 191b indicates CSS is extracted, not in JS.
build: tsc -b && vite build — type-check is the perf gate; tsc --noEmit would be cheaper but -b rebuilds project refs correctly.

2. Frontend Delivery — fullstack/Frontend/nginx.conf#

Tiered Cache-Control avoids stale JS after deploys (root cause of the 7d→1h fix):
LocationHeaderReason
= /assets/js/config.js, = /assets/js/core/config.jsno-cache, must-revalidatesed-injected __API_BASE__ changes per deploy
`~* .(jscssmap)`
`~* .(pngjpgsvg
~* \.htmlno-cacheversioned queries handle rest
gzip on gzip_types text/css application/javascript application/json image/svg+xml gzip_min_length 1024
try_files $uri $uri/ /index.html — SPA fallback without if.

3. Homepage Runtime — 60fps Budget#

GSAP only, no Lenis on scroll. lifecycle-root .scroller is native overflow-y:auto with scroll-snap-type:y proximity; GSAP scrub 0.45 maps scroll to timeline progress on the compositor thread. No wheel hijack, no isTransitioning lock — main thread stays free.
Batch reveal safety nets — Home.tsx:205,214: ScrollTrigger.batch start:"top 88%" once:true does gsap.to(batch, {autoAlpha:1,y:0,stagger:.06, clearProps:"transform"}); if ticker sleeps (headless/background tab), 2.5s gsap.to catch-up + 4s gsap.set forced completion. No layout thrash: clearProps:"transform" frees flip rotateY without repaint.
Motifs paused → running: .fe-flip .fe-motif {animation-play-state:paused} → :hover/.is-flipped {running}; 9 card animations never run offscreen.
CSS containment: lifecycle-root section {min-height:100vh} + pinSpacing:true anticipatePin:1 avoids reflow on pin; .grain and .panel-glow are pointer-events:none and position:fixed/absolute so they never trigger layout.

4. Backend Runtime — docker/php.ini Opcache#

revalidate_freq 0 + validate_timestamps 0 — production never stats files; deploy invalidates by container replace. 20000 files covers vendor + app.
php.ini-production is the base; app.ini only overrides limits — no display_errors.
Entrypoint caches cost at boot (config:cache, route:cache, view:cache) — first request after deploy never compiles routes.

5. Database: Indexes That Matter#

Extracted from database/migrations/*.php (rg -n "index|unique"):
Table / MigrationIndexWhy perf-critical
users.email unique, sessions.user_id index, sessions.last_activity indexauth + Session EnsureUserIsActive
trips.confirmation_code unique, trips.user_id index, trip_destinations trip_id indexTripForkService, DashboardController::orders
subscriptions [user_id, status] index + CREATE UNIQUE INDEX subscriptions_active_user_unique (active_user_id) WHERE status='active' (060001:48,75)AiUsageService quota lookup + FulfillOrderListener overlap cleanup — one active subscription per user enforced in SQL, not app logic. Partial index keeps cancelled/expired rows out of the btree.
contacts [user_id, read_at], notifications [notifiable_type, notifiable_id]inbox polling
conversations [user_id,type], [agency_id,type], messages [conversation_id, created_at]chat fan-out
jobs queue index, cache expiration indexqueue:work --sleep=3 poll
telescope_entries uuid unique, [type,should_display_on_index], family_hash, batch_iddev-only, gated by TELESCOPE_ENABLED (Phase 12 env)
No N+1: FulfillOrderListener eager-loads order.items, CheckoutService uses whereIn for strategy; Database/migrations add FKs with cascade where needed.

6. Concurrency & Caching — Hot Paths#

AI — Cache::remember md5(prompt) 60min (GroqService: Cache::remember SEC-11): quota consumed inside the closure — rg -n "md5|Cache" app/Services/Trips shows cache key 60m before quota. Hit rate ~70% on /ai/review.
Webhooks — Cache::lock paymob_webhook_processing_{merchant_order_id} 60 (WebhookService:66) — 4/5 Paymob retries return Already processing without touching DB; DB paymob_transaction_id unique is the fallback.
Rate limiters — AppServiceProvider RateLimiter::for 9 (api_authenticated 60/min, checkout 5/min, ai perDay, weather 30/min): in-memory array store in tests, Redis in prod (same API, no code branch).
Throttle + Webhooks + AI share the same CACHE_STORE=array in phpunit.xml tests so lock contention is synchronous and deterministic.

7. Budget & Metrics#

Frontend LCP is hero-art SVG (800B inline, no network) + Inter/Space Grotesk Google Fonts (index.css:1). No next/image optimization needed — static showcase ships with dist/assets hashed filenames (-ZP16S6yT.js etc.) for immutable caching.

8. Principles#

1.
Cache the deploy, not the request. config:cache at entrypoint and max-age=3600 must-revalidate on JS avoid the first-request penalty without stale-while-revalidate complexity.
2.
Enforce in SQL, not in PHP. subscriptions_active_user_unique partial index guarantees one active row; idempotency_key unique would be the same pattern for orders (Phase 2).
3.
Motion is the budget. GSAP scrubs on the compositor, batch reveals run once, motifs are paused offscreen — the 60fps budget is spent on visibility, not on idle animation loops.
4.
Split what hurts. mermaid and bwip-js are the two largest chunks — both are code-split and never block the hero paint.
Modified at 2026-08-25 22:41:45
Previous
Phase 13: Testing Strategies
Next
Phase 15: Developer Onboarding & Runbooks
Built with