▍ humdrum codex / soft
2.9 KB raw
 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
// db/schema.ts — local SQLite schema (Drizzle, better-sqlite3).
// Single-user, local-only. No users table — everything belongs to the one local user.

import { sql } from "drizzle-orm";
import {
  sqliteTable,
  text,
  integer,
  index,
} from "drizzle-orm/sqlite-core";

// A configured data source shown on the dashboard.
export const sources = sqliteTable("sources", {
  id: text("id").primaryKey(),
  kind: text("kind").notNull(),
  label: text("label").notNull(),
  enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
  config: text("config", { mode: "json" }).notNull().default(sql`'{}'`),
  refreshSeconds: integer("refresh_seconds").notNull().default(900),
  position: integer("position").notNull().default(0),
  size: text("size").notNull().default("md"), // vestigial; layout now uses cols/rows
  cols: integer("cols").notNull().default(1), // grid column span (free w×h bento)
  rows: integer("rows").notNull().default(2), // grid row span
});

// Cached fetch result per source.
export const snapshots = sqliteTable(
  "snapshots",
  {
    id: text("id").primaryKey(),
    sourceId: text("source_id")
      .notNull()
      .references(() => sources.id, { onDelete: "cascade" }),
    payload: text("payload", { mode: "json" }),
    fetchedAt: text("fetched_at").notNull(),
    ok: integer("ok", { mode: "boolean" }).notNull().default(true),
    error: text("error"),
  },
  (t) => ({
    sourceIdx: index("snapshots_source_idx").on(t.sourceId),
    fetchedIdx: index("snapshots_fetched_idx").on(t.fetchedAt),
  }),
);

// Local todos (this app owns them).
export const todos = sqliteTable(
  "todos",
  {
    id: text("id").primaryKey(),
    title: text("title").notNull(),
    done: integer("done", { mode: "boolean" }).notNull().default(false),
    due: text("due"),
    createdAt: text("created_at").notNull(),
  },
  (t) => ({
    createdIdx: index("todos_created_idx").on(t.createdAt),
  }),
);

// Generated daily PDF "newspaper" editions.
export const editions = sqliteTable(
  "editions",
  {
    id: text("id").primaryKey(),
    date: text("date").notNull(),
    pdfPath: text("pdf_path").notNull(),
    generatedAt: text("generated_at").notNull(),
  },
  (t) => ({
    dateIdx: index("editions_date_idx").on(t.date),
  }),
);

// App settings as key/value JSON rows.
export const settings = sqliteTable("settings", {
  key: text("key").primaryKey(),
  value: text("value", { mode: "json" }),
});

export type SourceRow = typeof sources.$inferSelect;
export type NewSourceRow = typeof sources.$inferInsert;
export type SnapshotRow = typeof snapshots.$inferSelect;
export type NewSnapshotRow = typeof snapshots.$inferInsert;
export type TodoRow = typeof todos.$inferSelect;
export type NewTodoRow = typeof todos.$inferInsert;
export type EditionRow = typeof editions.$inferSelect;
export type NewEditionRow = typeof editions.$inferInsert;
export type SettingRow = typeof settings.$inferSelect;