Change Request Versioning System for Prompt Modifications in prompts.chat
The prompts.chat platform implements an immutable versioning system where contributors submit change requests rather than editing prompts directly, enabling owners to review, approve, or reject modifications while maintaining a complete audit trail of every content evolution.
The change request versioning system for prompt modifications in prompts.chat treats every prompt as an immutable record that evolves through controlled contributions. Instead of allowing direct edits, the platform requires users to submit formal change requests that prompt owners must approve, creating a new version only upon acceptance. This workflow ensures content integrity and provides a complete history of who changed what and why.
Core Data Models in Prisma
The architecture rests on three interconnected models defined in prisma/schema.prisma. These entities separate the live prompt from its historical snapshots and pending proposals.
Prompt represents the public-facing entity. It stores the current title, content, and slug, while maintaining a relation to contributors—users whose changes have been accepted.
PromptVersion acts as an immutable snapshot. Each row captures a prompt's state at a specific moment, including content, title, changeNote, authorId, and createdAt. The system queries these records to build version histories.
ChangeRequest handles the proposal workflow. It stores proposedContent, proposedTitle, and a reason string, along with a status enum that tracks whether the request is PENDING, APPROVED, or REJECTED. When approved, the system promotes these values into a new PromptVersion and updates the live Prompt record.
Feature Flag Configuration
The entire workflow can be toggled via the centralized configuration in src/lib/config/index.ts. This allows administrators to enable or disable community contributions without deploying new code.
// src/lib/config/index.ts
export const config = {
features: {
changeRequests: envBool('PCHAT_FEATURE_CHANGE_REQUESTS', false),
},
};
When changeRequests evaluates to true, the UI renders "Suggest Change" links generated by getPromptChangesUrl in src/lib/urls.ts, and the API routes become accessible. By default, the feature remains disabled.
API Endpoints and Workflow
The system exposes a RESTful API that separates owner actions from contributor proposals. All routes utilize the Prisma client exported from src/lib/db.ts and enforce permissions through helper functions like checkPromptAccess.
Creating Versions (Owner Edits)
When a prompt owner modifies their own content, the system creates a new version immediately. The endpoint POST /api/prompts/:id/versions validates that the content differs from the latest snapshot before inserting a record.
// src/app/api/prompts/[id]/versions/route.ts
const schema = z.object({
changeNote: z.string().max(500).optional(),
});
const { content, changeNote } = await request.json().then(schema.parse);
const latest = await db.promptVersion.findFirst({
where: { promptId: id },
orderBy: { versionNumber: "desc" },
});
if (latest?.content === content) {
return NextResponse.json({ error: "no_change" }, { status: 400 });
}
const newVersion = await db.promptVersion.create({
data: {
promptId: id,
content,
changeNote: changeNote ?? `Version ${latest?.versionNumber + 1 || 1}`,
authorId: session.user.id,
},
});
This prevents duplicate versions and auto-generates version numbers when contributors omit change notes.
Submitting Change Requests (Contributor Proposals)
Non-owners must use POST /api/prompts/:id/changes to propose modifications. The route explicitly forbids owners from creating requests against their own prompts.
// src/app/api/prompts/[id]/changes/route.ts
if (prompt.ownerId === session.user.id) {
return NextResponse.json(
{ error: "forbidden", message: "You cannot create a change request for your own prompt" },
{ status: 403 }
);
}
const changeRequest = await db.changeRequest.create({
data: {
promptId: id,
authorId: session.user.id,
proposedContent: body.content,
proposedTitle: body.title,
reason: body.reason,
status: "PENDING",
},
});
The request remains in PENDING status until the owner reviews it.
Reviewing and Approving Requests (Owner Actions)
Owners manage proposals through PATCH /api/prompts/:id/changes/:changeId. Setting status to "APPROVED" triggers a multi-step transaction that atomically creates a version, updates the prompt, and records the contributor.
// src/app/api/prompts/[id]/changes/[changeId]/route.ts
if (status === "APPROVED") {
// 1. Archive the proposed content as a new version
await db.promptVersion.create({
data: {
promptId,
content: changeRequest.proposedContent,
changeNote: `Contribution by @${changeRequest.author.username}: ${changeRequest.reason ?? ""}`,
authorId: changeRequest.authorId,
},
});
// 2. Update the live prompt and link the contributor
await db.prompt.update({
where: { id: promptId },
data: {
content: changeRequest.proposedContent,
title: changeRequest.proposedTitle ?? undefined,
contributors: { connect: { id: changeRequest.authorId } },
},
});
// 3. Finalize the request status
await db.changeRequest.update({
where: { id: changeId },
data: { status: "APPROVED" },
});
}
Alternatively, owners may "REJECT" the request, or authors may DELETE their own pending proposals via DELETE /api/prompts/:id/changes/:changeId.
Key Source Files
prisma/schema.prisma– DefinesPrompt,PromptVersion, andChangeRequestmodels with their relations.src/lib/config/index.ts– Contains thechangeRequestsfeature flag that toggles the workflow.src/app/api/prompts/[id]/versions/route.ts– Handles version creation and listing for owner-initiated changes.src/app/api/prompts/[id]/changes/route.ts– Endpoint for submitting new change requests with ownership validation.src/app/api/prompts/[id]/changes/[changeId]/route.ts– Supports retrieval, approval, rejection, and dismissal of specific requests.src/lib/urls.ts– ExportsgetPromptChangesUrlfor generating frontend navigation links.src/lib/db.ts– Exports the Prisma client used across all API routes for database operations.
Summary
- Immutable versioning ensures every accepted change becomes a permanent
PromptVersionrecord linked to the author. - Feature-flagged workflow allows administrators to enable or disable change requests via the
PCHAT_FEATURE_CHANGE_REQUESTSenvironment variable. - Strict permission model prevents owners from creating change requests on their own prompts and restricts approval rights to the prompt owner.
- Automatic attribution adds approving contributors to the prompt's
contributorsrelation, creating a visible credit system. - Complete audit trail preserves the full history of proposed, rejected, and accepted modifications through discrete database records.
Frequently Asked Questions
How does the change request versioning system prevent unauthorized edits?
The system performs ownership checks in every API route. In src/app/api/prompts/[id]/changes/route.ts, the server compares prompt.ownerId against session.user.id and returns a 403 Forbidden error if they match, preventing self-requests. Additionally, the PATCH endpoint in [changeId]/route.ts verifies that only the prompt owner can approve or reject requests, while the DELETE endpoint restricts dismissal to the original author.
What happens when a prompt owner approves a change request?
Upon approval, the system executes a three-step transaction. First, it creates a new PromptVersion record containing the proposed content and a change note attributing the contributor. Second, it updates the live Prompt record with the new content and title, simultaneously connecting the contributor to the prompt's contributors relation. Third, it updates the ChangeRequest status to APPROVED, completing the workflow.
Can contributors delete their pending change requests?
Yes. Contributors may withdraw proposals that have not yet been reviewed by sending a DELETE request to /api/prompts/:id/changes/:changeId. The route verifies that the requesting user matches the authorId of the change request before removing the record from the database. Once approved or rejected, the request cannot be deleted by the contributor.
How do I enable the change request feature in a self-hosted prompts.chat instance?
Set the environment variable PCHAT_FEATURE_CHANGE_REQUESTS to true before starting the application. This variable is read by envBool() in src/lib/config/index.ts, which sets the changeRequests feature flag to enable the UI links and API endpoints. Without this flag set to true, the "Suggest Change" interface remains hidden and the change request routes return 404 responses.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →