Skip to main content

EVENT_SCHEMAS — reporting-service

Sibling: DOMAIN_MODEL · APPLICATION_LOGIC · API_CONTRACTS · DATA_MODEL

Strategic anchors: 04 Event-Driven Architecture · standards/NAMING · standards/ERROR_CODES

All events follow the platform event subject grammar: melmastoon.reporting.<aggregate>.<verb-past-tense>.v<n>. JSON Schemas are committed to event-schemas/melmastoon/reporting/<aggregate>/<verb>.v<n>.json and validated in CI on every PR.


1. Common envelope

Every event is wrapped in the canonical EventEnvelope<T> from 04 §4. Reporting-specific defaults:

FieldValue
producedBy.servicereporting-service
metadata.dataResidency<tenant.region> (typically gcp-me-central1, gcp-asia-south1, or gcp-europe-west4)
metadata.orderingKey<tenantId>:<runId> for run events; <tenantId>:<scheduleId> for schedule events; <tenantId>:<subscriptionId> for subscription events; <tenantId>:<templateId> for template events
causationIdthe consumed event id for inbox-driven emissions; absent for command-driven emissions

2. Subject taxonomy + retention + partition

SubjectRetention classPartition key
melmastoon.reporting.report.requested.v1operational (90d)tenantId:runId
melmastoon.reporting.report.started.v1operational (90d)tenantId:runId
melmastoon.reporting.report.completed.v1regulated (7y for regulatory templates; operational 1y otherwise)tenantId:runId
melmastoon.reporting.report.failed.v1operational (1y)tenantId:runId
melmastoon.reporting.report.delivered.v1regulated (7y)tenantId:subscriptionId
melmastoon.reporting.report.cancelled.v1operational (1y)tenantId:runId
melmastoon.reporting.template.published.v1regulated (10y)tenantId:templateId
melmastoon.reporting.template.archived.v1regulated (10y)tenantId:templateId
melmastoon.reporting.schedule.created.v1operational (2y)tenantId:scheduleId
melmastoon.reporting.schedule.fired.v1operational (90d)tenantId:scheduleId
melmastoon.reporting.schedule.disabled.v1operational (2y)tenantId:scheduleId
melmastoon.reporting.subscription.created.v1operational (2y)tenantId:subscriptionId
melmastoon.reporting.subscription.cancelled.v1operational (2y)tenantId:subscriptionId
melmastoon.reporting.regulatory.submission_due.v1regulated (10y)tenantId:submissionId
melmastoon.reporting.regulatory.submission_succeeded.v1regulated (10y)tenantId:submissionId
melmastoon.reporting.regulatory.submission_failed.v1regulated (10y)tenantId:submissionId

Retention classes follow 04 §5. Sensitive PII never lives in event payloads — recipient emails are reduced to email_hash; report titles in displayName may pass through if the template is non-regulatory and tenant policy allows.


3. Published events — payload + JSON schema sketch + example

3.1 melmastoon.reporting.report.requested.v1

interface ReportRequestedV1 {
runId: string; // run_…
tenantId: string; // tnt_…
reportId: string; // rep_…
templateId: string; // tpl_rep_…
templateVersionNumber: number;
resolvedFilters: Record<string, unknown>; // post-validation, pre-render
formats: Array<'pdf'|'xlsx'|'csv'>;
locale: string; // BCP-47
requestedBy: { type: 'user'|'system'|'scheduler'|'partner'; id: string };
correlationId: string;
idempotencyKey: string;
queuedAt: string; // RFC3339
}

Example envelope:

{
"id": "evt_01H...",
"subject": "melmastoon.reporting.report.requested.v1",
"occurredAt": "2026-04-22T10:00:00Z",
"producedBy": { "service": "reporting-service", "version": "1.4.0" },
"tenantId": "tnt_01H...",
"metadata": { "orderingKey": "tnt_01H...:run_01H...", "dataResidency": "gcp-me-central1" },
"data": {
"runId": "run_01H...",
"tenantId": "tnt_01H...",
"reportId": "rep_01H...",
"templateId": "tpl_rep_01H...",
"templateVersionNumber": 4,
"resolvedFilters": { "propertyId": "ppt_01H...", "stayDate": { "from": "2026-04-22", "to": "2026-04-22" } },
"formats": ["pdf","csv"],
"locale": "fa-AF",
"requestedBy": { "type": "scheduler", "id": "sch_01H..." },
"correlationId": "01H...",
"idempotencyKey": "01H...",
"queuedAt": "2026-04-22T10:00:00Z"
}
}

3.2 melmastoon.reporting.report.started.v1

