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.
Related Articles
See Also
Keywords
- Notification database
- Database Limitations
- Draft database documentation
Source References
microservices/src/notification-service/Infrastructure/NotificationDbContext.csmicroservices/src/notification-service/Domain/NotificationEntities.csmicroservices/src/notification-service/Application/NotificationDispatcher.csmicroservices/src/notification-service/Infrastructure/Migrations/20260705113059_InitialNotificationSchema.csmicroservices/src/notification-service/Api/NotificationEndpoints.csmicroservices/src/notification-service/Program.csmicroservices/scripts/smoke-notification.ps1
Revision Information
- Status: Draft
- Last reviewed: 2026-07-21
- Review cycle: Quarterly