Skip to content
167 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Docs: a workspace knowledge base people and agents write together1-- Docs: spaces, pages, history, suggestions, templates and search
2-- (docs/WORKSPACE.md, "Docs"). A page's live content is a Yjs document in
3-- its Durable Object (src/room.ts); this database keeps everything around
4-- it and the Markdown rendition the room saves after each burst of edits.
5-- Workspaces are kept by id; members are keys: `user:<id>`, `agent:<id>`,
6-- `team:<slug>`.
7
8CREATE TABLE spaces (
9 id TEXT PRIMARY KEY,
10 workspace_id TEXT NOT NULL,
11 slug TEXT NOT NULL,
12 name TEXT NOT NULL,
13 description TEXT,
14 icon TEXT,
15 -- workspace: every member gets default_role; team: the team's members do;
16 -- private: only listed members.
17 kind TEXT NOT NULL CHECK (kind IN ('workspace', 'team', 'private')),
18 team TEXT,
19 default_role TEXT CHECK (default_role IN ('view', 'comment', 'edit', 'manage')),
20 agent_mode TEXT NOT NULL DEFAULT 'suggest' CHECK (agent_mode IN ('suggest', 'edit')),
21 is_default INTEGER NOT NULL DEFAULT 0,
22 created_by TEXT NOT NULL,
23 created_at TEXT NOT NULL,
24 archived_at TEXT,
25 UNIQUE (workspace_id, slug)
26);
27
28-- One General space per workspace, made the first time Docs is opened.
29CREATE UNIQUE INDEX spaces_default ON spaces (workspace_id) WHERE is_default = 1;
30
31CREATE TABLE space_members (
32 space_id TEXT NOT NULL REFERENCES spaces (id) ON DELETE CASCADE,
33 principal TEXT NOT NULL,
34 role TEXT NOT NULL CHECK (role IN ('view', 'comment', 'edit', 'manage')),
35 added_by TEXT NOT NULL,
36 added_at TEXT NOT NULL,
37 PRIMARY KEY (space_id, principal)
38);
39
40-- Projects (repositories, `owner/name` lowercased) a space is about.
41CREATE TABLE space_projects (
42 space_id TEXT NOT NULL REFERENCES spaces (id) ON DELETE CASCADE,
43 repo TEXT NOT NULL,
44 PRIMARY KEY (space_id, repo)
45);
46CREATE INDEX space_projects_repo ON space_projects (repo);
47
48CREATE TABLE pages (
49 id TEXT PRIMARY KEY,
50 workspace_id TEXT NOT NULL,
51 space_id TEXT NOT NULL REFERENCES spaces (id) ON DELETE CASCADE,
52 parent_id TEXT,
53 position REAL NOT NULL,
54 title TEXT NOT NULL DEFAULT '',
55 icon TEXT,
56 cover TEXT,
57 -- As the room last saved it: the read view, search, agents and export.
58 markdown TEXT NOT NULL DEFAULT '',
59 created_by TEXT NOT NULL,
60 created_at TEXT NOT NULL,
61 updated_by TEXT,
62 updated_at TEXT NOT NULL,
63 archived_at TEXT,
64 archived_by TEXT,
65 -- People already told they were mentioned in the page, so a save tells only the new ones.
66 mentioned TEXT NOT NULL DEFAULT '[]'
67);
68CREATE INDEX pages_tree ON pages (space_id, parent_id, position);
69CREATE INDEX pages_recent ON pages (workspace_id, updated_at);
70
71CREATE TABLE page_owners (
72 page_id TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
73 principal TEXT NOT NULL,
74 PRIMARY KEY (page_id, principal)
75);
76CREATE INDEX page_owners_principal ON page_owners (principal);
77
78CREATE TABLE page_projects (
79 page_id TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
80 repo TEXT NOT NULL,
81 PRIMARY KEY (page_id, repo)
82);
83CREATE INDEX page_projects_repo ON page_projects (repo);
84
85-- Links from one page to another, rebuilt on each save: backlinks.
86CREATE TABLE page_links (
87 from_page TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
88 to_page TEXT NOT NULL,
89 PRIMARY KEY (from_page, to_page)
90);
91CREATE INDEX page_links_to ON page_links (to_page);
92
93CREATE TABLE page_views (
94 page_id TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
95 user_id TEXT NOT NULL,
96 viewed_at TEXT NOT NULL,
97 PRIMARY KEY (page_id, user_id)
98);
99CREATE INDEX page_views_user ON page_views (user_id, viewed_at);
100
101CREATE TABLE favorites (
102 user_id TEXT NOT NULL,
103 page_id TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
104 created_at TEXT NOT NULL,
105 PRIMARY KEY (user_id, page_id)
106);
107
108-- History: the Yjs state (for an exact restore) and its Markdown (for
109-- reading and diffs). `state` is null when it was too large to keep; a
110-- restore then rebuilds the page from the Markdown.
111CREATE TABLE page_versions (
112 id TEXT PRIMARY KEY,
113 page_id TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
114 created_at TEXT NOT NULL,
115 kind TEXT NOT NULL CHECK (kind IN ('created', 'edit', 'agent', 'suggestion', 'restore')),
116 authors TEXT NOT NULL DEFAULT '[]',
117 note TEXT,
118 markdown TEXT NOT NULL,
119 state BLOB
120);
121CREATE INDEX page_versions_page ON page_versions (page_id, created_at);
122
123-- Agents' tracked changes, waiting for a person.
124CREATE TABLE suggestions (
125 id TEXT PRIMARY KEY,
126 page_id TEXT NOT NULL REFERENCES pages (id) ON DELETE CASCADE,
127 author TEXT NOT NULL,
128 asked_by TEXT,
129 target TEXT NOT NULL,
130 before_markdown TEXT NOT NULL,
131 after_markdown TEXT NOT NULL,
132 note TEXT,
133 status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'accepted', 'rejected', 'stale')),
134 created_at TEXT NOT NULL,
135 decided_by TEXT,
136 decided_at TEXT
137);
138CREATE INDEX suggestions_page ON suggestions (page_id, status);
139
140-- The workspace's own templates; the built-in ones are in src/templates.ts.
141CREATE TABLE templates (
142 id TEXT PRIMARY KEY,
143 workspace_id TEXT NOT NULL,
144 name TEXT NOT NULL,
145 description TEXT NOT NULL DEFAULT '',
146 icon TEXT NOT NULL DEFAULT '📄',
147 markdown TEXT NOT NULL,
148 created_by TEXT NOT NULL,
149 created_at TEXT NOT NULL
150);
151CREATE INDEX templates_workspace ON templates (workspace_id);
152
153-- Files put in pages, kept in the files bucket under `key`.
154CREATE TABLE files (
155 id TEXT PRIMARY KEY,
156 workspace_id TEXT NOT NULL,
157 page_id TEXT,
158 key TEXT NOT NULL UNIQUE,
159 name TEXT NOT NULL,
160 content_type TEXT NOT NULL,
161 bytes INTEGER NOT NULL,
162 created_by TEXT NOT NULL,
163 created_at TEXT NOT NULL
164);
165
166-- Full text over titles and Markdown; rebuilt for a page on each save.
167CREATE VIRTUAL TABLE pages_fts USING fts5 (page_id UNINDEXED, title, body, tokenize = 'unicode61 remove_diacritics 2');