task ep.1.4

This commit is contained in:
phaichayon
2026-07-13 12:48:33 +07:00
parent d78c56148e
commit 06af36156f
18 changed files with 10513 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
import {
boolean,
doublePrecision,
index,
integer,
jsonb,
pgTable,
@@ -451,6 +452,172 @@ export const appNotificationDeliveries = pgTable('app_notification_deliveries',
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
});
export const businessEventOutbox = pgTable(
'business_event_outbox',
{
id: text('id').primaryKey(),
organizationId: text('organization_id').notNull(),
eventType: text('event_type').notNull(),
schemaVersion: integer('schema_version').notNull(),
entityType: text('entity_type').notNull(),
entityId: text('entity_id').notNull(),
correlationId: text('correlation_id').notNull(),
causationId: text('causation_id'),
eventEnvelope: jsonb('event_envelope').notNull(),
deliveryStatus: text('delivery_status').default('pending').notNull(),
attemptCount: integer('attempt_count').default(0).notNull(),
availableAt: timestamp('available_at', { withTimezone: true }).defaultNow().notNull(),
processingStartedAt: timestamp('processing_started_at', { withTimezone: true }),
dispatchedAt: timestamp('dispatched_at', { withTimezone: true }),
failedAt: timestamp('failed_at', { withTimezone: true }),
deadLetteredAt: timestamp('dead_lettered_at', { withTimezone: true }),
lastErrorCode: text('last_error_code'),
lastErrorMessage: text('last_error_message'),
occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => ({
statusAvailableIdx: index('business_event_outbox_status_available_idx').on(
table.deliveryStatus,
table.availableAt
),
organizationEventIdx: index('business_event_outbox_org_event_idx').on(
table.organizationId,
table.eventType
)
})
);
export const projectionConsumerCheckpoints = pgTable(
'projection_consumer_checkpoints',
{
id: text('id').primaryKey(),
organizationId: text('organization_id').notNull(),
consumerName: text('consumer_name').notNull(),
projectionName: text('projection_name').notNull(),
eventId: text('event_id').notNull(),
eventType: text('event_type').notNull(),
schemaVersion: integer('schema_version').notNull(),
processingStatus: text('processing_status').default('pending').notNull(),
attemptCount: integer('attempt_count').default(0).notNull(),
firstAttemptedAt: timestamp('first_attempted_at', { withTimezone: true }),
lastAttemptedAt: timestamp('last_attempted_at', { withTimezone: true }),
completedAt: timestamp('completed_at', { withTimezone: true }),
nextRetryAt: timestamp('next_retry_at', { withTimezone: true }),
errorCode: text('error_code'),
errorMessage: text('error_message'),
processingDurationMs: integer('processing_duration_ms'),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => ({
consumerEventIdx: uniqueIndex('projection_checkpoints_consumer_event_idx').on(
table.consumerName,
table.eventId
),
statusRetryIdx: index('projection_checkpoints_status_retry_idx').on(
table.processingStatus,
table.nextRetryAt
)
})
);
export const projectionDeadLetters = pgTable(
'projection_dead_letters',
{
id: text('id').primaryKey(),
organizationId: text('organization_id').notNull(),
consumerName: text('consumer_name').notNull(),
projectionName: text('projection_name').notNull(),
eventId: text('event_id').notNull(),
eventType: text('event_type').notNull(),
schemaVersion: integer('schema_version').notNull(),
attemptCount: integer('attempt_count').notNull(),
errorCode: text('error_code').notNull(),
errorMessage: text('error_message').notNull(),
failureMetadata: jsonb('failure_metadata'),
status: text('status').default('open').notNull(),
resolvedAt: timestamp('resolved_at', { withTimezone: true }),
resolvedBy: text('resolved_by'),
resolutionReason: text('resolution_reason'),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => ({
consumerEventIdx: uniqueIndex('projection_dead_letters_consumer_event_idx').on(
table.consumerName,
table.eventId
),
organizationStatusIdx: index('projection_dead_letters_org_status_idx').on(
table.organizationId,
table.status
)
})
);
export const projectionRebuildRuns = pgTable(
'projection_rebuild_runs',
{
id: text('id').primaryKey(),
organizationId: text('organization_id').notNull(),
projectionName: text('projection_name').notNull(),
entityType: text('entity_type'),
entityId: text('entity_id'),
occurredFrom: timestamp('occurred_from', { withTimezone: true }),
occurredTo: timestamp('occurred_to', { withTimezone: true }),
dryRun: boolean('dry_run').default(true).notNull(),
resetExisting: boolean('reset_existing').default(false).notNull(),
sourceStrategy: text('source_strategy').notNull(),
status: text('status').default('pending').notNull(),
processedCount: integer('processed_count').default(0).notNull(),
skippedCount: integer('skipped_count').default(0).notNull(),
failedCount: integer('failed_count').default(0).notNull(),
errorCode: text('error_code'),
errorMessage: text('error_message'),
requestedBy: text('requested_by').notNull(),
startedAt: timestamp('started_at', { withTimezone: true }),
completedAt: timestamp('completed_at', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => ({
organizationProjectionIdx: index('projection_rebuild_runs_org_projection_idx').on(
table.organizationId,
table.projectionName
)
})
);
export const projectionHealthSnapshots = pgTable(
'projection_health_snapshots',
{
id: text('id').primaryKey(),
organizationId: text('organization_id').notNull(),
projectionName: text('projection_name').notNull(),
consumerName: text('consumer_name').notNull(),
status: text('status').default('healthy').notNull(),
lastProcessedEventId: text('last_processed_event_id'),
lastSuccessfulProcessingAt: timestamp('last_successful_processing_at', { withTimezone: true }),
pendingCount: integer('pending_count').default(0).notNull(),
retryCount: integer('retry_count').default(0).notNull(),
deadLetterCount: integer('dead_letter_count').default(0).notNull(),
unsupportedVersionCount: integer('unsupported_version_count').default(0).notNull(),
processingLagMs: integer('processing_lag_ms').default(0).notNull(),
averageProcessingDurationMs: integer('average_processing_duration_ms').default(0).notNull(),
lastRebuildAt: timestamp('last_rebuild_at', { withTimezone: true }),
rebuildSource: text('rebuild_source'),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => ({
organizationConsumerIdx: uniqueIndex('projection_health_org_consumer_idx').on(
table.organizationId,
table.consumerName
)
})
);
export const crmCustomers = pgTable(
'crm_customers',
{