Add internal seed endpoint for demo data
Creates 3 proposals (ranking/voting/passed) with votes and final votes from 3 demo users showing governance lifecycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1c6f9c64df
commit
d6544cb394
|
|
@ -0,0 +1,136 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
/**
|
||||
* Internal seed endpoint — populates the demo space with sample proposals
|
||||
* and votes. Only reachable from Docker network.
|
||||
*
|
||||
* POST /api/internal/seed { space: "demo" }
|
||||
*/
|
||||
export async function POST(request: Request) {
|
||||
const body = await request.json();
|
||||
const spaceSlug: string = body.space?.trim();
|
||||
if (!spaceSlug) {
|
||||
return NextResponse.json({ error: "Missing space" }, { status: 400 });
|
||||
}
|
||||
|
||||
const space = await prisma.space.findUnique({ where: { slug: spaceSlug } });
|
||||
if (!space) {
|
||||
return NextResponse.json({ error: "Space not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
// Check if already seeded
|
||||
const existingProposals = await prisma.proposal.count({ where: { spaceId: space.id } });
|
||||
if (existingProposals > 0) {
|
||||
return NextResponse.json({ status: "already_seeded", proposals: existingProposals });
|
||||
}
|
||||
|
||||
// Create demo users (rvote requires email)
|
||||
const alice = await prisma.user.upsert({
|
||||
where: { email: "alice@demo.rspace.online" },
|
||||
update: {},
|
||||
create: { email: "alice@demo.rspace.online", name: "Alice", did: "did:demo:alice" },
|
||||
});
|
||||
const bob = await prisma.user.upsert({
|
||||
where: { email: "bob@demo.rspace.online" },
|
||||
update: {},
|
||||
create: { email: "bob@demo.rspace.online", name: "Bob", did: "did:demo:bob" },
|
||||
});
|
||||
const charlie = await prisma.user.upsert({
|
||||
where: { email: "charlie@demo.rspace.online" },
|
||||
update: {},
|
||||
create: { email: "charlie@demo.rspace.online", name: "Charlie", did: "did:demo:charlie" },
|
||||
});
|
||||
|
||||
// Add as space members with credits
|
||||
for (const user of [alice, bob, charlie]) {
|
||||
await prisma.spaceMember.upsert({
|
||||
where: { userId_spaceId: { userId: user.id, spaceId: space.id } },
|
||||
update: {},
|
||||
create: { userId: user.id, spaceId: space.id, role: "MEMBER", credits: 100 },
|
||||
});
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const weekFromNow = new Date(Date.now() + 7 * 86400000);
|
||||
|
||||
// Proposal 1: Active voting (high engagement)
|
||||
const prop1 = await prisma.proposal.create({
|
||||
data: {
|
||||
spaceId: space.id,
|
||||
title: "Increase community meeting frequency to biweekly",
|
||||
description:
|
||||
"Monthly meetings aren't enough to keep momentum. Proposing we switch to biweekly 30-minute check-ins to stay aligned on community projects and share progress.",
|
||||
authorId: alice.id,
|
||||
status: "VOTING",
|
||||
score: 15,
|
||||
votingEndsAt: weekFromNow,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.vote.createMany({
|
||||
data: [
|
||||
{ proposalId: prop1.id, userId: alice.id, weight: 8, creditCost: 64 },
|
||||
{ proposalId: prop1.id, userId: bob.id, weight: 5, creditCost: 25 },
|
||||
{ proposalId: prop1.id, userId: charlie.id, weight: 2, creditCost: 4 },
|
||||
],
|
||||
});
|
||||
|
||||
// Proposal 2: In ranking phase (newer)
|
||||
const prop2 = await prisma.proposal.create({
|
||||
data: {
|
||||
spaceId: space.id,
|
||||
title: "Allocate $500 from treasury for public art project",
|
||||
description:
|
||||
"Let's commission a local artist to create a mural for our community space. This would make the entrance more welcoming and showcase our values. Budget covers materials + artist stipend.",
|
||||
authorId: bob.id,
|
||||
status: "RANKING",
|
||||
score: 3,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.vote.createMany({
|
||||
data: [
|
||||
{ proposalId: prop2.id, userId: bob.id, weight: 3, creditCost: 9 },
|
||||
],
|
||||
});
|
||||
|
||||
// Proposal 3: Passed (shows completed governance)
|
||||
const prop3 = await prisma.proposal.create({
|
||||
data: {
|
||||
spaceId: space.id,
|
||||
title: "Adopt transparent decision-making framework",
|
||||
description:
|
||||
"All community decisions over $100 should go through quadratic voting. This ensures fair representation — those who care more can express stronger preferences, while preventing whale dominance.",
|
||||
authorId: charlie.id,
|
||||
status: "PASSED",
|
||||
score: 22,
|
||||
votingEndsAt: new Date(Date.now() - 3 * 86400000),
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.vote.createMany({
|
||||
data: [
|
||||
{ proposalId: prop3.id, userId: alice.id, weight: 10, creditCost: 100 },
|
||||
{ proposalId: prop3.id, userId: bob.id, weight: 7, creditCost: 49 },
|
||||
{ proposalId: prop3.id, userId: charlie.id, weight: 5, creditCost: 25 },
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.finalVote.createMany({
|
||||
data: [
|
||||
{ proposalId: prop3.id, userId: alice.id, vote: "YES" },
|
||||
{ proposalId: prop3.id, userId: bob.id, vote: "YES" },
|
||||
{ proposalId: prop3.id, userId: charlie.id, vote: "ABSTAIN" },
|
||||
],
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
status: "seeded",
|
||||
space: spaceSlug,
|
||||
proposals: 3,
|
||||
votes: 7,
|
||||
finalVotes: 3,
|
||||
users: 3,
|
||||
}, { status: 201 });
|
||||
}
|
||||
Loading…
Reference in New Issue