Files
baya-monorepo/archive/build-chain/working-context/backend/handoff/after-backend-phase-1.md
T
2026-08-02 18:48:32 +03:30

4.3 KiB

After backend-phase-1 — what b2…b15 and the frontend can rely on

The platform backbone is live. Six cross-cutting tables exist in a new ops schema on top of b0's InitialBaseline, seeded with real config + a sample holiday calendar. The mechanisms every later phase needs — typed config, holiday math, audit trail, analytics, in-app notifications, support alerts — are built once, here, behind Application contracts. Reuse them; do not re-create the tables.

Internal contracts b2…b15 must depend on (never reinvent)

All are DI-registered (Scoped) and implemented in Baya.Infrastructure.Persistence/Services/:

  • IPlatformConfigGetConfig<T>(key) (cached, parsed by data_type), SetConfig(key,value) (audited, evicts cache), ListAsync, GetConfigChangeHistory(key). Read money-critical constants here at compute time — never hardcode. Seeded keys: platform_fee_rate, vat_rate (0.10), dispute_window_hours (72), booking_payment_deadline_minutes (30), nurse_response_deadline_hours, nurse_payout_interval_days, evv_location_tolerance_meters, min_rating_for_support_alert, bnpl_merchant_of_record, bnpl_provider_commission_rate, bnpl_settlement_timing, cancellation_tiers. Snapshot the rate you use onto the priced row — a later config change must not re-price it.
  • IHolidayCalendarIsHoliday, IsBankClosed, NextBusinessDay (skips bank-closed days + the Iranian banking weekend = Friday), plus admin CRUD. b13 payout scheduling calls NextBusinessDay.
  • IAuditLoggerWriteAsync(entityType, entityId, action, changedFields?) for state changes with no row diff, plus GetTrailAsync. Row-level diffs on IAuditable entities are written automatically by the extended AuditFieldInterceptor (mark an entity IAuditable; annotate encrypted props [AuditRedacted]). platform_configs is the first IAuditable entity. audit_logs is append-only — never update/delete it.
  • IAnalyticsSinkEmitAsync(name, props); fire-and-forget (system_events). Never route compliance facts here — those go to IAuditLogger.
  • INotificationDispatcherDispatchAsync(Notification(userId, type, title, body?, dataJson?)) now writes a real in-app notifications row (b0 stub gone). This is how booking/payment/review domains mint a user notification. data_json is a typed, versioned deep-link payload — version it.
  • INotificationService — per-user reads/commands (list unread-first, unread count, mark read/all, purge). Always tenant-scoped to ICurrentUser.
  • ISupportAlertServiceRaiseAsync(type, entityType, entityId, severity, bookingId?, reviewId?) for review/EVV/verification/payment flows to call, plus assign/resolve/list. Support alerts are admin-only — never surface them on a user-facing route or in a user notification.

Live endpoints (contract: dev/contracts/domains/config-reference.md)

Admin (DynamicPermission): platform_config/*, holidays/*, audit/get_audit_trail, support_alerts/*. Current-user (Authorize): notifications/* (f14 notification center; f15 admin config/holidays/audit/alerts). Envelope unchanged (camelCase body, snake_case URLs); lists paginated page/page_size.

Migration / schema

New migration 20260701193257_InitialMarketplaceBaseline — the marketplace baseline every later phase adds onto. Applied cleanly to the dev DB (tables + indexes + seed present). Tables live in ops (keep new marketplace tables off usr).

Follow-ups later phases must close

  • FK constraints for support_alerts.booking_id / review_id. The columns exist now (no FK yet). b9 (bookings) adds FK SupportAlerts.BookingId → Bookings; b14 (reviews) adds FK SupportAlerts.ReviewId → Reviews. Do it in the migration that creates those tables.
  • Make-it-real seams (🟡): IHolidayCalendar (real feed/sync), IAnalyticsSink (warehouse), IJobScheduler retention (Hangfire/Quartz), INotificationDispatcher SMS/push channels — see reports/mocks-registry.md.

Caveat (unchanged from b0)

Non-Development Serilog targets the logDb connection; Development boots against the configured SqlServer. A reachable SQL Server is required to run the API (it applies migrations + seeds on boot).