Skip to main content

Notification Database Limitations

Summary​

Every limitation below is a verified property of the reviewed source, grouped by the concern it affects and cross-referenced to the page carrying the evidence.

Audience​

Engineers, architects, QA, support, DevOps engineers, security reviewers and product owners.

Reference Content​

The verified reference material for this topic is set out in the sections below.

Persistence​

  • No relationship is declared anywhere — no navigation property, no foreign key, no cascade rule — so referential integrity is unenforced across all six logical associations.
  • Persistence entities are returned directly on the API wire, coupling the storage model to the published contract.
  • No repository or unit-of-work abstraction exists, so query-level concerns such as tenant scoping cannot be enforced centrally.
  • Delivery attempts carry no tenant column and can only be attributed to a tenant through an unenforced identifier.
  • No check constraint exists on any of the six enumerated string columns, so any value within the length limit is storable.
  • No database-side defaults exist; every default is a C# property initialiser and does not apply to inserts made outside the application.

Concurrency​

  • No row version, concurrency token, locking hint or optimistic-concurrency handling exists anywhere.
  • The idempotency check-then-write window spans the entire processing pipeline, including provider sends and retry delays, so concurrent redelivery can duplicate messages and deliveries before the unique index rejects the second ledger row.
  • The recipient upsert and the template version allocation both read-then-insert without a transaction, producing two further race windows.
  • No unique-violation or update exception is caught anywhere, so every one of these races surfaces as an unhandled failure rather than a recoverable conflict.
  • Nothing prevents a manual retry and an in-flight delivery loop mutating the same message row concurrently; last write wins.

Tenant isolation​

  • The extracted context declares no global query filter, so isolation is opt-in per query and a new query omitting the predicate produces a cross-tenant read silently.
  • Eight of the fifteen resource query paths apply no tenant predicate, including the failed queue, the audit trail and the statistics counts.
  • The idempotency ledger is keyed on the event identifier alone, so event identifiers share one namespace across all tenants.
  • No row-level security, schema-per-tenant or partitioning exists at the database level.
  • The monolith's filters, by contrast, are present but carry a super-admin bypass — a different isolation model on the same logical data.

Transactions​

  • No explicit transaction, savepoint or execution strategy exists; each save is its own implicit transaction.
  • Event processing spans roughly a dozen independent saves and is therefore not atomic.
  • The idempotency ledger row is written last, so a crash mid-processing leaves committed side effects with no duplicate-suppression record, guaranteeing reprocessing on redelivery.
  • The provider send occurs before the state save, so a persistence failure after a successful send loses the record of a delivered notification.
  • Audit rows are saved independently and can record stages whose effects were never committed.

Retry​

  • No retry schedule, due time, lease or queue is persisted; backoff exists only in memory for the duration of one call.
  • A process restart mid-retry leaves the message in its last saved state with no record that further attempts were intended.
  • No dead-letter table exists, and the configured dead-letter names are not wired into the consumer's queue declaration.
  • The message attempt counter is overwritten by each new delivery run rather than accumulated, so it does not represent the lifetime attempt total.
  • No index leads with the message status column, so the failed-queue scan degrades as volume grows.

Testing​

  • No test project in the repository references the persistence context.
  • No mapping, migration, snapshot-drift, repository, concurrency, tenant-isolation or seeding test exists.
  • Persistence is verified only indirectly, through end-to-end smoke assertions on API responses.

Governance​

  • The design-time factory embeds a credentialed local development connection fallback in source.
  • Migrations are applied automatically at startup by every instance, so a multi-instance rollout produces concurrent migration attempts.
  • The migration skip guard also suppresses seeding, coupling two unrelated concerns to one environment variable.
  • The preference table has no write path in any reviewed component, so the feature can only be configured outside the application.

Retention​

  • No delete operation exists anywhere in the service; every table grows monotonically.
  • No cleanup job, purge endpoint, archival routine, retention setting or soft-delete flag exists.
  • Rendered subject and body content, which routinely carries personal data, is retained indefinitely.
  • No deletion path exists for removing an individual's notification history.
  • The idempotency ledger cannot be trimmed without weakening duplicate suppression, because an absent row is indistinguishable from an unprocessed event.

Schema evolution​

  • The schema has exactly one migration and has never been revised, so no upgrade path has been exercised.
  • No down-migration, rollback or idempotent-script artifact is maintained or tested.
  • No snapshot-drift detection runs in continuous integration.
  • Two unrelated persistence models for the same business concept coexist, with no adapter, synchronisation or migration between them.

Classification​

Verified limitations. The schema is Transitional; relationships, concurrency, retention and database testing are Not implemented; tenant isolation, transactions and retry persistence are Partial.

Requires confirmation​

Referential-integrity intent, retention periods, the concurrency posture, and the target state for the two coexisting models all require confirmation.

See Also​

Keywords​

  • Notification database
  • Database Limitations
  • Draft database documentation

Source References​

  • microservices/src/notification-service/Infrastructure/NotificationDbContext.cs
  • microservices/src/notification-service/Domain/NotificationEntities.cs
  • microservices/src/notification-service/Application/NotificationDispatcher.cs
  • microservices/src/notification-service/Infrastructure/Migrations/20260705113059_InitialNotificationSchema.cs
  • microservices/src/notification-service/Api/NotificationEndpoints.cs
  • microservices/src/notification-service/Program.cs
  • microservices/scripts/smoke-notification.ps1

Revision Information​

  • Status: Draft
  • Last reviewed: 2026-07-21
  • Review cycle: Quarterly