create-aron-app 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -31
- package/dist/index.js +39 -115
- package/package.json +7 -4
- package/templates/.cursor/rules/backend.mdc +112 -0
- package/templates/.cursor/rules/coding_standards.mdc +145 -0
- package/templates/.cursor/rules/frontend_architecture.mdc +334 -0
- package/templates/.github/workflows/ci.yml +40 -0
- package/templates/apps/api/_generated/api.d.ts +57 -0
- package/templates/apps/api/_generated/api.js +23 -0
- package/templates/apps/api/_generated/dataModel.d.ts +60 -0
- package/templates/apps/api/_generated/server.d.ts +143 -0
- package/templates/apps/api/_generated/server.js +93 -0
- package/templates/apps/api/http.ts +16 -0
- package/templates/apps/web/.env.example +10 -0
- package/templates/apps/web/.react-router/types/+future.ts +9 -0
- package/templates/apps/web/.react-router/types/+routes.ts +76 -0
- package/templates/apps/web/.react-router/types/+server-build.d.ts +18 -0
- package/templates/apps/web/.react-router/types/src/+types/root.ts +59 -0
- package/templates/apps/web/.react-router/types/src/routes/(auth)/+types/layout.ts +62 -0
- package/templates/apps/web/.react-router/types/src/routes/(auth)/sign-in/+types/index.ts +65 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/[id].ts +68 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/index.ts +68 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/layout.ts +65 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/+types/index.ts +65 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/+types/layout.ts +62 -0
- package/templates/{react-router → apps/web}/project.json +9 -2
- package/templates/{react-router → apps/web}/react-router.config.ts +1 -1
- package/templates/apps/web/src/app.css +3 -0
- package/templates/{react-router → apps/web}/src/components/error_boundary.tsx +1 -1
- package/templates/apps/web/src/libs/convex_query_client.ts +11 -0
- package/templates/apps/web/src/libs/react_query_client.ts +17 -0
- package/templates/apps/web/src/libs/server/auth.ts +32 -0
- package/templates/apps/web/src/libs/server/protected.ts +17 -0
- package/templates/apps/web/src/providers/api_auth_provider.tsx +26 -0
- package/templates/apps/web/src/providers/global_provider.tsx +28 -0
- package/templates/apps/web/src/providers/navigation_loading_bar_provider.tsx +72 -0
- package/templates/apps/web/src/root.tsx +68 -0
- package/templates/{react-router/src/routes/auth → apps/web/src/routes/(auth)}/layout.tsx +1 -1
- package/templates/apps/web/src/routes/(dashboard)/(todos)/[id].tsx +33 -0
- package/templates/apps/web/src/routes/(dashboard)/(todos)/index.tsx +26 -0
- package/templates/apps/web/src/routes/(dashboard)/(todos)/layout.tsx +9 -0
- package/templates/apps/web/src/routes/(dashboard)/index.tsx +20 -0
- package/templates/apps/web/src/routes/(dashboard)/layout.tsx +20 -0
- package/templates/apps/web/src/routes.ts +14 -0
- package/templates/apps/web/src/surfaces/home/bootstrap.ts +9 -0
- package/templates/apps/web/src/surfaces/home/home.tsx +25 -0
- package/templates/apps/web/src/surfaces/home/install.tsx +17 -0
- package/templates/apps/web/src/surfaces/home/layout.tsx +35 -0
- package/templates/apps/web/src/surfaces/home/main/create.tsx +32 -0
- package/templates/apps/web/src/surfaces/sidebar/install.tsx +19 -0
- package/templates/apps/web/src/surfaces/sidebar/layout.tsx +119 -0
- package/templates/apps/web/src/surfaces/sidebar/nav_main/create.tsx +31 -0
- package/templates/apps/web/src/surfaces/sidebar/nav_main/nav_main.tsx +42 -0
- package/templates/apps/web/src/surfaces/sidebar/sidebar.tsx +18 -0
- package/templates/apps/web/src/surfaces/sidebar/user_menu/create.tsx +26 -0
- package/templates/{react-router/src/layouts/sidebar/sidebar_aside → apps/web/src/surfaces/sidebar/user_menu}/user_menu.tsx +13 -9
- package/templates/apps/web/src/surfaces/todos/all_todos/all_todos.tsx +25 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/all_todos_controller.ts +47 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/bootstrap.ts +21 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/header/create.tsx +21 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/install.tsx +20 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/layout.tsx +35 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/create.tsx +47 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/main.tsx +68 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/new_todo_sheet/create.tsx +54 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/new_todo_sheet/new_todo_sheet.tsx +97 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/new_todo_sheet/schema.ts +11 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/bootstrap.ts +35 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/header/create.tsx +24 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/header/header.tsx +25 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/install.tsx +27 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/layout.tsx +45 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/main/create.tsx +35 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/main/main.tsx +47 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/single_todo.tsx +27 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/single_todo_controller.ts +16 -0
- package/templates/{react-router → apps/web}/vite.config.ts +27 -3
- package/templates/{_base/biome.json → biome.json} +12 -0
- package/templates/bun.lock +1917 -0
- package/templates/{_base/emails → emails}/project.json +1 -1
- package/templates/package.json +91 -0
- package/templates/{_base/shared → shared}/assets/src/styles/global.css +14 -8
- package/templates/shared/ui/src/base/collapsible.tsx +31 -0
- package/templates/shared/ui/src/base/hover-card.tsx +42 -0
- package/templates/shared/ui/src/base/input-group.tsx +168 -0
- package/templates/shared/ui/src/base/panel.tsx +93 -0
- package/templates/{_base/shared → shared}/ui/src/hooks/use_mobile.tsx +1 -1
- package/templates/{_base/shared → shared}/ui/src/hooks/use_query_params.tsx +6 -7
- package/templates/{_base/shared → shared}/ui/tsconfig.json +1 -1
- package/templates/shared/utils/src/convex.ts +4 -0
- package/templates/{_base/tsconfig.base.json → tsconfig.base.json} +2 -1
- package/templates/_base/.cursor/commands/builder.md +0 -0
- package/templates/_base/.cursor/rules/api_architecture.mdc +0 -268
- package/templates/_base/.cursor/rules/coding_standards.mdc +0 -64
- package/templates/_base/.cursor/rules/convex_rules.mdc +0 -675
- package/templates/_base/.cursor/rules/frontend_rules.mdc +0 -268
- package/templates/_base/.env.convex.example +0 -3
- package/templates/_base/.github/workflows/ci.yml +0 -29
- package/templates/_base/_gitignore +0 -58
- package/templates/_base/package.json +0 -73
- package/templates/_base/shared/utils/src/convex.ts +0 -3
- package/templates/nextjs/.env.example +0 -8
- package/templates/nextjs/index.d.ts +0 -6
- package/templates/nextjs/next-env.d.ts +0 -5
- package/templates/nextjs/next.config.js +0 -22
- package/templates/nextjs/postcss.config.js +0 -17
- package/templates/nextjs/project.json +0 -22
- package/templates/nextjs/src/app/(auth)/layout.tsx +0 -21
- package/templates/nextjs/src/app/(auth)/not-allowed/page.tsx +0 -22
- package/templates/nextjs/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +0 -15
- package/templates/nextjs/src/app/(dashboard)/layout.tsx +0 -27
- package/templates/nextjs/src/app/(dashboard)/page.tsx +0 -5
- package/templates/nextjs/src/app/(dashboard)/todos/[id]/page.tsx +0 -23
- package/templates/nextjs/src/app/(dashboard)/todos/page.tsx +0 -16
- package/templates/nextjs/src/app/app.css +0 -3
- package/templates/nextjs/src/app/layout.tsx +0 -26
- package/templates/nextjs/src/convex.ts +0 -11
- package/templates/nextjs/src/middleware.ts +0 -18
- package/templates/nextjs/src/providers/convex_provider.tsx +0 -44
- package/templates/nextjs/src/surfaces/home_surface.tsx +0 -22
- package/templates/nextjs/src/surfaces/todos/all_todos_surface.tsx +0 -97
- package/templates/nextjs/src/surfaces/todos/create_todo_sheet.tsx +0 -107
- package/templates/nextjs/src/surfaces/todos/single_todo_surface.tsx +0 -90
- package/templates/nextjs/src/ui/sidebar/nav_link.tsx +0 -36
- package/templates/nextjs/src/ui/sidebar/sidebar.tsx +0 -125
- package/templates/nextjs/src/utils/font.ts +0 -9
- package/templates/nextjs/tsconfig.json +0 -42
- package/templates/react-router/.env.example +0 -8
- package/templates/react-router/src/app.css +0 -3
- package/templates/react-router/src/layouts/sidebar/sidebar_aside/sidebar_aside.tsx +0 -76
- package/templates/react-router/src/layouts/sidebar/sidebar_layout.tsx +0 -22
- package/templates/react-router/src/providers/api_auth_provider.tsx +0 -38
- package/templates/react-router/src/root.tsx +0 -37
- package/templates/react-router/src/routes/index.tsx +0 -9
- package/templates/react-router/src/routes/layout.tsx +0 -26
- package/templates/react-router/src/routes/todos/[id].tsx +0 -22
- package/templates/react-router/src/routes/todos/index.tsx +0 -13
- package/templates/react-router/src/routes.ts +0 -12
- package/templates/react-router/src/surfaces/home_surface.tsx +0 -20
- package/templates/react-router/src/surfaces/todos/all_todos_surface.tsx +0 -87
- package/templates/react-router/src/surfaces/todos/create_todo_sheet.tsx +0 -102
- package/templates/react-router/src/surfaces/todos/single_todo_surface.tsx +0 -81
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/api-specs-context.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/execute-request.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-endpoint-detail.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-tag-endpoints.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-tags.js +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-in.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-up.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-in.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-up.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/show-component.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/api-routes.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/caching-auth.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/middleware-strategies.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/server-actions.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/server-vs-client.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-webhooks/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/agents/openai.yml +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/assets/shadcn-small.png +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/assets/shadcn.png +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/cli.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/customization.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/evals/evals.json +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/mcp.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/base-vs-radix.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/composition.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/forms.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/icons.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/styling.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/commands/pr.md +0 -0
- /package/templates/{_base/.nvmrc → .nvmrc} +0 -0
- /package/templates/{_base/.vscode → .vscode}/settings.json +0 -0
- /package/templates/{_base/apps → apps}/api/auth.config.ts +0 -0
- /package/templates/{_base/apps → apps}/api/functions.ts +0 -0
- /package/templates/{_base/apps → apps}/api/project.json +0 -0
- /package/templates/{_base/apps → apps}/api/schema.ts +0 -0
- /package/templates/{_base/apps → apps}/api/todos/crud.ts +0 -0
- /package/templates/{_base/apps → apps}/api/todos/schema.ts +0 -0
- /package/templates/{_base/apps → apps}/api/todos/types.ts +0 -0
- /package/templates/{_base/apps → apps}/api/tsconfig.json +0 -0
- /package/templates/{_base/apps → apps}/api/types.ts +0 -0
- /package/templates/{react-router → apps/web}/postcss.config.js +0 -0
- /package/templates/{react-router → apps/web}/public/favicon.ico +0 -0
- /package/templates/{react-router/src/routes/auth/sign-in.tsx → apps/web/src/routes/(auth)/sign-in/index.tsx} +0 -0
- /package/templates/{react-router → apps/web}/tsconfig.json +0 -0
- /package/templates/{_base/convex.json → convex.json} +0 -0
- /package/templates/{_base/emails → emails}/tsconfig.json +0 -0
- /package/templates/{_base/emails → emails}/welcome_email.tsx +0 -0
- /package/templates/{_base/nx.json → nx.json} +0 -0
- /package/templates/{_base/scripts → scripts}/sync_convex_env.ts +0 -0
- /package/templates/{_base/shared → shared}/assets/image.d.ts +0 -0
- /package/templates/{_base/shared → shared}/assets/tsconfig.json +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/alert_dialog.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/badge.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/basic_data_table.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/button.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/button_group.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/card.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/checkbox.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/command.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/dialog.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/dropdown_menu.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/form.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/input.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/label.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/popover.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/radio_group.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/resizable.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/scroll_area.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/select.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/separator.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/sheet.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/side_bar.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/skeleton.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/spinner.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/switch.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/table.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/text_area.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/tooltip.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/utils.ts +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_keyboard_press.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_keyboard_release.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_mouse_click.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_mouse_location.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_outside_click.tsx +0 -0
- /package/templates/{_base/shared → shared}/utils/src/time.ts +0 -0
- /package/templates/{_base/shared → shared}/utils/tsconfig.json +0 -0
- /package/templates/{_base/skills-lock.json → skills-lock.json} +0 -0
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Backend architecture overview for the Convex API. Covers folder structure, schema design patterns, function conventions, and getting started steps.
|
|
3
|
-
globs: apps/api/**/*.ts
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Backend API Architecture
|
|
7
|
-
|
|
8
|
-
This is the Convex backend located in `apps/api/`. It uses `convex-ents` for relational data modeling and `zQuery`/`zMutation` wrappers from `convex-helpers` for all public functions.
|
|
9
|
-
|
|
10
|
-
## Folder Structure
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
apps/api/
|
|
14
|
-
├── <entity>/
|
|
15
|
-
│ ├── schema.ts # Ent definition (table shape + edges + indexes)
|
|
16
|
-
│ ├── types.ts # Zod schemas and TypeScript types
|
|
17
|
-
│ └── crud.ts # CRUD operations (GET → UPDATE → CREATE → DELETE)
|
|
18
|
-
├── schema.ts # Main schema — spreads all entity ent objects
|
|
19
|
-
├── types.ts # Shared context types (QueryCtx, MutationCtx, Ent<T>)
|
|
20
|
-
└── functions.ts # zQuery / zMutation wrappers using convex-ents
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Example: `todos/`
|
|
24
|
-
|
|
25
|
-
The `todos/` directory is the canonical example of how to structure a new entity:
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
apps/api/todos/
|
|
29
|
-
├── schema.ts # todoEnts — defines the todos table
|
|
30
|
-
├── types.ts # CreateTodo, UpdateTodo Zod types
|
|
31
|
-
└── crud.ts # getTodo, listTodos, updateTodo, createTodo, deleteTodo
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Adding a New Entity
|
|
35
|
-
|
|
36
|
-
1. Create `apps/api/<entity>/schema.ts` — define the ent and export `<entity>Ents`
|
|
37
|
-
2. Create `apps/api/<entity>/types.ts` — define Zod schemas and TypeScript types
|
|
38
|
-
3. Create `apps/api/<entity>/crud.ts` — implement CRUD using `zQuery`/`zMutation`
|
|
39
|
-
4. Spread the new ent in `apps/api/schema.ts`:
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
import { todoEnts } from "@/api/todos/schema";
|
|
43
|
-
import { entityEnts } from "@/api/<entity>/schema";
|
|
44
|
-
import { defineEntSchema, getEntDefinitions } from "convex-ents";
|
|
45
|
-
|
|
46
|
-
const schema = defineEntSchema({
|
|
47
|
-
...todoEnts,
|
|
48
|
-
...entityEnts,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
export default schema;
|
|
52
|
-
export const entDefinitions = getEntDefinitions(schema);
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Schema Design Patterns
|
|
56
|
-
|
|
57
|
-
### Ent Definitions (`schema.ts`)
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import { v } from "convex/values";
|
|
61
|
-
import { defineEnt } from "convex-ents";
|
|
62
|
-
|
|
63
|
-
export const entityEnts = {
|
|
64
|
-
entities: defineEnt({
|
|
65
|
-
title: v.string(),
|
|
66
|
-
userId: v.string(),
|
|
67
|
-
isCompleted: v.boolean(),
|
|
68
|
-
})
|
|
69
|
-
.edge("relatedEntity")
|
|
70
|
-
.index("by_user_id", ["userId"]),
|
|
71
|
-
};
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
- Export as `{ tableName: defineEnt({...}) }` objects
|
|
75
|
-
- Always add indexes for fields you query by
|
|
76
|
-
- Name indexes `by_<field>` or `by_<field1>_and_<field2>`
|
|
77
|
-
|
|
78
|
-
### Types (`types.ts`)
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
import { z } from "zod";
|
|
82
|
-
|
|
83
|
-
export type CreateEntity = z.infer<typeof CreateEntity>;
|
|
84
|
-
export const CreateEntity = z.object({
|
|
85
|
-
title: z.string().min(1),
|
|
86
|
-
userId: z.string(),
|
|
87
|
-
});
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
- All Zod schemas go here, not in schema.ts
|
|
91
|
-
- Use `zodToConvex()` from `convex-helpers/server/zod` when you need a Convex validator from a Zod schema
|
|
92
|
-
|
|
93
|
-
### CRUD (`crud.ts`)
|
|
94
|
-
|
|
95
|
-
Functions are always ordered: **GET → UPDATE → CREATE → DELETE**
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
import { zMutation, zQuery } from "@/api/functions";
|
|
99
|
-
import { zid } from "convex-helpers/server/zod";
|
|
100
|
-
import { z } from "zod";
|
|
101
|
-
|
|
102
|
-
export const getEntity = zQuery({
|
|
103
|
-
args: { entityId: zid("entities") },
|
|
104
|
-
handler: async (ctx, args) => ctx.table("entities").getX(args.entityId),
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
export const listEntities = zQuery({
|
|
108
|
-
args: { userId: z.string() },
|
|
109
|
-
handler: async (ctx, args) =>
|
|
110
|
-
ctx.table("entities", "by_user_id", (q) => q.eq("userId", args.userId)),
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
export const updateEntity = zMutation({
|
|
114
|
-
args: { entityId: zid("entities"), title: z.string().optional() },
|
|
115
|
-
handler: async (ctx, args) => {
|
|
116
|
-
const { entityId, ...updates } = args;
|
|
117
|
-
const entity = await ctx.table("entities").getX(entityId);
|
|
118
|
-
return entity.patch(updates);
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
export const createEntity = zMutation({
|
|
123
|
-
args: { title: z.string().min(1), userId: z.string() },
|
|
124
|
-
handler: async (ctx, args) =>
|
|
125
|
-
ctx.table("entities").insert({ title: args.title, userId: args.userId, isCompleted: false }),
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
export const deleteEntity = zMutation({
|
|
129
|
-
args: { entityId: zid("entities") },
|
|
130
|
-
handler: async (ctx, args) => {
|
|
131
|
-
const entity = await ctx.table("entities").getX(args.entityId);
|
|
132
|
-
await entity.delete();
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Documentation Style
|
|
138
|
-
|
|
139
|
-
- **NEVER** add JSDoc or any comments before exported function definitions
|
|
140
|
-
- Function names should be self-documenting
|
|
141
|
-
- Only add inline comments for complex business logic that can't be expressed through code alone
|
|
142
|
-
- NO comments like `// Get entity by ID` or `// Update entity` above functions
|
|
143
|
-
|
|
144
|
-
## Ent Methods
|
|
145
|
-
|
|
146
|
-
Prefer the throwing variants when you expect the entity to exist:
|
|
147
|
-
|
|
148
|
-
| Use | When |
|
|
149
|
-
|---|---|
|
|
150
|
-
| `getX(id)` | Entity must exist — throws if not found |
|
|
151
|
-
| `get(id)` | Entity may not exist — returns `null` |
|
|
152
|
-
| `uniqueX(...)` | Index query must return exactly one result |
|
|
153
|
-
| `unique(...)` | Index query may return zero results |
|
|
154
|
-
| `firstX(...)` | Query must return at least one result |
|
|
155
|
-
| `first(...)` | Query may return zero results |
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
// Good — entity is expected to exist
|
|
159
|
-
const todo = await ctx.table("todos").getX(todoId);
|
|
160
|
-
return todo.patch(updates);
|
|
161
|
-
|
|
162
|
-
// Good — entity may not exist
|
|
163
|
-
const entity = await ctx.table("entities").get(entityId);
|
|
164
|
-
if (!entity) {
|
|
165
|
-
throw new ConvexError("Entity not found");
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Bad — redundant null-check on getX result
|
|
169
|
-
const todo = await ctx.table("todos").get(todoId);
|
|
170
|
-
if (!todo) {
|
|
171
|
-
throw new ConvexError("Todo not found");
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Error Handling
|
|
176
|
-
|
|
177
|
-
- Use `ConvexError` from `convex/values` for all business logic errors
|
|
178
|
-
- Trust `getX()` and `uniqueX()` to throw — don't add redundant null checks after them
|
|
179
|
-
- Only add explicit null checks when using `get()` or `first()`
|
|
180
|
-
- Keep error messages concise and actionable
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
import { ConvexError } from "convex/values";
|
|
184
|
-
|
|
185
|
-
// validate before the DB operation
|
|
186
|
-
if (count <= 0) {
|
|
187
|
-
throw new ConvexError("Limit reached");
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Common Patterns
|
|
192
|
-
|
|
193
|
-
### Edge Operations
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
// Load a related entity
|
|
197
|
-
const related = await entity.edge("relatedEntity");
|
|
198
|
-
|
|
199
|
-
// Add to an edge collection
|
|
200
|
-
await entity.patch({
|
|
201
|
-
relation: { add: [relatedId] },
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// Remove from an edge collection
|
|
205
|
-
await entity.patch({
|
|
206
|
-
relation: { remove: [relatedId] },
|
|
207
|
-
});
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Returning an Entity with Edges
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
const related = await entity.edge("relatedEntity");
|
|
214
|
-
return { ...entity, related };
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Standard Update Pattern
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
const { entityId, ...updates } = args;
|
|
221
|
-
const entity = await ctx.table("entities").getX(entityId);
|
|
222
|
-
return entity.patch(updates);
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Index Queries
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
// Query by named index
|
|
229
|
-
return ctx.table("entities", "by_user_id", (q) =>
|
|
230
|
-
q.eq("userId", args.userId)
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
// Query with a filter (use indexes instead where possible)
|
|
234
|
-
return ctx
|
|
235
|
-
.table("entities")
|
|
236
|
-
.filter((q) => q.eq(q.field("fieldName"), value))
|
|
237
|
-
.first();
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Validation Helpers
|
|
241
|
-
|
|
242
|
-
- Validation functions belong in the shared `@/utils/` package
|
|
243
|
-
- Keep CRUD files focused solely on database operations
|
|
244
|
-
- Reuse validators across multiple entities rather than duplicating logic
|
|
245
|
-
|
|
246
|
-
## Getting Started
|
|
247
|
-
|
|
248
|
-
### 1. Install dependencies
|
|
249
|
-
|
|
250
|
-
```bash
|
|
251
|
-
bun install
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### 2. Start the Convex dev server
|
|
255
|
-
|
|
256
|
-
```bash
|
|
257
|
-
npx convex dev
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
This pushes the schema and regenerates types in `_generated/`.
|
|
261
|
-
|
|
262
|
-
### 3. Configure environment
|
|
263
|
-
|
|
264
|
-
Copy `.env.local.example` to `.env.local` and fill in:
|
|
265
|
-
- `CONVEX_DEPLOYMENT` — from Convex dashboard
|
|
266
|
-
- `NEXT_PUBLIC_CONVEX_URL` — from Convex dashboard
|
|
267
|
-
- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` — from Clerk dashboard
|
|
268
|
-
- `CLERK_SECRET_KEY` — from Clerk dashboard
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Project-wide coding standards covering import ordering, naming conventions, code style, and testing policy. Apply across all TypeScript/TSX files.
|
|
3
|
-
globs: **/*.ts,**/*.tsx
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Coding Standards
|
|
7
|
-
|
|
8
|
-
## Naming Conventions
|
|
9
|
-
|
|
10
|
-
### Functions
|
|
11
|
-
- Use verb + noun: `getEntity`, `updateEntity`, `createEntity`, `deleteEntity`
|
|
12
|
-
- Be specific when needed: `getEntityByEmail`, `updateEntityField`
|
|
13
|
-
- Avoid abbreviations unless widely understood
|
|
14
|
-
- Avoid verbose qualifiers: prefer `updateEntity` over `updateEntityCoreDetails`
|
|
15
|
-
|
|
16
|
-
### Fields
|
|
17
|
-
- `camelCase` for all field names
|
|
18
|
-
- Use `userId` — not `clerkId` or other provider-specific names
|
|
19
|
-
|
|
20
|
-
### Variables
|
|
21
|
-
- Keep names concise and descriptive
|
|
22
|
-
- Use singular for single items (`todo`, `entity`) and plural for collections (`todos`, `entities`)
|
|
23
|
-
- Destructure to extract IDs: `const { entityId, ...updates } = args;`
|
|
24
|
-
|
|
25
|
-
## Code Style
|
|
26
|
-
|
|
27
|
-
### Formatting
|
|
28
|
-
- Single blank line between functions
|
|
29
|
-
- No blank lines at the start or end of a function body
|
|
30
|
-
- 2-space indentation
|
|
31
|
-
- Trailing commas in multi-line arrays and objects
|
|
32
|
-
|
|
33
|
-
### Conditional Logic
|
|
34
|
-
|
|
35
|
-
Prefer concise conditionals — avoid unnecessary intermediate variables:
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
// Good
|
|
39
|
-
const count = entity.limit ?? 0;
|
|
40
|
-
if (count <= 0) {
|
|
41
|
-
throw new ConvexError("Limit reached");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Bad
|
|
45
|
-
const remaining = entity.limit ?? 0;
|
|
46
|
-
if (!entity.limit || entity.limit <= 0) {
|
|
47
|
-
throw new ConvexError("Limit reached");
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Async / Await
|
|
52
|
-
- Always `await` async operations — never fire-and-forget unless intentional
|
|
53
|
-
- Chain operations when it improves readability
|
|
54
|
-
- Use `Promise.all()` for independent parallel operations
|
|
55
|
-
|
|
56
|
-
### Validation
|
|
57
|
-
- Validate business rules before any database operation
|
|
58
|
-
- Centralise reusable validation in `@/utils/`
|
|
59
|
-
- Throw `ConvexError` with clear, actionable messages
|
|
60
|
-
- Keep CRUD files thin — validation logic belongs in utils
|
|
61
|
-
|
|
62
|
-
## Testing
|
|
63
|
-
|
|
64
|
-
Test files **should not** be created unless explicitly requested. Focus on implementation quality over test coverage.
|