with one click
notifly-metric-tracing
// Trace how a Notifly metric label (e.g. send_success, failover_text_message_send_success) is produced from delivery_result/message_events through campaign statistics and API aggregation.
// Trace how a Notifly metric label (e.g. send_success, failover_text_message_send_success) is produced from delivery_result/message_events through campaign statistics and API aggregation.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | notifly-metric-tracing |
| description | Trace how a Notifly metric label (e.g. send_success, failover_text_message_send_success) is produced from delivery_result/message_events through campaign statistics and API aggregation. |
| version | 1.0.0 |
| author | Hermes Agent |
| license | MIT |
Use this when a question asks what a metric in Notifly "really means", whether one event is included in another, or why a campaign stat differs from raw delivery logs.
Map a user-facing metric label to:
delivery_result_* or message_events_*campaign_statistics_*Search for the metric label in the web console and API layers.
Typical files:
services/server/web-console/src/models/campaignStatistics.tsservices/server/api-service/lib/api/v1/statistics/constants.jsservices/server/api-service/lib/api/v1/statistics/services/campaignService.jsservices/server/api-service/lib/api/v1/statistics/services/index.jsservices/server/api-service/lib/api/v1/statistics/utils/aggregateMetricByChannel.jsQuestions to answer:
send_success, failover_text_message_send_success, etc.)message_sent to send_success for that channel?channel, or does it overwrite channel from campaign metadata?services/index.js may reattach channel from campaigns_${projectId} / user journey node details before aggregateMetricByChannel, so verify whether channel semantics come from raw rows or campaign metadata.Search the lambdas that write delivery results.
Useful search patterns:
send_success|send_failurefailover_text_message_send_success|failover_text_message_send_failureis_failover_text_messageorigin_channel|failover_reasonImportant source areas:
services/lambda/*delivery*/services/lambda/*result-poller*/services/lambda/delivery-result-webhook-receiver/services/lambda/notifly-nhn-delivery-result-collector/Check:
channel is writtenevent_name is writtensend_success/send_failure plus a flagWeb console falls back to raw delivery_result if campaign_statistics_* has no rows.
Relevant file:
services/server/web-console/src/services/CampaignStatisticService.tsservices/server/web-console/src/repositories/DeliveryResultRepository.tsKey behavior to verify:
campaign_id and event_nameevent_name AS metric_namechannel separationThis is a common source of semantic drift: text-message failover rows can be counted under a brand-message campaign if grouped only by campaign and event.
Notifly has at least two materially different Kakao/failover paths:
Files:
services/lambda/notifly-nhn-delivery-result-collector/lib/constants.jsservices/lambda/notifly-nhn-delivery-result-collector/lib/kakao_brand_message.jsBehavior:
failover_text_message_send_successfailover_text_message_send_failureImplication:
send_successFiles:
services/lambda/kakao-brand-message-delivery/lib/kakao_bizmessage/send_kakao_brand_message.tsservices/lambda/kakao-delivery-result-poller/service/result_service.tsservices/lambda/kakao-delivery-result-poller/service/failover_service.tsservices/lambda/scheduled-batch-text-message-delivery/services/lambda/delivery-result-webhook-receiver/lib/delivery_result.tsBehavior:
send_success / send_failureevent_params.is_failover_text_message = trueorigin_channelfailover_reasonsend_success / send_failureextra_data.is_failover_text_message = trueImplication:
send_successIf the user asks "Does send_success include failover SMS success?" answer in layers:
campaign_id + event_name and ignores/folds channel, failover text-message send_success can appear inside campaign send_success.failover_text_message_send_success, while newer kakao_bizmessage pipeline uses send_success + failover flags.Use this path when a user has push delivery history but the current user detail screen shows no device information.
users_<projectId> by external_user_id; note notifly_user_id, created_at, and updated_at.device_<projectId> both by current notifly_user_id and by external_user_id; absence here only means the user has no current device row.delivery_result_<projectId> by the resolved notifly_user_id, grouped by channel,event_name; inspect recent rows and extra_data keys.extra_data.token, join that token to current device_<projectId>.device_token. If it now belongs to a different notifly_user_id with blank external_user_id, suspect logout/anonymous transition rather than data loss.message_events_<projectId> for the same old notifly_user_id. Pair delivery_result.send_success with SDK-side events such as push_delivered, push_not_delivered, and push_click; send_success is provider/send-request success, not proof of device display.notifly_event_logs around the device/user transition window for session_start, set_user_properties, and remove_external_user_id filtered by old/new notifly_user_id, external_user_id, and notifly_device_id.services/lambda/kds-consumer/lib/event_utils.ts makes remove_external_user_id return device data with force_update_user_id=true; services/lambda/kds-consumer/lib/device_utils.ts then updates notifly_user_id and external_user_id on conflict for the same notifly_device_id.Common interpretation:
notifly_user_id after remove_external_user_id.message_events.event_name='push_not_delivered' and event_params.reason='missing POST_NOTIFICATIONS permission', the UI may show âëŠěě§ ë°ěĄ ěąęłľâ from delivery_result.send_success, but the actual device-side outcome was push receipt/display failure due to Android notification permission.See references/user-push-history-missing-device.md for a compact SQL/Athena recipe from an investigated case.
services/server/web-console/src/models/campaignStatistics.tsservices/server/web-console/src/services/CampaignStatisticService.tsservices/server/web-console/src/repositories/DeliveryResultRepository.tsservices/server/api-service/lib/api/v1/statistics/constants.jsservices/server/api-service/lib/api/v1/statistics/services/campaignService.jsservices/lambda/notifly-nhn-delivery-result-collector/lib/constants.jsservices/lambda/notifly-nhn-delivery-result-collector/lib/kakao_brand_message.jsservices/lambda/kakao-delivery-result-poller/service/result_service.tsservices/lambda/kakao-delivery-result-poller/service/failover_service.tsservices/lambda/delivery-result-webhook-receiver/lib/delivery_result.tsservices/lambda/kds-consumer/lib/event_utils.tsservices/lambda/kds-consumer/lib/device_utils.tsservices/server/web-console/src/components/users/list/PushLogListComponent.tsxdelivery_result.event_name semantics.campaign_statistics_* is absent, web console derives stats directly from delivery_result_*, which can materially change semantics.Answer with three layers: