Skip to content

feat(template): impl remix template w/ direct copy#72

Merged
phasehumans merged 2 commits into
mainfrom
chaitanya/remix-template
May 5, 2026
Merged

feat(template): impl remix template w/ direct copy#72
phasehumans merged 2 commits into
mainfrom
chaitanya/remix-template

Conversation

@phasehumans

@phasehumans phasehumans commented May 5, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Enhanced template remixing with improved file and manifest handling
  • Changes

    • Removed "Design Systems" link from sidebar navigation
    • Removed API Keys tab from profile settings

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements template remixing functionality that derives and materializes projects from template versions, refactors project-service exports to support this, hardens user-deletion validation in project duplication, and removes disabled or incomplete frontend navigation features (Design Systems link and API Keys tab).

Changes

Template Remixing and Project Service Refactoring

Layer / File(s) Summary
Type & Helper Exports
server/src/modules/project/project.service.ts
StoredProjectFile type and loadGeneratedFilesFromManifest async function are exported to support external manifest loading.
User Validation
server/src/modules/project/project.service.ts
duplicateProject now treats deleted users (where isDeleted === true) as "user not found" before proceeding with project duplication.
Core Remixing Logic
server/src/modules/template/template.service.ts
remixTemplate fetches the latest stored projectVersion of a shared template, creates a new project with derived prompts and status, parses and loads the manifest, saves generated files, creates an initial projectVersion record with storage metadata, and updates version tracking on the new project.

Navigation UI Removals

Layer / File(s) Summary
Sidebar Navigation
web/src/features/navigation/components/Sidebar.tsx
Removed the "Design Systems" navigation link (SidebarNavItem with Icons.DesignSystems).
Profile Settings Tabs
web/src/features/profile/components/ProfileSettings.tsx
Commented out the "API Keys" tab button, preventing navigation to that view via the sidebar.

Placeholder Cleanup

Layer / File(s) Summary
Route Comment Removal
server/src/modules/docs/docs.routes.ts
Removed the placeholder comment // add feedback route here.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The primary complexity stems from understanding the new remixTemplate workflow across manifest parsing, file persistence, and version tracking. The user-deletion validation and navigation removals are straightforward, but the template logic requires verification that manifest hydration, file storage, and project version initialization align with the intended remix behavior and existing data models.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing remix template functionality with direct file copying, which aligns with the substantial changes to template.service.ts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chaitanya/remix-template

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
web/src/features/profile/components/ProfileSettings.tsx (1)

157-167: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Clean up the API Keys path end-to-end (hide + unreachable view).

With this button removed, activeTab no longer has a UI path to 'API Keys', so the activeTab === 'API Keys' branch (Line 239-Line 240) is effectively dead in this component. Could you either remove the API Keys render branch/import too, or wire this behind an explicit feature flag/deep-link entry so intent stays clear and testable?

server/src/modules/project/project.service.ts (1)

62-67: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail fast when a manifest entry is missing in storage.

Falling back to '' here turns object-store drift into silent file corruption in download, duplicate, and remix flows. It would be safer to throw and fail the request than materialize empty files.

Proposed fix
 export const loadGeneratedFilesFromManifest = async (manifest: StoredProjectFile[]) => {
     const files = await Promise.all(
-        manifest.map(async (file) => [file.path, (await getTextFile(file.key)) ?? ''] as const)
+        manifest.map(async (file) => {
+            const content = await getTextFile(file.key)
+            if (content === null) {
+                throw new AppError(`missing stored file for "${file.path}"`, 500)
+            }
+            return [file.path, content] as const
+        })
     )

     return Object.fromEntries(files)
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b7ddc965-0939-475e-99c8-dbc897d571e9

📥 Commits

Reviewing files that changed from the base of the PR and between 5ee13db and 39b905f.

📒 Files selected for processing (20)
  • server/src/modules/docs/docs.controller.ts
  • server/src/modules/docs/docs.routes.ts
  • server/src/modules/docs/docs.schema.ts
  • server/src/modules/docs/docs.service.ts
  • server/src/modules/docs/docs.utils.ts
  • server/src/modules/keys/keys.controller.ts
  • server/src/modules/keys/keys.routes.ts
  • server/src/modules/keys/keys.schema.ts
  • server/src/modules/keys/keys.service.ts
  • server/src/modules/keys/keys.utils.ts
  • server/src/modules/project/project.service.ts
  • server/src/modules/template/template.service.ts
  • server/tests/integration/docs/docs.routes.test.ts
  • server/tests/integration/docs/docs.service.test.ts
  • server/tests/integration/keys/keys.routes.test.ts
  • server/tests/integration/keys/keys.service.test.ts
  • server/tests/unit/docs.unit.test.ts
  • server/tests/unit/keys.unit.test.ts
  • web/src/features/navigation/components/Sidebar.tsx
  • web/src/features/profile/components/ProfileSettings.tsx
💤 Files with no reviewable changes (2)
  • server/src/modules/docs/docs.routes.ts
  • web/src/features/navigation/components/Sidebar.tsx

Comment on lines +95 to +148
const newProject = await prisma.project.create({
data: {
name: `Remix of ${template.name}`,
description: template.description,
prompt: currentVersion?.sourcePrompt ?? template.prompt,
projectStatus: currentVersion ? 'READY' : template.projectStatus,
userId: userId,
},
})

if (!currentVersion) {
return newProject
}

const manifest = parseStoredProjectFiles(currentVersion.manifestJson)
const generatedFiles = await loadGeneratedFilesFromManifest(manifest)

const versionRecordId = crypto.randomUUID()

const savedFiles = await saveProjectFiles({
projectId: newProject.id,
versionId: versionRecordId,
files: Object.entries(generatedFiles).map(([path, content]) => ({
path,
content,
})),
})

await prisma.projectVersion.create({
data: {
id: versionRecordId,
projectId: newProject.id,
versionNumber: 1,
label: 'v1',
sourcePrompt: currentVersion.sourcePrompt,
status: 'READY',
objectStoragePrefix: `projects/${newProject.id}/v1/${versionRecordId}`,

manifestJson: savedFiles.map((file) => ({
path: file.path,
key: file.key,
size: file.size,
...(file.contentType ? { contentType: file.contentType } : {}),
})),
},
})

await prisma.project.update({
where: { id: newProject.id },
data: {
currentVersionId: versionRecordId,
versionCount: 1,
},
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Make the remix creation all-or-nothing.

After project.create, any failure in file loading, file saving, projectVersion.create, or the final project.update leaves behind a partially initialized project, and in the currentVersion path it is created as READY before the copy actually succeeds. Could we wrap the DB writes in a transaction and add compensating cleanup for saved files, or keep the project non-ready until the copy completes?

Comment on lines +123 to +139
await prisma.projectVersion.create({
data: {
id: versionRecordId,
projectId: newProject.id,
versionNumber: 1,
label: 'v1',
sourcePrompt: currentVersion.sourcePrompt,
status: 'READY',
objectStoragePrefix: `projects/${newProject.id}/v1/${versionRecordId}`,

manifestJson: savedFiles.map((file) => ({
path: file.path,
key: file.key,
size: file.size,
...(file.contentType ? { contentType: file.contentType } : {}),
})),
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Was dropping the version metadata intentional?

This persists the remixed version's file manifest, but it does not carry forward canvasStateJson, canvasAssetManifestJson, intentJson, or planJson from currentVersion. If the goal is a direct copy, templates created through the canvas flow will remix into a blank state.

@phasehumans phasehumans merged commit d7bddf3 into main May 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant