Overview
System Map
The complete map of Auburn MyGov modules, their responsibilities, and the integration seams between them. This is the entry point for the integration design — all other documents zoom into specific seams described here.
| Status | Draft |
| Last updated | — |
| Scope | Public website modules and their integration points; excludes internal system implementation details |
Purpose & Scope
Auburn's public website is not a single application — it is a collection of purpose-built modules (Employees, Facilities, Calendars, Programs, Reservations, eNotifier, Pages) running on a shared platform with shared infrastructure. Each module manages its own domain. The design challenge is not the internal workings of any one module but the seams between them: what data flows where, who initiates it, and how.
This document answers three questions for every integration:
- Connection — what links to what, and why?
- Direction — which system is the source of truth, and which consumes?
- Trigger — is the integration automated, scheduled, manual, or pull-on-demand?
Separately, several external systems sit at the boundary: Microsoft 365 (Exchange resource mailboxes, Entra authentication, Outlook calendars), ESRI / county GIS services, and third-party registration platforms used by Parks and Library. Those boundaries are also mapped here, though the integration design for each is covered in its own document.
Modules
Internal modules are owned by MyGov and managed in the admin portal. External systems are shown with a dashed border — we integrate with them but do not own them.
The website content management system. Non-technical staff author pages. Pages reference other modules (contact cards, calendars, program lists) rather than duplicating their data.
InternalStaff directory. Maintains the record of truth (HR data) separately from the public-facing contact card (EmployeeContact). A page may surface an employee contact card without exposing the underlying record.
InternalCity facilities (buildings, parks, libraries, etc.). Maintains FacilityContact for public display — hours, address, phone — separate from the operational facility record. The physical anchor for Programs, Events, and Reservations.
InternalMunicipal calendars for meetings, events, holidays, and programs. Supports parent/child hierarchy so a parent calendar (e.g., "Parks Programs") can aggregate many child calendars. Programs and standalone events both surface here.
InternalParks and Library program listings. A program has one or more sessions (which are time-bound occurrences), optional registration rules (cost, capacity, deadlines), and a location. Programs push into Calendars for unified time-based views. Registration is internal — the goal is a first-party module that works for both Parks and Library before either department goes live with an external platform. Library is evaluating Vega; Parks may use a separate external system. If a department goes external, integration (not replacement) is the path.
InternalBookable spaces within facilities (rooms, fields, equipment). Maintains FacilitySpaceContact for public display. Reservations carry rules: lead time, padding, occupancy limits. The most greenfield module — not yet in production.
InternalMass-mailer and interest list manager. Sends announcements across many content categories: job openings, programs, events, road closures, meeting schedules, press releases. Integrates with other modules either by push (a system event queues a notification) or pull (a user composing a mailer selects content from other modules).
InternalAutomation engine. Triggers actions on a schedule or in response to form submissions. The primary mechanism for cross-module automation — not a user-facing module but the plumbing behind most automated integrations.
Internal / PlatformExchange resource mailboxes (each is a calendar), Entra/Azure for employee authentication, and Outlook calendar feeds. MyGov is the authority for public-facing data; M365 may be the authority for operational room booking depending on integration decisions.
ExternalAuthoritative spatial data: parcels, addresses, boundaries. MyGov queries these services and/or maintains SQL geometry data internally. Referenced by Facilities, Programs, and Reservations for location data.
External
Third-party registration platform used by Parks. Programs that
require registration link out via registrationUrl rather
than handling registration internally.
Integration Seams
Each row is one integration seam: a directional connection between two modules. Direction shows which system is the source → which is the consumer. Trigger describes how the data moves. Detailed design for each seam lives in its own document (linked in the sidebar).
| From | To | What | Direction | Trigger | Mechanism | Detail doc |
|---|---|---|---|---|---|---|
| Employees | Pages | EmployeeContact card surfaced on page | → consume | Pull | Page references EmployeeContact by ID; rendered at display time | Contact Surface |
| Facilities | Pages | FacilityContact card surfaced on page | → consume | Pull | Page references FacilityContact by ID; rendered at display time | Contact Surface |
| Facility Spaces | Pages | FacilitySpaceContact surfaced on page | → consume | Pull | Page references FacilitySpaceContact by ID; rendered at display time | Contact Surface |
| Programs | Calendars | Program sessions appear as calendar entries | → push | Automated | Creating/updating a program session writes to the associated calendar; category → calendar mapping drives which calendar receives it | Calendar Aggregation |
| Reservations | Calendars | Confirmed reservations block time on a facility calendar | → push | Automated | Reservation confirmation writes a calendar entry (or blocks the Exchange resource mailbox — TBD per Microsoft Ecosystem doc) | Reservations |
| Programs / Calendars | eNotifier | Content blocks added to a mailer | ← pull | Pull | Staff composing a mailer selects a calendar or program; block inserts recent/upcoming items. A prototyped pattern — preferred over auto-push for this seam. | eNotifier |
| Employees | eNotifier | Job opening announcements | → push | Manual | Staff publishing a job opening opts to queue an eNotifier announcement; interest list subscribers are notified | eNotifier |
| Programs | eNotifier | New season / brochure announcements | → push | Manual | Staff publishes a program season and opts to notify subscribers; or staff compose a mailer and pull in program content blocks | eNotifier |
| Facilities / Facility Spaces | Location (ESRI / GIS) | Spatial location linked to facility record | ← pull | Pull | Facility record stores a spatial reference (parcel ID, address ID, or coordinates); resolved against ESRI / county GIS on display or query | Location |
| Programs / Events | Facilities / Facility Spaces | Location of a program session or event | → reference | Pull | Program session or calendar event carries a FacilitySpace (or Facility) foreign key; resolved at display time | Location |
| Reservations | Facility Spaces | Availability and rule enforcement | ← pull | Pull | Reservation request checks FacilitySpace for occupancy, lead time, and padding rules before confirming | Reservations |
| Reservations | Microsoft 365 (Exchange) | Resource mailbox calendar block | → push | Automated | TBD — confirmed reservation may write to the Exchange resource mailbox for the space, keeping Outlook in sync. Decision pending Microsoft Ecosystem doc. | Microsoft Ecosystem |
| Calendars | Microsoft 365 (Outlook) | Calendar feed for public/staff subscription | → publish | Scheduled | MyGov calendars publish an iCal/ICS feed; Outlook and other clients subscribe. MyGov is the source of truth — not Exchange. WCAG-compliant web view is the primary citizen surface. | Microsoft Ecosystem |
| Microsoft 365 (Entra) | MyGov (all modules) | Employee authentication / identity | ← pull | Automated | MyGov admin portal authenticates staff via Azure/Entra SSO. No credentials stored in MyGov. Group/role claims may inform module permissions. | Microsoft Ecosystem |
| Workflow Engine | Any module | Cross-module automation (schedule or form-response triggered) | → orchestrate | Automated Scheduled | ServerJobs execute on a schedule or in response to citizen form submissions. Used to implement automated integration seams — e.g., sync, notification queuing, status updates — without hard-coding them into module logic. | Workflow Engine |
Implementation Status — Audit Summary
All design docs audited against codebase as of 2026-06-09. Each module-level doc has a full Audit Findings section. Summary below.
Overall status by module
| Module | Core entities | Integration seams | Key gaps | Design doc |
|---|---|---|---|---|
| Employees / EmployeeContact | ✓ BUILT | ✓ BUILT — SyncUsersDelta, GetUserPhoto | Legacy OverrideName/Phone on organization.employee needs migration; EnotifierEmployee is a parallel table | Contact Surface |
| Facilities / FacilityContact | ✓ BUILT | ⚠ PARTIAL — GIS sync fields exist; sync job not fully audited | GIS sync mechanism not confirmed; useType not normalized | Location, Contact Surface |
| FacilitySpaces / FacilitySpaceContact | ✓ BUILT | ✓ BUILT — Exchange mailbox link on FacilitySpace | bookingRules is a JSON blob; typed ReservationConfig with Divisions not yet built | Location |
| Calendars | ✓ BUILT (Option A schema) | ⚠ PARTIAL — pull + program push built; no on-publish auto-trigger | No Option B extension fields (sourceType/sourceId/imageUrl); no parent/child hierarchy; no Reservation→Calendar push | Calendar Aggregation |
| Programs | ✓ BUILT | ⚠ PARTIAL — sync-calendar built; manual trigger only | On-publish auto-trigger missing; Exchange blocking requires FacilitySpace.ExchangeResourceMailbox | Calendar Aggregation |
| Reservations | ✓ BUILT | ⚠ PARTIAL — Exchange events + GUID cancel + workflow trigger all built | Approval flow always confirms immediately; Divisions not built; no CalendarEvent for citizen-facing calendar; no waitlist | Reservations |
| eNotifier | ✓ BUILT | ⚠ PARTIAL — Events Block pull built; NDR handler built (needs activation) | HMAC unsubscribe token security gap; EnotifierEmployee is a parallel table; auto-push hooks not built; hard-coded Parks/Library facilityContactId=16 | eNotifier |
| Workflow Engine | ✓ BUILT | ✓ BUILT — 20 handlers registered | No async/pause state (multi-step approval must be simulated); V1 fields on FormAction not retired; reservation-specific actions not yet defined | Workflow Engine |
| Microsoft 365 | N/A (external) | ⚠ PARTIAL — read/write Exchange events built; employee sync built; NDR handler built (needs activation) | Resource mailbox provisioning not built; Entra group management for portal roles not audited | Microsoft Ecosystem |
| ESRI / GIS | N/A (external) | ⚠ PARTIAL — Facility/FacilitySpace have geometry columns + GIS ID fields | ArcGIS import workflow not fully audited; ArcGisHandler exists in workflow engine but actions not documented | Location |
| Polaris ILS (Library) | N/A (external) | ✓ BUILT — DragonstoneContext queries Polaris for barcode/patron lookup | Used in reservation flow; patron registration query uses raw SQL — should be encapsulated | Reservations |
Top priority implementation gaps
- HMAC unsubscribe tokens — eNotifier security gap. Must be resolved before the public unsubscribe endpoint is promoted.
NDR processing activation— ✓ Done. ServerJob active; processed bounces from first live campaign.- On-publish calendar sync trigger — Program publish should automatically call sync-calendar; currently manual only.
- Reservation approval flow — per-space requiresApproval flag; Exchange event should only be created on confirmation, not submit.
- CalendarEvent for reservations — confirmed reservations should write a CalendarEvent so they appear on the citizen-facing calendar.
- Option B extension fields — add sourceType/sourceId to CalendarEvent; update program sync to populate them.
- EnotifierEmployee → unified employee model — EnotifierEmployee is a parallel table; should be a role flag on organization.Employee or EmployeeContact.
- Legacy override fields on organization.employee — OverrideName/OverridePhone should migrate to EmployeeContact then be dropped.
- EventsBlockModal hard-coding — facilityContactId===16 check needs to be replaced with a theme/department field on Calendar.
- Resource mailbox provisioning — admin portal + API action to create new Exchange resource mailboxes via Graph.
Design vs. Audit — Deviation Analysis
The following items represent the largest gaps between the design intent and the current implementation, ranked by long-term impact. These are not bugs — they are known deviations that will compound over time if not addressed.
1. Reservation confirmation is immediate — no approval flow
Severity: High. The design describes a per-space requiresApproval flag and a Pending → Confirmed workflow. The current implementation always sets Status = "Confirmed" immediately on submit and creates the Exchange calendar event before any staff review. This is the single most consequential deviation because:
- It cannot be corrected after data accumulates — reversing confirmed reservations retroactively is operationally difficult.
- Exchange events are already created on submit. Removing them if staff later rejects is possible but creates a confusing history.
- The Workflow Engine's multi-step approval pattern (schedule string mechanism) is already built — the reservation controller just needs to be wired to it. The fix is targeted.
Recommended fix: Add requiresApproval to FacilitySpaceContact. On submit, set status to Pending and skip Exchange event creation. Create the Exchange event only when staff runs StartWorkflow(formResponse, "Status:Approved") via an admin action. The cancel-by-GUID flow and idempotency guard are already in place.
2. EnotifierEmployee is a parallel, unlinked employee table
Severity: Medium-High. eNotifier.EnotifierEmployee is a separate table with no FK to organization.Employee or cms.EmployeeContact. This means:
- Employee onboarding/offboarding must be done in two places. When someone leaves, they may retain eNotifier access if the parallel table isn't updated.
- There is no access audit trail connecting eNotifier campaign sends to the Azure AD identity of the sender.
- As the employee directory grows (more sync fields, role structures), keeping eNotifier in sync becomes increasingly manual.
Recommended fix: Add a permission flag (e.g. canUseEnotifier) to cms.EmployeeContact or a junction table. Migrate eNotifier-specific fields (smsRelayAddress, displayName override) to that record. Retire eNotifier.EnotifierEmployee. Authentication is already Azure AD — the link is the AzureId.
3. CalendarEvent is Option A — no sourceType/sourceId linkage
Severity: Medium. The design calls for CalendarEvents to carry sourceType / sourceId linking back to their originating entity (Program, Reservation, external ICS, etc.). The current schema is pure iCal fields only. This means:
- A CalendarEvent row has no machine-readable indication of where it came from. Querying "all calendar events for Program 42" requires parsing the
uidfield convention ("program-session-{id}-{date}") — fragile. - When a program is cancelled or rescheduled, finding all associated CalendarEvents requires the same uid prefix parsing.
- Future sources (reservations, GIS events) will need the same convention, leading to proliferating uid formats.
Recommended fix: Add sourceType (varchar, e.g. "program", "reservation", "ics-feed") and sourceId (int, nullable) to data.CalendarEvent. Populate them during program sync. Index (sourceType, sourceId) for efficient reverse lookups.
4. bookingRules is an untyped JSON blob
Severity: Medium. cms.FacilitySpaceContact.bookingRules is a JSON blob with no schema enforcement. The validator (BookingRulesValidator) reads scalar fields from it, but the structure is not validated against a typed model at the DB or API boundary. As reservation rules grow (Divisions/occupancy tiers, approval config, blackout dates with recurrence), maintaining consistency in an untyped blob becomes increasingly error-prone. A migration to a typed ReservationConfig entity gets harder the more configs are in production.
Recommended fix: Define a typed ReservationConfig class. Keep it as a JSON column for now (EF can project it), but add a JsonSchema or record type that BookingRulesValidator uses. Add API validation on write. Full normalization into a relational entity can wait until the Divisions/approval model is designed.
5. organization.employee is a [Keyless] graph table with legacy fields
Severity: Low-Medium. The [Keyless] EF annotation means no primary key tracking — adds friction to any query that needs to join or update by ID. The graph features ($node_id, edge tables) do not appear to be leveraged in any current code path. The legacy OverrideName / OverridePhone columns duplicate functionality that now lives in EmployeeContact. While not urgent, this creates ongoing confusion: new developers see a graph table and expect graph queries; none exist. Legacy fields on the source table blur the single-responsibility intent of the Entity/Contact split.
Recommended fix: Migrate OverrideName/OverridePhone to EmployeeContact (likely already-populated — just map the data). Drop the columns. The graph table structure can remain if there is a future plan for it; if not, document the intent or migrate to a standard keyed table.
Summary table
| Deviation | Impact | Effort to fix | Urgency |
|---|---|---|---|
| Reservation always confirms immediately | High — operational, data integrity | Medium (workflow wiring) | Before production reservation launch |
| EnotifierEmployee unlinked from org.Employee | Medium — security, maintenance | Medium (schema + data migration) | Before staff turnover creates orphan access |
| CalendarEvent no sourceType/sourceId | Medium — query correctness, future-proofing | Low (additive migration) | Before additional source types added |
| bookingRules untyped JSON blob | Medium — correctness at scale | Low (add typed class, defer normalization) | Before Divisions/approval model is built |
| organization.employee legacy fields | Low — developer confusion, schema noise | Low (data migration + column drop) | Next planned schema cleanup |