feat(api): manage localized push template definitions
Add revision-protected reads, atomic upsert and deletion with structured actions. Preserve omitted translations and fix insertion of new push languages. Ref: IT-1627
This commit is contained in:
@@ -264,3 +264,81 @@ allowlist. Rider reported no errors in inspected changed production files; warni
|
||||
remain for existing Firebase Token deprecation, defensive JSON null checks and style.
|
||||
Cognitive complexity was reviewed structurally against the limit of 10; numeric
|
||||
scores were not measured. All changes remain uncommitted for owner review/testing.
|
||||
|
||||
## Push template management REST API (IT-1627, 2026-10-31)
|
||||
|
||||
Push definitions now have the same service-scoped management operations as Email:
|
||||
|
||||
| Method | Route | Purpose |
|
||||
| --- | --- | --- |
|
||||
| GET | `/api/v1/services/{serviceId}/push-template-definitions?key={key}` | Read one exact key |
|
||||
| GET | `/api/v1/services/{serviceId}/push-template-definitions/all` | List Push definitions |
|
||||
| POST | `/api/v1/services/{serviceId}/push-template-definitions/upsert?key={key}` | Create or atomically patch a definition |
|
||||
| DELETE | `/api/v1/services/{serviceId}/push-template-definitions?key={key}&revision={revision}` | Delete only Push, preserving Email |
|
||||
|
||||
Requests and responses use camelCase and the existing `success/data/error` envelope.
|
||||
Create with omitted/null `revision`; an existing key returns 409. Update with the
|
||||
last read nonempty revision; stale/missing definitions return 409. Successful
|
||||
creation returns 201 with Location; update/read/delete return 200. Unknown services
|
||||
or absent reads/deletes return 404; invalid requests return 400.
|
||||
|
||||
Example creation body:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision": null,
|
||||
"variables": [{ "name": "ActorName", "required": true }],
|
||||
"translations": [{
|
||||
"languageCode": "uk",
|
||||
"title": "Довірені контакти",
|
||||
"body": "{{ActorName}} додав вас до довірених контактів.",
|
||||
"actions": {
|
||||
"defaultAction": "contacts",
|
||||
"buttons": [{ "action": "contacts", "label": "Перейти в розділ" }]
|
||||
}
|
||||
}],
|
||||
"removeLanguageCodes": []
|
||||
}
|
||||
```
|
||||
|
||||
The action key above illustrates a producer/client agreement; this endpoint neither
|
||||
registers actions nor activates any Invemory producer. Object IDs are per-message
|
||||
metadata, not template content. `actions` is a structured object, not an escaped JSON
|
||||
string. Omission means no actions for a supplied translation; explicit null is invalid.
|
||||
|
||||
`variables` and `translations` arrays are required (empty is valid). Variables replace
|
||||
the channel-wide contract. Supplied translations replace their full content, including
|
||||
actions. Omitted translations remain; only `removeLanguageCodes` removes versions.
|
||||
Removing every language retains the definition and variables. Codes exactly match the
|
||||
service catalog; duplicate/unknown codes and simultaneous replace/remove are rejected.
|
||||
The final merged definition is validated, including retained translations' placeholders,
|
||||
so a variable change cannot invalidate an omitted translation. Invalid/stale requests
|
||||
leave content and revision unchanged. The existing transaction/advisory lock covers
|
||||
catalog checks, merge and revision-guarded persistence. API and administration share
|
||||
validation and storage, including explicit EF insertion when adding a new language.
|
||||
|
||||
Existing Email endpoints remain unchanged. Both channels can independently use the
|
||||
same service/key. No migration, new registry, access boundary or Android change is
|
||||
needed for these management endpoints. Keep them within the existing private
|
||||
Notification Service administration network boundary.
|
||||
|
||||
Validation of the management API increment: 84 service/unit and 187 PostgreSQL
|
||||
integration tests passed (271 total). After review cleanup, all 29 focused Push API,
|
||||
editor and model tests passed again. Coverage includes parallel create/update conflicts,
|
||||
atomic invalid writes, retained translations, structured localized actions, explicit
|
||||
language removal and Email preservation. Rider reported no errors in inspected files;
|
||||
manual structural complexity review was performed, with no numeric score recorded.
|
||||
Reuse review compared Email definition controllers/handlers, API validation/envelopes,
|
||||
TemplateMutationRunner and the existing Push editor/storage path.
|
||||
|
||||
A separate local Web launch for additional browser validation was rejected by the
|
||||
automatic execution policy without further reason. No standalone-browser or installed
|
||||
Android validation is claimed for this increment; API requests were exercised through
|
||||
the ASP.NET integration host with real PostgreSQL. Changes await owner testing and
|
||||
remain uncommitted; the previously delivered service does not yet include these endpoints.
|
||||
|
||||
Owner follow-up: authorized code delivery and another Kubernetes deployment after
|
||||
verification, and authorized stopping the Rider Web process. The Rider process was
|
||||
stopped. A second background Web launch was rejected by the execution tool with only
|
||||
`blocked by policy`; this is an execution-tool restriction, not a request for more
|
||||
owner permission. The automated API/PostgreSQL checks remain available.
|
||||
|
||||
Reference in New Issue
Block a user