Files
hrynco-notification-service/docs/email-channel-service-link.md
agrynco 1631786ce2 feat(push): add service-owned firebase channels and delivery
Add push contracts, provider delivery and channel diagnostics. Link email channels to services and document migration and validation.

Ref: IT-1074
2026-10-24 12:31:35 +03:00

80 lines
4.9 KiB
Markdown

# Email channels: stable service association
Email channels reference `services.id` (UUID) through required `email_channels.service_id`.
The `(service_id, priority)` index supports channel selection; the service FK uses RESTRICT,
so service deletion cannot remove channels or their usage. Service names in channel reads
come from the related service, not a copied string. Create/Edit select an existing service;
Edit can reassign a channel without changing its identity or statistics.
## Migration
`LinkEmailChannelsToServices` validates every legacy channel name before replacing the
string column. An exact, case-sensitive service-name match is accepted. The owner-approved
legacy mapping `StoreMate-Prod` → `Invemory-Prod` is also accepted; the existing staging
name `Invemory.Staging.Sandbox` uses an exact match. Every channel must have exactly one
candidate service. Missing names or ambiguity (for example both legacy and renamed
services existing) abort the migration. No service is guessed, created, renamed or deleted.
The migration runs in an EF transaction and locks services/channels while checking and
backfilling. Failure rolls back schema and data. Channel IDs, SMTP settings (including
secrets and sender settings), priority, quotas, warning threshold, active state, timestamps
and usage records remain unchanged. No SMTP settings are logged by the migration.
Downgrade reconstructs the current service names; historical names are not restored.
Before a separately authorized rollout, audit unmatched/ambiguous names and resolve them
with the owner, take the normal backup, and coordinate Web/Worker downtime with migration:
old binaries use the removed `service_name` column. Administrative POST/PUT clients must
send `serviceId`; name-only writes are no longer supported. RabbitMQ producers retain
their existing `ServiceName` wire field and must send the current service name. The
approved legacy mapping applies only during migration, never as a runtime fallback.
## Verification
### Local database update on Windows
Run from any directory, without arguments or environment setup:
```bat
C:\projects\HrynCo\hrynco-notification-service\HrynCo.NotificationService.DAL.EF\update-development-database.bat
```
The script resolves its directory through %~dp0, reads the existing Web
`appsettings.Development.json`, builds the EF project in Release and applies pending
migrations. It requires dotnet-ef and Windows PowerShell. It validates a loopback host and a nonempty database name before invoking EF.
The port and database come from the Development configuration without hardcoded overrides.
A remote host is rejected; this script is specifically for the local development database. It never installs, recreates or restarts containers.
The connection is passed only through the child process's `App__ConnectionString`;
the design-time factory reads it. Credentials are neither echoed nor passed as CLI
arguments, and inherited connection overrides are replaced with the verified Development
configuration. The script returns EF's exit code (or a nonzero code for configuration
failure). Restart local Web/Worker after a schema change to use matching binaries.
### Tests
PostgreSQL integration tests exercise exact and approved-alias backfill, preserved channel
settings/limits/usage, downgrade, missing/ambiguous-name rollback, FK enforcement, service
rename, API validation, editable reassignment with a blank password, and service deletion
after reassignment. Worker tests verify name-to-ID channel resolution and sending/usage.
All migration rehearsals use disposable local databases; they do not alter production.
On 2026-10-24, the Release solution build, 54 service/worker tests and 145 integration
tests passed. A follow-up check explicitly verified both invalid update IDs reach the
service-existence validator (2/2 passed). Rider inspected the changed production methods;
remaining findings were existing/style suggestions. Cognitive complexity was reviewed
structurally against the limit of 10; no numeric score was produced by the inspection.
After separate owner authorization, the existing local container database was backed up
and updated with the already-built Migrator. Its two pending migrations were
`20261023223753_AddPushDeliveries` and `20261024073202_LinkEmailChannelsToServices`.
No email channels or usage records existed in this local database before the update;
their unchanged empty state and the installed RESTRICT FK were verified afterwards.
The development batch script was then executed from its own folder and another working
directory: both returned 0 and reported no pending migrations. An isolated fake EF
failure verified exit-code propagation (37). The current local Web at port 5188 rendered
the dropdown with the existing service catalog. Disposable test containers were removed.
Production was not accessed or migrated.
The existing private-network administration access model is unchanged. This change does
not configure Firebase or resume the paused push-channel architecture.