Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | /**
* Vision Training Sync History Schema
*
* Tracks sync operations between local development and production.
* Provides audit trail for when data was synced, what changed, and tombstone maintenance.
*/
import { createId } from '@paralleldrive/cuid2'
import { index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
/**
* Sync status enum
*/
export type SyncStatus = 'success' | 'failed' | 'cancelled'
/**
* Model type for sync operations
*/
export type SyncModelType = 'column-classifier' | 'boundary-detector'
/**
* Vision training sync history table
*/
export const visionTrainingSyncHistory = sqliteTable(
'vision_training_sync_history',
{
/** Primary key */
id: text('id')
.primaryKey()
.$defaultFn(() => createId()),
// ---- Sync Identification ----
/** Model type: 'column-classifier' | 'boundary-detector' */
modelType: text('model_type').$type<SyncModelType>().notNull(),
/** Sync status */
status: text('status').$type<SyncStatus>().notNull(),
// ---- Timing ----
/** When sync started */
startedAt: integer('started_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
/** When sync completed (null if still running or cancelled) */
completedAt: integer('completed_at', { mode: 'timestamp' }),
/** Duration in milliseconds */
durationMs: integer('duration_ms'),
// ---- Transfer Stats ----
/** Number of files transferred from remote */
filesTransferred: integer('files_transferred').notNull().default(0),
/** Remote file count at sync time */
remoteFilesCount: integer('remote_files_count'),
/** Local file count before sync */
localFilesBefore: integer('local_files_before'),
/** Local file count after sync */
localFilesAfter: integer('local_files_after'),
// ---- Tombstone Stats ----
/** Tombstone entries before pruning */
tombstoneEntriesBefore: integer('tombstone_entries_before'),
/** Tombstone entries after pruning */
tombstoneEntriesAfter: integer('tombstone_entries_after'),
/** Number of tombstone entries pruned */
tombstonePruned: integer('tombstone_pruned'),
/** Files excluded by tombstone during this sync */
filesExcludedByTombstone: integer('files_excluded_by_tombstone'),
// ---- Error Info ----
/** Error message if sync failed */
error: text('error'),
// ---- Metadata ----
/** Remote host used for sync */
remoteHost: text('remote_host'),
/** Additional notes or context */
notes: text('notes'),
},
(table) => ({
/** Index for filtering by model type */
modelTypeIdx: index('vision_sync_history_model_type_idx').on(table.modelType),
/** Index for filtering by status */
statusIdx: index('vision_sync_history_status_idx').on(table.status),
/** Index for sorting by start time */
startedAtIdx: index('vision_sync_history_started_at_idx').on(table.startedAt),
/** Compound index for model type + start time (common query) */
modelTypeStartedAtIdx: index('vision_sync_history_model_type_started_at_idx').on(
table.modelType,
table.startedAt
),
})
)
export type VisionTrainingSyncHistory = typeof visionTrainingSyncHistory.$inferSelect
export type NewVisionTrainingSyncHistory = typeof visionTrainingSyncHistory.$inferInsert
// ============================================================================
// Helper Types
// ============================================================================
/**
* Summary for display in UI
*/
export interface SyncHistorySummary {
id: string
modelType: SyncModelType
status: SyncStatus
startedAt: Date
completedAt: Date | null
durationMs: number | null
filesTransferred: number
tombstonePruned: number | null
error: string | null
}
/**
* Convert a full record to a summary
*/
export function toSyncHistorySummary(record: VisionTrainingSyncHistory): SyncHistorySummary {
return {
id: record.id,
modelType: record.modelType,
status: record.status,
startedAt: record.startedAt,
completedAt: record.completedAt,
durationMs: record.durationMs,
filesTransferred: record.filesTransferred,
tombstonePruned: record.tombstonePruned,
error: record.error,
}
}
|