interface ReportStartedV1 {
runId: string; tenantId: string; reportId: string;
templateVersionNumber: number;
startedAt: string;
workerInstance: string; // Cloud Run instance id (for ops)
}

3.3 melmastoon.reporting.report.completed.v1

interface ReportCompletedV1 {
runId: string; tenantId: string; reportId: string;
templateId: string; templateVersionId: string; templateVersionNumber: number;
completedAt: string;
artifacts: Array<{
artifactId: string; // art_…
format: 'pdf'|'xlsx'|'csv';
locale: string;
sizeBytes: number;
sha256: string;
objectPath: string; // 'tnt_…/run_…/<sha>.pdf'
retentionClass: 'operational_2y'|'operational_7y'|'regulatory_10y_objectlock';
}>;
regulatory?: { jurisdictionCode: string; adapterRef: string }; // when template is regulatory
aiProvenance?: AIProvenance; // when AI assisted (anomaly callouts)
}

JSON Schema (excerpt):

{
"$id": "https://schemas.melmastoon.ghasi.io/reporting/report/completed.v1.json",
"type": "object",
"required": ["runId","tenantId","reportId","templateId","templateVersionId","templateVersionNumber","completedAt","artifacts"],
"properties": {
"runId": { "type": "string", "pattern": "^run_[0-9A-HJKMNP-TV-Z]{26}$" },
"tenantId": { "type": "string", "pattern": "^tnt_[0-9A-HJKMNP-TV-Z]{26}$" },
"artifacts": {
"type": "array", "minItems": 1,
"items": { "type": "object",
"required": ["artifactId","format","locale","sizeBytes","sha256","objectPath","retentionClass"],
"properties": {
"format": { "enum": ["pdf","xlsx","csv"] },
"retentionClass": { "enum": ["operational_2y","operational_7y","regulatory_10y_objectlock"] },
"sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
}
}
}
}
}

3.4 melmastoon.reporting.report.failed.v1

interface ReportFailedV1 {
runId: string; tenantId: string; reportId: string;
templateVersionNumber: number;
failedAt: string;
errorCode: string; // 'MELMASTOON.REPORTING.…' or 'MELMASTOON.GENERAL.INTERNAL'
errorDetail: string; // safe-to-show summary; never includes PII
retriable: boolean;
retryCount: number;
willRetry: boolean;
nextAttemptAt?: string;
}

3.5 melmastoon.reporting.report.delivered.v1

interface ReportDeliveredV1 {
runId: string; tenantId: string; reportId: string;
subscriptionId: string;
channel: 'email'|'in_app'|'desktop_sync'|'webdav'|'sftp';
recipientHash: string; // sha256(tenantSalt + canonical recipient)
deliveredAt: string;
proof?: { kind: 'smtp_250'|'in_app_ack'|'sync_pulled'|'webdav_201'|'sftp_201'; reference?: string };
}

3.6 melmastoon.reporting.report.cancelled.v1

interface ReportCancelledV1 {
runId: string; tenantId: string; reportId: string;
cancelledAt: string;
cancelledBy: { type: 'user'|'system'; id: string };
reason: 'manual'|'scheduler_disabled'|'template_archived'|'tenant_suspended';
}

3.7 melmastoon.reporting.template.published.v1

interface TemplatePublishedV1 {
templateId: string; tenantId: string | null;
templateVersionId: string; versionNumber: number;
key: string; category: 'operational'|'financial'|'compliance'|'regulatory'|'manager_dashboard';
regulatory: boolean;
jurisdictionCode?: string;
retentionClass: 'operational_2y'|'operational_7y'|'regulatory_10y_objectlock';
supportedFormats: Array<'pdf'|'xlsx'|'csv'>;
publishedAt: string;
publishedBy: { type: 'user'|'platform_admin'; id: string };
changesetSummary?: string; // human note from publisher
}

3.8 melmastoon.reporting.template.archived.v1

interface TemplateArchivedV1 {
templateId: string; tenantId: string | null;
archivedAt: string;
archivedBy: { type: 'user'|'platform_admin'; id: string };
reason?: string;
}

3.9 melmastoon.reporting.schedule.created.v1

interface ScheduleCreatedV1 {
scheduleId: string; tenantId: string; reportId: string;
cronExpr: string; timezone: string;
templateVersionPin: number | null;
filters: Record<string, unknown>;
subscriptionIds: string[];
createdAt: string;
createdBy: { type: 'user'; id: string };
}

3.10 melmastoon.reporting.schedule.fired.v1

interface ScheduleFiredV1 {
scheduleId: string; tenantId: string; reportId: string;
firedAt: string; // when Cloud Scheduler hit our endpoint
expectedAt: string; // ideal cron time
driftMs: number; // firedAt - expectedAt
firedRunId?: string; // populated once dispatch succeeded
}

