feat(broker+api): every mesh ships with a default #general topic
The web chat surface needed a guaranteed landing room — a topic that exists for every mesh from creation onward so the dashboard always has somewhere to drop the user. #general is the convention; ephemeral DMs remain ephemeral (mesh.message_queue) so agentic privacy is unchanged. Three hooks plus a backfill: - packages/api/src/modules/mesh/mutations.ts — createMyMesh now calls ensureGeneralTopic() right after the mesh insert. New helper is idempotent via the unique (mesh_id, name) index. - apps/broker/src/index.ts — handleMeshCreate (CLI claudemesh new) inserts #general + subscribes the owner member as 'lead' in the same handler. - apps/broker/src/crypto.ts — invite-claim flow auto-subscribes the newly minted member to #general as 'member', defensively ensuring the topic exists if predates this change. - packages/db/migrations/0024_general_topic_backfill.sql — one-shot backfill: creates #general for every active mesh that doesn't have one, subscribes every active member, and marks the mesh owner as 'lead' based on owner_user_id == member.user_id. Idempotent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5945,6 +5945,22 @@ async function handleCliMeshCreate(req: IncomingMessage, res: ServerResponse, st
|
||||
VALUES (${memberId}, ${meshId}, ${auth.userId}, ${body.pubkey}, ${body.name + "-owner"}, ${"admin"})
|
||||
`);
|
||||
|
||||
// Auto-create the conventional #general topic + subscribe the owner.
|
||||
// Idempotent via unique (mesh_id, name) — re-running is a no-op.
|
||||
const generalTopicId = generateId();
|
||||
await db.execute(sql`
|
||||
INSERT INTO mesh.topic (id, mesh_id, name, description, visibility, created_by_member_id)
|
||||
VALUES (${generalTopicId}, ${meshId}, ${"general"}, ${"Default mesh-wide channel. Every member can read and post."}, ${"public"}, ${memberId})
|
||||
ON CONFLICT (mesh_id, name) DO NOTHING
|
||||
`);
|
||||
await db.execute(sql`
|
||||
INSERT INTO mesh.topic_member (topic_id, member_id, role)
|
||||
SELECT t.id, ${memberId}, ${"lead"}
|
||||
FROM mesh.topic t
|
||||
WHERE t.mesh_id = ${meshId} AND t.name = ${"general"}
|
||||
ON CONFLICT (topic_id, member_id) DO NOTHING
|
||||
`);
|
||||
|
||||
writeJson(res, 200, { id: meshId, slug, name: body.name, member_id: memberId });
|
||||
log.info("mesh-create", { route: "POST /cli/mesh/create", slug, user_id: auth.userId, latency_ms: Date.now() - started });
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user