stagent 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -2
- package/dist/cli.js +226 -1
- package/docs/.coverage-gaps.json +66 -16
- package/docs/.last-generated +1 -1
- package/docs/features/dashboard-kanban.md +13 -7
- package/docs/features/settings.md +15 -3
- package/docs/features/tables.md +122 -0
- package/docs/index.md +3 -2
- package/docs/journeys/developer.md +26 -16
- package/docs/journeys/personal-use.md +23 -9
- package/docs/journeys/power-user.md +40 -14
- package/docs/journeys/work-use.md +43 -15
- package/docs/manifest.json +27 -17
- package/package.json +3 -1
- package/src/app/api/chat/entities/search/route.ts +12 -3
- package/src/app/api/projects/[id]/route.ts +37 -0
- package/src/app/api/projects/__tests__/delete-project.test.ts +12 -0
- package/src/app/api/snapshots/[id]/restore/route.ts +62 -0
- package/src/app/api/snapshots/[id]/route.ts +44 -0
- package/src/app/api/snapshots/route.ts +54 -0
- package/src/app/api/snapshots/settings/route.ts +67 -0
- package/src/app/api/tables/[id]/charts/[chartId]/route.ts +89 -0
- package/src/app/api/tables/[id]/charts/route.ts +72 -0
- package/src/app/api/tables/[id]/columns/route.ts +70 -0
- package/src/app/api/tables/[id]/export/route.ts +94 -0
- package/src/app/api/tables/[id]/history/route.ts +15 -0
- package/src/app/api/tables/[id]/import/route.ts +111 -0
- package/src/app/api/tables/[id]/route.ts +86 -0
- package/src/app/api/tables/[id]/rows/[rowId]/history/route.ts +32 -0
- package/src/app/api/tables/[id]/rows/[rowId]/route.ts +51 -0
- package/src/app/api/tables/[id]/rows/route.ts +101 -0
- package/src/app/api/tables/[id]/triggers/[triggerId]/route.ts +65 -0
- package/src/app/api/tables/[id]/triggers/route.ts +122 -0
- package/src/app/api/tables/route.ts +65 -0
- package/src/app/api/tables/templates/route.ts +92 -0
- package/src/app/globals.css +14 -0
- package/src/app/settings/page.tsx +2 -0
- package/src/app/tables/[id]/page.tsx +67 -0
- package/src/app/tables/page.tsx +21 -0
- package/src/app/tables/templates/page.tsx +19 -0
- package/src/components/book/book-reader.tsx +62 -9
- package/src/components/book/content-blocks.tsx +6 -1
- package/src/components/chat/chat-table-result.tsx +139 -0
- package/src/components/documents/document-browser.tsx +1 -1
- package/src/components/projects/project-form-sheet.tsx +3 -27
- package/src/components/schedules/schedule-form.tsx +5 -27
- package/src/components/settings/data-management-section.tsx +17 -12
- package/src/components/settings/database-snapshots-section.tsx +469 -0
- package/src/components/shared/app-sidebar.tsx +2 -0
- package/src/components/shared/document-picker-sheet.tsx +214 -11
- package/src/components/tables/table-browser.tsx +234 -0
- package/src/components/tables/table-cell-editor.tsx +226 -0
- package/src/components/tables/table-chart-builder.tsx +288 -0
- package/src/components/tables/table-chart-view.tsx +146 -0
- package/src/components/tables/table-column-header.tsx +103 -0
- package/src/components/tables/table-column-sheet.tsx +331 -0
- package/src/components/tables/table-create-sheet.tsx +240 -0
- package/src/components/tables/table-detail-sheet.tsx +144 -0
- package/src/components/tables/table-detail-tabs.tsx +278 -0
- package/src/components/tables/table-grid.tsx +61 -0
- package/src/components/tables/table-history-tab.tsx +148 -0
- package/src/components/tables/table-import-wizard.tsx +542 -0
- package/src/components/tables/table-list-table.tsx +95 -0
- package/src/components/tables/table-relation-combobox.tsx +217 -0
- package/src/components/tables/table-row-sheet.tsx +271 -0
- package/src/components/tables/table-spreadsheet.tsx +394 -0
- package/src/components/tables/table-template-gallery.tsx +162 -0
- package/src/components/tables/table-template-preview.tsx +219 -0
- package/src/components/tables/table-toolbar.tsx +79 -0
- package/src/components/tables/table-triggers-tab.tsx +446 -0
- package/src/components/tables/types.ts +6 -0
- package/src/components/tables/use-spreadsheet-keys.ts +171 -0
- package/src/components/tables/utils.ts +29 -0
- package/src/components/tasks/task-create-panel.tsx +5 -31
- package/src/components/tasks/task-edit-dialog.tsx +5 -27
- package/src/components/workflows/workflow-form-view.tsx +11 -35
- package/src/components/workflows/workflow-status-view.tsx +1 -1
- package/src/instrumentation.ts +3 -0
- package/src/lib/agents/__tests__/claude-agent.test.ts +5 -1
- package/src/lib/agents/claude-agent.ts +3 -1
- package/src/lib/agents/profiles/builtins/document-writer/SKILL.md +23 -0
- package/src/lib/agents/profiles/builtins/technical-writer/SKILL.md +10 -0
- package/src/lib/agents/profiles/builtins/technical-writer/profile.yaml +1 -1
- package/src/lib/agents/runtime/anthropic-direct.ts +29 -0
- package/src/lib/agents/runtime/openai-direct.ts +29 -0
- package/src/lib/book/chapter-generator.ts +81 -5
- package/src/lib/book/chapter-mapping.ts +58 -24
- package/src/lib/book/content.ts +83 -47
- package/src/lib/book/markdown-parser.ts +1 -1
- package/src/lib/book/reading-paths.ts +8 -8
- package/src/lib/book/types.ts +1 -1
- package/src/lib/book/update-detector.ts +4 -1
- package/src/lib/chat/stagent-tools.ts +2 -0
- package/src/lib/chat/tool-catalog.ts +34 -0
- package/src/lib/chat/tools/table-tools.ts +955 -0
- package/src/lib/chat/tools/workflow-tools.ts +9 -1
- package/src/lib/constants/table-status.ts +68 -0
- package/src/lib/data/__tests__/clear.test.ts +1 -1
- package/src/lib/data/clear.ts +45 -0
- package/src/lib/data/seed-data/__tests__/profiles.test.ts +28 -23
- package/src/lib/data/seed-data/conversations.ts +350 -42
- package/src/lib/data/seed-data/documents.ts +564 -591
- package/src/lib/data/seed-data/learned-context.ts +101 -22
- package/src/lib/data/seed-data/notifications.ts +344 -70
- package/src/lib/data/seed-data/profile-test-results.ts +92 -11
- package/src/lib/data/seed-data/profiles.ts +144 -46
- package/src/lib/data/seed-data/projects.ts +50 -18
- package/src/lib/data/seed-data/repo-imports.ts +28 -13
- package/src/lib/data/seed-data/schedules.ts +208 -41
- package/src/lib/data/seed-data/table-templates.ts +234 -0
- package/src/lib/data/seed-data/tasks.ts +614 -116
- package/src/lib/data/seed-data/usage-ledger.ts +182 -103
- package/src/lib/data/seed-data/user-tables.ts +203 -0
- package/src/lib/data/seed-data/views.ts +52 -7
- package/src/lib/data/seed-data/workflows.ts +231 -84
- package/src/lib/data/seed.ts +55 -14
- package/src/lib/data/tables.ts +417 -0
- package/src/lib/db/bootstrap.ts +227 -0
- package/src/lib/db/index.ts +9 -0
- package/src/lib/db/migrations/0019_add_tables_feature.sql +160 -0
- package/src/lib/db/migrations/0020_add_table_triggers.sql +19 -0
- package/src/lib/db/migrations/0021_add_row_history.sql +15 -0
- package/src/lib/db/schema.ts +368 -0
- package/src/lib/snapshots/auto-backup.ts +132 -0
- package/src/lib/snapshots/retention.ts +64 -0
- package/src/lib/snapshots/snapshot-manager.ts +429 -0
- package/src/lib/tables/computed.ts +61 -0
- package/src/lib/tables/context-builder.ts +139 -0
- package/src/lib/tables/formula-engine.ts +415 -0
- package/src/lib/tables/history.ts +115 -0
- package/src/lib/tables/import.ts +343 -0
- package/src/lib/tables/query-builder.ts +152 -0
- package/src/lib/tables/trigger-evaluator.ts +146 -0
- package/src/lib/tables/types.ts +141 -0
- package/src/lib/tables/validation.ts +119 -0
- package/src/lib/utils/stagent-paths.ts +20 -0
- package/src/lib/workflows/types.ts +1 -1
- package/tsconfig.json +3 -1
- /package/docs/features/{playbook.md → user-guide.md} +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
-- User-defined structured data tables
|
|
2
|
+
CREATE TABLE IF NOT EXISTS `user_tables` (
|
|
3
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
4
|
+
`project_id` TEXT,
|
|
5
|
+
`name` TEXT NOT NULL,
|
|
6
|
+
`description` TEXT,
|
|
7
|
+
`column_schema` TEXT NOT NULL DEFAULT '[]',
|
|
8
|
+
`row_count` INTEGER DEFAULT 0 NOT NULL,
|
|
9
|
+
`source` TEXT DEFAULT 'manual' NOT NULL,
|
|
10
|
+
`template_id` TEXT,
|
|
11
|
+
`created_at` INTEGER NOT NULL,
|
|
12
|
+
`updated_at` INTEGER NOT NULL,
|
|
13
|
+
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS `idx_user_tables_project_id` ON `user_tables`(`project_id`);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS `idx_user_tables_source` ON `user_tables`(`source`);
|
|
18
|
+
|
|
19
|
+
CREATE TABLE IF NOT EXISTS `user_table_columns` (
|
|
20
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
21
|
+
`table_id` TEXT NOT NULL,
|
|
22
|
+
`name` TEXT NOT NULL,
|
|
23
|
+
`display_name` TEXT NOT NULL,
|
|
24
|
+
`data_type` TEXT NOT NULL,
|
|
25
|
+
`position` INTEGER NOT NULL,
|
|
26
|
+
`required` INTEGER DEFAULT 0 NOT NULL,
|
|
27
|
+
`default_value` TEXT,
|
|
28
|
+
`config` TEXT,
|
|
29
|
+
`created_at` INTEGER NOT NULL,
|
|
30
|
+
`updated_at` INTEGER NOT NULL,
|
|
31
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_columns_table_id` ON `user_table_columns`(`table_id`);
|
|
35
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_columns_position` ON `user_table_columns`(`table_id`, `position`);
|
|
36
|
+
|
|
37
|
+
CREATE TABLE IF NOT EXISTS `user_table_rows` (
|
|
38
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
39
|
+
`table_id` TEXT NOT NULL,
|
|
40
|
+
`data` TEXT NOT NULL DEFAULT '{}',
|
|
41
|
+
`position` INTEGER NOT NULL,
|
|
42
|
+
`created_by` TEXT DEFAULT 'user',
|
|
43
|
+
`created_at` INTEGER NOT NULL,
|
|
44
|
+
`updated_at` INTEGER NOT NULL,
|
|
45
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_rows_table_id` ON `user_table_rows`(`table_id`);
|
|
49
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_rows_position` ON `user_table_rows`(`table_id`, `position`);
|
|
50
|
+
|
|
51
|
+
CREATE TABLE IF NOT EXISTS `user_table_views` (
|
|
52
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
53
|
+
`table_id` TEXT NOT NULL,
|
|
54
|
+
`name` TEXT NOT NULL,
|
|
55
|
+
`type` TEXT DEFAULT 'grid' NOT NULL,
|
|
56
|
+
`config` TEXT,
|
|
57
|
+
`is_default` INTEGER DEFAULT 0 NOT NULL,
|
|
58
|
+
`created_at` INTEGER NOT NULL,
|
|
59
|
+
`updated_at` INTEGER NOT NULL,
|
|
60
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_views_table_id` ON `user_table_views`(`table_id`);
|
|
64
|
+
|
|
65
|
+
CREATE TABLE IF NOT EXISTS `user_table_relationships` (
|
|
66
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
67
|
+
`from_table_id` TEXT NOT NULL,
|
|
68
|
+
`from_column` TEXT NOT NULL,
|
|
69
|
+
`to_table_id` TEXT NOT NULL,
|
|
70
|
+
`to_column` TEXT NOT NULL,
|
|
71
|
+
`relationship_type` TEXT NOT NULL,
|
|
72
|
+
`config` TEXT,
|
|
73
|
+
`created_at` INTEGER NOT NULL,
|
|
74
|
+
FOREIGN KEY (`from_table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
|
|
75
|
+
FOREIGN KEY (`to_table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_rels_from` ON `user_table_relationships`(`from_table_id`);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_rels_to` ON `user_table_relationships`(`to_table_id`);
|
|
80
|
+
|
|
81
|
+
CREATE TABLE IF NOT EXISTS `user_table_templates` (
|
|
82
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
83
|
+
`name` TEXT NOT NULL,
|
|
84
|
+
`description` TEXT,
|
|
85
|
+
`category` TEXT NOT NULL,
|
|
86
|
+
`column_schema` TEXT NOT NULL,
|
|
87
|
+
`sample_data` TEXT,
|
|
88
|
+
`scope` TEXT DEFAULT 'system' NOT NULL,
|
|
89
|
+
`icon` TEXT,
|
|
90
|
+
`created_at` INTEGER NOT NULL,
|
|
91
|
+
`updated_at` INTEGER NOT NULL
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_templates_category` ON `user_table_templates`(`category`);
|
|
95
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_templates_scope` ON `user_table_templates`(`scope`);
|
|
96
|
+
|
|
97
|
+
CREATE TABLE IF NOT EXISTS `user_table_imports` (
|
|
98
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
99
|
+
`table_id` TEXT NOT NULL,
|
|
100
|
+
`document_id` TEXT,
|
|
101
|
+
`row_count` INTEGER DEFAULT 0 NOT NULL,
|
|
102
|
+
`error_count` INTEGER DEFAULT 0 NOT NULL,
|
|
103
|
+
`errors` TEXT,
|
|
104
|
+
`status` TEXT DEFAULT 'pending' NOT NULL,
|
|
105
|
+
`created_at` INTEGER NOT NULL,
|
|
106
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
|
|
107
|
+
FOREIGN KEY (`document_id`) REFERENCES `documents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_imports_table_id` ON `user_table_imports`(`table_id`);
|
|
111
|
+
|
|
112
|
+
-- Junction tables for linking tables to other domain objects
|
|
113
|
+
CREATE TABLE IF NOT EXISTS `table_document_inputs` (
|
|
114
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
115
|
+
`table_id` TEXT NOT NULL,
|
|
116
|
+
`document_id` TEXT NOT NULL,
|
|
117
|
+
`created_at` INTEGER NOT NULL,
|
|
118
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
|
|
119
|
+
FOREIGN KEY (`document_id`) REFERENCES `documents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
CREATE INDEX IF NOT EXISTS `idx_tdi_table` ON `table_document_inputs`(`table_id`);
|
|
123
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `idx_tdi_table_doc` ON `table_document_inputs`(`table_id`, `document_id`);
|
|
124
|
+
|
|
125
|
+
CREATE TABLE IF NOT EXISTS `task_table_inputs` (
|
|
126
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
127
|
+
`task_id` TEXT NOT NULL,
|
|
128
|
+
`table_id` TEXT NOT NULL,
|
|
129
|
+
`created_at` INTEGER NOT NULL,
|
|
130
|
+
FOREIGN KEY (`task_id`) REFERENCES `tasks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
|
|
131
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
CREATE INDEX IF NOT EXISTS `idx_tti_task` ON `task_table_inputs`(`task_id`);
|
|
135
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `idx_tti_task_table` ON `task_table_inputs`(`task_id`, `table_id`);
|
|
136
|
+
|
|
137
|
+
CREATE TABLE IF NOT EXISTS `workflow_table_inputs` (
|
|
138
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
139
|
+
`workflow_id` TEXT NOT NULL,
|
|
140
|
+
`table_id` TEXT NOT NULL,
|
|
141
|
+
`step_id` TEXT,
|
|
142
|
+
`created_at` INTEGER NOT NULL,
|
|
143
|
+
FOREIGN KEY (`workflow_id`) REFERENCES `workflows`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
|
|
144
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
CREATE INDEX IF NOT EXISTS `idx_wti_workflow` ON `workflow_table_inputs`(`workflow_id`);
|
|
148
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `idx_wti_workflow_table_step` ON `workflow_table_inputs`(`workflow_id`, `table_id`, `step_id`);
|
|
149
|
+
|
|
150
|
+
CREATE TABLE IF NOT EXISTS `schedule_table_inputs` (
|
|
151
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
152
|
+
`schedule_id` TEXT NOT NULL,
|
|
153
|
+
`table_id` TEXT NOT NULL,
|
|
154
|
+
`created_at` INTEGER NOT NULL,
|
|
155
|
+
FOREIGN KEY (`schedule_id`) REFERENCES `schedules`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
|
|
156
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
CREATE INDEX IF NOT EXISTS `idx_sti_schedule` ON `schedule_table_inputs`(`schedule_id`);
|
|
160
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `idx_sti_schedule_table` ON `schedule_table_inputs`(`schedule_id`, `table_id`);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- Workflow triggers for user-defined tables
|
|
2
|
+
CREATE TABLE IF NOT EXISTS `user_table_triggers` (
|
|
3
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
4
|
+
`table_id` TEXT NOT NULL,
|
|
5
|
+
`name` TEXT NOT NULL,
|
|
6
|
+
`trigger_event` TEXT NOT NULL,
|
|
7
|
+
`condition` TEXT,
|
|
8
|
+
`action_type` TEXT NOT NULL,
|
|
9
|
+
`action_config` TEXT NOT NULL,
|
|
10
|
+
`status` TEXT DEFAULT 'active' NOT NULL,
|
|
11
|
+
`fire_count` INTEGER DEFAULT 0 NOT NULL,
|
|
12
|
+
`last_fired_at` INTEGER,
|
|
13
|
+
`created_at` INTEGER NOT NULL,
|
|
14
|
+
`updated_at` INTEGER NOT NULL,
|
|
15
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_triggers_table_id` ON `user_table_triggers`(`table_id`);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS `idx_user_table_triggers_status` ON `user_table_triggers`(`status`);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Row version history for user-defined tables
|
|
2
|
+
CREATE TABLE IF NOT EXISTS `user_table_row_history` (
|
|
3
|
+
`id` TEXT PRIMARY KEY NOT NULL,
|
|
4
|
+
`row_id` TEXT NOT NULL,
|
|
5
|
+
`table_id` TEXT NOT NULL,
|
|
6
|
+
`previous_data` TEXT NOT NULL,
|
|
7
|
+
`changed_by` TEXT DEFAULT 'user',
|
|
8
|
+
`change_type` TEXT NOT NULL,
|
|
9
|
+
`created_at` INTEGER NOT NULL,
|
|
10
|
+
FOREIGN KEY (`table_id`) REFERENCES `user_tables`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE INDEX IF NOT EXISTS `idx_row_history_row_id` ON `user_table_row_history`(`row_id`);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS `idx_row_history_table_id` ON `user_table_row_history`(`table_id`);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS `idx_row_history_created_at` ON `user_table_row_history`(`created_at`);
|
package/src/lib/db/schema.ts
CHANGED
|
@@ -755,6 +755,332 @@ export const projectDocumentDefaults = sqliteTable(
|
|
|
755
755
|
|
|
756
756
|
export type ProjectDocumentDefaultRow = InferSelectModel<typeof projectDocumentDefaults>;
|
|
757
757
|
|
|
758
|
+
// ── User-Defined Tables (structured data) ───────────────────────────────
|
|
759
|
+
|
|
760
|
+
export const userTables = sqliteTable(
|
|
761
|
+
"user_tables",
|
|
762
|
+
{
|
|
763
|
+
id: text("id").primaryKey(),
|
|
764
|
+
projectId: text("project_id").references(() => projects.id),
|
|
765
|
+
name: text("name").notNull(),
|
|
766
|
+
description: text("description"),
|
|
767
|
+
/** JSON array of column definitions — denormalized for fast reads */
|
|
768
|
+
columnSchema: text("column_schema").notNull().default("[]"),
|
|
769
|
+
/** Denormalized row count for list views */
|
|
770
|
+
rowCount: integer("row_count").default(0).notNull(),
|
|
771
|
+
/** How this table was created */
|
|
772
|
+
source: text("source", {
|
|
773
|
+
enum: ["manual", "imported", "agent", "template"],
|
|
774
|
+
})
|
|
775
|
+
.default("manual")
|
|
776
|
+
.notNull(),
|
|
777
|
+
/** Template ID if created from a template */
|
|
778
|
+
templateId: text("template_id"),
|
|
779
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
780
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
781
|
+
},
|
|
782
|
+
(table) => [
|
|
783
|
+
index("idx_user_tables_project_id").on(table.projectId),
|
|
784
|
+
index("idx_user_tables_source").on(table.source),
|
|
785
|
+
]
|
|
786
|
+
);
|
|
787
|
+
|
|
788
|
+
export const userTableColumns = sqliteTable(
|
|
789
|
+
"user_table_columns",
|
|
790
|
+
{
|
|
791
|
+
id: text("id").primaryKey(),
|
|
792
|
+
tableId: text("table_id")
|
|
793
|
+
.references(() => userTables.id)
|
|
794
|
+
.notNull(),
|
|
795
|
+
name: text("name").notNull(),
|
|
796
|
+
displayName: text("display_name").notNull(),
|
|
797
|
+
dataType: text("data_type", {
|
|
798
|
+
enum: [
|
|
799
|
+
"text",
|
|
800
|
+
"number",
|
|
801
|
+
"date",
|
|
802
|
+
"boolean",
|
|
803
|
+
"select",
|
|
804
|
+
"url",
|
|
805
|
+
"email",
|
|
806
|
+
"relation",
|
|
807
|
+
"computed",
|
|
808
|
+
],
|
|
809
|
+
}).notNull(),
|
|
810
|
+
position: integer("position").notNull(),
|
|
811
|
+
required: integer("required", { mode: "boolean" }).default(false).notNull(),
|
|
812
|
+
defaultValue: text("default_value"),
|
|
813
|
+
/** JSON config for type-specific settings (select options, formula, relation target, etc.) */
|
|
814
|
+
config: text("config"),
|
|
815
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
816
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
817
|
+
},
|
|
818
|
+
(table) => [
|
|
819
|
+
index("idx_user_table_columns_table_id").on(table.tableId),
|
|
820
|
+
index("idx_user_table_columns_position").on(table.tableId, table.position),
|
|
821
|
+
]
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
export const userTableRows = sqliteTable(
|
|
825
|
+
"user_table_rows",
|
|
826
|
+
{
|
|
827
|
+
id: text("id").primaryKey(),
|
|
828
|
+
tableId: text("table_id")
|
|
829
|
+
.references(() => userTables.id)
|
|
830
|
+
.notNull(),
|
|
831
|
+
/** JSON object with column values keyed by column name */
|
|
832
|
+
data: text("data").notNull().default("{}"),
|
|
833
|
+
position: integer("position").notNull(),
|
|
834
|
+
/** Who created this row: 'user' or agent profile ID */
|
|
835
|
+
createdBy: text("created_by").default("user"),
|
|
836
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
837
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
838
|
+
},
|
|
839
|
+
(table) => [
|
|
840
|
+
index("idx_user_table_rows_table_id").on(table.tableId),
|
|
841
|
+
index("idx_user_table_rows_position").on(table.tableId, table.position),
|
|
842
|
+
]
|
|
843
|
+
);
|
|
844
|
+
|
|
845
|
+
export const userTableViews = sqliteTable(
|
|
846
|
+
"user_table_views",
|
|
847
|
+
{
|
|
848
|
+
id: text("id").primaryKey(),
|
|
849
|
+
tableId: text("table_id")
|
|
850
|
+
.references(() => userTables.id)
|
|
851
|
+
.notNull(),
|
|
852
|
+
name: text("name").notNull(),
|
|
853
|
+
type: text("type", { enum: ["grid", "chart", "joined"] })
|
|
854
|
+
.default("grid")
|
|
855
|
+
.notNull(),
|
|
856
|
+
/** JSON config: filters, sorting, column visibility, chart config, join config */
|
|
857
|
+
config: text("config"),
|
|
858
|
+
isDefault: integer("is_default", { mode: "boolean" })
|
|
859
|
+
.default(false)
|
|
860
|
+
.notNull(),
|
|
861
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
862
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
863
|
+
},
|
|
864
|
+
(table) => [
|
|
865
|
+
index("idx_user_table_views_table_id").on(table.tableId),
|
|
866
|
+
]
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
export const userTableRelationships = sqliteTable(
|
|
870
|
+
"user_table_relationships",
|
|
871
|
+
{
|
|
872
|
+
id: text("id").primaryKey(),
|
|
873
|
+
fromTableId: text("from_table_id")
|
|
874
|
+
.references(() => userTables.id)
|
|
875
|
+
.notNull(),
|
|
876
|
+
fromColumn: text("from_column").notNull(),
|
|
877
|
+
toTableId: text("to_table_id")
|
|
878
|
+
.references(() => userTables.id)
|
|
879
|
+
.notNull(),
|
|
880
|
+
toColumn: text("to_column").notNull(),
|
|
881
|
+
relationshipType: text("relationship_type", {
|
|
882
|
+
enum: ["one_to_one", "one_to_many", "many_to_many"],
|
|
883
|
+
}).notNull(),
|
|
884
|
+
/** JSON config for display column, cascade behavior, etc. */
|
|
885
|
+
config: text("config"),
|
|
886
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
887
|
+
},
|
|
888
|
+
(table) => [
|
|
889
|
+
index("idx_user_table_rels_from").on(table.fromTableId),
|
|
890
|
+
index("idx_user_table_rels_to").on(table.toTableId),
|
|
891
|
+
]
|
|
892
|
+
);
|
|
893
|
+
|
|
894
|
+
export const userTableTemplates = sqliteTable(
|
|
895
|
+
"user_table_templates",
|
|
896
|
+
{
|
|
897
|
+
id: text("id").primaryKey(),
|
|
898
|
+
name: text("name").notNull(),
|
|
899
|
+
description: text("description"),
|
|
900
|
+
category: text("category", {
|
|
901
|
+
enum: ["business", "personal", "pm", "finance", "content"],
|
|
902
|
+
}).notNull(),
|
|
903
|
+
/** JSON array of column definitions */
|
|
904
|
+
columnSchema: text("column_schema").notNull(),
|
|
905
|
+
/** JSON array of sample row data */
|
|
906
|
+
sampleData: text("sample_data"),
|
|
907
|
+
scope: text("scope", { enum: ["system", "user"] })
|
|
908
|
+
.default("system")
|
|
909
|
+
.notNull(),
|
|
910
|
+
icon: text("icon"),
|
|
911
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
912
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
913
|
+
},
|
|
914
|
+
(table) => [
|
|
915
|
+
index("idx_user_table_templates_category").on(table.category),
|
|
916
|
+
index("idx_user_table_templates_scope").on(table.scope),
|
|
917
|
+
]
|
|
918
|
+
);
|
|
919
|
+
|
|
920
|
+
export const userTableImports = sqliteTable(
|
|
921
|
+
"user_table_imports",
|
|
922
|
+
{
|
|
923
|
+
id: text("id").primaryKey(),
|
|
924
|
+
tableId: text("table_id")
|
|
925
|
+
.references(() => userTables.id)
|
|
926
|
+
.notNull(),
|
|
927
|
+
documentId: text("document_id").references(() => documents.id),
|
|
928
|
+
/** Number of rows imported */
|
|
929
|
+
rowCount: integer("row_count").default(0).notNull(),
|
|
930
|
+
/** Number of rows that failed validation */
|
|
931
|
+
errorCount: integer("error_count").default(0).notNull(),
|
|
932
|
+
/** JSON array of error details */
|
|
933
|
+
errors: text("errors"),
|
|
934
|
+
status: text("status", { enum: ["pending", "completed", "failed"] })
|
|
935
|
+
.default("pending")
|
|
936
|
+
.notNull(),
|
|
937
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
938
|
+
},
|
|
939
|
+
(table) => [
|
|
940
|
+
index("idx_user_table_imports_table_id").on(table.tableId),
|
|
941
|
+
]
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
// ── Table Junction Tables ───────────────────────────────────────────────
|
|
945
|
+
|
|
946
|
+
export const tableDocumentInputs = sqliteTable(
|
|
947
|
+
"table_document_inputs",
|
|
948
|
+
{
|
|
949
|
+
id: text("id").primaryKey(),
|
|
950
|
+
tableId: text("table_id")
|
|
951
|
+
.references(() => userTables.id)
|
|
952
|
+
.notNull(),
|
|
953
|
+
documentId: text("document_id")
|
|
954
|
+
.references(() => documents.id)
|
|
955
|
+
.notNull(),
|
|
956
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
957
|
+
},
|
|
958
|
+
(table) => [
|
|
959
|
+
index("idx_tdi_table").on(table.tableId),
|
|
960
|
+
uniqueIndex("idx_tdi_table_doc").on(table.tableId, table.documentId),
|
|
961
|
+
]
|
|
962
|
+
);
|
|
963
|
+
|
|
964
|
+
export const taskTableInputs = sqliteTable(
|
|
965
|
+
"task_table_inputs",
|
|
966
|
+
{
|
|
967
|
+
id: text("id").primaryKey(),
|
|
968
|
+
taskId: text("task_id")
|
|
969
|
+
.references(() => tasks.id)
|
|
970
|
+
.notNull(),
|
|
971
|
+
tableId: text("table_id")
|
|
972
|
+
.references(() => userTables.id)
|
|
973
|
+
.notNull(),
|
|
974
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
975
|
+
},
|
|
976
|
+
(table) => [
|
|
977
|
+
index("idx_tti_task").on(table.taskId),
|
|
978
|
+
uniqueIndex("idx_tti_task_table").on(table.taskId, table.tableId),
|
|
979
|
+
]
|
|
980
|
+
);
|
|
981
|
+
|
|
982
|
+
export const workflowTableInputs = sqliteTable(
|
|
983
|
+
"workflow_table_inputs",
|
|
984
|
+
{
|
|
985
|
+
id: text("id").primaryKey(),
|
|
986
|
+
workflowId: text("workflow_id")
|
|
987
|
+
.references(() => workflows.id)
|
|
988
|
+
.notNull(),
|
|
989
|
+
tableId: text("table_id")
|
|
990
|
+
.references(() => userTables.id)
|
|
991
|
+
.notNull(),
|
|
992
|
+
/** null = table available to all steps; set = scoped to specific step */
|
|
993
|
+
stepId: text("step_id"),
|
|
994
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
995
|
+
},
|
|
996
|
+
(table) => [
|
|
997
|
+
index("idx_wti_workflow").on(table.workflowId),
|
|
998
|
+
uniqueIndex("idx_wti_workflow_table_step").on(
|
|
999
|
+
table.workflowId,
|
|
1000
|
+
table.tableId,
|
|
1001
|
+
table.stepId
|
|
1002
|
+
),
|
|
1003
|
+
]
|
|
1004
|
+
);
|
|
1005
|
+
|
|
1006
|
+
export const scheduleTableInputs = sqliteTable(
|
|
1007
|
+
"schedule_table_inputs",
|
|
1008
|
+
{
|
|
1009
|
+
id: text("id").primaryKey(),
|
|
1010
|
+
scheduleId: text("schedule_id")
|
|
1011
|
+
.references(() => schedules.id)
|
|
1012
|
+
.notNull(),
|
|
1013
|
+
tableId: text("table_id")
|
|
1014
|
+
.references(() => userTables.id)
|
|
1015
|
+
.notNull(),
|
|
1016
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
1017
|
+
},
|
|
1018
|
+
(table) => [
|
|
1019
|
+
index("idx_sti_schedule").on(table.scheduleId),
|
|
1020
|
+
uniqueIndex("idx_sti_schedule_table").on(
|
|
1021
|
+
table.scheduleId,
|
|
1022
|
+
table.tableId
|
|
1023
|
+
),
|
|
1024
|
+
]
|
|
1025
|
+
);
|
|
1026
|
+
|
|
1027
|
+
// ── Table Workflow Triggers ──────────────────────────────────────────
|
|
1028
|
+
|
|
1029
|
+
export const userTableTriggers = sqliteTable(
|
|
1030
|
+
"user_table_triggers",
|
|
1031
|
+
{
|
|
1032
|
+
id: text("id").primaryKey(),
|
|
1033
|
+
tableId: text("table_id")
|
|
1034
|
+
.references(() => userTables.id)
|
|
1035
|
+
.notNull(),
|
|
1036
|
+
name: text("name").notNull(),
|
|
1037
|
+
triggerEvent: text("trigger_event", {
|
|
1038
|
+
enum: ["row_added", "row_updated", "row_deleted"],
|
|
1039
|
+
}).notNull(),
|
|
1040
|
+
/** JSON condition using filter format (null = always fire) */
|
|
1041
|
+
condition: text("condition"),
|
|
1042
|
+
actionType: text("action_type", {
|
|
1043
|
+
enum: ["run_workflow", "create_task"],
|
|
1044
|
+
}).notNull(),
|
|
1045
|
+
/** JSON config: { workflowId } or { title, description, projectId } */
|
|
1046
|
+
actionConfig: text("action_config").notNull(),
|
|
1047
|
+
status: text("status", { enum: ["active", "paused"] })
|
|
1048
|
+
.default("active")
|
|
1049
|
+
.notNull(),
|
|
1050
|
+
fireCount: integer("fire_count").default(0).notNull(),
|
|
1051
|
+
lastFiredAt: integer("last_fired_at", { mode: "timestamp" }),
|
|
1052
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
1053
|
+
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
1054
|
+
},
|
|
1055
|
+
(table) => [
|
|
1056
|
+
index("idx_user_table_triggers_table_id").on(table.tableId),
|
|
1057
|
+
index("idx_user_table_triggers_status").on(table.status),
|
|
1058
|
+
]
|
|
1059
|
+
);
|
|
1060
|
+
|
|
1061
|
+
// ── Table Row Version History ────────────────────────────────────────
|
|
1062
|
+
|
|
1063
|
+
export const userTableRowHistory = sqliteTable(
|
|
1064
|
+
"user_table_row_history",
|
|
1065
|
+
{
|
|
1066
|
+
id: text("id").primaryKey(),
|
|
1067
|
+
rowId: text("row_id").notNull(),
|
|
1068
|
+
tableId: text("table_id")
|
|
1069
|
+
.references(() => userTables.id)
|
|
1070
|
+
.notNull(),
|
|
1071
|
+
/** JSON snapshot of the row data before the change */
|
|
1072
|
+
previousData: text("previous_data").notNull(),
|
|
1073
|
+
changedBy: text("changed_by").default("user"),
|
|
1074
|
+
changeType: text("change_type", { enum: ["update", "delete"] }).notNull(),
|
|
1075
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
1076
|
+
},
|
|
1077
|
+
(table) => [
|
|
1078
|
+
index("idx_row_history_row_id").on(table.rowId),
|
|
1079
|
+
index("idx_row_history_table_id").on(table.tableId),
|
|
1080
|
+
index("idx_row_history_created_at").on(table.createdAt),
|
|
1081
|
+
]
|
|
1082
|
+
);
|
|
1083
|
+
|
|
758
1084
|
// Shared types derived from schema — use these in components instead of `as any`
|
|
759
1085
|
export type ProjectRow = InferSelectModel<typeof projects>;
|
|
760
1086
|
export type TaskRow = InferSelectModel<typeof tasks>;
|
|
@@ -780,3 +1106,45 @@ export type ReadingProgressRow = InferSelectModel<typeof readingProgress>;
|
|
|
780
1106
|
export type BookmarkRow = InferSelectModel<typeof bookmarks>;
|
|
781
1107
|
export type RepoImportRow = InferSelectModel<typeof repoImports>;
|
|
782
1108
|
export type AgentMessageRow = InferSelectModel<typeof agentMessages>;
|
|
1109
|
+
export type UserTableRow = InferSelectModel<typeof userTables>;
|
|
1110
|
+
export type UserTableColumnRow = InferSelectModel<typeof userTableColumns>;
|
|
1111
|
+
export type UserTableRowRow = InferSelectModel<typeof userTableRows>;
|
|
1112
|
+
export type UserTableViewRow = InferSelectModel<typeof userTableViews>;
|
|
1113
|
+
export type UserTableRelationshipRow = InferSelectModel<typeof userTableRelationships>;
|
|
1114
|
+
export type UserTableTemplateRow = InferSelectModel<typeof userTableTemplates>;
|
|
1115
|
+
export type UserTableImportRow = InferSelectModel<typeof userTableImports>;
|
|
1116
|
+
export type TableDocumentInputRow = InferSelectModel<typeof tableDocumentInputs>;
|
|
1117
|
+
export type TaskTableInputRow = InferSelectModel<typeof taskTableInputs>;
|
|
1118
|
+
export type WorkflowTableInputRow = InferSelectModel<typeof workflowTableInputs>;
|
|
1119
|
+
export type ScheduleTableInputRow = InferSelectModel<typeof scheduleTableInputs>;
|
|
1120
|
+
export type UserTableTriggerRow = InferSelectModel<typeof userTableTriggers>;
|
|
1121
|
+
export type UserTableRowHistoryRow = InferSelectModel<typeof userTableRowHistory>;
|
|
1122
|
+
|
|
1123
|
+
// ── Snapshots ──────────────────────────────────────────────────────────
|
|
1124
|
+
|
|
1125
|
+
export const snapshots = sqliteTable(
|
|
1126
|
+
"snapshots",
|
|
1127
|
+
{
|
|
1128
|
+
id: text("id").primaryKey(),
|
|
1129
|
+
label: text("label").notNull(),
|
|
1130
|
+
type: text("type", { enum: ["manual", "auto"] })
|
|
1131
|
+
.default("manual")
|
|
1132
|
+
.notNull(),
|
|
1133
|
+
status: text("status", { enum: ["in_progress", "completed", "failed"] })
|
|
1134
|
+
.default("in_progress")
|
|
1135
|
+
.notNull(),
|
|
1136
|
+
filePath: text("file_path").notNull(),
|
|
1137
|
+
sizeBytes: integer("size_bytes").default(0).notNull(),
|
|
1138
|
+
dbSizeBytes: integer("db_size_bytes").default(0).notNull(),
|
|
1139
|
+
filesSizeBytes: integer("files_size_bytes").default(0).notNull(),
|
|
1140
|
+
fileCount: integer("file_count").default(0).notNull(),
|
|
1141
|
+
error: text("error"),
|
|
1142
|
+
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
1143
|
+
},
|
|
1144
|
+
(table) => [
|
|
1145
|
+
index("idx_snapshots_type").on(table.type),
|
|
1146
|
+
index("idx_snapshots_created_at").on(table.createdAt),
|
|
1147
|
+
]
|
|
1148
|
+
);
|
|
1149
|
+
|
|
1150
|
+
export type SnapshotRow = InferSelectModel<typeof snapshots>;
|