Files
clockula/app/schemas/de.jeanlucmakiola.clockula.data.db.ClockulaDatabase/2.json
T
makiolajandClaude Opus 5 f4b7c1a16c feat(data): ring state in a new alarm_states table at schema v2
Snooze, the handled-occurrence watermark and the skip watermark need somewhere
to live that survives a process death. They go in their own table rather than
as columns on alarms: a missing row is the initial record, and the FK cascade
means deleting an alarm cannot leave orphaned ring state behind.

Schema v2 is exported and committed alongside v1, so MIGRATION_1_2 is
reviewable and testable rather than taken on faith.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:04:26 +02:00

370 lines
11 KiB
JSON

{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "5e5fd3a9d31d77a7aa57306836ab19ad",
"entities": [
{
"tableName": "alarms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `hour` INTEGER NOT NULL, `minute` INTEGER NOT NULL, `label` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `repeat_days` INTEGER NOT NULL, `skip_next_occurrence` INTEGER NOT NULL, `ringtone_uri` TEXT, `vibrate` INTEGER, `snooze_minutes` INTEGER, `snooze_limit` INTEGER, `volume_ramp_seconds` INTEGER, `dismiss_challenge` TEXT, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "hour",
"columnName": "hour",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minute",
"columnName": "minute",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "label",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enabled",
"columnName": "enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "repeatDays",
"columnName": "repeat_days",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "skipNextOccurrence",
"columnName": "skip_next_occurrence",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ringtoneUri",
"columnName": "ringtone_uri",
"affinity": "TEXT"
},
{
"fieldPath": "vibrate",
"columnName": "vibrate",
"affinity": "INTEGER"
},
{
"fieldPath": "snoozeMinutes",
"columnName": "snooze_minutes",
"affinity": "INTEGER"
},
{
"fieldPath": "snoozeLimit",
"columnName": "snooze_limit",
"affinity": "INTEGER"
},
{
"fieldPath": "volumeRampSeconds",
"columnName": "volume_ramp_seconds",
"affinity": "INTEGER"
},
{
"fieldPath": "dismissChallenge",
"columnName": "dismiss_challenge",
"affinity": "TEXT"
},
{
"fieldPath": "createdAt",
"columnName": "created_at",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "updatedAt",
"columnName": "updated_at",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_alarms_enabled",
"unique": false,
"columnNames": [
"enabled"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_alarms_enabled` ON `${TABLE_NAME}` (`enabled`)"
}
]
},
{
"tableName": "alarm_states",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alarm_id` INTEGER NOT NULL, `snoozed_until` INTEGER, `snooze_count` INTEGER NOT NULL, `ringing_since` INTEGER, `handled_occurrence` INTEGER, `skipped_occurrence` INTEGER, PRIMARY KEY(`alarm_id`), FOREIGN KEY(`alarm_id`) REFERENCES `alarms`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "alarmId",
"columnName": "alarm_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "snoozedUntil",
"columnName": "snoozed_until",
"affinity": "INTEGER"
},
{
"fieldPath": "snoozeCount",
"columnName": "snooze_count",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ringingSince",
"columnName": "ringing_since",
"affinity": "INTEGER"
},
{
"fieldPath": "handledOccurrence",
"columnName": "handled_occurrence",
"affinity": "INTEGER"
},
{
"fieldPath": "skippedOccurrence",
"columnName": "skipped_occurrence",
"affinity": "INTEGER"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"alarm_id"
]
},
"foreignKeys": [
{
"table": "alarms",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"alarm_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "timers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `label` TEXT NOT NULL, `duration_millis` INTEGER NOT NULL, `state` TEXT NOT NULL, `remaining_millis` INTEGER NOT NULL, `started_at_elapsed_realtime_millis` INTEGER, `ends_at_elapsed_realtime_millis` INTEGER, `ends_at_wall_clock_millis` INTEGER, `ringtone_uri` TEXT, `sort_order` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "label",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "durationMillis",
"columnName": "duration_millis",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "state",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "remainingMillis",
"columnName": "remaining_millis",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "startedAtElapsedRealtimeMillis",
"columnName": "started_at_elapsed_realtime_millis",
"affinity": "INTEGER"
},
{
"fieldPath": "endsAtElapsedRealtimeMillis",
"columnName": "ends_at_elapsed_realtime_millis",
"affinity": "INTEGER"
},
{
"fieldPath": "endsAtWallClockMillis",
"columnName": "ends_at_wall_clock_millis",
"affinity": "INTEGER"
},
{
"fieldPath": "ringtoneUri",
"columnName": "ringtone_uri",
"affinity": "TEXT"
},
{
"fieldPath": "sortOrder",
"columnName": "sort_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "createdAt",
"columnName": "created_at",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "updatedAt",
"columnName": "updated_at",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_timers_sort_order",
"unique": false,
"columnNames": [
"sort_order"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_timers_sort_order` ON `${TABLE_NAME}` (`sort_order`)"
}
]
},
{
"tableName": "world_clocks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `zone_id` TEXT NOT NULL, `label` TEXT, `sort_order` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "zoneId",
"columnName": "zone_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "label",
"affinity": "TEXT"
},
{
"fieldPath": "sortOrder",
"columnName": "sort_order",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_world_clocks_zone_id",
"unique": true,
"columnNames": [
"zone_id"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_world_clocks_zone_id` ON `${TABLE_NAME}` (`zone_id`)"
},
{
"name": "index_world_clocks_sort_order",
"unique": false,
"columnNames": [
"sort_order"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_world_clocks_sort_order` ON `${TABLE_NAME}` (`sort_order`)"
}
]
},
{
"tableName": "stopwatch_laps",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `lap_index` INTEGER NOT NULL, `split_millis` INTEGER NOT NULL, `cumulative_millis` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lapIndex",
"columnName": "lap_index",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "splitMillis",
"columnName": "split_millis",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "cumulativeMillis",
"columnName": "cumulative_millis",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_stopwatch_laps_lap_index",
"unique": true,
"columnNames": [
"lap_index"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_stopwatch_laps_lap_index` ON `${TABLE_NAME}` (`lap_index`)"
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5e5fd3a9d31d77a7aa57306836ab19ad')"
]
}
}