Skip to content

fix(notif-seed): align seed.sh + schemas with live config-service behavior (corrections for #37) - #41

Closed
KDwevedi wants to merge 5 commits into
ChakshuGautam:nairobifrom
KDwevedi:feat/notif-pgr-lifecycle-fixes
Closed

fix(notif-seed): align seed.sh + schemas with live config-service behavior (corrections for #37)#41
KDwevedi wants to merge 5 commits into
ChakshuGautam:nairobifrom
KDwevedi:feat/notif-pgr-lifecycle-fixes

Conversation

@KDwevedi

Copy link
Copy Markdown
Collaborator

Surfaces the fixes I had to apply when running #37's seed end-to-end against bomet (ke.bomet, WhatsApp via Twilio production sender). Stacked on top of #37's branch — when #37 merges these merge in cleanly.

Architectural fix (biggest one)

PR #37's `seed.sh` writes data via `mdms-v2 /v2/_create/`. But the runtime chain (`novu-bridge → digit-config-service`) resolves templates from config-service's OWN postgres table (`eg_config_data`), NOT from MDMS-v2. Records written via mdms-v2 _create were invisible to the bridge — every dispatch errored with `NB_CONFIG_RESOLVE_FAILED: No config found for schemaCode=TemplateBinding`.

Fixed: data `_create` now POSTs to `/config-service/config/v1/_create/`. Schema-create stays on mdms-v2 because config-service validates against the schema registered there.

Schema fix

`TemplateBinding.json`: `locale` moved into `required`. Was in `x-unique` only — MDMS-v2 rejected the schema registration with `UNIQUE_ATTRIBUTE_LIST_ERR: Fields provided under unique fields must be a subset of required attributes list`.

Data-file fix

`template-bindings.json`: dropped empty `"contentSid": ""` keys. The `^HX[a-fA-F0-9]{32}$` pattern rejects empty strings; keeping the key absent until a real Twilio Content SID is registered is cleaner. README updated with the WhatsApp Content Template flow.

seed.sh fixes

  • `userInfo` in every RequestInfo. Both mdms-v2 and config-service throw `NullCheckException: UserInfo present inside RequestInfo being sent to enrichAuditDetails method must not be null` without it. Script now captures the full `/oauth/token` response, lifts `UserRequest` into `USERINFO_JSON`, includes it in schema-create AND data-create bodies.
  • Deterministic `uniqueIdentifier`. Built per-schema from x-unique fields. Re-runs reliably hit the existing-record path.
  • Auto-detected config-service URL. Probes `$DIGIT_URL/config-service` first; falls back to `$CONFIG_SERVICE_URL` direct (default `http://digit-config-service:8080\`) when Kong has no `/config-service` route. Lets the script run inside the docker network OR through Kong.

Test plan

  • `docker exec novu-bridge bash /opt/digit/db/notif-mdms-seed/seed.sh` with TENANT + Twilio envs returns `successful` for 2 schemas + 6 TemplateBinding + 1 ProviderDetail records
  • Re-running the seed reports `(already exists — fine)` for each, no errors
  • `POST /user-otp/v1/_send` (with the otp-publisher service from feat(notif): otp-publisher service — real OTPs over Novu + Twilio (implements #38 approach A) #39) triggers SMS / WhatsApp delivery end-to-end
  • Twilio API confirms delivery (status=delivered or status=read)
  • Re-seeding with a tenant that doesn't exist surfaces a clear auth error rather than silently failing

Related

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 16d100f0-a539-474f-ac4f-fdbf55eec407

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

… events

Seeds the TemplateBinding and ProviderDetail records that wire the PGR
complaint-lifecycle events and OTP.SEND to the Novu workflows, so the
novu-bridge can resolve a workflow + provider per (tenant, event,
channel, locale).

Folds the original seed (was WIP ChakshuGautam#37) together with the corrections
that aligned it to live config-service behavior (was ChakshuGautam#41), as one
coherent change on nairobi:

- Data records POST to config-service /config/v1/_create/<schema>,
  not mdms-v2 — config-service has its own eg_config_data table and is
  not a pass-through; records seeded via mdms-v2 were invisible to the
  bridge. Schemas are still registered in mdms-v2 (config-service
  validates creates against them).
- seed.sh captures the full /oauth/token response and includes
  userInfo in every RequestInfo (config-service NullCheckException
  without it); deterministic uniqueIdentifier per schema; auto-detects
  Kong /config-service routing with CONFIG_SERVICE_URL fallback.
- TemplateBinding schema: locale moved to required (MDMS rejected it
  as x-unique-only with UNIQUE_ATTRIBUTE_LIST_ERR).
- template-bindings.json: empty contentSid keys dropped (schema
  pattern ^HX[a-fA-F0-9]{32}$ rejects empty string).
- README documents the config-service architecture + Content Template
  flow for production WhatsApp.

Supersedes ChakshuGautam#37 and ChakshuGautam#38 (WIP plans).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@KDwevedi
KDwevedi force-pushed the feat/notif-pgr-lifecycle-fixes branch from 2fcf2c1 to e73667d Compare May 16, 2026 05:25
@KDwevedi
KDwevedi changed the base branch from feat/notif-pgr-lifecycle to nairobi May 16, 2026 05:25
KDwevedi and others added 3 commits May 16, 2026 12:17
…ved Content SIDs

The 5 lifecycle TemplateBindings (APPLY/ASSIGN/RESOLVE/REJECT/REOPEN)
now carry the real, Meta-approved Twilio WhatsApp Content SIDs that
already exist on the eGov account (EN, *_message_new family), instead
of leaving contentSid absent.

- channel sms -> whatsapp (these SIDs are WhatsApp-approved; the bridge
  resolves the whatsapp channel).
- paramOrder rewritten to map ComplaintsDomainEvent.data keys
  (serviceName/complaintNo/submittedDate/assigneeName/
  assigneeDesignation/departmentName/comment) onto each template's
  {{1}},{{2}},... positions, verified per-SID via the Twilio Content
  API rather than inferred from names.
- templateId unchanged — all 5 Novu workflow ids already exist in
  novu-bridge-endpoint/workflows.js.

OTP.SEND intentionally left on the hardcoded path (no contentSid,
channel sms, not routed): no twilio/authentication template exists on
the account and SMS-OTP needs CCRS ChakshuGautam#43 + an SMS-capable sender first.

README updated: lifecycle WhatsApp is now zero-touch on deploy; Hindi
SIDs exist but stay a follow-up (HI {{n}} order unverified); serviceName
ships as the PGR serviceCode (display-name resolution tracked
separately).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Completes complainant lifecycle coverage (5 -> 7). Both templates are
already Meta-approved on the eGov Twilio account; paramOrder verified
against the live Content API bodies:
- REASSIGN -> HX7dc390... (serviceName,complaintNo,submittedDate,
  assigneeName,assigneeDesignation,departmentName) — same shape as ASSIGN
- RATE -> HXa0ad0e... (serviceName,complaintNo,submittedDate)

Adds matching complaints-workflow-reassign / -rate Novu workflows in
novu-bridge-endpoint (the trigger needs the workflow to exist even
though WhatsApp content is rendered from the Twilio contentSid
passthrough). Requires a novu-bridge-endpoint redeploy + bridge
re-sync to go live; seed rows land on next deploy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rect live tenants)

A create-only seed cannot fix an already-deployed tenant: config-service
rejects a repeat _create for the same x-unique tuple with
DUPLICATE_RECORD, so a stale row (wrong channel / missing contentSid /
placeholder Twilio token) silently survives a re-run. Surfaced on Bomet
2026-05-16 — lifecycle bindings AND the Twilio ProviderDetail were stale
and the reseed was a no-op until corrected by hand.

- On DUPLICATE: _search the existing record, match on the x-unique DATA
  tuple (eventName,channel,locale / providerName,channel) NOT the
  uniqueIdentifier string (legacy rows carry a stale '.sms.' id whose
  data was later flipped to whatsapp), then _update by its id (which
  config-service _update requires).
- Probe for a base that can _search; Kong routes _create/_resolve but
  not _search/_update, so the upsert needs config-service directly.
  Falls back to create-only with a loud WARNING when only Kong is
  reachable (re-run in-cluster to apply corrections).
- Explicit per-record status: created / updated / SKIPPED / FAILED.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nant scoping

Two corrections surfaced deploying the producer to Bomet (2026-05-16):

- provider-details.json had channel=sms. The bridge dispatches on
  NOVU_BRIDGE_CHANNEL (default whatsapp, ChakshuGautam#42) and the lifecycle
  bindings are whatsapp, so an sms provider is never resolved
  (NB_PROVIDERS_NOT_FOUND) — WhatsApp lifecycle silently never sends.
  Set channel=whatsapp to match the bindings + bridge default.

- README: config-service resolves TemplateBinding/ProviderDetail by
  EXACT tenantId (no hierarchy fallback). On a single-city deploy the
  citizen UI files complaints under the root tenant (ke), not the city
  tenant (ke.bomet); seeding only ke.bomet makes every real complaint
  fail CONFIG_NOT_RESOLVED. Documented: seed at the tenant the PGR
  events actually carry.

Verified end-to-end on Bomet: real CCRS pgr-services emits
COMPLAINTS.WORKFLOW.APPLY (tenant ke) -> bridge resolves -> Twilio
WhatsApp delivered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@KDwevedi

Copy link
Copy Markdown
Collaborator Author

Pulled into #52 (notif-mdms-seed PGR-lifecycle schemas + seed.sh). Closing as merged-via-#52.

@KDwevedi KDwevedi closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant