feat(web): restore payload CMS (cuidecar pattern + importMap)
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled
Release / Publish multi-arch images (push) Has been cancelled

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-06 14:30:16 +01:00
parent 7a5f786e0c
commit 0b4e389f2b
22 changed files with 9651 additions and 4 deletions

View File

@@ -0,0 +1,33 @@
CREATE TABLE "mesh"."context" (
"id" text PRIMARY KEY NOT NULL,
"mesh_id" text NOT NULL,
"presence_id" text,
"peer_name" text,
"summary" text NOT NULL,
"files_read" text[] DEFAULT '{}',
"key_findings" text[] DEFAULT '{}',
"tags" text[] DEFAULT '{}',
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "mesh"."task" (
"id" text PRIMARY KEY NOT NULL,
"mesh_id" text NOT NULL,
"title" text NOT NULL,
"assignee" text,
"claimed_by_name" text,
"claimed_by_presence" text,
"priority" text DEFAULT 'normal' NOT NULL,
"status" text DEFAULT 'open' NOT NULL,
"tags" text[] DEFAULT '{}',
"result" text,
"created_by_name" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"claimed_at" timestamp,
"completed_at" timestamp
);
--> statement-breakpoint
ALTER TABLE "mesh"."context" ADD CONSTRAINT "context_mesh_id_mesh_id_fk" FOREIGN KEY ("mesh_id") REFERENCES "mesh"."mesh"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "mesh"."context" ADD CONSTRAINT "context_presence_id_presence_id_fk" FOREIGN KEY ("presence_id") REFERENCES "mesh"."presence"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "mesh"."task" ADD CONSTRAINT "task_mesh_id_mesh_id_fk" FOREIGN KEY ("mesh_id") REFERENCES "mesh"."mesh"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "mesh"."task" ADD CONSTRAINT "task_claimed_by_presence_presence_id_fk" FOREIGN KEY ("claimed_by_presence") REFERENCES "mesh"."presence"("id") ON DELETE no action ON UPDATE no action;

View File

@@ -0,0 +1,10 @@
CREATE TABLE "mesh"."stream" (
"id" text PRIMARY KEY NOT NULL,
"mesh_id" text NOT NULL,
"name" text NOT NULL,
"created_by_name" text,
"created_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "mesh"."stream" ADD CONSTRAINT "stream_mesh_id_mesh_id_fk" FOREIGN KEY ("mesh_id") REFERENCES "mesh"."mesh"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
CREATE UNIQUE INDEX "stream_mesh_name_idx" ON "mesh"."stream" USING btree ("mesh_id","name");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -71,6 +71,20 @@
"when": 1775480008546,
"tag": "0009_add-file-tables",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1775480729014,
"tag": "0010_add-context-and-tasks",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1775481222701,
"tag": "0011_add-streams",
"breakpoints": true
}
]
}

View File

@@ -327,6 +327,68 @@ export const meshFileAccess = meshSchema.table("file_access", {
accessedAt: timestamp().defaultNow().notNull(),
});
/**
* Per-peer context snapshot. Each peer (presence) has at most one context
* entry per mesh, upserted on each share_context call. Allows peers to
* discover what others are working on, which files they've read, and
* key findings — without sending a direct message.
*/
export const meshContext = meshSchema.table("context", {
id: text().primaryKey().notNull().$defaultFn(generateId),
meshId: text()
.references(() => mesh.id, { onDelete: "cascade", onUpdate: "cascade" })
.notNull(),
presenceId: text().references(() => presence.id, { onDelete: "cascade" }),
peerName: text(),
summary: text().notNull(),
filesRead: text().array().default([]),
keyFindings: text().array().default([]),
tags: text().array().default([]),
updatedAt: timestamp().defaultNow().notNull(),
});
/**
* Mesh-scoped task board. Peers can create tasks, claim them, and mark
* them done. Lightweight project management for multi-agent workflows.
*/
export const meshTask = meshSchema.table("task", {
id: text().primaryKey().notNull().$defaultFn(generateId),
meshId: text()
.references(() => mesh.id, { onDelete: "cascade", onUpdate: "cascade" })
.notNull(),
title: text().notNull(),
assignee: text(),
claimedByName: text(),
claimedByPresence: text().references(() => presence.id),
priority: text().notNull().default("normal"),
status: text().notNull().default("open"),
tags: text().array().default([]),
result: text(),
createdByName: text(),
createdAt: timestamp().defaultNow().notNull(),
claimedAt: timestamp(),
completedAt: timestamp(),
});
/**
* Named real-time data channels within a mesh. One peer publishes, all
* subscribers receive. No message history — streams are live.
* Use cases: build logs, deploy status, monitoring data, live code diffs.
*/
export const meshStream = meshSchema.table(
"stream",
{
id: text().primaryKey().notNull().$defaultFn(generateId),
meshId: text()
.references(() => mesh.id, { onDelete: "cascade", onUpdate: "cascade" })
.notNull(),
name: text().notNull(),
createdByName: text(),
createdAt: timestamp().defaultNow().notNull(),
},
(table) => [uniqueIndex("stream_mesh_name_idx").on(table.meshId, table.name)],
);
export const meshRelations = relations(mesh, ({ one, many }) => ({
owner: one(user, {
fields: [mesh.ownerUserId],
@@ -469,3 +531,45 @@ export type SelectMeshFile = typeof meshFile.$inferSelect;
export type InsertMeshFile = typeof meshFile.$inferInsert;
export type SelectMeshFileAccess = typeof meshFileAccess.$inferSelect;
export type InsertMeshFileAccess = typeof meshFileAccess.$inferInsert;
export const selectMeshContextSchema = createSelectSchema(meshContext);
export const insertMeshContextSchema = createInsertSchema(meshContext);
export const selectMeshTaskSchema = createSelectSchema(meshTask);
export const insertMeshTaskSchema = createInsertSchema(meshTask);
export type SelectMeshContext = typeof meshContext.$inferSelect;
export type InsertMeshContext = typeof meshContext.$inferInsert;
export type SelectMeshTask = typeof meshTask.$inferSelect;
export type InsertMeshTask = typeof meshTask.$inferInsert;
export const meshContextRelations = relations(meshContext, ({ one }) => ({
mesh: one(mesh, {
fields: [meshContext.meshId],
references: [mesh.id],
}),
presence: one(presence, {
fields: [meshContext.presenceId],
references: [presence.id],
}),
}));
export const meshTaskRelations = relations(meshTask, ({ one }) => ({
mesh: one(mesh, {
fields: [meshTask.meshId],
references: [mesh.id],
}),
claimedPresence: one(presence, {
fields: [meshTask.claimedByPresence],
references: [presence.id],
}),
}));
export const meshStreamRelations = relations(meshStream, ({ one }) => ({
mesh: one(mesh, {
fields: [meshStream.meshId],
references: [mesh.id],
}),
}));
export const selectMeshStreamSchema = createSelectSchema(meshStream);
export const insertMeshStreamSchema = createInsertSchema(meshStream);
export type SelectMeshStream = typeof meshStream.$inferSelect;
export type InsertMeshStream = typeof meshStream.$inferInsert;