Architecture¶
Platform¶
- Mendix 10.24.21 (LTS), split-MPR format v2.
WildernessWindow.mpris a SQLite database containing only theUnittable - the document tree (UnitID, ContainerID, ContainmentName, ContentsHash). Document content lives inmprcontents/<xx>/<yy>/<guid>.mxunitbinary blobs, one per document. Practical effect: git diffs are per-document, so parallel work merges far better than the old single-file.mpr, but nothing in the model is greppable without a decoder (see tools/mxinspect.py).- Java layer: 872
.javafiles across 50 packages, 551 Java actions.pom.xmlexists only for IDE support and still declares source/target 1.8 while Mendix 10 runs on Java 21 - harmless for the runtime, misleading for IDE users. - Front end: Atlas Core / Atlas Web Content plus 71 widget packages, mixing current
Mendix widgets (Datagrid 2, Gallery, Combobox) with older third-party and one-off
widgets (
jQueryUIDateTimePicker,InterActiveGrid,mobino.RichTextCustome,nagarro.WrittingAssistant,wilderness destinations.StringHtml).
Module layout¶
108 modules; the full table is inventory/module-inventory.md. Functionally they group like this:
| Group | Modules |
|---|---|
| Core selling | Booking, BookingTemplates, BookingGuestManagement, Pricing, PricingDynamic, Availability, XtremeAvailability, LiveRequest |
| Master data | BookingMasterData (RARA), Configuration, Common, SetupWizard |
| Customers / CRM | GuestManagement, GuestManagementAPI, Agency, AgentOnBoarding, Enquiries, HubSpot, HubSpot_DMC, WildernessLeadModel, Media, DonorDatabase, Windfall |
| Products | Itinerary, Itinerary_SafariPortal, Touring, Explorations, Transfers, Interconnect, WAir, TravelStart, Prepurchases, Exo, PanStrat, Wedge |
| Money | FinancePortal, TourplanInvoicing, PaymentGateway, StaffRemuneration |
| Operations | LodgeManagement, IncidentManagement, Maintenance, EAH, SRM, Supplier_Portal |
| Portals / content | AgentPortal, InformationCentre, Training, Awards, Anonymous, Layouts |
| Integration | API, API_V3, DataManagement, WishAPI, hostConnect, HTI, HConnect, SiteConnect, Siteminder, Nightsbridge, NightsBridge_V5, Profitroom, ResRequest, Mautourco, SchedwinAPI, Onbase, Jotform, Interconnect, History |
| Platform / support | Administration, Logging, Tools, Dashboard, WildernessScheduler, Encryption, Ldap, GoogleAnalytics, OpenAIConnector, EnumEntityBuilder |
| Marketplace (28) | Atlas_Core, Atlas_Web_Content, CommunityCommons, DataWidgets, DocumentGeneration, Email_Connector, ExcelImporter, ExternalDatabaseConnector, GenAICommons, MxModelReflection, NanoflowCommons, OQL, PDFUtils, ProcessQueue, TaskQueueManager, WebActions, WordTemplate, XLSReport, Calendar, Countries, Encryption, EnumToList, FileDropper, ImageCrop, Ldap, LocalFileOperations, OpenAIConnector, RedirectURLUsingJs |
Module boundaries are not enforced barriers: Booking alone holds 2,553 microflows and
496 pages, and cross-module calls are common (Pricing.Sub_PriceBookingAll has 89
callers spread across modules).
Pricing and PricingDynamic are documented in depth, and the shape is worth knowing at
architecture level: there is no rule engine. Pricing.PricingRule is a 54-attribute
entity with 23 specialisations, qualification is a pipeline of list filters, and application
is a type switch — so pricing behaviour is configuration data, not model logic. Detail in
pricing-rules.md,
pricing-calculation.md and
pricing-manual-adjustments.md.
Data model¶
2,773 entities, 96 domain models. Biggest:
| Module | Entities |
|---|---|
BookingMasterData |
176 |
Booking |
147 |
DataManagement |
135 |
API |
132 |
Siteminder |
115 |
HTI |
114 |
SiteConnect |
110 |
GuestManagement |
95 |
Note the shape: integration modules carry very large domain models because each channel
partner's payload is mirrored into its own entities before being mapped onto core
booking entities. Core booking objects are Booking -> TravelDay / TravelLocation ->
BookingLine -> DetailedBookingLine, plus Referral, BookingCorrespondence,
TourplanBookingServiceLine, TPItinerary.
Full entity lists: inventory/data-model.md, inventory/entities.json.
Runtime configuration¶
Settings$ProjectSettingsholds 17 server configurations.DefaultandConfigurationare HSQLDB placeholders; the other 15 are individual developers' local SQL Server setups (Joeg,Joeg_Dev,Joeg_Test,Ashley D,Ashley T,AllistairSquirrel,Allistair2ndWork,Matt_Squirrel,faiz,Rion_Lyan,Carl - Home,Stanley-lion,Altostratus,Local,WINDOWSSERV-001). Several carry plaintext database passwords - see 05-conventions-and-risks.md.- Most configurations set
-Dhttps.proxyHost=172.22.0.17 -Dhttps.proxyPort=8080, so outbound integration traffic goes through a corporate proxy. - Environment awareness is in the model, not just config:
AdministrationexposesLocalEnvironment/TestEnvironment/AcceptanceEnvironment/ProductionEnvironmentconstants,Administration.GetServerSettings(466 callers) andGetEnvironment(118 callers), plusAdministration/DetermineServerflows. Flows use these to suppress real emails and integration calls off production (AdvEmail.DevelopmentMailRedirect). - 108 constants, heavily used for routing addresses (
AdvEmail.*Email), retries and retention.
Security model¶
| Setting | Value |
|---|---|
| Security level | CheckEverything (entity + page + microflow security enforced) |
| Demo users | disabled |
| Guest access | enabled, guest role Anonymous_UseWithCaution |
| Strict mode / strict page URL check | off |
| Password policy | min length 8, digit + mixed case + symbol required |
| Admin account | MxAdmin, role Debug |
| User roles | 66 |
66 user roles is large; roles are fine-grained by function and by portal
(InfoPortalRates, InfoPortalAP, AfterHours, AfterHoursRead, FinanceReadOnly,
RaraSupplier, SupplierUser, MediaMember, SchedwinApiUser, GuestManagementApiUser,
SiteConnectUser...). Anonymous access is genuinely used - the Anonymous module serves
supplier deep links, uploads and issue reporting without login.
Batch processing¶
Two layers, and the important part is that the job list is data, not model:
- Mendix scheduled events (31) - declared in the model
(inventory/scheduled-jobs.md).
Maintenanceowns 16 of them, on fixed cadences:SE_Every30Seconds,SE_Every1MinuteOther,SE_Every1MinuteDailyJobs,SE_Every2Minute,SE_Every10Minute,SE_Every30Minute,SE_EveryHour,SE_EveryDay,SE_EndOfDayProcesses, plus email fetch/send andSE_WishHistory.
But only 2 of the 31 are enabled and included in the model - both
GenAICommons cleanup jobs. Every Maintenance.SE_* job is marked Enabled: false
and/or Excluded from deployment. On Mendix Cloud, scheduled events are switched on
per environment, so the model tells you a job exists and its interval, not whether it
runs. To know the live schedule you must look at the environment's model options in the
Mendix Cloud portal (or the runtime's scheduled-event settings).
2. A home-grown process queue - Maintenance.Every30Seconds_QueueBuilder ->
BuildProcessQueue -> AddProcessesToQueueConfig, and
Every30Seconds_QueueRunner -> RunProcessQueue (with
RunProcessQueue_Backup as a second runner). Which processes run, and in what order,
comes from queue configuration rows in the database. Reading the model tells you the
scheduler exists but not what it schedules; you need a database query or the
in-app admin screens for that.
Alongside it: the Marketplace ProcessQueue module (with SE_ReinitializeQueues,
SE_CleanupFinishedQueuedActions), TaskQueueManager, and 5 Mendix task queues
(Hubspot_Task_Queue, LogPricingQueue, RARA_Task_Queue, GMAPI_TaskQueue,
API_TaskQueue).
- Fire-and-forget background microflows —
CommunityCommons.executeMicroflowInBackgroundat 49 call sites, running 17 distinct targets in their own transaction after the caller commits. The return value is checked at none of them, so failures are silent.Onbase.BookingStatus_Postaccounts for 27 of the 49; the rest include outbound partner webhooks, HubSpot deal updates, a NightsBridge channel booking, and — in one path — a booking confirmation. Inventory: reports/async-handoffs.md.
Four overlapping asynchronous mechanisms — scheduled events, the home-grown process queue, Mendix task queues and fire-and-forget background calls — is itself a finding. They differ in ways that matter operationally: queued work is retried and observable, background work is neither, and neither appears in a synchronous call graph. Choosing between them currently looks like a matter of habit rather than of policy.
Logging and observability¶
Logging.LogMessageis the single most-called microflow in the app (823 callers), withTools.LogMicroflow(349) andBooking.LogEvent(200) close behind. Logging is applied by convention, in-model, rather than via platform log nodes only.WishAPI.LogWishMessagesToDisk(92 callers) andAPI.LogXMLRequestResponse(45) persist integration payloads for dispute resolution.Tools.UptimeMonitoris a published REST service used for external health checking, with a dedicatedHealthCheckuser role.- One developer configuration references New Relic (
-Dnewrelic.environment=), so APM exists at least in some environments.