Full Development Plan
End-to-End Web Application — Adventures Overland
Product Overview
Adventures Overland (AO) is a premium adventure travel company offering self-drive road trips, expeditions, and curated overland experiences. This web application serves as their primary digital platform for:
- Showcasing trips across categories (World Series, Road Trips in India, Supercar Drives, AO Experiences)
- Enabling users to browse, filter, search, and compare trips
- Collecting booking requests and enquiries
- Processing payments and managing reservations
- Publishing content (blogs, travel guides, news)
- Building brand presence and trust (testimonials, media coverage, company story)
Target users: Adventure-seeking travelers (25–55), primarily India-based, browsing on mobile (60%) and desktop (40%).
System Architecture
┌─────────── CLOUDFLARE ───────────┐
│ DNS · CDN · WAF · DDoS │
└──────────────┬──────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ ANGULAR SPA │ │ NODE.JS API │ │ ADMIN PANEL │
│ (ao-web) │ │ (ao-api) │ │ (ao-admin) │
│ Azure Static │ │ Azure App Svc │ │ Azure Static │
│ Angular 19 │ │ Express.js │ │ Angular 19 │
│ Material + SCSS │ │ TypeScript │ │ PrimeNG Tables │
│ NgRx Signals │ │ Mongoose │ │ Material │
└──────────────────┘ └────────┬─────────┘ └──────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ MongoDB │ │ Azure Blob │ │ Azure Comms │
│ Atlas / │ │ Storage │ │ Services │
│ Cosmos DB │ │ (files) │ │ (email) │
└──────────────┘ └──────────────┘ └──────────────────┘
Key Architectural Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Frontend-Backend split | Decoupled SPA + REST API | Independent scaling, separate deploy cycles |
| Two repos | ao-web + ao-api | Clear ownership, independent CI/CD |
| SSR approach | Angular Universal | SEO for public pages, hydration for interactivity |
| Database | MongoDB (document store) | Flexible trip schemas, embedded itineraries, fast reads |
| API style | REST (not GraphQL) | Simpler, well-understood, sufficient for this domain |
| Admin panel | Separate Angular app | Different auth context, independent deploy |
Information Architecture & Sitemap
/ → Home ├── /trips → All Trips (Listing + Search + Filter) │ ├── /trips/fixed-departures → Fixed Departures │ ├── /trips/road-trips-india → Road Trips in India │ ├── /trips/supercar-drives → Supercar Drives │ ├── /trips/ao-experiences → AO Experiences │ └── /trips/:slug → Trip Detail (#overview #itinerary #faq #enquire) ├── /about → About Us │ ├── /about/our-story → Our Story │ ├── /about/our-team → Team │ ├── /about/testimonials → Testimonials │ └── /about/careers → Careers ├── /resources │ ├── /resources/blog → Blog listing │ ├── /resources/blog/:slug → Blog post │ ├── /resources/in-the-news → Press / Media │ ├── /resources/travel-guides → Travel Guides │ └── /resources/faq → Global FAQ ├── /book/:tripSlug → Booking Flow (multi-step) ├── /account → User Account (auth guard) │ ├── /account/bookings → My Bookings │ ├── /account/wishlist → Saved Trips │ └── /account/profile → Profile Settings ├── /auth → Login / Register / Password Reset ├── /legal → Privacy · Terms · Cancellation │ │ ADMIN (admin.adventuresoverland.com) └── /admin → Dashboard · Trips · Bookings · Enquiries · ...
Responsive Design Strategy
The Figma only contains mobile (390px) screens. The responsive strategy defines how each layout adapts across 5 breakpoints.
Breakpoints
| Token | Width | Target Devices |
|---|---|---|
| xs | 0–599px | Phones (portrait) |
| sm | 600px | Phones (landscape), small tablets |
| md | 960px | Tablets (portrait) |
| lg | 1280px | Tablets (landscape), laptops |
| xl | 1920px | Desktops, large monitors |
Layout Rules
| Element | Mobile (xs–sm) | Tablet (md) | Desktop (lg+) |
|---|---|---|---|
| Header | Logo + hamburger | Logo + condensed nav | Full nav + CTA button |
| Navigation | Full-screen sidenav | Full-screen sidenav | Horizontal bar + dropdowns |
| Trip Cards | Single column | 2-column grid | 3-column grid (4 on xl) |
| Hero Carousel | Full-width, 60vh | Full-width, 50vh | Full-width, 70vh + overlay |
| Trip Detail | Single column | Single column, wider | 2-col: content + sticky sidebar |
| Filter | Bottom sheet | Side panel (slide right) | Persistent sidebar |
| Itinerary | Accordion, full width | Accordion + side map | Timeline left + map right |
| Testimonials | Swipe carousel | 2-card carousel | 3-card row with arrows |
Desktop-Specific Additions
- Mega menu dropdown for Trips (category previews + featured trip)
- Breadcrumbs on interior pages
- Sticky sidebar on Trip Detail (price, CTAs, upcoming dates)
- Trip comparison (side-by-side, desktop only)
- Search in header with autocomplete
- Hover states on cards (lift shadow + quick-view overlay)
- Lightbox gallery for trip highlights
- Sticky sub-nav on Trip Detail (Overview / Itinerary / FAQ / Enquire)
Screen-by-Screen Scope
Home Page
| Section | Mobile | Desktop |
|---|---|---|
| Hero | Full-screen video/image + CTA | Full-viewport video + headline overlay |
| Trip Categories | Horizontal scroll cards | 4-column grid with hover effects |
| Featured Trips | Vertical card stack | 3-column card grid |
| Why AO | Stacked value props | 3-column icon+text row |
| Testimonials | Swipe carousel | 3-card row |
| Newsletter | Stacked form | Inline form centered |
Trip Listing Page
| Section | Mobile | Desktop |
|---|---|---|
| Search + Filter | Search input + filter icon | Inline search + filter dropdowns |
| Category Tabs | Horizontal scroll pills | Full row of tabs |
| Trip Grid | 1 column | 3 columns with sidebar filters |
| Pagination | "Load More" button | Numbered pagination |
Trip Detail Page
| Section | Mobile | Desktop |
|---|---|---|
| Hero Carousel | Full-width, dots | Full-width with thumbnail strip |
| Sticky Sub-nav | None (scroll to section) | Sticky tabs: Overview / Itinerary / FAQ / Enquire |
| Overview | Title + CTAs stacked | Content left + sticky price card right |
| Itinerary | Accordion per day | Timeline view left + map right |
| Highlights | 2×2 image grid | Masonry gallery or lightbox |
| Enquiry Form | Full-width stacked | 2-column form in card |
| FAQ | Accordion | Accordion, max-width 800px centered |
Booking Flow & Account
| Step / Section | Mobile | Desktop |
|---|---|---|
| Select Date + Travelers | Full page form | Multi-step stepper, left panel |
| Traveler Details | Full page form | Same, wider layout |
| Review & Payment | Stacked summary | Summary left + payment right |
| My Bookings | Card list with status badges | Table view with filters |
| Wishlist | Saved trip cards | 3-column grid |
User Flows
Trip Discovery → Enquiry
Trip Discovery → Booking
Wishlist / Favorites
Brochure Download
Tech Stack
Frontend (Angular SPA)
| Layer | Choice | Rationale |
|---|---|---|
| Framework | Angular 19 | Enterprise-grade, strong typing, built-in DI/routing |
| SSR | Angular Universal | Server-side rendering for SEO on public pages |
| UI Components | Angular Material 19 | Sidenav, dialog, tabs, chips, slider, expansion panel, bottom sheet |
| Styling | SCSS + Material theming | Custom theme with AO brand tokens, responsive mixins |
| Carousel | Swiper.js (Angular wrapper) | Touch-optimized, SSR-compatible |
| Forms | Reactive Forms + validators | Type-safe with FormGroup/FormArray |
| State | NgRx SignalStore | Signal-based state for filters, wishlist, cart, auth |
| HTTP | HttpClient + interceptors | JWT interceptor, error interceptor |
| Maps | Azure Maps / Mapbox | Route polylines, interactive itinerary map |
| Icons | Material Icons + custom SVGs | Consistent iconography matching Figma |
Backend (Node.js API)
| Layer | Choice | Rationale |
|---|---|---|
| Runtime | Node.js 20 LTS | Stable, Azure-native support |
| Framework | Express.js + TypeScript | Lightweight, flexible, massive ecosystem |
| Database | MongoDB 7 | Document model fits trip/itinerary data |
| ODM | Mongoose 8 | Schema validation, middleware, TypeScript |
| Auth | Passport.js + JWT | Google OAuth + local strategy |
| Validation | Zod | Schema validation on all API inputs |
| File Storage | Azure Blob Storage | Trip images, brochures, user uploads |
| Image CDN | Cloudinary | On-the-fly transforms, WebP/AVIF |
| Azure Communication Services | Transactional emails, Azure-native | |
| Search | MongoDB Atlas Search | Full-text with fuzzy matching, facets |
| Payment | Razorpay | India-focused — UPI, cards, wallets, EMI |
| CAPTCHA | Cloudflare Turnstile | Privacy-friendly, invisible |
| Jobs | Agenda.js (MongoDB-backed) | Email reminders, slot updates, reports |
Frontend Architecture
Repository: ao-web
core/ auth/ auth.service · auth.guard · auth.interceptor api/ trip.service · booking.service · enquiry.service · content.service error.interceptor · seo.service · breakpoint.service shared/ components/ header · footer · mobile-nav · image-carousel · trip-card category-tabs · date-chips · cta-section · testimonial-card breadcrumbs · search-autocomplete · gallery-lightbox icon-info-row · accordion-group · lead-capture-dialog sticky-price-bar · loading-skeleton · brand-value-card pipes/ currency · truncate · date-range directives/ lazy-image · scroll-spy · click-outside store/ auth.store · trip-filter.store · wishlist.store · booking.store · ui.store features/ (all lazy-loaded) home/ Home page trips/ trip-listing · category-landing · trip-detail · filter-panel booking/ booking-wizard · step-date · step-travelers · step-addons · step-review account/ my-bookings · wishlist · profile auth/ login · register · forgot-password about/ About Us pages resources/ blog-listing · blog-detail contact/ Contact page legal/ Privacy · Terms · Cancellation
Component Library (25+ reusable components)
| Component | Material Base | Variants |
|---|---|---|
| HeaderComponent | MatToolbar, MatButton | transparent / solid, mobile / desktop |
| MobileNavComponent | MatSidenav | Slide-out with links + social icons |
| ImageCarouselComponent | Swiper.js | dots / arrows / thumbs, autoplay |
| TripCardComponent | MatCard | vertical / horizontal, compact / full |
| FilterPanelComponent | MatBottomSheet / MatSidenav | bottom-sheet (mobile) / sidebar (desktop) |
| ItineraryTimelineComponent | MatStepper / custom | vertical (mobile) / split with map (desktop) |
| EnquiryFormComponent | Reactive Forms + MatFormField | standalone / embedded, with CAPTCHA |
| BookingWizardComponent | MatStepper | multi-step horizontal/vertical |
| StickyPriceBarComponent | — | mobile bottom bar / desktop sidebar card |
| GalleryLightboxComponent | CDK Overlay | grid + fullscreen overlay with zoom |
Backend Architecture
Repository: ao-api
config/ db · cloudinary · azure-blob · passport · razorpay · env (Zod) models/ user · trip · booking · enquiry · testimonial · blog-post · faq · newsletter · team · coupon routes/ trip · booking · payment · enquiry · auth · user · wishlist · search · content · upload · newsletter admin/ admin-trip · admin-booking · admin-enquiry · admin-content · admin-user · admin-analytics controllers/ Route handlers (mirrors routes structure) services/ trip · booking · payment · pricing · email · search · upload · analytics middleware/ auth · admin · validate (Zod) · rate-limit · error validators/ Zod schemas: trip · booking · enquiry · auth · common jobs/ trip-reminder (7-day) · slot-status (auto-update) · report (weekly summary) utils/ jwt · password (bcrypt) · slug · pagination · booking-number (AO-2026-00001) types/ trip.types · booking.types · user.types · api.types
Database Schema (MongoDB)
10 collections using embedded subdocuments for denormalized, fast reads.
Trips Collection
{
slug: String, // unique, indexed — "ladakh-expedition"
name: String, // "Ladakh Expedition"
category: "world_series" | "road_trips_india" | "supercar_drives" | "ao_experiences",
badge: String, // "Trending", "Limited seats"
heroImages: [String], // Cloudinary URLs
duration: { nights: Number, days: Number },
cost: { amount: Number, currency: "INR", emiAvailable: Boolean },
tripType: "adventure" | "leisure" | "short_trip",
experienceLevel: "beginner" | "intermediate" | "experienced",
driveType: "self_drive" | "assisted",
// Embedded subdocuments
dates: [{ startDate, endDate, slotsTotal, slotsBooked, status: "open" | "filling_fast" | "sold_out" }],
itinerary: [{ dayNumber, title, description, images, activities, distance }],
faqs: [{ question, answer, sortOrder }],
seo: { metaTitle, metaDesc, ogImage }
}Bookings Collection
{
bookingNumber: "AO-2026-00001",
userId: ObjectId, tripId: ObjectId, tripDateId: ObjectId,
tripSnapshot: { name, slug, startDate, endDate, heroImage },
travelers: [{ name, age, idType: "passport" | "aadhar", idNumber }],
addOns: [{ name, price }],
pricing: { basePerPerson, travelerCount, addOnsTotal, subtotal, gst, tcs, couponDiscount, total },
status: "pending" | "confirmed" | "cancelled" | "completed",
payment: { razorpayOrderId, razorpayPaymentId, method, paidAt }
}Other Collections
users
Email/Google auth, roles, embedded wishlist array
enquiries
General / custom / brochure leads, assignment, status
testimonials
Reviews linked to trips, rating, featured toggles
blog_posts
Rich-text, tags, SEO, publish/draft, cover image
global_faqs
Categorized Q&A, sort order, published
newsletter
Email, source (footer/popup/brochure), dates
team_members
Name, role, bio, photo, sort order
coupons
% or fixed, validity, limits, trip restrictions
API Design (REST)
Base URL: https://api.adventuresoverland.com/v1
── PUBLIC (no auth) ────────────────────────────────────────── GET /v1/trips → List trips (filter, sort, paginate, search) GET /v1/trips/categories → Categories with counts GET /v1/trips/:slug → Trip detail (full + itinerary + FAQs) GET /v1/trips/:slug/dates → Available dates with slot availability GET /v1/trips/:slug/related → Related trips GET /v1/search?q=ladakh → Full-text search (trips, blog) GET /v1/content/testimonials → Testimonials (paginated) GET /v1/content/blog → Blog posts (by tag) GET /v1/content/blog/:slug → Single blog post POST /v1/enquiries → Submit enquiry POST /v1/leads/brochure → Brochure lead capture POST /v1/newsletter → Newsletter signup ── AUTH ────────────────────────────────────────────────────── POST /v1/auth/register → Create account POST /v1/auth/login → Login (returns JWT) POST /v1/auth/google → Google OAuth POST /v1/auth/forgot-password → Send reset email POST /v1/auth/refresh → Refresh JWT ── PROTECTED (JWT required) ───────────────────────────────── GET /v1/users/profile → Get / update profile POST /v1/wishlist/:tripId → Add / remove wishlist POST /v1/bookings → Create booking GET /v1/bookings → User's bookings POST /v1/payments/verify → Verify Razorpay signature ── ADMIN (JWT + role=ADMIN) ───────────────────────────────── GET /v1/admin/dashboard → Stats + charts CRUD /v1/admin/trips → Trip management CRUD /v1/admin/bookings → Booking management + CSV export CRUD /v1/admin/enquiries → Enquiry management CRUD /v1/admin/testimonials|blog|faq|team|users
Standard Response Envelope
{ "success": true,
"data": { ... },
"meta": { "page": 1, "total": 47 }
}{ "success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid email"
}
}Admin Panel
Separate Angular application (ao-admin) deployed at admin.adventuresoverland.com. Same Angular 19 stack + PrimeNG DataTable for complex grids.
| Module | Features |
|---|---|
| Dashboard | Booking count (today/week/month), revenue chart, new enquiries, upcoming trips, slot fill rate |
| Trips | CRUD, Quill rich text, Cloudinary upload, itinerary builder (drag-reorder), date slot manager, FAQ editor |
| Bookings | DataTable with sort/filter, status update, traveler details, payment info, CSV/Excel export |
| Enquiries | DataTable, filter by type/status, assign to team, status flow (new → contacted → closed), inline notes |
| Testimonials | CRUD, approve/reject workflow, link to trip, toggle featured, avatar upload |
| Blog | CRUD, Quill editor, cover image, tag management, publish/draft, SEO fields |
| Team | CRUD, photo upload, drag-reorder |
| Coupons | CRUD, date range, usage tracking, trip restriction |
| Newsletter | Subscriber list, search, export CSV, bulk unsubscribe |
| Users | List, role management (user/admin), view bookings per user |
Authentication & User Accounts
Angular SPA ──(credentials)──→ Node.js API ──(verify)──→ MongoDB │ ├── Issue JWT (access + refresh) │ Angular SPA ←──(JWT in response)──←──┘ │ ├── Store access token in memory (AuthStore) ├── Store refresh token in httpOnly cookie (Set-Cookie by API) └── Attach access token via HttpInterceptor on every API call
| Method | Implementation |
|---|---|
| Email + Password | Passport local strategy, bcrypt hashing (12 rounds) |
| Google OAuth | Passport Google strategy → JWT exchange |
| Phone OTP | Azure Communication Services SMS → verify code → JWT |
| Access Token | Short-lived JWT (15min), stored in memory (SignalStore) |
| Refresh Token | Long-lived JWT (7d), httpOnly secure cookie |
| Password Reset | Crypto token in MongoDB, email link, 1hr expiry |
Guest browsing: All trip pages are fully accessible without login. Login is required for wishlist, booking, and profile pages. Login prompt is triggered via MatDialog when needed.
Booking & Payment
Booking Flow (MatStepper)
Payment Integration (Razorpay)
Angular SPA Node.js API Razorpay │ │ │ │──POST /v1/bookings──────────→ │──Create booking (pending)──→ │ │ │──Create Razorpay order─────→ │ │ ←──orderId + amount────────── │ ←──order_id──────────────── │ │ │ │ │──Open Razorpay checkout────────────────────────────────────→ │ │ ←──paymentId + signature──────────────────────────────────── │ │ │ │ │──POST /v1/payments/verify───→ │──Verify HMAC signature──→ │ │ │──Update booking → confirmed │ │ ←──Booking confirmed────── │──Send confirmation email │
Pricing Logic
Base Price trip.cost.amount (per person, in paise) × Travelers count + Add-ons sum of selected add-on prices = Subtotal + GST 5% of subtotal + TCS 5% (domestic) or 20% (international, above ₹7L) = Gross Total − Coupon percentage or fixed discount (capped at maxDiscount) = Payable
Email & Notifications
Transactional emails via Azure Communication Services. Templates built with MJML → compiled to HTML, stored as Handlebars templates.
| Trigger | Recipient | Template |
|---|---|---|
| Booking confirmed | User | Booking details, itinerary summary, PDF attachment |
| Payment receipt | User | Amount, payment ID, invoice |
| Booking cancelled | User | Refund info, cancellation policy |
| Enquiry received | User + Admin | Acknowledgement + full details with CTA link |
| Brochure download | User | PDF attachment + related trips |
| Newsletter welcome | User | Welcome message + featured trips |
| Password reset | User | Reset link (expires in 1hr) |
| Trip reminder | User | 7 days before departure (Agenda.js job) |
SEO Strategy (Angular Universal)
SSR vs Client-Only Pages
| Page Type | Rendering | Rationale |
|---|---|---|
| Home, Trip Listing | SSR | SEO-critical, high organic traffic |
| Trip Detail | SSR | SEO-critical, structured data |
| Blog posts | SSR | Content marketing, Google indexing |
| About, Contact, Legal | SSR | Indexable static content |
| Booking flow | Client-only | Behind auth, no SEO value |
| Account pages | Client-only | Behind auth, no SEO value |
| Admin panel | Client-only | Separate app, no SEO value |
Structured Data (JSON-LD)
TouristTripon trip detail pagesFAQPageon FAQ sectionsOrganizationon about pageBlogPostingon blog postsBreadcrumbListon all interior pagesReview/AggregateRatingfrom testimonials
On-Page SEO
- Clean URL slugs (
/trips/ladakh-expedition) - Admin-editable meta title + description per trip and blog post
- Alt text on all images (stored in CMS)
- Dynamic sitemap via
GET /v1/sitemap.xml - Canonical URLs, Open Graph + Twitter Card meta
- Core Web Vitals targets: LCP < 2.5s, CLS < 0.1, INP < 200ms
Performance & Caching
| Layer | Strategy |
|---|---|
| SSR Pages | Cloudflare edge cache (s-maxage=60, stale-while-revalidate=300) |
| API Responses | Cloudflare cache on GET endpoints (60s TTL, purge on write) |
| Static Assets | Azure CDN + Cloudflare (immutable, 1yr cache) |
| Images | Cloudinary CDN with auto-format (WebP/AVIF), blur placeholder |
| MongoDB | Compound indexes, Atlas Search dedicated indexes with facets |
| Angular Bundles | Lazy-loaded feature modules, tree-shaking, production AOT |
| Heavy Components | Dynamic imports for Map, Swiper, Quill (loaded on demand) |
| Fonts | Self-hosted, font-display: swap, subset to Latin + Devanagari |
| Transfer State | Prevents duplicate API calls after SSR hydration |
Testing Strategy
Frontend (Angular)
| Type | Tool | Coverage Target |
|---|---|---|
| Unit Tests | Jasmine + Karma | Services, pipes, guards, validators |
| Component Tests | Jasmine + TestBed | All shared + feature components |
| E2E Tests | Playwright | Booking, enquiry, search, filter flows |
| Visual Regression | Playwright screenshots | Key pages at mobile + desktop breakpoints |
| Accessibility | axe-core + Lighthouse | WCAG 2.1 AA compliance |
Backend (Node.js)
| Type | Tool | Coverage Target |
|---|---|---|
| Unit Tests | Jest | Services, validators, utilities |
| Integration Tests | Jest + Supertest | API endpoints with test MongoDB |
| Load Testing | k6 | API endpoints under traffic spikes (500 users) |
| Performance | Lighthouse CI | Core Web Vitals in CI pipeline |
| Security | npm audit + Snyk | Dependency vulnerabilities |
Security
| Concern | Mitigation |
|---|---|
| XSS | Angular's built-in sanitization + CSP headers (Cloudflare) |
| CSRF | JWT in Authorization header (not cookies for API calls) |
| NoSQL Injection | Mongoose schema validation + Zod input parsing |
| Auth | bcrypt (12 rounds), JWT with short expiry, refresh rotation |
| CORS | Strict origin allowlist (only ao-web and ao-admin domains) |
| Rate Limiting | express-rate-limit per endpoint + Cloudflare WAF rules |
| Input Validation | Zod schemas on all API inputs (server-side, never trust client) |
| File Upload | Type + size validation (allowlist: jpg, png, webp, pdf) |
| Payment | Razorpay server-side HMAC signature verification |
| Secrets | Azure Key Vault for production, .env for local dev |
| HTTPS | Cloudflare Full (Strict) SSL, Azure origin cert |
| DDoS | Cloudflare DDoS protection + rate limiting |
| Admin Access | Separate domain, role middleware, optional IP allowlist |
DevOps & Infrastructure
Environments
| Env | Frontend URL | API URL | Branch |
|---|---|---|---|
| Development | localhost:4200 | localhost:3000 | develop |
| Staging | staging.adventuresoverland.com | api-staging.adventuresoverland.com | staging |
| Production | www.adventuresoverland.com | api.adventuresoverland.com | main |
Azure Resources
Resource Group: rg-adventures-overland-prod ├── Static Web App: ao-web-prod (Angular SPA + Universal SSR) ├── Static Web App: ao-admin-prod (Admin Angular SPA) ├── App Service: ao-api-prod (Node.js API, Linux, B2) ├── App Service Plan: asp-ao-prod (B2 tier, auto-scale 1–4) ├── Blob Storage: aofilesprod (brochures, uploads) ├── Key Vault: kv-ao-prod (JWT_SECRET, DB_URI, RAZORPAY_KEY) ├── Communication Svc: acs-ao-prod (transactional email) └── App Insights: ai-ao-prod (APM, logging, metrics) External Services: ├── MongoDB Atlas ao-production cluster (M10+, Azure East US) ├── Cloudinary ao-prod account (image CDN) ├── Cloudflare adventuresoverland.com (DNS, CDN, WAF, SSL) ├── Razorpay production account (payments) └── Sentry ao-prod project (error tracking)
CI/CD Pipelines (GitHub Actions)
ao-web (Frontend)
# On Pull Request → Lint (ng lint) → Type check (tsc --noEmit) → Unit tests (ng test) → Build (staging config) → Deploy preview → staging slot # On Merge to main → All of above (prod config) → E2E tests (Playwright) → Lighthouse CI → Deploy → production → Purge Cloudflare cache
ao-api (Backend)
# On Pull Request → Lint (ESLint) → Type check (tsc --noEmit) → Unit tests (Jest) → Integration tests (Supertest) → Deploy → staging slot # On Merge to main → All of above → Deploy → production → Smoke tests → Notify Slack
Monitoring & Alerting
| Tool | Purpose |
|---|---|
| Azure App Insights | API performance, request tracing, dependency tracking, custom metrics |
| Sentry | Frontend + backend error tracking, source maps, release tracking |
| Cloudflare Analytics | CDN hit rate, WAF events, DDoS attempts, edge latency |
| Microsoft Clarity | Session replays, heatmaps, user behavior analysis |
| Azure Alerts | CPU > 80%, memory > 80%, 5xx rate > 1%, response time > 2s |
| Better Uptime | Pings API + frontend every 60s |