Logistics MFE DTOs & Services Contracts¶
Goal¶
Provide implementation-ready DTO shapes and service abstractions so the logistics Blazor microfrontend can be built stub-first (UI + navigation + service interfaces ship before the real logistics backend API exists).
This document is explicitly mapped to:
- LOG-MFE-001 (epic) / FOUND / ADMIN / SELF / INTG slices
Stub-first architecture & boundaries¶
The logistics MFE uses a configuration flag (name may be UseStubLogisticsApi or an equivalent) to switch between:
- Stub/in-memory service implementations (seeded data, deterministic IDs for tests)
- Future HTTP implementations (typed HttpClient and real backend)
Contract boundaries: 1. Razor pages/components should bind to UI view models, not DTOs directly. 2. Razor pages/components call UI services, which depend on service abstraction interfaces (queries/commands). 3. Service abstractions accept request DTOs and return response DTOs (including validation/error shapes). 4. DI wiring selects stub vs HTTP implementations without changing page code.
flowchart TB
UI[Razor Pages/Components] --> VM[UI View Models]
VM --> Svc[UI Services]
Svc --> IFace[Service Abstractions - Queries/Commands]
IFace --> Stub[Stub/InMemory Implementations]
IFace --> Http[Future HttpClient Implementations]
Stub --> DTO[Response DTOs]
Http --> DTO[Response DTOs]
DTO --> Map[DTO-to-VM Mapping]
Map --> VM
Suggested repository folder layout¶
Use a layout that keeps DTOs, interfaces, implementations, and mapping clearly separated.
Recommended (example) layout for the logistics MFE repository:
Contracts/Common/(shared IDs, pagination, error DTOs)Equipment/(EquipmentType*Dto,Location*Dto)Inventory/(InventoryByLocation*Dto, move-related DTOs)Events/(EventOrder*Dto,EventCalendar*Dto,EventOrderSummaryDto)BrokenEquipment/(BrokenEquipment*Dto)Audit/(ActivityLog*Dto)Services/Abstractions/- query interfaces (
*Queries) - command interfaces (
*Commands) Services/Stub/- in-memory seed stores + stub implementations
Services/Http/(placeholder for the API epic)ViewModels/- page-specific view models and lightweight UI types
Mapping/- DTO-to-VM mappers and request builders helpers
Shared DTO building blocks¶
These are DTOs that appear across all operations in this MFE.
Identity / tenancy references (IDs)¶
Use lightweight ID DTOs/types instead of full user entities:
- TenantId (GUID/string)
- UserId or ActorId (GUID/string)
Pagination¶
PagedRequestDtopageNumber(int, 1-based)pageSize(int)PagedResponseDto<TItem>items(TItem[])pageNumber,pageSizetotalCount(long)
Validation + domain errors¶
Choose one consistent pattern across all service abstractions. Recommended (contract-explicit) approach:
- ValidationProblemDto
- title (string)
- status (int, optional)
- errors (dictionary: fieldName -> string[])
- traceId (string, optional)
- DomainErrorDto
- code (string)
- message (string)
- OperationResultDto<T>
- isSuccess (bool)
- data (T, nullable)
- validation (ValidationProblemDto, nullable)
- error (DomainErrorDto, nullable)
Notes:
- The UI should rely on validation and/or error rather than parsing exception messages.
- Stub implementations should emulate the same validation shapes so UI logic is stable.
DTO families mapped to List-It screens¶
This section lists DTO families needed to implement the following screen numbers:
- Screen 3 Dashboard
- Screen 7 Manage equipment types
- Screen 8 Manage locations
- Screen 9 Move equipment
- Screen 10 Create / update event order
- Screen 11 Lock order
- Screen 12 Calendar view
- Screen 13 Report broken equipment
- Screen 14 Update status + resolve
- Screen 15 Activity log with filters
- Screen 16 Event order summary / print
1) Equipment catalog DTOs (Screens 7-8)¶
Equipment types¶
EquipmentTypeDtoidnameicon(string)description(string, optional)imageUrl(string, optional)EquipmentTypeListQueryRequestDto- pagination + optional search
EquipmentTypeUpsertRequestDto- fields for create/update
EquipmentTypeDeleteRequestDtoid
Locations¶
LocationDtoidnametype(e.g.,Hall,Storage) as string/enumLocationListQueryRequestDto- pagination + optional search
LocationUpsertRequestDto- fields for create/update
LocationDeleteRequestDtoid
2) Dashboard + inventory summary DTOs (Screen 3)¶
DashboardQueryRequestDto- tenant scope (implicit via auth) + optional “asOf” timestamp
DashboardDtoinventorySummary(InventoryByLocationDto[])recentActivityPreview(ActivityLogEntryPreviewDto[])quickActions(lightweight UI hints; optional)
InventoryByLocationDto shape:
- locationId, locationName
- equipmentQuantities (list of: equipmentTypeId, equipmentTypeName, quantityAvailable)
3) Inventory move DTOs (Screen 9)¶
MoveEquipmentRequestDtosourceLocationIdtargetLocationIditems(MoveEquipmentLineItemDto[])equipmentTypeIdquantity
note(optional)MoveEquipmentResultDtoactivityLogEntryId(optional for UI)updatedInventory(optional, can be refreshed by re-querying)validationand/orerrorcome viaOperationResultDtoMoveEquipmentValidationLineItemDto(optional)equipmentTypeIdrequestedQuantityavailableQuantity(for insufficient stock hints)
4) Event orders & scheduling DTOs (Screens 10-12, 16)¶
Terminology used here aligns with glossary:
- Event order: date/time window + hall + equipment list + notes + status
- Status flow at MVP: Pending -> Locked -> Completed/Cancelled (completion/cancel can be supported later; lock is core)
Create/update event order (Screen 10)¶
EventOrderUpsertRequestDtoid(nullable for create)eventDate(date)startTime,endTime(time)hallLocationIdequipmentLines(EventOrderEquipmentLineDto[])equipmentTypeIdquantity
notes(optional)seating(optional; if in scope for MVP)participants(optional; if in scope for MVP)desiredStatus(recommended to be implicit:Pendingon save while editing)EventOrderDtoideventDate,startTime,endTimehallLocationIdequipmentLines(normalized)status(Pending/Locked/Completed/Cancelled)
Lock order (Screen 11)¶
LockOrderRequestDtoorderId- optional
lockMoment(timestamp) for deterministic stub behavior LockOrderAvailabilityResultDtohallOccupancyavailability result:isHallFree(bool)conflictingOrderIds(optional)
equipmentAvailabilityavailability result:lines(EquipmentAvailabilityLineDto[])equipmentTypeIdavailableQuantityrequestedQuantityisSufficient(bool)
canLock(bool) computed from both hall + equipment checksLockOrderResultDtolockedOrderId(same as input)newStatus(Locked)- error/validation shapes come from
OperationResultDto
This is where UI validation errors should surface: - When hall occupancy fails (AC-O7) - When equipment availability fails (AC-O5)
Calendar view (Screen 12)¶
EventCalendarQueryRequestDtofromDate,toDate- optional filters:
hallLocationId,status includeHebrewCalendarContext(bool) (AC-O6)EventCalendarDtodays(EventCalendarDayDto[])- each day includes:
datehebrewDateLabel(optional ifincludeHebrewCalendarContext)cards(EventCalendarCardDto[])orderIdstatusstartTime,endTimehallLocationName
Event order summary / print (Screen 16)¶
EventOrderSummaryDtoidorderMetadataorderer(optional display fields)eventDate,startTime,endTimehallLocationName
equipmentLines(EventOrderEquipmentLineDto[])notesseating(optional)participantCount(optional)activity(optional for trace)
5) Broken equipment DTOs (Screens 13-14)¶
Glossary-aligned concepts:
- Broken equipment report tied to a location, equipment type, quantity, reason/status
- Resolve updates status and returns quantity to a target location
Report broken (Screen 13)¶
BrokenEquipmentReportRequestDtolocationIdequipmentTypeIdquantityreasonorstatusReason(string/enum)BrokenEquipmentDtoidlocationIdequipmentTypeIdquantitycurrentStatuscreatedAt
Update status + resolve (Screen 14)¶
BrokenEquipmentStatusUpdateRequestDtobrokenEquipmentIdnewStatus(enum)note(optional)BrokenEquipmentResolveRequestDtobrokenEquipmentIdresolvedQuantitytargetLocationIdnote(optional)BrokenEquipmentResolveResultDtonewStatus- optional
activityLogEntryId
6) Activity log DTOs (Screen 15)¶
ActivityLogQueryRequestDto- filters:
dateFrom,dateTotype(move/order/broken/etc.)- optional
userId
- pagination
ActivityLogEntryDtoidtimestamptypemessage(or structured payload for rendering)actorUserId/actorDisplayName- optional
relatedEntityId(orderId/locationId/brokenEquipmentId) ActivityLogEntryPreviewDto- a reduced version used by dashboard
Service abstractions (queries/commands) mapped to backlog slices¶
This section maps the needed service contracts to the backlog plan slices:
- LOG-MFE-FOUND-001 (Foundation)
- LOG-MFE-ADMIN-001 (Admin)
- LOG-MFE-SELF-001 (Self-service)
- LOG-MFE-INTG-001 (Shell integration)
LOG-MFE-FOUND-001 (Foundation)¶
Foundation establishes: - the DTO + service abstractions mentioned below - stub implementations (seeded data) controlled by the stub config flag - a minimal “smoke path” proving routing + stubs + Flowbite/UIKit assets work (per backlog plan)
Minimum service interfaces (include both queries and commands used across admin/self):
- Queries
- IDashboardQueries
- GetDashboardAsync(DashboardQueryRequestDto, CancellationToken)
- IEquipmentCatalogQueries
- ListEquipmentTypesAsync(EquipmentTypeListQueryRequestDto, CancellationToken)
- ListLocationsAsync(LocationListQueryRequestDto, CancellationToken)
- IInventoryQueries
- GetInventoryByLocationAsync(LocationId/List request, CancellationToken) (optional if dashboard covers it)
- IEventOrdersQueries
- GetEventCalendarAsync(EventCalendarQueryRequestDto, CancellationToken)
- GetEventOrderSummaryAsync(orderId, CancellationToken)
- IActivityLogQueries
- QueryActivityLogAsync(ActivityLogQueryRequestDto, CancellationToken)
- Commands
IEquipmentCatalogCommandsUpsertEquipmentTypeAsync(EquipmentTypeUpsertRequestDto, CancellationToken)DeleteEquipmentTypeAsync(EquipmentTypeDeleteRequestDto, CancellationToken)
ILocationsCommandsUpsertLocationAsync(LocationUpsertRequestDto, CancellationToken)DeleteLocationAsync(LocationDeleteRequestDto, CancellationToken)
IMoveEquipmentCommandsMoveEquipmentAsync(MoveEquipmentRequestDto, CancellationToken)
IEventOrdersCommandsUpsertEventOrderAsync(EventOrderUpsertRequestDto, CancellationToken)(returnsPendingstate)LockOrderAsync(LockOrderRequestDto, CancellationToken)(returnsLockOrderAvailabilityResultDtoorLocked)
IBrokenEquipmentCommandsReportBrokenEquipmentAsync(BrokenEquipmentReportRequestDto, CancellationToken)UpdateBrokenEquipmentStatusAsync(BrokenEquipmentStatusUpdateRequestDto, CancellationToken)ResolveBrokenEquipmentAsync(BrokenEquipmentResolveRequestDto, CancellationToken)
Stub implementations should return OperationResultDto<T> with consistent validation/error shapes.
LOG-MFE-ADMIN-001 (Admin)¶
Admin slice implements screens tied to admin navigation and role requirements, including at least:
- Screen 3 Dashboard
- Screen 7 Manage equipment types
- Screen 8 Manage locations
- Screen 9 Move equipment
- Screen 10 Create/update event order
- Screen 11 Lock order
- Screen 12 Calendar view
- Screen 13 Report broken equipment
- Screen 14 Update status + resolve
- Screen 15 Activity log with filters
- Screen 16 Event order summary / print
DTO/service usage mapping (high level):
- Catalog screens use: EquipmentType*Dto, Location*Dto + catalog commands/queries.
- Dashboard uses: DashboardDto, InventoryByLocationDto, ActivityLogEntryPreviewDto.
- Move uses: MoveEquipmentRequestDto and MoveEquipmentResultDto.
- Orders/Calendar/Print use: EventOrder*Dto, LockOrder*Dto, EventCalendar*Dto, EventOrderSummaryDto.
- Broken equipment uses: BrokenEquipment*Dto request DTOs for report/status/update/resolve.
- Activity log uses: ActivityLogQueryRequestDto and ActivityLogEntryDto.
LOG-MFE-SELF-001 (Self-service)¶
Self-service slice:
- routes under a self-service route group (e.g. /logistics/self)
- reuses the same DTO shapes and service abstractions as Admin
- provides a smaller set of pages according to self-service operator needs
At minimum, the self-service slice must support:
- Screen 9 Move equipment
- plus whichever order/broken workflows are permitted for self-service operators
Contract-wise, no new DTO families are required unless self-service needs different response payloads. Prefer reuse:
- Use the same MoveEquipmentRequestDto
- Use the same EventOrderUpsertRequestDto, LockOrderRequestDto, and broken equipment request DTOs where allowed
LOG-MFE-INTG-001 (Shell integration)¶
Shell integration slice is expected to wire: - MFE registration/configuration for navigation - route entry points for admin/self-service UI groups
No new domain DTOs are required here; reuse the contracts above and ensure: - DI registration for interface implementations (stub in MVP; HTTP in the next epic) - shell→MFE route loading works in dev/staging
Stub implementation expectations¶
Stub implementations (in-memory) must emulate the real contract behavior closely enough that UI logic is stable:
Deterministic seed data¶
- Use deterministic IDs and stable timestamps for seeded entities.
- Make time-dependent behavior (like filtering by date range) independent of local machine time by allowing a “clock” or using fixed seed time.
Validation behavior (order + lock)¶
Lock and upsert flows must reflect key business validation surfaced in UI:
- Hall occupancy check failure should populate ValidationProblemDto for form errors or return availability details in LockOrderAvailabilityResultDto.
- Equipment availability check failure should populate availability line details so UI can show “requested vs available”.
Pagination and filtering¶
PagedRequestDtoshould map toPagedResponseDto<T>consistently.- Filtering fields from request DTOs must be honored:
- calendar: date range + optional hall/status
- activity log: date range + type/user + pagination
Error/validation return shape¶
All service methods must return:
- success with data OR
- validation errors in validation OR
- domain errors in error
Avoid mixing exception-driven flows with result-driven flows. If exceptions are used internally, convert them at the service boundary.
UI view-model mapping rules¶
Rule of thumb: - DTOs are contract shapes (service boundary). - View models are UI shapes (page/section boundary). - Mapping must happen in a dedicated mapping layer (or UI service wrapper) so Razor pages remain thin.
Example mapping: calendar list row¶
DTO:
- EventCalendarDto contains EventCalendarCardDto list per day.
VM:
- CalendarCardVm contains the exact fields/labels the calendar component renders (status badge text, click target route, display time format).
Mapping:
- EventCalendarCardDto.status -> CalendarCardVm.statusBadge
- EventCalendarCardDto.startTime/endTime -> CalendarCardVm.displayTimeRange
- EventCalendarCardDto.orderId -> CalendarCardVm.orderId (for navigation)
Example mapping: print/details¶
DTO:
- EventOrderSummaryDto is print-friendly and read-only.
VM:
- EventOrderSummaryVm formats/renames labels, computes derived display strings (e.g., localized time formatting), and provides “Print” metadata.
Mapping:
- EventOrderSummaryDto.equipmentLines -> EventOrderSummaryVm.equipmentRows
- EventOrderSummaryDto.eventDate/startTime/endTime -> EventOrderSummaryVm.timeRangeDisplay
Testing checklist for DTO/service contracts¶
Even before the real backend exists, stub contracts should be testable:
- Unit tests for stub filtering/pagination:
- calendar date range selection
- activity log filters by type/date/user
- Unit tests for validation and availability:
- LockOrderAsync hall occupancy failure returns consistent LockOrderAvailabilityResultDto
- LockOrderAsync equipment insufficiency returns line-level availability
- Unit tests for mapping:
- DTO-to-VM mapping populates the exact fields the UI expects (status badge text, display time ranges)
Implementation notes¶
This doc is intentionally contract-focused:
- It does not assume a specific backend transport.
- It supports stub-first development by stabilizing DTO/service shapes early.
- When the HTTP backend epic arrives, implementations can be swapped without changing UI pages, only by updating the Services/Http implementations and DTO conformance if needed.