Skip to content

System Architecture Overview

The Portugal Odyssey platform is a microservice-based system built to power a tourism marketplace. This document provides the technical context a developer needs to understand the architecture, service responsibilities, and the common workflows used across the stack.

Wave 1 simplification (ADR-002, complete): Elasticsearch + search-service removed 2026-04-25 (W1-1). Loki + Promtail + Prometheus + Grafana removed 2026-04-25 (W1-2+3). mcp-server consolidated into ai-service 2026-04-26 (W1-5) — ai-service is now the single external MCP surface, deployed in qual + prod. Qdrant consolidated into Postgres+pgvector 2026-04-26 (W1-4). Wave 1 closed.

Wave 2 progress: booking-service stub + analytics-service removed (W2-1/W2-4); user-management mothballed (W2-3); orphan RabbitMQ exchanges cleaned (W2-10); admin AIConsolePage removed (W2-11) — all 2026-04-30. Auth-service GraphQL surface dropped (W2-8) and ai-service trimmed of langgraph + dead ai_tasks/ai_results queues (W2-9 partial) — 2026-04-29. rag-service folded into ai-service (W2-7) — 2026-04-30: vector pipeline + Docling consumer + /api/v1/{search,chat,convert} moved in-process; the 3 rag.* MCP tools no longer round-trip httpx; rag_qual / rag_prod Postgres dbs preserved.


1. High-Level Architecture

+---------------------------+       +---------------------------+
|        Front Office       |       |      Backoffice / CMS     |
|  (React + Vite, public)   |       |   (Strapi Admin, services)|
+-------------+-------------+       +-------------+-------------+
              |                                   |
              v                                   v
        +------------+                 +------------------------+
        | API Gateway|                 |      Microservices     |
        +------------+                 |  (NestJS/Express APIs) |
              |                        +------------------------+
              v                                   |
      +--------------------+                     v
      | Infrastructure Tier|  <-- RabbitMQ, Postgres+pgvector,
      |  Docker + Traefik  |      Redis, MinIO/S3
      +--------------------+

Layers

  • Frontendsfrontends/public-fo renders the public experience and communicates with backend APIs.
  • Backend services – Decomposed by domain (payment, notification, review, file handling, experience, partner, contract, calendar, etc.). Most services are NestJS or TypeScript Express applications.
  • CMSservices/strapi-cms stores editorial content and acts as the source of truth for experiences, landing pages, etc.
  • Infrastructure – Docker Compose orchestrates services per environment (dev, qualification, production). Traefik routes subdomains to the appropriate container. Support tooling includes Postgres+pgvector, Redis, RabbitMQ, MinIO. (No Elasticsearch, Qdrant, or Prometheus/Grafana/Loki/Promtail — all removed in Wave 1; see the per-component notes below and ADR-002.)

2. Service Grouping & Responsibilities

Frontend

Service Role Tech
frontends/public-fo Customer-facing site, booking funnel, integration with APIs React 19, TypeScript, Vite

Core Backend APIs

Service Role
services/api-gateway Entry point for REST requests, routes to downstream services, handles auth/caching policies.
services/auth-service Facade over Keycloak for authentication/authorization workflows.
[MOTHBALLED W2-3, 2026-04-30] services/user-management User-editable profile fields (display_name, phone). Source kept; not deployed since W2-3 — profile-editing UI is post-launch (architecture review Q3, 2026-04-29).
services/experience-service Experience catalog API and metadata.
services/payment-service Stripe integration, payment intents, refunds.
services/notification-service Email, push, websocket notifications; publishes events via RabbitMQ.
[REMOVED W2-1, 2026-04-30] services/booking-service 65-LoC in-memory stub. Reservation lifecycle handled inline by experience-service; the stub had zero callers.
[REMOVED W2-4, 2026-04-30] services/analytics-service 221 LoC of hardcoded fixtures with zero callers. Reintroduce via real KPI store when the admin dashboard needs it.
services/file-service Upload/download abstraction across S3/MinIO/GCS/local filesystem.
services/review-service Collects internal reviews and syncs with external providers (Yelp/Tripadvisor/Google).
[FOLDED W2-7, 2026-04-30] services/rag-service Multimodal RAG engine. Folded into ai-service: vector_service, docling_service, document-ingest consumer and /api/v1/{search,chat,convert} endpoints all moved in-process. The 3 rag.* MCP tools are now local function calls instead of httpx round-trips. rag_qual / rag_prod Postgres dbs preserved.
services/ai-service LangChain orchestrator + RAG pipeline (rag-service folded in W2-7). Exposes the platform's single external FastMCP endpoint at /api/v1/mcp with 9 tools (6 local ai.* + 3 rag.* — all in-process). HTTP API at /api/v1/{translate,summarize,sentiment,sanitize,enhance,search,chat,convert}. API-key auth via X-API-Key against MCP_API_KEYS env. Externally reachable at ai.portugalodyssey.pt (prod) / ai.qual.portugalodyssey.pt (qual) / mcp-dev.portugalodyssey.pt (dev).
[REMOVED W1-5, 2026-04-26] services/mcp-server TypeScript MCP facade. Removed: of its 956 LOC, only ~270 were wired (auth + proxy); the rest was unused RMQ/credential-vault scaffolding. Auth folded into ai-service as a starlette middleware (~60 LOC).
services/strapi-cms Content management (landing pages, partner data, editorial copy).

