diff --git a/modules/rgov/mod.ts b/modules/rgov/mod.ts index c91aacf..f332750 100644 --- a/modules/rgov/mod.ts +++ b/modules/rgov/mod.ts @@ -12,6 +12,7 @@ import { renderShell } from "../../server/shell"; import { getModuleInfoList } from "../../shared/module"; import type { RSpaceModule } from "../../shared/module"; import { renderLanding } from "./landing"; +import { addShapes, getDocumentData } from "../../server/community-store"; const routes = new Hono(); @@ -63,6 +64,138 @@ routes.get("/api/shapes", (c) => { }); }); +// ── Seed template: example governance circuits ── + +function seedTemplateGov(space: string) { + const docData = getDocumentData(space); + const govTypes = [ + "folk-gov-binary", "folk-gov-threshold", "folk-gov-knob", + "folk-gov-project", "folk-gov-amendment", + ]; + if (docData?.shapes) { + const existing = Object.values(docData.shapes as Record) + .filter((s: any) => !s.forgotten && govTypes.includes(s.type)); + if (existing.length > 0) return; + } + + const now = Date.now(); + + // ── Circuit 1: "Build a Climbing Wall" ── + // Labor threshold + Capital threshold + Proprietor signoff → Project aggregator + const laborId = `gov-labor-${now}`; + const capitalId = `gov-capital-${now}`; + const signoffId = `gov-signoff-${now}`; + const projectId = `gov-project-${now}`; + + // ── Circuit 2: "Community Event Approval" ── + // Budget knob → Attendance threshold, plus Venue signoff → Event project + const knobId = `gov-knob-${now}`; + const attendId = `gov-attend-${now}`; + const venueId = `gov-venue-${now}`; + const eventId = `gov-event-${now}`; + + const baseY = 2600; + + const shapes: Record[] = [ + // ── Circuit 1 shapes ── + { + id: laborId, type: "folk-gov-threshold", + x: 50, y: baseY, width: 240, height: 160, rotation: 0, + title: "Labor Contributed", target: 50, unit: "hours", + contributions: [ + { who: "Alice", amount: 12, timestamp: now - 86400000 }, + { who: "Bob", amount: 8, timestamp: now - 43200000 }, + ], + }, + { + id: capitalId, type: "folk-gov-threshold", + x: 50, y: baseY + 200, width: 240, height: 160, rotation: 0, + title: "Capital Raised", target: 3000, unit: "$", + contributions: [ + { who: "Community Fund", amount: 1500, timestamp: now - 172800000 }, + { who: "Sponsor A", amount: 500, timestamp: now - 86400000 }, + ], + }, + { + id: signoffId, type: "folk-gov-binary", + x: 50, y: baseY + 440, width: 240, height: 120, rotation: 0, + title: "Proprietor Approval", assignee: "Dana (proprietor)", + satisfied: false, signedBy: "", timestamp: 0, + }, + { + id: projectId, type: "folk-gov-project", + x: 400, y: baseY + 140, width: 300, height: 240, rotation: 0, + title: "Build a Climbing Wall", + description: "Community climbing wall project — requires labor, capital, and proprietor signoff.", + status: "active", + }, + // Arrows wiring Circuit 1 + { + id: `gov-arrow-labor-${now}`, type: "folk-arrow", + x: 0, y: 0, width: 0, height: 0, rotation: 0, + sourceId: laborId, targetId: projectId, color: "#0891b2", + }, + { + id: `gov-arrow-capital-${now}`, type: "folk-arrow", + x: 0, y: 0, width: 0, height: 0, rotation: 0, + sourceId: capitalId, targetId: projectId, color: "#0891b2", + }, + { + id: `gov-arrow-signoff-${now}`, type: "folk-arrow", + x: 0, y: 0, width: 0, height: 0, rotation: 0, + sourceId: signoffId, targetId: projectId, color: "#7c3aed", + }, + + // ── Circuit 2 shapes ── + { + id: knobId, type: "folk-gov-knob", + x: 800, y: baseY, width: 200, height: 170, rotation: 0, + title: "Event Budget", min: 100, max: 5000, step: 100, + value: 1500, unit: "$", cooldown: 0, + }, + { + id: attendId, type: "folk-gov-threshold", + x: 800, y: baseY + 210, width: 240, height: 160, rotation: 0, + title: "RSVPs Collected", target: 20, unit: "people", + contributions: [ + { who: "Mailing list", amount: 14, timestamp: now - 86400000 }, + ], + }, + { + id: venueId, type: "folk-gov-binary", + x: 800, y: baseY + 410, width: 240, height: 120, rotation: 0, + title: "Venue Confirmed", assignee: "Events Team", + satisfied: true, signedBy: "Carlos", timestamp: now - 43200000, + }, + { + id: eventId, type: "folk-gov-project", + x: 1140, y: baseY + 140, width: 300, height: 240, rotation: 0, + title: "Community Potluck", + description: "Monthly community potluck — needs budget, RSVPs, and venue confirmation.", + status: "active", + }, + // Arrows wiring Circuit 2 + { + id: `gov-arrow-knob-${now}`, type: "folk-arrow", + x: 0, y: 0, width: 0, height: 0, rotation: 0, + sourceId: knobId, targetId: eventId, color: "#b45309", + }, + { + id: `gov-arrow-attend-${now}`, type: "folk-arrow", + x: 0, y: 0, width: 0, height: 0, rotation: 0, + sourceId: attendId, targetId: eventId, color: "#0891b2", + }, + { + id: `gov-arrow-venue-${now}`, type: "folk-arrow", + x: 0, y: 0, width: 0, height: 0, rotation: 0, + sourceId: venueId, targetId: eventId, color: "#7c3aed", + }, + ]; + + addShapes(space, shapes); + console.log(`[rGov] Template seeded for "${space}": 2 circuits (8 shapes + 6 arrows)`); +} + // ── Module export ── export const govModule: RSpaceModule = { @@ -73,6 +206,7 @@ export const govModule: RSpaceModule = { routes, scoping: { defaultScope: "space", userConfigurable: false }, landingPage: renderLanding, + seedTemplate: seedTemplateGov, canvasShapes: [ "folk-gov-binary", "folk-gov-threshold",