B2B travel platform — a tour operator builds dynamic packaged offers (accommodation, transport, transfer, insurance, extras) and distributes them to partner travel agencies, which search live-priced packages and book them.
v2 reboot — fresh start. The previous white-label widget platform is preserved on the
archive/v1branch (tagv1.0-final).
- Backend — .NET 10 modular monolith (
backend/): Agencies, Catalog, Pricing, Booking, Integrations, Documents modules over a single PostgreSQL database (schema per module). - Integrations — provider-agnostic reservation contract (
IReservationProvider): Mock adapter first; external systems (TourVisio, Sejour, …) plug in behind the same interface. - Frontend — Angular 21 B2B portal (
frontend/portal): agency area (search, booking wizard, bookings, documents) and admin area (planned: agencies, programs, pricing rules, bookings oversight). - External agencies — integrated partner systems call the same REST API with a per-agency key (
X-Api-Key) and get exactly the agency scoping a portal login gets.
backend/
Odisea.slnx .NET 10 solution (slnx format, VS 17.14+)
Directory.Build.props shared build settings (nullable, warnings as errors)
Directory.Packages.props central package versions
src/
Odisea.Api/ host: Serilog, Swagger, ProblemDetails, /health
Odisea.SharedKernel/ Entity, Money, DateRange, Pax, IClock, ICurrentUser
Modules/
Odisea.Modules.Agencies/ identity (JWT + API keys), agencies, users, credit limits, commissions
Odisea.Modules.Catalog/ destinations, hotels, programs, departures, mappings
Odisea.Modules.Pricing/ pricing rules, exchange rates, pricing engine
Odisea.Modules.Booking/ reservations, passengers, payments, status history with actors
Odisea.Modules.Integrations/ provider contract + adapters (Mock, TourVisio, …)
Odisea.Modules.Documents/ Bulgarian tax documents: фактури, известия, PDFs; contracts from Word templates
Odisea.Modules.Notifications/ transactional e-mail outbox + SMTP dispatcher
Odisea.Modules.Workspace/ paid agency tier: external reservations + public tracking, inquiry forms
tests/
Odisea.UnitTests/ unit + module-boundary architecture tests (EF InMemory)
Odisea.IntegrationTests/ HTTP tests over the real host against Postgres
Each module keeps a PublicApi/ namespace — the only surface other modules may reference (enforced by an architecture test). One Postgres database, one schema per module.
docker compose up -d db # Postgres 17 (host port 5433)
dotnet run --project backend/src/Odisea.Api # migrate + seed + listen on :8080
# portal: cd frontend/portal && npm start # Angular on :4200, /api proxied
# or everything at once: docker compose up -d --build # portal on :4200 behind nginxPortal dev logins: agency agent@odisea.local / DevOnly-Odisea-Agent-2026! · operator admin@odisea.local / DevOnly-Odisea-Admin-2026!
Open http://localhost:8080/swagger, call POST /api/v1/auth/login (dev: admin@odisea.local / DevOnly-Odisea-Admin-2026!), click Authorize, paste the token — every endpoint is now testable from the browser. Everything is 401 without a token by design.
| Doc | What it answers |
|---|---|
| docs/ARCHITECTURE.md | The overall picture: tiers, module boundaries, data & auth model, provider abstraction |
| docs/ROADMAP.md | The implementation plan: phases, status, definition of done |
| backend/README.md | How to run, test, and add migrations; project index |
backend/src/**/README.md |
Each project's purpose and relations |
| Project board | Task-level source of truth |
Repo workflow skills for Claude Code live in .claude/skills/ (run-stack, add-migration, new-module, pick-task, start-feature, commit-changes, finish-feature), plus create-program, which turns an operator's brief into a complete program through the API (content guide, spec format, import script).
Backend complete through Phase 4 + hardening: auth (#96), dev stack/CI (#97), provider contract + mock (#107), catalog (#108), pricing engine (#109), live-priced search (#110), booking lifecycle (#111), rate limiting/headers/CORS/HSTS (#112). Open: Angular portal (#98), real provider adapter (Phase 5 — gated on the intermediary decision), remaining ops items (#100). See docs/ROADMAP.md.