Skip to content

[#392] Create issue templates schema and router#419

Merged
DVidal1205 merged 15 commits intomainfrom
blade/templates
Mar 12, 2026
Merged

[#392] Create issue templates schema and router#419
DVidal1205 merged 15 commits intomainfrom
blade/templates

Conversation

@luciano093
Copy link
Member

@luciano093 luciano093 commented Mar 12, 2026

Why

To have templates to quickly make new issues

What

Closes: #392
Closes: #393

Added the template schema, a template router, and procedures to create, update, delete, and get templates.

Test Plan

Tested by checking that all new procedures could be called successfully from a server component and that the database was updated correctly.

Checklist

  • Database: No schema changes, OR I have contacted the Development Lead to run db:push before merging
  • Environment Variables: No environment variables changed, OR I have contacted the Development Lead to modify them on Coolify BEFORE merging.

Summary by CodeRabbit

  • New Features
    • Introduced issue template management with full CRUD (create, read, update, delete) and hierarchical sub-issue support.
    • Added persistent storage for templates so created templates are saved and retrievable.
    • Added two new permissions to control access: Edit Issue Templates and Read Issue Templates.

@luciano093 luciano093 added Database Change modifies code in the DB package API Change modifies code in the global API/tRPC package labels Mar 12, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: dce95030-d465-4ee5-b4f0-67cd2a407446

📥 Commits

Reviewing files that changed from the base of the PR and between a7ba99e and fe3ab91.

📒 Files selected for processing (1)
  • packages/consts/src/permissions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/consts/src/permissions.ts

📝 Walkthrough

Walkthrough

Added issue template management: two new permissions, a new Template DB table (with JSONB body), and four API router procedures for creating, updating, deleting, and listing templates plus supporting schemas/types for template sub-issues.

Changes

Cohort / File(s) Summary
Permissions
packages/consts/src/permissions.ts
Appended EDIT_ISSUE_TEMPLATES (idx: 22) and READ_ISSUE_TEMPLATES (idx: 23) to PERMISSION_DATA.
Database schema
packages/db/src/schemas/knight-hacks.ts
Added Template table (id, name, body as jsonb, createdAt, updatedAt) and InsertTemplateSchema for inserts.
API router / types
packages/api/src/routers/issues.ts
Imported Template/InsertTemplateSchema; added baseTemplateSubIssueSchema, recursive templateSubIssueSchema, TemplateSubIssue type; implemented createTemplate, updateTemplate, deleteTemplate, and getTemplates procedures with validation and permission checks.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as IssuesRouter
  participant Auth as PermissionsCheck
  participant DB as TemplatesTable

  Client->>API: POST /createTemplate (name, body)
  API->>Auth: verify `EDIT_ISSUE_TEMPLATES`
  Auth-->>API: allowed / denied
  alt allowed
    API->>DB: INSERT Template (name, body)
    DB-->>API: inserted record
    API-->>Client: 200 Created (template)
  else denied
    API-->>Client: 403 Forbidden
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Constants, Feature, Major

Suggested reviewers

  • DVidal1205
🚥 Pre-merge checks | ✅ 7 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows the required format with issue number in brackets and clearly describes the main changes: creating schema and router for issue templates.
Linked Issues check ✅ Passed The PR implements all requirements from #392 and #393: schema with template model, body supporting placeholders and date macros, and router with CRUD procedures and permissions.
Out of Scope Changes check ✅ Passed All changes are directly related to the issue template feature: permissions constants, database schema, and API router endpoints with no unrelated modifications.
No Hardcoded Secrets ✅ Passed Pull request contains no hardcoded secrets, API keys, passwords, or tokens. All files use proper environment variables for sensitive configuration.
Validated Env Access ✅ Passed No direct process.env usage found outside of env.ts config files or .config. files in the modified files.
No Typescript Escape Hatches ✅ Passed Pull request contains no problematic TypeScript escape hatches. All as assertions follow best practices with legitimate patterns for type preservation and safety.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch blade/templates
📝 Coding Plan for PR comments
  • Generate coding plan

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
packages/consts/src/permissions.ts (1)

118-127: Minor: Inconsistent title casing in name fields.

Other permission entries use Title Case (e.g., "Read Issues", "Edit Forms"), but these use lowercase ("Edit issue templates", "Read issue templates"). Consider updating for consistency:

✏️ Suggested fix for consistency
   EDIT_ISSUE_TEMPLATES: {
     idx: 22,
-    name: "Edit issue templates",
+    name: "Edit Issue Templates",
     desc: "Allows creating, editing, or deleting templates.",
   },
   READ_ISSUE_TEMPLATES: {
     idx: 23,
-    name: "Read issue templates",
+    name: "Read Issue Templates",
     desc: "Grants access to issue templates.",
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/consts/src/permissions.ts` around lines 118 - 127, The permission
entries EDIT_ISSUE_TEMPLATES and READ_ISSUE_TEMPLATES use inconsistent
lowercased names; update their name fields to Title Case to match the rest of
the file (change "Edit issue templates" to "Edit Issue Templates" and "Read
issue templates" to "Read Issue Templates") so naming is consistent across
permissions.
packages/api/src/routers/templates.ts (2)

24-27: Consider limiting recursion depth for the nested children schema.

The recursive templateSubIssueSchema allows unbounded nesting depth. While Zod handles this gracefully, deeply nested payloads could impact performance and storage. You might want to enforce a practical limit.

🛡️ Example: Enforce max depth of 3 levels
// Helper to create depth-limited schema
const createDepthLimitedSchema = (maxDepth: number): z.ZodType<TemplateSubIssue> => {
  if (maxDepth <= 0) {
    return baseTemplateSubIssueSchema as z.ZodType<TemplateSubIssue>;
  }
  return baseTemplateSubIssueSchema.extend({
    children: z.array(createDepthLimitedSchema(maxDepth - 1)).optional(),
  }) as z.ZodType<TemplateSubIssue>;
};

const templateSubIssueSchema = createDepthLimitedSchema(3);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/routers/templates.ts` around lines 24 - 27, The recursive
templateSubIssueSchema allows unbounded nesting; replace it with a depth-limited
constructor to prevent deeply nested payloads impacting performance/storage:
implement a helper like createDepthLimitedSchema(maxDepth) that returns
baseTemplateSubIssueSchema when maxDepth <= 0 and otherwise extends
baseTemplateSubIssueSchema with children:
z.array(createDepthLimitedSchema(maxDepth - 1)).optional(), then assign
templateSubIssueSchema = createDepthLimitedSchema(3) (or another practical
limit) and update any references to templateSubIssueSchema accordingly.

116-127: Consider adding pagination for getTemplates.

Currently returns all templates without limit. This is fine for a small dataset, but as templates grow, you may want pagination to avoid large payloads.

📄 Example pagination approach
getTemplates: permProcedure
  .input(z.object({
    limit: z.number().int().min(1).max(100).default(50),
    cursor: z.string().uuid().optional(),
  }).optional())
  .query(async ({ ctx, input }) => {
    permissions.controlPerms.or(
      ["READ_ISSUE_TEMPLATES", "EDIT_ISSUE_TEMPLATES"],
      ctx,
    );

    const templates = await db.query.Template.findMany({
      limit: input?.limit ?? 50,
      orderBy: (templates, { desc }) => [desc(templates.createdAt)],
      // Add cursor-based pagination if needed
    });

    return templates;
  }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/routers/templates.ts` around lines 116 - 127, Add
cursor/limit pagination to the getTemplates procedure: change getTemplates
(permProcedure.query) to accept an optional input schema (z.object with
limit:number default 50, min1 max100, and optional cursor:string/uuid) and
enforce permissions via permissions.controlPerms.or as before; then pass
input?.limit (or default) into db.query.Template.findMany and implement
cursor-based filtering using the cursor (e.g., where createdAt < cursor
timestamp or use startAfter/startFrom API of the ORM) and preserve the orderBy
(desc createdAt); return the page of templates and the nextCursor to the caller.
packages/db/src/schemas/knight-hacks.ts (1)

619-629: Consider adding an index on createdAt for query performance.

The getTemplates procedure in packages/api/src/routers/templates.ts orders results by createdAt descending. Without an index, this becomes a full table scan as the template count grows.

📊 Suggested index addition
 export const Template = createTable("template", (t) => ({
   id: t.uuid().notNull().primaryKey().defaultRandom(),
   name: t.text().notNull(),
   body: t.jsonb().notNull(),
   createdAt: t.timestamp().defaultNow().notNull(),
   updatedAt: t
     .timestamp()
     .defaultNow()
     .$onUpdate(() => new Date())
     .notNull(),
-}));
+}), (table) => ({
+  createdAtIdx: index("template_created_at_idx").on(table.createdAt),
+}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/db/src/schemas/knight-hacks.ts` around lines 619 - 629, Add a DB
index on Template.createdAt to support the getTemplates ordering: locate the
Template table definition (symbol Template from createTable) and add an index on
the createdAt column (either via your schema helper e.g. createIndex for the
"template" table or create a migration that adds an index named something like
template_created_at_idx on createdAt) so ORDER BY createdAt DESC in getTemplates
uses the index for efficient scans.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/api/src/routers/templates.ts`:
- Around line 24-27: The recursive templateSubIssueSchema allows unbounded
nesting; replace it with a depth-limited constructor to prevent deeply nested
payloads impacting performance/storage: implement a helper like
createDepthLimitedSchema(maxDepth) that returns baseTemplateSubIssueSchema when
maxDepth <= 0 and otherwise extends baseTemplateSubIssueSchema with children:
z.array(createDepthLimitedSchema(maxDepth - 1)).optional(), then assign
templateSubIssueSchema = createDepthLimitedSchema(3) (or another practical
limit) and update any references to templateSubIssueSchema accordingly.
- Around line 116-127: Add cursor/limit pagination to the getTemplates
procedure: change getTemplates (permProcedure.query) to accept an optional input
schema (z.object with limit:number default 50, min1 max100, and optional
cursor:string/uuid) and enforce permissions via permissions.controlPerms.or as
before; then pass input?.limit (or default) into db.query.Template.findMany and
implement cursor-based filtering using the cursor (e.g., where createdAt <
cursor timestamp or use startAfter/startFrom API of the ORM) and preserve the
orderBy (desc createdAt); return the page of templates and the nextCursor to the
caller.

In `@packages/consts/src/permissions.ts`:
- Around line 118-127: The permission entries EDIT_ISSUE_TEMPLATES and
READ_ISSUE_TEMPLATES use inconsistent lowercased names; update their name fields
to Title Case to match the rest of the file (change "Edit issue templates" to
"Edit Issue Templates" and "Read issue templates" to "Read Issue Templates") so
naming is consistent across permissions.

In `@packages/db/src/schemas/knight-hacks.ts`:
- Around line 619-629: Add a DB index on Template.createdAt to support the
getTemplates ordering: locate the Template table definition (symbol Template
from createTable) and add an index on the createdAt column (either via your
schema helper e.g. createIndex for the "template" table or create a migration
that adds an index named something like template_created_at_idx on createdAt) so
ORDER BY createdAt DESC in getTemplates uses the index for efficient scans.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: c520a73e-2aae-4534-9585-456e707883aa

📥 Commits

Reviewing files that changed from the base of the PR and between 82faebd and c3799f4.

📒 Files selected for processing (4)
  • packages/api/src/root.ts
  • packages/api/src/routers/templates.ts
  • packages/consts/src/permissions.ts
  • packages/db/src/schemas/knight-hacks.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/api/src/routers/issues.ts`:
- Around line 299-303: The router is exposing table-owned fields by reusing
InsertTemplateSchema for public create inputs; instead define an explicit public
input schema (e.g., CreateTemplateInputSchema or TemplatePublicCreateSchema)
that only includes the allowed fields (name: z.string().min(1, "...") and body:
z.array(templateSubIssueSchema)) and use that in the tRPC route instead of
InsertTemplateSchema.extend(...); update both places that currently derive from
InsertTemplateSchema so the public write shape remains explicit and cannot
accidentally include new DB columns.
- Around line 35-41: The schema currently uses a numeric-only dateMs field which
rejects template date strings and stores the wrong key; update
baseTemplateSubIssueSchema to replace dateMs with a string-based date field
named "date" (optional) that accepts template expressions (e.g., "{-7 days}"),
and then update any usages such as createTemplate and updateTemplate to
read/write the "date" key instead of "dateMs" so the persisted template JSON
matches the feature contract.
🪄 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: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 677b1b56-bce1-46f5-9550-790f3729c5a1

📥 Commits

Reviewing files that changed from the base of the PR and between c3799f4 and a7ba99e.

📒 Files selected for processing (1)
  • packages/api/src/routers/issues.ts

Copy link
Contributor

@DVidal1205 DVidal1205 left a comment

Choose a reason for hiding this comment

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

Superb, pushing schema and merging now!

@DVidal1205 DVidal1205 added this pull request to the merge queue Mar 12, 2026
Merged via the queue into main with commit eb9cb00 Mar 12, 2026
7 checks passed
@DVidal1205 DVidal1205 deleted the blade/templates branch March 12, 2026 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API Change modifies code in the global API/tRPC package Database Change modifies code in the DB package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SPRINT-01] Create Issue Templates Router [SPRINT-01] Create Issue Templates Schema

3 participants