Skip to content

feat(api): add community template API - #61

Closed
David-2610 wants to merge 2 commits into
Openlabsops:mainfrom
David-2610:feat/create-template-api
Closed

David-2610 wants to merge 2 commits into
Openlabsops:mainfrom
David-2610:feat/create-template-api

Conversation

@David-2610

@David-2610 David-2610 commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

What's Changed

This PR introduces a Community Templates system that allows users to publish forms as reusable templates and browse publicly available templates created by other users.

Closes #47

Key Implementation Details

1. Database Schema Updates

Added a new Template model with support for:

  • Template metadata (title, description, category)
  • Form field snapshot storage using JSON
  • Preview assets (iconSymbol, images)
  • Template status management (DRAFT, PUBLISHED, ARCHIVED)
  • Template ownership through createdById
  • Optional source form reference via formId
  • Community metrics (featured, useCount)

Updated the User model to include a templates relation.

Added indexes for:

  • category
  • createdById
  • status
  • featured

2. Validation Layer

Created CreateTemplateSchema for template creation requests.

Validation includes:

  • Required title validation
  • Optional description, category, and icon support
  • URL validation for template preview images
  • Maximum image count enforcement
  • Support for both direct field definitions and form snapshot creation
  • Draft and published template states

3. Template Creation API

Added:

POST /api/v1/templates

Implementation details:

  • Requires authentication
  • Supports creating templates from supplied form definitions
  • Supports snapshotting an existing form using formId
  • Verifies ownership of the source form before snapshot creation
  • Associates templates with the authenticated user
  • Stores templates as either drafts or published entries

Error handling:

  • Returns 404 Not Found if the referenced form does not exist or is not owned by the authenticated user

4. Template Listing API

Added:

GET /api/v1/templates

Implementation details:

  • Publicly accessible endpoint

  • Returns only published templates

  • Supports optional category-based filtering

  • Orders results by:

    • Featured status
    • Usage count
    • Creation date

Response includes:

  • Template metadata
  • Preview information
  • Creator information
  • Usage statistics

5. Route Registration

Registered template routes under:

/api/v1/templates

Available endpoints:

  • GET /api/v1/templates
  • POST /api/v1/templates

Template creation is protected using the existing authentication middleware.


Community Template API

Added backend support for community templates, enabling:

  • Publishing forms as reusable templates
  • Snapshot-based template creation from existing forms
  • Public template discovery
  • Template categorization
  • Ownership validation and access control

Checklist

  • Code follows project conventions
  • API routes registered and protected where required
  • Schema validation implemented
  • Prisma schema updated
  • Documentation/comments updated where applicable

Release Notes

Community Templates support has been added to the API. Authenticated users can now publish forms as reusable templates, while all users can browse published templates through the new templates endpoint.

  • Added the first version of the Template API so users can publish reusable community templates.
  • Introduced template creation with support for building from form fields directly or by turning an existing form into a template.
  • Added public template browsing for published templates, with optional category filtering.
  • Included template visual assets, description, status, and usage/ownership tracking so templates can be surfaced on the front page.
  • Enforced ownership checks when creating a template from an existing form.
  • Registered the new template routes under /api/v1/templates.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@David-2610, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 26 seconds. Learn how PR review limits work.

To continue reviewing without waiting, enable usage-based billing in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 05bebe5d-6d1b-45c0-8bc9-cc3a7f76834a

📥 Commits

Reviewing files that changed from the base of the PR and between bece041 and b61c197.

📒 Files selected for processing (3)
  • apps/api/src/controllers/template.controller.ts
  • apps/api/src/lib/template-schemas.ts
  • packages/db/prisma/schema/templates.prisma
📝 Walkthrough

Walkthrough

Adds a template management feature: the Prisma Template model is extended with status, images, formId, and createdById/createdBy ownership fields; a TemplateStatus enum is introduced. A Zod CreateTemplateSchema is added, along with createTemplate and listTemplates Express controller handlers and a new router mounted at /api/v1/templates.

Changes

Template API

