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-serviceremoved 2026-04-25 (W1-1). Loki + Promtail + Prometheus + Grafana removed 2026-04-25 (W1-2+3).mcp-serverconsolidated intoai-service2026-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+ deadai_tasks/ai_resultsqueues (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 3rag.*MCP tools no longer round-trip httpx;rag_qual/rag_prodPostgres 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¶
- Frontends –
frontends/public-forenders 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.
- CMS –
services/strapi-cmsstores 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 hostspgvectorfor ai-service's RAG embeddings andtsvector+pg_trgmfor 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-alpine→pgvector/pgvector:pg15. Schema ininfrastructure/migrations/rag/00001_pgvector_initial.sql(managed by dbmate, ADR-003). asyncpg pool now inservices/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 noexperiencecontent type), no consumer (frontends use local mocks); all query shapes fit Postgres FT. When real experience data lands, full-text search will live astsvector+ GIN onexperience-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}-logsandmake remote-docker-logscover MVP ops; container JSON logs now capped at 50 MB via Dockerlog-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.prometheusstanza 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:
- Notification Service
- Publishes events such as
email.sent,push.sent,websocket.emittedto thenotificationsqueue. - SMTP and push integrations operate in mock mode when credentials are absent.
- Review Service
- Emits
review.createdevents via thereviews.eventsexchange for moderation or downstream consumers. - Payment Service
- Future enhancement: emit
payment.intent.created,payment.refundedfor 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¶
- Email –
POST /api/notifications/emailwith{ to, subject, text/html }. Uses SMTP when configured; otherwise logs mock send operations. - Push –
POST /api/notifications/pushwith device tokens. Placeholder integration ready for FCM/OneSignal. - Websocket – WebSocket namespace
/notificationswith events broadcast viaPOST /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.mdto trigger notifications from CMS workflows.
5. Development Workflows¶
Local Development¶
- Copy env templates:
cp infrastructure/env-templates/.env.development .env.dev(and equivalents for other environments). - Run the stack:
make dev(includes infrastructure + services + frontend). - Tail logs:
make dev-logs. - Stop stack:
make dev-stop.
Individual Service¶
- Navigate to service directory and run
npm install, thennpm run devfor hot reload. - Express services use nodemon + ts-node; NestJS services use the Nest runtime.
- Use
.envfiles in each service (.env.exampleprovided where relevant).
Testing¶
- React frontend uses Vite test tooling (configure
npm run test). - Node services compile with
npm run buildbefore 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.tsper domain. - Use dependency injection (Nest providers) for testability.
- Limit shared utilities to clearly named folders (e.g.,
src/common).
File & Folder Organization¶
- NestJS services –
src/app.module.ts,src/<domain>.controller.ts,src/<domain>.service.ts,src/<domain>.module.ts(if necessary). - Express services –
src/index.tsentry point + domain-specific folders (routes,controllers,services). - Frontend – Organize by component layer (
components,features,hooks,pages,services). Useimport.meta.envfor runtime configs.
6. External Integrations¶
- Stripe – Payment intents, confirmations, refunds via
payment-service. - Yelp/Tripadvisor/Google –
review-servicehas a mockExternalReviewService; 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¶
- Create a feature branch from
main. - Update or create service-level docs when adding new endpoints (
README.md,CMS_INTEGRATION.mdwithin each service). - Run
npm run build(ornpm run test) for services you change. - Update Compose env vars / README when new environment variables are introduced.
- 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.