Oddy
The backend platform for Oddy's live Albania travel, discovery, booking, and rewards product.
Context
Oddy helps travelers discover businesses, events, and experiences across Albania, make reservations, and earn rewards, while a separate merchant portal supports business operations. Its Django API coordinates both independently delivered applications across discovery, merchant operations, reservations, visits and rewards, notifications, identity review, and external-service integrations. Relational and geospatial data, background processing, caching, audit records, containerized environments, backups, and centralized logs support the application beyond its request/response boundary.
Provide one backend platform for distinct traveler and merchant experiences while keeping their shared business, reservation, reward, notification, and operational state consistent.
Travelers use the mobile application to explore Albania, make reservations, and earn rewards. Merchants use a separate web portal to manage their work. One backend must provide role-appropriate contracts to both experiences while keeping shared business, reservation, reward, notification, and operational state consistent.
- Preserve clear public, client, merchant, partner, and provider boundaries within one backend platform.
- Keep merchant access reproducible while supporting business memberships, roles, and deliberate overrides.
- Make concurrent reservation, reward, and financial state changes explicit and transaction-safe.
- Dispatch asynchronous side effects only after their source state is durable.
- Keep slower document and provider workflows outside normal API response latency.
- Run the same application stack across isolated development, staging, and production environments.
My role
At VM Tech, I contribute to and maintain Oddy's backend platform, overseeing the backend architecture, API and domain implementation, integrations, deployment setup, and production operations.
Contribution boundaries
- Product OwnershipOddy and its code belong to VM Tech.
- Client FrontendsThe consumer mobile and merchant web applications are separate clients; I do not present them as my frontend work.
Backend Platform
Django API and domain workflows serving the consumer-mobile and merchant-web applications.
Backend Architecture
Backend boundaries, domain organization, transaction behavior, and API evolution.
Integrations
Notification, identity, data, financial, partner, and storage provider boundaries.
Deployment And Operations
Containerized environments, workers, backups, logging, observability, and production operation.
Architecture
Platform context
09 boundaries · 12 declared relationships
- 01Consumer mobile applicationExternal Client
- 02Merchant web applicationExternal Client
- 03Django REST APIAPI
- 04Background workers and schedulerWorker
- 05PostgreSQL with PostGISDatastore
- 06Redis queue and cacheDatastore
- 07Isolated document-processing servicesService
- 08Messaging, data, financial, partner, and storage providersExternal Provider
- 09Centralized logs and dashboardsMonitoring
Relationship mapInspect 12 connectionsToggle architecture relationships
- Consumer mobile applicationRequestDjango REST API
- Merchant web applicationRequestDjango REST API
- Django REST APIPersistencePostgreSQL with PostGIS
- Django REST APIAsyncRedis queue and cache
- Background workers and schedulerAsyncRedis queue and cache
- Background workers and schedulerPersistencePostgreSQL with PostGIS
- Django REST APIIntegrationIsolated document-processing services
- Background workers and schedulerIntegrationIsolated document-processing services
- Django REST APIIntegrationMessaging, data, financial, partner, and storage providers
- Background workers and schedulerIntegrationMessaging, data, financial, partner, and storage providers
- Django REST APIMonitoringCentralized logs and dashboards
- Background workers and schedulerMonitoringCentralized logs and dashboards
Engineering decisions
01Keep client experiences separate at the API boundary
Toggle decision details
Context
Consumer-mobile and merchant-web applications have different actors and workflows.
Selected approach
Maintain explicit public, client, and merchant API surfaces over shared backend domains.
Rationale
Keep role-specific contracts legible without duplicating the underlying business state.
Trade-offs
- Shared workflows must preserve consistent behavior across multiple API surfaces.
- Contract changes require coordination with independently delivered clients.
02Synchronize role defaults without erasing explicit overrides
Toggle decision details
Context
Merchant access uses database-backed memberships and roles while baseline definitions evolve with the code.
Selected approach
Synchronize a code-defined role catalog into runtime data and preserve deliberate membership overrides.
Rationale
Keep environment defaults reproducible while retaining operational exceptions.
Trade-offs
- Synchronization must distinguish changed defaults from intentional overrides.
- Deployment procedures must include the catalog synchronization path.
03Dispatch asynchronous effects after commit
Toggle decision details
Context
Reservation alerts and other background effects originate during transactional state changes.
Selected approach
Queue delivery after the source transaction commits and recheck access before protected notifications are sent.
Rationale
Avoid announcing rolled-back state or delivering merchant activity after access changes.
Trade-offs
- Delivery needs explicit retry, skip, and audit states.
- A post-commit queue failure needs an operational recovery path.
04Keep mobile and merchant notification transports separate
Toggle decision details
Context
Native clients and merchant browsers use different subscription and delivery mechanisms.
Selected approach
Keep transport-specific registration and dispatch while sharing delivery auditing.
Rationale
Preserve each client's provider, security, and outcome semantics.
Trade-offs
- Two registration and delivery paths must be maintained.
- Provider acceptance does not always prove that a notification was displayed or read.
05Preserve reservation history through derived expiry
Toggle decision details
Context
An unresolved reservation can pass its scheduled time without a final response.
Selected approach
Derive an expired read state from time and workflow status instead of rewriting historical state.
Rationale
Keep the original workflow record while presenting an accurate actionable state to both clients.
Trade-offs
- Reads, filters, statistics, and mutation rules must use the same derivation.
06Organize growing Django layers by domain
Toggle decision details
Context
Large view, serializer, and service modules become difficult to navigate as domains expand.
Selected approach
Split large application layers into domain-named packages with stable aggregate imports.
Rationale
Keep code ownership and boundaries legible without changing external API behavior.
Trade-offs
- Re-exports and test patch paths need deliberate compatibility handling.
Runtime ownership
- 01Containerization
Docker Compose isolates development, staging, production, and observability environments.
- 02Reverse Proxy
Public routing is separated from application containers.
- 03Storage
PostgreSQL/PostGIS, Redis, and object storage support relational, geospatial, queued, cached, and media state.
- 04Backups
A dedicated service schedules PostgreSQL backups and retention in object storage.
- 05Monitoring
Loki, Alloy, and Grafana provide centralized collection and exploration.
- 06Logging
Application, worker, delivery, and audit logs use environment-aware retention and sensitive-data controls.
- 07Scheduled Tasks
Scheduled work covers domain maintenance, refresh, reconciliation, recovery, and backups.
- 08Background Jobs
Workers handle delivery, document support, provider status, and data refresh.
- 09Notifications
Native mobile and browser push use separate subscriptions with shared delivery auditing.
- 10Email
Environment-configured SMTP delivers account and transactional email.
- 11Deployment
The API, workers, scheduler, and internal processing services have explicit runtime boundaries.
Inspect operational detail
- Prebuilt versioned images are reused across environments.
Current state
- Current
Oddy's backend is live in production and serves its consumer-mobile and merchant-web applications.
Depth B / Technical inspectionInspect supporting evidence
Domains, provider boundaries, and evidence classifications.
Toggle technical inspection
Inspect supporting evidence
Domain structure
- Identity and accessAccount lifecycle, authentication, verification, and role-based merchant access.
- Business and merchant operationsBusiness profiles, memberships, staff, invitations, availability, and merchant-facing management.
- Discovery and eventsGeospatial business and event discovery, categorization, visibility, filters, and curated sections.
- ReservationsClient requests, merchant responses, counter-offers, lifecycle rules, statistics, and delivery side effects.
- Visits, referrals, and rewardsVisit registration, attribution, referrals, staff rewards, and client point activity.
- Identity reviewSecure document submission and a review workflow in which manual review remains authoritative.
- NotificationsNative mobile push, merchant browser push, transactional email, retries, and delivery auditing.
- PayoutsBackend-managed payout requests and provider status handling with guarded balance updates.
- Partner integrationsBackend-owned boundaries for selected external partner services.
- Platform operationsBackground scheduling, media storage, backups, structured logging, and observability.
Integrations
- IdentitySocial identity providers
Support external identity sign-in for client accounts.
Provider authentication integrations - NotificationsMobile and browser push providers
Deliver transport-specific client and merchant notifications.
Native mobile push and standards-based Web Push - Transactional EmailSMTP email delivery
Deliver account and transactional messages.
Environment-configured SMTP - Geospatial Business DataMapping and business-review data
Support business discovery and reviewable location data.
Backend provider integration - Foreign ExchangeExchange-rate data
Supply exchange-rate context to relevant workflows.
Backend provider integration - FinancialPayment and payout provider boundary
Coordinate payout requests and provider status without exposing provider mechanics.
Backend provider registry - Partner ServiceTransport partner boundary
Isolate selected transport-partner workflows from client applications.
Backend-mediated partner API - Media Backup StorageS3-compatible object storage
Store environment-configured media and database backups.
S3-compatible object API
Capability evidence
- System architectureI oversee and maintain the backend architecture serving two independently delivered clients.
- API designI implement role-appropriate public, client, and merchant API surfaces.
- Domain modellingI maintain business, reservations, engagement, rewards, identity, and provider domains.
- Relational persistenceI use relational and geospatial state for discovery and operational workflows.
- Authentication and authorizationI maintain membership, role, default, and controlled override behavior.
- Transactional workflowsI implement guarded reservation, reward, and financial state transitions.
- Background processingI operate notification, document, reconciliation, and refresh work outside API latency.
- Systems integrationI maintain provider boundaries across identity, messaging, data, finance, partners, and storage.
- Deployment and operationsI maintain and operate isolated containerized application environments.
- ObservabilityI oversee centralized logs, delivery auditing, and dashboards.
- Backup and recoveryI maintain scheduled database backups and retention handling.