3.11 melmastoon.reporting.schedule.disabled.v1

interface ScheduleDisabledV1 {
scheduleId: string; tenantId: string;
disabledAt: string;
reason: 'manual'|'consecutive_failures'|'template_archived'|'tenant_suspended';
consecutiveFailures: number;
}

3.12 melmastoon.reporting.subscription.created.v1

interface SubscriptionCreatedV1 {
subscriptionId: string; tenantId: string; reportId: string;
recipient: { kind: 'user'|'email'|'desktop_device'|'webdav'|'sftp'; ref: string }; // email reduced to email_hash
channel: 'email'|'in_app'|'desktop_sync'|'webdav'|'sftp';
format: 'pdf'|'xlsx'|'csv';
locale: string;
createdAt: string;
createdBy: { type: 'user'|'system'; id: string };
}

3.13 melmastoon.reporting.subscription.cancelled.v1

interface SubscriptionCancelledV1 {
subscriptionId: string; tenantId: string; reportId: string;
cancelledAt: string;
cancelledBy: { type: 'user'|'system'; id: string };
reason: 'manual'|'recipient_unsubscribed'|'recipient_invalid'|'tenant_suspended';
}

3.14 melmastoon.reporting.regulatory.submission_due.v1

Emitted when a regulatory submission has failed terminally OR when the regulatory window is approaching its deadline without a successful submission. Used by notification-service to escalate to tenant.owner.

interface RegulatorySubmissionDueV1 {
submissionId: string; runId: string; tenantId: string;
jurisdictionCode: string;
adapterRef: string;
due: 'window_approaching' | 'window_missed' | 'retry_exhausted';
windowEndsAt: string;
failureCode?: string;
failureDetail?: string;
attempts: number;
emittedAt: string;
}

3.15 melmastoon.reporting.regulatory.submission_succeeded.v1

interface RegulatorySucceededV1 {
submissionId: string; runId: string; tenantId: string;
jurisdictionCode: string;
adapterRef: string;
attempts: number;
succeededAt: string;
proofOfDelivery: {
receiptKind: 'http_2xx_body'|'signed_xml_receipt'|'sftp_inode_ack'|'paper_print_signature';
receiptHash: string;
receivedAt: string;
registerReference?: string;
storedAtObjectPath: string;
};
}

3.16 melmastoon.reporting.regulatory.submission_failed.v1

interface RegulatoryFailedV1 {
submissionId: string; runId: string; tenantId: string;
jurisdictionCode: string;
adapterRef: string;
attempts: number;
failedAt: string;
errorCode: string; // adapter-mapped, prefixed 'MELMASTOON.REPORTING.SUBMISSION.…'
errorDetail: string;
willRetry: boolean;
nextAttemptAt?: string;
}

4. Consumed events (inbox)

SubjectProducerEffect
melmastoon.reporting.report.completed.v1 (self)this serviceTrigger subscription dispatch + (if regulatory) regulatory dispatch
melmastoon.notification.delivery.recorded.v1notification-serviceUpdate ReportSubscription.lastDeliveryStatus; emit report.delivered.v1
melmastoon.tenant.settings.changed.v1tenant-serviceRefresh tenant cache (jurisdiction, locale, branding ref)
melmastoon.theme_config.theme.updated.v1theme-config-serviceInvalidate branding cache for the tenant
melmastoon.tenant.deleted.v1tenant-serviceCascade soft-delete templates (tenant-private), schedules, subscriptions; mark artifacts for retention-respectful purge
melmastoon.analytics.projection.refreshed.v1analytics-service(Optional) trigger near-realtime template re-render for streaming reports
internal report.run.queued (worker queue)selfWorker pulls and runs StartReportRunUseCase
internal report.run.requeue (backoff)selfRe-queue after delay computed by ReportRun.retryAfter()

All consumers run inside InboxIdempotency middleware keyed by (subject, messageId).


5. Versioning policy

  • Additive changes only within vN: optional new fields with safe defaults.
  • Breaking change (rename, type change, semantic change, required field removal) requires a new v(N+1). Both versions ship in parallel for ≥ 60 days; consumer migration is tracked via the schema registry consumer-status board.
  • Deprecation marks the old version deprecated=true in the registry and emits a daily warning metric reporting_event_deprecated_consumed_total until consumers cut over.

6. Cross-references

  • Outbox / inbox patterns: 04 §6
  • Trace propagation across Pub/Sub: 04 §10
  • Audit / Merkle anchoring of regulatory submissions: 07 §9
  • Notification consumer contract: services/notification-service/EVENT_SCHEMAS.md