Supporting Infrastructure

  • Postgres – Persistent data for services (reviews, experience, payment, notification, iam, etc.). Post-ADR-002: also hosts pgvector for ai-service's RAG embeddings and tsvector + pg_trgm for experience-service full-text search. Image: pgvector/pgvector:pg15.
  • Redis – Caching layer (sessions, rate-limiting; W2-6 will add Strapi reads + partner catalog cache).
  • RabbitMQ – Event bus (notifications, reviews, payments, RAG processing).
  • [REMOVED W1-4, 2026-04-26] Qdrant — vector store. Consolidated into the platform Postgres via pgvector. Image swapped postgres:15-alpinepgvector/pgvector:pg15. Schema in infrastructure/migrations/rag/00001_pgvector_initial.sql (managed by dbmate, ADR-003). asyncpg pool now in services/ai-service/app/services/vector_service.py (moved from rag-service in W2-7). Re-evaluation threshold per ADR-002: revisit if vector corpus grows past ~1–5M vectors or hybrid-search becomes a real requirement.
  • Docling Serve – Advanced document conversion API (PDF, DOCX, etc.).
  • [REMOVED W1-1, 2026-04-25] Elasticsearch — search indices for search-service. Removed: no live index, no live producer (Strapi has no experience content type), no consumer (frontends use local mocks); all query shapes fit Postgres FT. When real experience data lands, full-text search will live as tsvector + GIN on experience-service's Postgres table.
  • MinIO / S3 / GCS – File storage backends for file-service.
  • [REMOVED W1-2+3, 2026-04-25] Prometheus / Grafana / Loki / Promtail — observability stack. Removed: zero committed dashboards (verified by SQLite probe), zero app-level instrumentation, zero LogQL queries. make {dev,qual,prod}-logs and make remote-docker-logs cover MVP ops; container JSON logs now capped at 50 MB via Docker log-opts. Reintroduce via Grafana Cloud (+ versioned dashboards) when a service actually needs custom metrics. External uptime via UptimeRobot/BetterStack/Healthchecks.io in the interim.
  • Traefik – Reverse proxy and TLS termination. metrics.prometheus stanza removed post-ADR-002; request-level signal available via access logs.
  • Keycloak – Identity provider (realm export in infrastructure/keycloak/realm-export.json). Not in Wave 1 scope.

3. Message Queue Workflow

RabbitMQ underpins asynchronous workflows. Key events:

  1. Notification Service
  2. Publishes events such as email.sent, push.sent, websocket.emitted to the notifications queue.
  3. SMTP and push integrations operate in mock mode when credentials are absent.
  4. Review Service
  5. Emits review.created events via the reviews.events exchange for moderation or downstream consumers.
  6. Payment Service
  7. Future enhancement: emit payment.intent.created, payment.refunded for auditing (the scaffolding is ready).

Consumers (audit workers, future BI sinks) can bind to these exchanges without impacting API latency. When RabbitMQ is unavailable, services log mock publishes so development remains frictionless.


4. Notification Service Usage

  • EmailPOST /api/notifications/email with { to, subject, text/html }. Uses SMTP when configured; otherwise logs mock send operations.
  • PushPOST /api/notifications/push with device tokens. Placeholder integration ready for FCM/OneSignal.
  • Websocket – WebSocket namespace /notifications with events broadcast via POST /api/notifications/websocket.
  • RabbitMQ – All notifications publish to RabbitMQ for downstream auditing or real-time dashboards.
  • Strapi Integration – Use the wrapper in services/notification-service/CMS_INTEGRATION.md to trigger notifications from CMS workflows.

5. Development Workflows

Local Development

  1. Copy env templates: cp infrastructure/env-templates/.env.development .env.dev (and equivalents for other environments).
  2. Run the stack: make dev (includes infrastructure + services + frontend).
  3. Tail logs: make dev-logs.
  4. Stop stack: make dev-stop.

Individual Service

  • Navigate to service directory and run npm install, then npm run dev for hot reload.
  • Express services use nodemon + ts-node; NestJS services use the Nest runtime.
  • Use .env files in each service (.env.example provided where relevant).

Testing

  • React frontend uses Vite test tooling (configure npm run test).
  • Node services compile with npm run build before deployment. Add unit/integration tests per service conventions.

Linting & Formatting

  • TypeScript strict mode enabled across services.
  • Follow NestJS module conventions: module.ts, controller.ts, service.ts per domain.
  • Use dependency injection (Nest providers) for testability.
  • Limit shared utilities to clearly named folders (e.g., src/common).

File & Folder Organization

  • NestJS servicessrc/app.module.ts, src/<domain>.controller.ts, src/<domain>.service.ts, src/<domain>.module.ts (if necessary).
  • Express servicessrc/index.ts entry point + domain-specific folders (routes, controllers, services).
  • Frontend – Organize by component layer (components, features, hooks, pages, services). Use import.meta.env for runtime configs.

6. External Integrations

  • Stripe – Payment intents, confirmations, refunds via payment-service.
  • Yelp/Tripadvisor/Googlereview-service has a mock ExternalReviewService; swap in real API calls (with API keys) once available.
  • SMTP / Push – Notification service supports SMTP credentials; push integration is ready for FCM.
  • Search – Postgres full-text (tsvector + GIN / pg_trgm) once real experience data lands; semantic search via pgvector (rag_document_vectors). Elasticsearch was removed in Wave 1 (W1-1) — not used.

7. Contribution Checklist

  1. Create a feature branch from main.
  2. Update or create service-level docs when adding new endpoints (README.md, CMS_INTEGRATION.md within each service).
  3. Run npm run build (or npm run test) for services you change.
  4. Update Compose env vars / README when new environment variables are introduced.
  5. Submit a merge request with a summary of changes and testing steps.

This document will evolve as new services and integrations appear. Please keep it in sync when making architectural changes.