Layer / File(s) Summary
Prisma schema: TemplateStatus enum, Template model extensions, User relation
packages/db/prisma/schema/templates.prisma, packages/db/prisma/schema/user.prisma
Adds TemplateStatus enum (DRAFT, PUBLISHED, ARCHIVED). Extends Template with status, images, formId, createdById, and createdBy relation with cascade delete. Adds indexes on createdById and status. Adds templates relation to User.
Zod schema, router, and route registration
apps/api/src/lib/template-schemas.ts, apps/api/src/routes/template/template.routes.ts, apps/api/src/routes/index.ts
Defines CreateTemplateSchema with validations for title, images URL array, status enum, and optional formId/fields. Creates templateRouter with GET / → listTemplates and POST / → requireAuth + validate + createTemplate. Mounts the router at /api/v1/templates.
createTemplate and listTemplates controllers
apps/api/src/controllers/template.controller.ts
createTemplate resolves fields from the request or a user-owned source form via formId, returns 404 if the form is not found/owned, and creates the template with a 201 response. listTemplates returns only PUBLISHED templates, optionally filtered by category, sorted by featured, useCount, and createdAt, with a fixed projection including nested createdBy.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant templateRouter
    participant createTemplate
    participant listTemplates
    participant Prisma DB

    rect rgba(100, 149, 237, 0.5)
        note over Client,Prisma DB: POST /api/v1/templates
        Client->>templateRouter: POST / with auth token + body
        templateRouter->>createTemplate: validated body (title, formId?, fields?)
        alt formId present, fields absent
            createTemplate->>Prisma DB: form.findFirst(id=formId, createdById=userId)
            Prisma DB-->>createTemplate: form | null
            alt form not found/not owned
                createTemplate-->>Client: 404 Source form not found
            end
        end
        createTemplate->>Prisma DB: template.create({...body, createdById, status})
        Prisma DB-->>createTemplate: created template record
        createTemplate-->>Client: 201 + template
    end

    rect rgba(60, 179, 113, 0.5)
        note over Client,Prisma DB: GET /api/v1/templates
        Client->>templateRouter: GET /?category=...
        templateRouter->>listTemplates: req.query.category
        listTemplates->>Prisma DB: template.findMany(status=PUBLISHED, category?, orderBy, select)
        Prisma DB-->>listTemplates: Template[] with createdBy
        listTemplates-->>Client: 200 + {success: true, templates}
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Openlabsops/Snap-form#34: The main PR mounts the new templateRouter in apps/api/src/routes/index.ts, which is the same routing index file refactored in this prior PR.
  • Openlabsops/Snap-form#38: The main PR extends packages/db/prisma/schema/templates.prisma with new fields and enums, directly building on the Template model introduced in this PR.

Poem

🐇 A template blooms from fields and forms,
With status, images, and schema norms.
The router hops to POST and GET,
A published template—ready to set!
No form unfound, no owner astray,
Snap-form's templates are here to stay! 🌟

🚥 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 is concise and accurately summarizes the main API addition in this PR.
Linked Issues check ✅ Passed The PR adds POST /api/v1/templates, image/description support, and Template.images as required by #47.
Out of Scope Changes check ✅ Passed The changed files all support the template API; no clearly unrelated code changes are evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/controllers/template.controller.ts`:
- Around line 39-51: The template creation flow is allowing an unverified formId
to be saved when fields are also present, so tighten the request validation in
template-schemas.ts to enforce the intended formId XOR fields rule. Update the
create path in template.controller.ts around prisma.template.create so formId
cannot be persisted unless it has already passed the ownership/existence check,
and ensure the branch that handles resolvedFields does not carry through a raw
formId.
- Around line 68-93: The template listing in the controller uses
prisma.template.findMany without any pagination, so it can grow unbounded as the
catalog expands. Update the community templates endpoint to accept pagination
inputs (such as page/limit or cursor-based params), apply skip/take or
cursor/limit in the findMany call, and enforce a reasonable maximum page size.
Keep the existing ordering and selected fields in the template query while
adding the pagination logic around that same findMany call.

In `@apps/api/src/lib/template-schemas.ts`:
- Around line 14-16: The template schema currently allows invalid combinations
because both formId and fields are optional, so the “either formId or fields”
contract is not enforced. Add a refine/superRefine on the schema in
template-schemas.ts to reject requests when neither or both are provided, and
make sure the validation failure surfaces as a 400 before the controller reaches
the resolvedFields logic.

In `@packages/db/prisma/schema/templates.prisma`:
- Around line 30-32: The `createdBy` relation in the templates Prisma model is
cascading deletes, which will remove community templates when a user is deleted.
Update the `createdById`/`createdBy` schema so shared templates survive author
deletion, using either a nullable `createdById` with `onDelete: SetNull` or a
restrictive relation instead of `Cascade`. Make this change in the
`templates.prisma` model definition where `createdById` and `createdBy` are
declared.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7fea9167-84ea-475d-8d29-28aaef64b9e3

📥 Commits

Reviewing files that changed from the base of the PR and between 733a40f and bece041.

📒 Files selected for processing (6)
  • apps/api/src/controllers/template.controller.ts
  • apps/api/src/lib/template-schemas.ts
  • apps/api/src/routes/index.ts
  • apps/api/src/routes/template/template.routes.ts
  • packages/db/prisma/schema/templates.prisma
  • packages/db/prisma/schema/user.prisma
📜 Review details
🔇 Additional comments (3)
packages/db/prisma/schema/user.prisma (1)

33-33: LGTM!

apps/api/src/routes/template/template.routes.ts (1)

12-13: LGTM!

apps/api/src/routes/index.ts (1)

9-9: LGTM!

Also applies to: 26-26

Comment thread apps/api/src/controllers/template.controller.ts
Comment thread apps/api/src/controllers/template.controller.ts
Comment thread apps/api/src/lib/template-schemas.ts
Comment thread packages/db/prisma/schema/templates.prisma Outdated

@Basharkhan7776 Basharkhan7776 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the user delete form from its id, then template would be exist or not?

@David-2610

Copy link
Copy Markdown
Contributor Author

If the user delete form from its id, then template would be exist or not?

Yes, the template will still exist

@David-2610 David-2610 closed this Jun 26, 2026
@David-2610
David-2610 deleted the feat/create-template-api branch June 26, 2026 08:32
@David-2610

Copy link
Copy Markdown
Contributor Author

If the user delete form from its id, then template would be exist or not?

I closed the previous PR and opened a new one with the latest changes.

The new PR separates the onDelete: SetNull behavior. Now, when a form is deleted, the template remains and only its formId is set to null.

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.

[Block] Create Template APIs

2 participants