원클릭으로
source-command-convex-quickstart
Scaffold a new feature module in this Convex project - creates schema, functions, and frontend integration
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Scaffold a new feature module in this Convex project - creates schema, functions, and frontend integration
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Set up Convex authentication with proper user management, identity mapping, and access control patterns. Use when implementing auth flows.
Guide to using Convex components for feature encapsulation. Learn about sibling components, creating your own, and when to use components vs monolithic code.
Discover and use convex-helpers utilities for relationships, filtering, sessions, custom functions, and more. Use when you need pre-built Convex patterns.
Create Convex queries, mutations, and actions with proper validation, authentication, and error handling. Use when implementing new API endpoints.
Plan and execute Convex schema migrations safely, including adding fields, creating tables, and data transformations. Use when schema changes affect existing data.
Design and generate Convex database schemas with proper validation, indexes, and relationships. Use when creating schema.ts or modifying table definitions.
| name | source-command-convex-quickstart |
| description | Scaffold a new feature module in this Convex project - creates schema, functions, and frontend integration |
Use this skill when the user asks to run the migrated source command convex-quickstart.
This project already has Convex set up. Use this guide to add a new feature module with proper schema, functions, and frontend integration.
Add your table(s) to convex/schema.ts:
// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
// ... existing tables
// Add your new table
yourFeature: defineTable({
userId: v.id("users"), // Foreign key
title: v.string(),
status: v.union(
v.literal("draft"),
v.literal("active"),
v.literal("archived"),
),
metadata: v.optional(
v.object({
tags: v.array(v.string()),
}),
),
createdAt: v.number(),
})
.index("by_userId", ["userId"])
.index("by_status", ["status"])
.index("by_userId_and_status", ["userId", "status"]),
});
Index naming: Include all fields (e.g., by_userId_and_status).
Create convex/yourFeature.ts:
import { v } from "convex/values";
import { query, mutation } from "./_generated/server";
import { authComponent } from "./auth";
// List items for authenticated user
export const list = query({
args: {},
returns: v.array(
v.object({
_id: v.id("yourFeature"),
title: v.string(),
status: v.union(
v.literal("draft"),
v.literal("active"),
v.literal("archived"),
),
createdAt: v.number(),
}),
),
handler: async (ctx) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
return await ctx.db
.query("yourFeature")
.withIndex("by_userId", (q) => q.eq("userId", user._id))
.collect();
},
});
// Create a new item
export const create = mutation({
args: {
title: v.string(),
},
returns: v.id("yourFeature"),
handler: async (ctx, args) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
return await ctx.db.insert("yourFeature", {
userId: user._id,
title: args.title,
status: "draft",
createdAt: Date.now(),
});
},
});
// Update an item (with ownership check)
export const update = mutation({
args: {
id: v.id("yourFeature"),
title: v.optional(v.string()),
status: v.optional(
v.union(v.literal("draft"), v.literal("active"), v.literal("archived")),
),
},
returns: v.null(),
handler: async (ctx, args) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
const item = await ctx.db.get(args.id);
if (!item) throw new Error("Not found");
if (item.userId !== user._id) throw new Error("Unauthorized");
const updates: Record<string, unknown> = {};
if (args.title !== undefined) updates.title = args.title;
if (args.status !== undefined) updates.status = args.status;
await ctx.db.patch(args.id, updates);
return null;
},
});
// Delete an item (with ownership check)
export const remove = mutation({
args: { id: v.id("yourFeature") },
returns: v.null(),
handler: async (ctx, args) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
const item = await ctx.db.get(args.id);
if (!item) throw new Error("Not found");
if (item.userId !== user._id) throw new Error("Unauthorized");
await ctx.db.delete(args.id);
return null;
},
});
"use client";
import { useQuery, useMutation } from "convex/react";
import { api } from "@/convex/_generated/api";
export function YourFeatureList() {
const items = useQuery(api.yourFeature.list);
const createItem = useMutation(api.yourFeature.create);
const deleteItem = useMutation(api.yourFeature.remove);
if (items === undefined) return <div>Loading...</div>;
return (
<div>
<button onClick={() => createItem({ title: "New Item" })}>
Add Item
</button>
{items.map((item) => (
<div key={item._id}>
<span>{item.title}</span>
<button onClick={() => deleteItem({ id: item._id })}>
Delete
</button>
</div>
))}
</div>
);
}
Create convex/yourFeature.test.ts:
import { convexTest } from "convex-test";
import { describe, it, expect } from "vitest";
import { api } from "./_generated/api";
import schema from "./schema";
import { modules } from "./test.setup";
describe("yourFeature", () => {
it("should create and list items", async () => {
const t = convexTest(schema, modules);
const asUser = t.withIdentity({ subject: "user1", name: "Test User" });
const id = await asUser.mutation(api.yourFeature.create, {
title: "Test Item",
});
const items = await asUser.query(api.yourFeature.list, {});
expect(items).toHaveLength(1);
expect(items[0].title).toBe("Test Item");
});
});
npx convex codegen # Generate types for new schema
pnpm run test:once # Run tests
convex/schema.ts with proper indexesargs and returns validatorsauthComponent.getAuthUser(ctx)internal.* for any scheduled functionsconvex/yourFeature.test.tsnpx convex codegen after schema changes