migrations.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. package store
  2. func migrationStatements(version int) []string {
  3. switch version {
  4. case 1:
  5. return []string{
  6. `CREATE TABLE IF NOT EXISTS admins (
  7. id INTEGER PRIMARY KEY CHECK (id = 1),
  8. username TEXT NOT NULL UNIQUE,
  9. password_hash BLOB NOT NULL,
  10. created_at INTEGER NOT NULL,
  11. updated_at INTEGER NOT NULL
  12. )`,
  13. `CREATE TABLE IF NOT EXISTS sessions (
  14. token_hash BLOB PRIMARY KEY,
  15. admin_id INTEGER NOT NULL,
  16. csrf_hash BLOB NOT NULL,
  17. expires_at INTEGER NOT NULL,
  18. created_at INTEGER NOT NULL,
  19. FOREIGN KEY (admin_id) REFERENCES admins(id) ON DELETE CASCADE
  20. )`,
  21. `CREATE INDEX IF NOT EXISTS sessions_expires_at_idx ON sessions(expires_at)`,
  22. }
  23. case 2:
  24. return domainSchemaV2
  25. case 3:
  26. return []string{
  27. `CREATE TABLE phone_associations (
  28. iccid TEXT PRIMARY KEY,
  29. device_id TEXT NOT NULL DEFAULT '',
  30. number TEXT NOT NULL,
  31. source TEXT NOT NULL,
  32. created_at INTEGER NOT NULL,
  33. updated_at INTEGER NOT NULL
  34. )`,
  35. `CREATE INDEX phone_associations_device_idx
  36. ON phone_associations(device_id, updated_at DESC)`,
  37. }
  38. case 4:
  39. return []string{
  40. // The conversation UI is a received-message view. Keep the SMSC
  41. // timestamp for diagnostics, but display the first local receipt time.
  42. `UPDATE sms_messages
  43. SET extra_json = json_set(
  44. extra_json,
  45. '$.service_center_timestamp_unix', message_time,
  46. '$.received_at_unix', created_at
  47. ),
  48. message_time = created_at,
  49. updated_at = CAST(strftime('%s', 'now') AS INTEGER)
  50. WHERE source = 'ims'
  51. AND json_valid(extra_json)
  52. AND COALESCE(json_extract(extra_json, '$.raw_tpdu'), '') <> ''`,
  53. }
  54. case 5:
  55. return []string{
  56. // Earlier IMS persistence labelled every non-delivered submission as
  57. // accepted_by_ims, including explicit SIP/RP rejection evidence.
  58. `UPDATE sms_messages
  59. SET delivery_state = 'failed',
  60. updated_at = CAST(strftime('%s', 'now') AS INTEGER)
  61. WHERE source = 'ims'
  62. AND direction IN ('outbound', 'sent')
  63. AND delivery_state = 'accepted_by_ims'
  64. AND (
  65. LOWER(status) LIKE '%reject%'
  66. OR LOWER(status) LIKE '%fail%'
  67. OR LOWER(status) LIKE '%partial%'
  68. )`,
  69. }
  70. case 6:
  71. return []string{
  72. `CREATE TABLE IF NOT EXISTS device_proxy_bindings (
  73. device_id TEXT PRIMARY KEY,
  74. upstream_proxy_id TEXT NOT NULL,
  75. created_at INTEGER NOT NULL,
  76. updated_at INTEGER NOT NULL,
  77. FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE,
  78. FOREIGN KEY (upstream_proxy_id) REFERENCES upstream_proxies(id) ON DELETE CASCADE
  79. )`,
  80. `CREATE INDEX IF NOT EXISTS device_proxy_bindings_proxy_idx
  81. ON device_proxy_bindings(upstream_proxy_id)`,
  82. }
  83. default:
  84. return nil
  85. }
  86. }
  87. var domainSchemaV2 = []string{
  88. `CREATE TABLE devices (
  89. id TEXT PRIMARY KEY,
  90. name TEXT NOT NULL,
  91. interface TEXT NOT NULL DEFAULT '',
  92. control_device TEXT NOT NULL DEFAULT '',
  93. at_port TEXT NOT NULL DEFAULT '',
  94. usb_path TEXT NOT NULL DEFAULT '',
  95. audio_device TEXT NOT NULL DEFAULT '',
  96. modem_imei TEXT NOT NULL DEFAULT '',
  97. apn TEXT NOT NULL DEFAULT '',
  98. proxy_port INTEGER NOT NULL DEFAULT 0 CHECK (proxy_port BETWEEN 0 AND 65535),
  99. baud_rate INTEGER NOT NULL DEFAULT 115200 CHECK (baud_rate > 0),
  100. data_bits INTEGER NOT NULL DEFAULT 8,
  101. stop_bits INTEGER NOT NULL DEFAULT 1,
  102. parity TEXT NOT NULL DEFAULT 'none',
  103. device_backend TEXT NOT NULL DEFAULT 'at',
  104. esim_transport TEXT NOT NULL DEFAULT 'at',
  105. qmi_use_proxy INTEGER NOT NULL DEFAULT 1 CHECK (qmi_use_proxy IN (0, 1)),
  106. qmi_proxy_path TEXT NOT NULL DEFAULT '',
  107. qmi_proxy_executable TEXT NOT NULL DEFAULT '',
  108. network_enabled INTEGER NOT NULL DEFAULT 0 CHECK (network_enabled IN (0, 1)),
  109. sms_enabled INTEGER NOT NULL DEFAULT 1 CHECK (sms_enabled IN (0, 1)),
  110. vowifi_enabled INTEGER NOT NULL DEFAULT 0 CHECK (vowifi_enabled IN (0, 1)),
  111. extra_json TEXT NOT NULL DEFAULT '{}',
  112. created_at INTEGER NOT NULL,
  113. updated_at INTEGER NOT NULL
  114. )`,
  115. `CREATE INDEX devices_interface_idx ON devices(interface)`,
  116. `CREATE INDEX devices_imei_idx ON devices(modem_imei)`,
  117. `CREATE TABLE device_runtime (
  118. device_id TEXT PRIMARY KEY,
  119. running INTEGER NOT NULL DEFAULT 0 CHECK (running IN (0, 1)),
  120. healthy INTEGER NOT NULL DEFAULT 0 CHECK (healthy IN (0, 1)),
  121. control_online INTEGER NOT NULL DEFAULT 0 CHECK (control_online IN (0, 1)),
  122. physical_present INTEGER NOT NULL DEFAULT 0 CHECK (physical_present IN (0, 1)),
  123. worker_running INTEGER NOT NULL DEFAULT 0 CHECK (worker_running IN (0, 1)),
  124. data_connected INTEGER NOT NULL DEFAULT 0 CHECK (data_connected IN (0, 1)),
  125. radio_registered INTEGER NOT NULL DEFAULT 0 CHECK (radio_registered IN (0, 1)),
  126. network_connected INTEGER NOT NULL DEFAULT 0 CHECK (network_connected IN (0, 1)),
  127. flight_mode INTEGER NOT NULL DEFAULT 0 CHECK (flight_mode IN (0, 1)),
  128. lifecycle_phase TEXT NOT NULL DEFAULT '',
  129. lifecycle_reason TEXT NOT NULL DEFAULT '',
  130. public_ip TEXT NOT NULL DEFAULT '',
  131. private_ip TEXT NOT NULL DEFAULT '',
  132. operator TEXT NOT NULL DEFAULT '',
  133. native_mcc TEXT NOT NULL DEFAULT '',
  134. native_mnc TEXT NOT NULL DEFAULT '',
  135. native_spn TEXT NOT NULL DEFAULT '',
  136. network_mode TEXT NOT NULL DEFAULT '',
  137. network_duplex TEXT NOT NULL DEFAULT '',
  138. radio_band TEXT NOT NULL DEFAULT '',
  139. radio_channel INTEGER NOT NULL DEFAULT 0,
  140. signal_dbm INTEGER NOT NULL DEFAULT 0,
  141. signal_rsrp INTEGER,
  142. signal_rsrq INTEGER,
  143. signal_sinr INTEGER,
  144. imei TEXT NOT NULL DEFAULT '',
  145. iccid TEXT NOT NULL DEFAULT '',
  146. imsi TEXT NOT NULL DEFAULT '',
  147. firmware TEXT NOT NULL DEFAULT '',
  148. reg_status INTEGER NOT NULL DEFAULT 0,
  149. reg_status_text TEXT NOT NULL DEFAULT '',
  150. ps_attached INTEGER CHECK (ps_attached IN (0, 1)),
  151. sim_inserted INTEGER CHECK (sim_inserted IN (0, 1)),
  152. operating_mode INTEGER,
  153. phone_number TEXT NOT NULL DEFAULT '',
  154. phone_number_source TEXT NOT NULL DEFAULT '',
  155. traffic_json TEXT NOT NULL DEFAULT '{}',
  156. extra_json TEXT NOT NULL DEFAULT '{}',
  157. updated_at INTEGER NOT NULL,
  158. FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE
  159. )`,
  160. `CREATE INDEX device_runtime_iccid_idx ON device_runtime(iccid)`,
  161. `CREATE INDEX device_runtime_imsi_idx ON device_runtime(imsi)`,
  162. `CREATE TABLE vowifi_runtime (
  163. device_id TEXT PRIMARY KEY,
  164. phase TEXT NOT NULL DEFAULT '',
  165. dataplane_mode TEXT NOT NULL DEFAULT '',
  166. iccid TEXT NOT NULL DEFAULT '',
  167. imsi TEXT NOT NULL DEFAULT '',
  168. sim_ready INTEGER NOT NULL DEFAULT 0 CHECK (sim_ready IN (0, 1)),
  169. access_ready INTEGER NOT NULL DEFAULT 0 CHECK (access_ready IN (0, 1)),
  170. tunnel_ready INTEGER NOT NULL DEFAULT 0 CHECK (tunnel_ready IN (0, 1)),
  171. ims_ready INTEGER NOT NULL DEFAULT 0 CHECK (ims_ready IN (0, 1)),
  172. sms_ready INTEGER NOT NULL DEFAULT 0 CHECK (sms_ready IN (0, 1)),
  173. reg_status INTEGER NOT NULL DEFAULT 0,
  174. reg_status_text TEXT NOT NULL DEFAULT '',
  175. network_mode TEXT NOT NULL DEFAULT '',
  176. local_phone TEXT NOT NULL DEFAULT '',
  177. phone_number_source TEXT NOT NULL DEFAULT '',
  178. last_error_class TEXT NOT NULL DEFAULT '',
  179. last_error TEXT NOT NULL DEFAULT '',
  180. last_reason TEXT NOT NULL DEFAULT '',
  181. tunnel_json TEXT NOT NULL DEFAULT '{}',
  182. imscore_json TEXT NOT NULL DEFAULT '{}',
  183. smsip_json TEXT NOT NULL DEFAULT '{}',
  184. extra_json TEXT NOT NULL DEFAULT '{}',
  185. updated_at INTEGER NOT NULL,
  186. FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE
  187. )`,
  188. `CREATE INDEX vowifi_runtime_ims_ready_idx ON vowifi_runtime(ims_ready)`,
  189. `CREATE TABLE sms_messages (
  190. id INTEGER PRIMARY KEY AUTOINCREMENT,
  191. message_id TEXT NOT NULL DEFAULT '',
  192. device_id TEXT NOT NULL,
  193. imsi TEXT NOT NULL DEFAULT '',
  194. peer TEXT NOT NULL,
  195. direction TEXT NOT NULL,
  196. body TEXT NOT NULL DEFAULT '',
  197. message_time INTEGER NOT NULL,
  198. status TEXT NOT NULL DEFAULT '',
  199. source TEXT NOT NULL DEFAULT '',
  200. parts_total INTEGER NOT NULL DEFAULT 1 CHECK (parts_total > 0),
  201. delivery_state TEXT NOT NULL DEFAULT '',
  202. is_read INTEGER NOT NULL DEFAULT 0 CHECK (is_read IN (0, 1)),
  203. extra_json TEXT NOT NULL DEFAULT '{}',
  204. created_at INTEGER NOT NULL,
  205. updated_at INTEGER NOT NULL
  206. )`,
  207. `CREATE UNIQUE INDEX sms_messages_external_id_idx
  208. ON sms_messages(device_id, message_id)
  209. WHERE message_id <> ''`,
  210. `CREATE INDEX sms_messages_thread_idx
  211. ON sms_messages(device_id, imsi, peer, message_time DESC, id DESC)`,
  212. `CREATE INDEX sms_messages_time_idx ON sms_messages(message_time DESC)`,
  213. `CREATE TABLE local_proxy_config (
  214. id TEXT PRIMARY KEY,
  215. name TEXT NOT NULL,
  216. mode TEXT NOT NULL CHECK (mode IN ('socks5', 'http')),
  217. device_id TEXT NOT NULL,
  218. listen_addr TEXT NOT NULL,
  219. listen_port INTEGER NOT NULL CHECK (listen_port BETWEEN 1 AND 65535),
  220. enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1)),
  221. auth_enabled INTEGER NOT NULL DEFAULT 0 CHECK (auth_enabled IN (0, 1)),
  222. username TEXT NOT NULL DEFAULT '',
  223. password TEXT NOT NULL DEFAULT '',
  224. extra_json TEXT NOT NULL DEFAULT '{}',
  225. created_at INTEGER NOT NULL,
  226. updated_at INTEGER NOT NULL,
  227. FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE
  228. )`,
  229. `CREATE INDEX local_proxy_device_idx ON local_proxy_config(device_id)`,
  230. `CREATE TABLE upstream_proxies (
  231. id TEXT PRIMARY KEY,
  232. name TEXT NOT NULL,
  233. addr TEXT NOT NULL,
  234. username TEXT NOT NULL DEFAULT '',
  235. password TEXT NOT NULL DEFAULT '',
  236. enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1)),
  237. extra_json TEXT NOT NULL DEFAULT '{}',
  238. created_at INTEGER NOT NULL,
  239. updated_at INTEGER NOT NULL
  240. )`,
  241. `CREATE TABLE country_rules (
  242. country_code TEXT PRIMARY KEY,
  243. country_name TEXT NOT NULL DEFAULT '',
  244. upstream_proxy_id TEXT NOT NULL,
  245. enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1)),
  246. extra_json TEXT NOT NULL DEFAULT '{}',
  247. created_at INTEGER NOT NULL,
  248. updated_at INTEGER NOT NULL,
  249. FOREIGN KEY (upstream_proxy_id) REFERENCES upstream_proxies(id) ON DELETE CASCADE
  250. )`,
  251. `CREATE INDEX country_rules_proxy_idx ON country_rules(upstream_proxy_id)`,
  252. `CREATE TABLE notification_settings (
  253. channel TEXT PRIMARY KEY,
  254. enabled INTEGER NOT NULL DEFAULT 0 CHECK (enabled IN (0, 1)),
  255. config_json TEXT NOT NULL DEFAULT '{}',
  256. sensitive_fields_json TEXT NOT NULL DEFAULT '[]',
  257. created_at INTEGER NOT NULL,
  258. updated_at INTEGER NOT NULL
  259. )`,
  260. `CREATE TABLE app_settings (
  261. key TEXT PRIMARY KEY,
  262. value_json TEXT NOT NULL,
  263. sensitive INTEGER NOT NULL DEFAULT 0 CHECK (sensitive IN (0, 1)),
  264. updated_at INTEGER NOT NULL
  265. )`,
  266. `CREATE TABLE audit_events (
  267. id INTEGER PRIMARY KEY AUTOINCREMENT,
  268. actor TEXT NOT NULL DEFAULT '',
  269. action TEXT NOT NULL,
  270. entity_type TEXT NOT NULL DEFAULT '',
  271. entity_id TEXT NOT NULL DEFAULT '',
  272. outcome TEXT NOT NULL DEFAULT '',
  273. remote_addr TEXT NOT NULL DEFAULT '',
  274. details_json TEXT NOT NULL DEFAULT '{}',
  275. created_at INTEGER NOT NULL
  276. )`,
  277. `CREATE INDEX audit_events_created_idx ON audit_events(created_at DESC, id DESC)`,
  278. `CREATE INDEX audit_events_entity_idx ON audit_events(entity_type, entity_id, created_at DESC)`,
  279. `CREATE TABLE log_events (
  280. id INTEGER PRIMARY KEY AUTOINCREMENT,
  281. event_time INTEGER NOT NULL,
  282. level TEXT NOT NULL,
  283. message TEXT NOT NULL,
  284. caller TEXT NOT NULL DEFAULT '',
  285. fields_json TEXT NOT NULL DEFAULT '{}'
  286. )`,
  287. `CREATE INDEX log_events_time_idx ON log_events(event_time DESC, id DESC)`,
  288. `CREATE INDEX log_events_level_idx ON log_events(level, event_time DESC)`,
  289. `CREATE TABLE card_policies (
  290. iccid TEXT PRIMARY KEY,
  291. network_enabled INTEGER NOT NULL DEFAULT 0 CHECK (network_enabled IN (0, 1)),
  292. vowifi_enabled INTEGER NOT NULL DEFAULT 0 CHECK (vowifi_enabled IN (0, 1)),
  293. airplane_enabled INTEGER NOT NULL DEFAULT 0 CHECK (airplane_enabled IN (0, 1)),
  294. apn TEXT NOT NULL DEFAULT '',
  295. ip_version TEXT NOT NULL DEFAULT '',
  296. source TEXT NOT NULL DEFAULT '',
  297. created_at INTEGER NOT NULL,
  298. updated_at INTEGER NOT NULL,
  299. CHECK (NOT (vowifi_enabled = 1 AND airplane_enabled = 1))
  300. )`,
  301. `CREATE TABLE traffic_buckets (
  302. device_id TEXT NOT NULL,
  303. bucket TEXT NOT NULL,
  304. period_start INTEGER NOT NULL,
  305. rx_bytes INTEGER NOT NULL DEFAULT 0 CHECK (rx_bytes >= 0),
  306. tx_bytes INTEGER NOT NULL DEFAULT 0 CHECK (tx_bytes >= 0),
  307. PRIMARY KEY (device_id, bucket, period_start)
  308. )`,
  309. `CREATE INDEX traffic_buckets_period_idx
  310. ON traffic_buckets(bucket, period_start DESC)`,
  311. }