feat(rgov): add seed template with two example governance circuits

Seeds demo spaces with a "Build a Climbing Wall" circuit (labor threshold +
capital threshold + proprietor signoff → project) and a "Community Potluck"
circuit (budget knob + RSVPs threshold + venue signoff → project), each
pre-wired with arrows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-03 13:15:25 -07:00
parent 559d146099
commit 16f224f065
1 changed files with 134 additions and 0 deletions

View File

@ -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<string, any>)
.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<string, unknown>[] = [
// ── 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",