better-ts-stack 2.1.1 → 2.2.0
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/LICENSE +21 -21
- package/README.md +16 -8
- package/dist/args.js +7 -0
- package/dist/builder/buildPlanner.js +7 -1
- package/dist/builder/configGenerator.js +28 -3
- package/dist/builder/index.js +2 -1
- package/dist/builder/moduleSelector.js +6 -1
- package/dist/builder/readmeGenerator.js +8 -2
- package/dist/builder/templateContext.js +1 -0
- package/dist/output/nextSteps.js +2 -4
- package/dist/prompts/stack.js +6 -1
- package/dist/types/index.js +2 -0
- package/dist/ui/messages.js +2 -0
- package/package.json +71 -71
- package/templates/backend/express/.prettierignore +52 -52
- package/templates/backend/express/.prettierrc +16 -16
- package/templates/backend/express/gitignore +3 -1
- package/templates/backend/express/src/env.ts.hbs +13 -2
- package/templates/backend/express/src/index.ts.hbs +31 -2
- package/templates/backend/express/tsconfig.eslint.json +9 -9
- package/templates/backend/nestjs/.prettierignore +52 -52
- package/templates/backend/nestjs/gitignore +3 -1
- package/templates/backend/nestjs/src/app.module.ts.hbs +4 -1
- package/templates/backend/nestjs/src/env.ts.hbs +13 -2
- package/templates/backend/nestjs/src/health/health.controller.ts.hbs +7 -0
- package/templates/backend/nestjs/src/{main.ts → main.ts.hbs} +11 -0
- package/templates/backend/nestjs/tsconfig.eslint.json +9 -9
- package/templates/frontend/nextjs/app/globals.css +129 -89
- package/templates/frontend/nextjs/app/layout.tsx +36 -34
- package/templates/frontend/nextjs/app/page.tsx.hbs +63 -43
- package/templates/frontend/nextjs/components/ui/alert.tsx +75 -0
- package/templates/frontend/nextjs/components/ui/badge.tsx +51 -0
- package/templates/frontend/nextjs/components/ui/button.tsx +57 -51
- package/templates/frontend/nextjs/components/ui/card.tsx +102 -60
- package/templates/frontend/nextjs/components/ui/field.tsx +238 -67
- package/templates/frontend/nextjs/components/ui/input.tsx +19 -18
- package/templates/frontend/nextjs/components/ui/label.tsx +19 -0
- package/templates/frontend/nextjs/components/ui/separator.tsx +24 -0
- package/templates/frontend/nextjs/components/ui/skeleton.tsx +13 -0
- package/templates/frontend/nextjs/components/ui/spinner.tsx +10 -0
- package/templates/frontend/nextjs/components.json +11 -5
- package/templates/frontend/nextjs/config.json +36 -35
- package/templates/frontend/nextjs/eslint.config.mjs +11 -11
- package/templates/frontend/nextjs/lib/utils.ts +1 -6
- package/templates/frontend/nextjs/next.config.ts.hbs +12 -12
- package/templates/frontend/nextjs/postcss.config.mjs +7 -7
- package/templates/frontend/nextjs/public/file.svg +1 -1
- package/templates/frontend/nextjs/public/globe.svg +1 -1
- package/templates/frontend/nextjs/public/window.svg +1 -1
- package/templates/frontend/tanstack/components.json +25 -18
- package/templates/frontend/tanstack/config.json +5 -2
- package/templates/frontend/tanstack/eslint.config.mjs +23 -23
- package/templates/frontend/tanstack/gitignore +39 -39
- package/templates/frontend/tanstack/public/favicon.svg +7 -7
- package/templates/frontend/tanstack/src/components/ui/alert.tsx +75 -0
- package/templates/frontend/tanstack/src/components/ui/badge.tsx +51 -0
- package/templates/frontend/tanstack/src/components/ui/button.tsx +57 -51
- package/templates/frontend/tanstack/src/components/ui/card.tsx +102 -60
- package/templates/frontend/tanstack/src/components/ui/field.tsx +236 -67
- package/templates/frontend/tanstack/src/components/ui/input.tsx +19 -18
- package/templates/frontend/tanstack/src/components/ui/label.tsx +17 -0
- package/templates/frontend/tanstack/src/components/ui/separator.tsx +24 -0
- package/templates/frontend/tanstack/src/components/ui/skeleton.tsx +13 -0
- package/templates/frontend/tanstack/src/components/ui/spinner.tsx +10 -0
- package/templates/frontend/tanstack/src/lib/utils.ts +1 -6
- package/templates/frontend/tanstack/src/router.tsx +31 -31
- package/templates/frontend/tanstack/src/routes/__root.tsx +69 -69
- package/templates/frontend/tanstack/src/routes/index.tsx.hbs +64 -45
- package/templates/frontend/tanstack/src/styles/app.css +100 -55
- package/templates/frontend/tanstack/tsconfig.json +22 -22
- package/templates/modules/agents/AGENTS.md.hbs +245 -0
- package/templates/modules/agents/CLAUDE.md +1 -0
- package/templates/modules/agents/config.json +10 -0
- package/templates/modules/auth/express/config.json +12 -11
- package/templates/modules/auth/express/src/lib/auth.ts.hbs +143 -0
- package/templates/modules/auth/express/src/lib/email.ts +37 -0
- package/templates/modules/auth/express/src/middleware/requireAuth.ts +29 -0
- package/templates/modules/auth/express/src/routes/me.ts +13 -0
- package/templates/modules/auth/nestjs/config.json +13 -11
- package/templates/modules/auth/nestjs/src/auth/auth.module.ts.hbs +64 -14
- package/templates/modules/auth/nestjs/src/auth/auth.ts.hbs +152 -0
- package/templates/modules/auth/nestjs/src/auth/email.ts +37 -0
- package/templates/modules/auth/nestjs/src/me/me.controller.ts +15 -0
- package/templates/modules/auth/nextjs/app/api/auth/[...all]/route.ts +4 -4
- package/templates/modules/auth/nextjs/app/dashboard/page.tsx +101 -45
- package/templates/modules/auth/nextjs/app/forgot-password/page.tsx +11 -0
- package/templates/modules/auth/nextjs/app/reset-password/page.tsx +17 -0
- package/templates/modules/auth/nextjs/app/sign-in/page.tsx +23 -17
- package/templates/modules/auth/nextjs/app/sign-up/page.tsx +25 -19
- package/templates/modules/auth/nextjs/components/auth/change-password-form.tsx +125 -0
- package/templates/modules/auth/nextjs/components/auth/email-verification-card.tsx +91 -0
- package/templates/modules/auth/nextjs/components/auth/forgot-password-form.tsx +133 -0
- package/templates/modules/auth/nextjs/components/auth/reset-password-form.tsx +155 -0
- package/templates/modules/auth/nextjs/components/auth/sign-in-form.tsx +46 -32
- package/templates/modules/auth/nextjs/components/auth/sign-out-button.tsx +6 -5
- package/templates/modules/auth/nextjs/components/auth/sign-up-form.tsx +36 -30
- package/templates/modules/auth/nextjs/components/auth/social-buttons.tsx +73 -0
- package/templates/modules/auth/nextjs/config.json +24 -18
- package/templates/modules/auth/nextjs/lib/auth-client.ts +3 -3
- package/templates/modules/auth/nextjs/lib/auth-schema.ts +27 -2
- package/templates/modules/auth/nextjs/lib/auth.ts.hbs +65 -0
- package/templates/modules/auth/nextjs/lib/email.ts +43 -0
- package/templates/modules/auth/nextjs/lib/session.ts +12 -0
- package/templates/modules/auth/tanstack/config.json +25 -19
- package/templates/modules/auth/tanstack/src/components/auth/change-password-form.tsx +123 -0
- package/templates/modules/auth/tanstack/src/components/auth/email-verification-card.tsx +89 -0
- package/templates/modules/auth/tanstack/src/components/auth/forgot-password-form.tsx +131 -0
- package/templates/modules/auth/tanstack/src/components/auth/reset-password-form.tsx +149 -0
- package/templates/modules/auth/tanstack/src/components/auth/sign-in-form.tsx +44 -35
- package/templates/modules/auth/tanstack/src/components/auth/sign-out-button.tsx +7 -6
- package/templates/modules/auth/tanstack/src/components/auth/sign-up-form.tsx +37 -34
- package/templates/modules/auth/tanstack/src/components/auth/social-buttons.tsx +71 -0
- package/templates/modules/auth/tanstack/src/lib/auth-client.ts +2 -2
- package/templates/modules/auth/tanstack/src/lib/auth-functions.ts +14 -8
- package/templates/modules/auth/tanstack/src/lib/auth-schema.ts +27 -2
- package/templates/modules/auth/tanstack/src/lib/auth.ts.hbs +98 -38
- package/templates/modules/auth/tanstack/src/lib/email.ts +43 -0
- package/templates/modules/auth/tanstack/src/routeTree.gen.ts +61 -3
- package/templates/modules/auth/tanstack/src/routes/api/auth/$.ts +15 -15
- package/templates/modules/auth/tanstack/src/routes/dashboard.tsx +119 -111
- package/templates/modules/auth/tanstack/src/routes/forgot-password.tsx +17 -0
- package/templates/modules/auth/tanstack/src/routes/reset-password.tsx +25 -0
- package/templates/modules/auth/tanstack/src/routes/sign-in.tsx +44 -37
- package/templates/modules/auth/tanstack/src/routes/sign-up.tsx +44 -37
- package/templates/modules/docker/.dockerignore +2 -0
- package/templates/modules/docker/config.json +15 -15
- package/templates/modules/drizzle/express/config.json +26 -26
- package/templates/modules/drizzle/express/src/lib/schema.ts.hbs +90 -0
- package/templates/modules/drizzle/nestjs/config.json +26 -26
- package/templates/modules/drizzle/nestjs/src/database/schema.ts.hbs +90 -0
- package/templates/modules/drizzle/nextjs/config.json +26 -26
- package/templates/modules/drizzle/nextjs/drizzle.config.ts +13 -13
- package/templates/modules/drizzle/tanstack/config.json +26 -26
- package/templates/modules/drizzle/tanstack/drizzle.config.ts +12 -12
- package/templates/modules/drizzle/tanstack/src/lib/db.ts +13 -13
- package/templates/modules/mongoose/express/config.json +15 -15
- package/templates/modules/mongoose/express/src/lib/db.ts +43 -43
- package/templates/modules/mongoose/express/src/models/User.ts +48 -48
- package/templates/modules/mongoose/nestjs/config.json +16 -15
- package/templates/modules/mongoose/nextjs/config.json +15 -15
- package/templates/modules/mongoose/nextjs/models/User.ts +48 -48
- package/templates/modules/mongoose/tanstack/config.json +16 -16
- package/templates/modules/mongoose/tanstack/src/models/User.ts +48 -48
- package/templates/modules/prisma/express/config.json +27 -27
- package/templates/modules/prisma/express/prisma/schema.prisma.hbs +92 -0
- package/templates/modules/prisma/nestjs/config.json +27 -27
- package/templates/modules/prisma/nestjs/prisma/schema.prisma.hbs +91 -0
- package/templates/modules/prisma/nextjs/config.json +28 -28
- package/templates/modules/prisma/nextjs/lib/prisma.ts +18 -18
- package/templates/modules/prisma/nextjs/prisma.config.ts +14 -14
- package/templates/modules/prisma/tanstack/config.json +28 -28
- package/templates/modules/prisma/tanstack/prisma/schema.prisma.hbs +91 -91
- package/templates/modules/prisma/tanstack/prisma.config.ts +14 -14
- package/templates/modules/prisma/tanstack/src/lib/prisma.ts +17 -17
- package/templates/modules/rate-limit/express/src/middleware/rateLimit.ts +0 -8
- package/templates/modules/vscode/.vscode/extensions.json.hbs +29 -0
- package/templates/modules/vscode/.vscode/settings.json.hbs +22 -0
- package/templates/modules/vscode/config.json +10 -0
- package/templates/modules/auth/express/src/controllers/authController.ts.hbs +0 -116
- package/templates/modules/auth/express/src/lib/jwt.ts.hbs +0 -27
- package/templates/modules/auth/express/src/middleware/requireAuth.ts.hbs +0 -25
- package/templates/modules/auth/express/src/routes/auth.ts.hbs +0 -27
- package/templates/modules/auth/express/src/services/userStore.ts.hbs +0 -117
- package/templates/modules/auth/nestjs/src/auth/auth.controller.ts.hbs +0 -61
- package/templates/modules/auth/nestjs/src/auth/auth.guard.ts +0 -36
- package/templates/modules/auth/nestjs/src/auth/auth.schemas.ts +0 -35
- package/templates/modules/auth/nestjs/src/auth/auth.service.ts +0 -70
- package/templates/modules/auth/nestjs/src/auth/jwt.ts +0 -27
- package/templates/modules/auth/nestjs/src/auth/users.service.ts.hbs +0 -144
- package/templates/modules/auth/nestjs/src/auth/zod-validation.pipe.ts +0 -16
- package/templates/modules/drizzle/express/src/lib/schema.ts +0 -12
- package/templates/modules/drizzle/nestjs/src/database/schema.ts +0 -12
- package/templates/modules/prisma/express/prisma/schema.prisma +0 -24
- package/templates/modules/prisma/nestjs/prisma/schema.prisma +0 -23
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { createFileRoute{{#if useAuth}}, Link{{/if}} } from "@tanstack/react-router";
|
|
2
2
|
import { ArrowRight } from "lucide-react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { Alert, AlertDescription } from "~/components/ui/alert";
|
|
5
|
+
import { Badge } from "~/components/ui/badge";
|
|
6
|
+
import { Button } from "~/components/ui/button";
|
|
7
|
+
import {
|
|
8
|
+
Card,
|
|
9
|
+
CardContent,
|
|
10
|
+
CardFooter,
|
|
11
|
+
CardHeader,
|
|
12
|
+
CardTitle,
|
|
13
|
+
} from "~/components/ui/card";
|
|
7
14
|
|
|
8
15
|
export const Route = createFileRoute("/")({
|
|
9
16
|
component: Home,
|
|
@@ -13,7 +20,7 @@ const featureList = [
|
|
|
13
20
|
"TanStack Start SSR",
|
|
14
21
|
"TanStack Router and Query",
|
|
15
22
|
"React 19 and TypeScript",
|
|
16
|
-
"Tailwind CSS v4",
|
|
23
|
+
"Tailwind CSS v4 and shadcn/ui on Base UI",
|
|
17
24
|
{{#if useAuth}}"Better Auth-ready session flow",{{/if}}
|
|
18
25
|
{{#if (eq database "prisma")}}"Prisma database tooling",{{/if}}
|
|
19
26
|
{{#if (eq database "drizzle")}}"Drizzle database tooling",{{/if}}
|
|
@@ -22,66 +29,74 @@ const featureList = [
|
|
|
22
29
|
|
|
23
30
|
function Home() {
|
|
24
31
|
return (
|
|
25
|
-
<main className="min-h-
|
|
26
|
-
<div className="mx-auto flex min-h-
|
|
32
|
+
<main className="min-h-svh">
|
|
33
|
+
<div className="mx-auto flex min-h-svh max-w-6xl flex-col justify-center gap-12 px-6 py-16 sm:px-10 lg:px-12">
|
|
27
34
|
<section className="grid gap-10 lg:grid-cols-[1.2fr_0.8fr] lg:items-center">
|
|
28
|
-
<div className="
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
</span>
|
|
32
|
-
<div className="space-y-4">
|
|
35
|
+
<div className="flex flex-col gap-6">
|
|
36
|
+
<Badge variant="outline">Created with better-ts-stack</Badge>
|
|
37
|
+
<div className="flex flex-col gap-4">
|
|
33
38
|
<h1 className="max-w-3xl text-4xl font-semibold tracking-tight sm:text-5xl">
|
|
34
39
|
Ship your stack faster with a polished TypeScript foundation.
|
|
35
40
|
</h1>
|
|
36
41
|
<p className="max-w-2xl text-base leading-7 text-muted-foreground sm:text-lg">
|
|
37
42
|
Your project already includes the core app shell, database wiring,
|
|
38
|
-
and
|
|
39
|
-
|
|
43
|
+
and shadcn/ui components so you can keep building instead of
|
|
44
|
+
setting up boilerplate.
|
|
40
45
|
</p>
|
|
41
46
|
</div>
|
|
42
47
|
<div className="flex flex-col gap-3 sm:flex-row">
|
|
43
48
|
{{#if useAuth}}
|
|
44
|
-
<Link
|
|
45
|
-
to="/sign-up"
|
|
46
|
-
className={cn(buttonVariants({ size: "lg" }), "gap-2")}
|
|
47
|
-
>
|
|
49
|
+
<Button size="lg" nativeButton={false} render={<Link to="/sign-up" />}>
|
|
48
50
|
Create an account
|
|
49
|
-
<ArrowRight
|
|
50
|
-
</
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
<ArrowRight data-icon="inline-end" />
|
|
52
|
+
</Button>
|
|
53
|
+
<Button
|
|
54
|
+
size="lg"
|
|
55
|
+
variant="outline"
|
|
56
|
+
nativeButton={false}
|
|
57
|
+
render={<Link to="/sign-in" />}
|
|
54
58
|
>
|
|
55
59
|
Login
|
|
56
|
-
</
|
|
60
|
+
</Button>
|
|
57
61
|
{{else}}
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
<Button
|
|
63
|
+
size="lg"
|
|
64
|
+
nativeButton={false}
|
|
65
|
+
render={
|
|
66
|
+
<a
|
|
67
|
+
href="https://better-ts-stack.abdullahtech.me/docs"
|
|
68
|
+
target="_blank"
|
|
69
|
+
rel="noreferrer"
|
|
70
|
+
/>
|
|
71
|
+
}
|
|
63
72
|
>
|
|
64
73
|
Explore the docs
|
|
65
|
-
<ArrowRight
|
|
66
|
-
</
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
<ArrowRight data-icon="inline-end" />
|
|
75
|
+
</Button>
|
|
76
|
+
<Button
|
|
77
|
+
size="lg"
|
|
78
|
+
variant="outline"
|
|
79
|
+
nativeButton={false}
|
|
80
|
+
render={
|
|
81
|
+
<a
|
|
82
|
+
href="https://tanstack.com/start/latest"
|
|
83
|
+
target="_blank"
|
|
84
|
+
rel="noreferrer"
|
|
85
|
+
/>
|
|
86
|
+
}
|
|
72
87
|
>
|
|
73
88
|
TanStack guide
|
|
74
|
-
</
|
|
89
|
+
</Button>
|
|
75
90
|
{{/if}}
|
|
76
91
|
</div>
|
|
77
92
|
</div>
|
|
78
93
|
|
|
79
|
-
<Card
|
|
94
|
+
<Card>
|
|
80
95
|
<CardHeader>
|
|
81
96
|
<CardTitle>Included in this starter</CardTitle>
|
|
82
97
|
</CardHeader>
|
|
83
|
-
<CardContent
|
|
84
|
-
<ul className="
|
|
98
|
+
<CardContent>
|
|
99
|
+
<ul className="flex flex-col gap-3 text-muted-foreground">
|
|
85
100
|
{featureList.map((feature) => (
|
|
86
101
|
<li key={feature} className="flex items-center gap-3">
|
|
87
102
|
<span className="size-2 rounded-full bg-primary" />
|
|
@@ -89,15 +104,19 @@ function Home() {
|
|
|
89
104
|
</li>
|
|
90
105
|
))}
|
|
91
106
|
</ul>
|
|
92
|
-
<div className="rounded-2xl border border-border bg-muted px-4 py-3 text-sm text-muted-foreground">
|
|
93
|
-
Start editing{" "}
|
|
94
|
-
<code className="font-mono">src/routes/index.tsx</code> and
|
|
95
|
-
shape the project around your product instead of setup chores.
|
|
96
|
-
</div>
|
|
97
107
|
</CardContent>
|
|
108
|
+
<CardFooter>
|
|
109
|
+
<Alert>
|
|
110
|
+
<AlertDescription>
|
|
111
|
+
Start editing{" "}
|
|
112
|
+
<code className="font-mono">src/routes/index.tsx</code> and
|
|
113
|
+
shape the project around your product instead of setup chores.
|
|
114
|
+
</AlertDescription>
|
|
115
|
+
</Alert>
|
|
116
|
+
</CardFooter>
|
|
98
117
|
</Card>
|
|
99
118
|
</section>
|
|
100
119
|
</div>
|
|
101
120
|
</main>
|
|
102
121
|
);
|
|
103
|
-
}
|
|
122
|
+
}
|
|
@@ -1,49 +1,95 @@
|
|
|
1
1
|
@import "tailwindcss" source("../");
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
@import "shadcn/tailwind.css";
|
|
4
|
+
@import "@fontsource-variable/inter";
|
|
5
|
+
|
|
6
|
+
@custom-variant dark (&:is(.dark *));
|
|
2
7
|
|
|
3
8
|
@theme inline {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
--font-heading: var(--font-sans);
|
|
10
|
+
--font-sans: 'Inter Variable', sans-serif;
|
|
11
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
12
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
13
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
14
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
15
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
16
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
17
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
18
|
+
--color-sidebar: var(--sidebar);
|
|
19
|
+
--color-chart-5: var(--chart-5);
|
|
20
|
+
--color-chart-4: var(--chart-4);
|
|
21
|
+
--color-chart-3: var(--chart-3);
|
|
22
|
+
--color-chart-2: var(--chart-2);
|
|
23
|
+
--color-chart-1: var(--chart-1);
|
|
24
|
+
--color-ring: var(--ring);
|
|
25
|
+
--color-input: var(--input);
|
|
26
|
+
--color-border: var(--border);
|
|
27
|
+
--color-destructive: var(--destructive);
|
|
28
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
29
|
+
--color-accent: var(--accent);
|
|
30
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
31
|
+
--color-muted: var(--muted);
|
|
32
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
33
|
+
--color-secondary: var(--secondary);
|
|
34
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
35
|
+
--color-primary: var(--primary);
|
|
36
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
37
|
+
--color-popover: var(--popover);
|
|
38
|
+
--color-card-foreground: var(--card-foreground);
|
|
39
|
+
--color-card: var(--card);
|
|
40
|
+
--color-foreground: var(--foreground);
|
|
41
|
+
--color-background: var(--background);
|
|
42
|
+
--radius-sm: calc(var(--radius) * 0.6);
|
|
43
|
+
--radius-md: calc(var(--radius) * 0.8);
|
|
44
|
+
--radius-lg: var(--radius);
|
|
45
|
+
--radius-xl: calc(var(--radius) * 1.4);
|
|
46
|
+
--radius-2xl: calc(var(--radius) * 1.8);
|
|
47
|
+
--radius-3xl: calc(var(--radius) * 2.2);
|
|
48
|
+
--radius-4xl: calc(var(--radius) * 2.6);
|
|
20
49
|
}
|
|
21
50
|
|
|
22
51
|
:root {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
--background: oklch(1 0 0);
|
|
53
|
+
--foreground: oklch(0.145 0 0);
|
|
54
|
+
--card: oklch(1 0 0);
|
|
55
|
+
--card-foreground: oklch(0.145 0 0);
|
|
56
|
+
--popover: oklch(1 0 0);
|
|
57
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
58
|
+
--primary: oklch(0.205 0 0);
|
|
59
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
60
|
+
--secondary: oklch(0.97 0 0);
|
|
61
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
62
|
+
--muted: oklch(0.97 0 0);
|
|
63
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
64
|
+
--accent: oklch(0.97 0 0);
|
|
65
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
66
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
67
|
+
--border: oklch(0.922 0 0);
|
|
68
|
+
--input: oklch(0.922 0 0);
|
|
69
|
+
--ring: oklch(0.708 0 0);
|
|
70
|
+
--chart-1: oklch(0.87 0 0);
|
|
71
|
+
--chart-2: oklch(0.556 0 0);
|
|
72
|
+
--chart-3: oklch(0.439 0 0);
|
|
73
|
+
--chart-4: oklch(0.371 0 0);
|
|
74
|
+
--chart-5: oklch(0.269 0 0);
|
|
75
|
+
--radius: 0.625rem;
|
|
76
|
+
--sidebar: oklch(0.985 0 0);
|
|
77
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
78
|
+
--sidebar-primary: oklch(0.205 0 0);
|
|
79
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
80
|
+
--sidebar-accent: oklch(0.97 0 0);
|
|
81
|
+
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
82
|
+
--sidebar-border: oklch(0.922 0 0);
|
|
83
|
+
--sidebar-ring: oklch(0.708 0 0);
|
|
39
84
|
}
|
|
40
85
|
|
|
41
|
-
|
|
42
|
-
:root {
|
|
86
|
+
.dark {
|
|
43
87
|
--background: oklch(0.145 0 0);
|
|
44
88
|
--foreground: oklch(0.985 0 0);
|
|
45
89
|
--card: oklch(0.205 0 0);
|
|
46
90
|
--card-foreground: oklch(0.985 0 0);
|
|
91
|
+
--popover: oklch(0.205 0 0);
|
|
92
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
47
93
|
--primary: oklch(0.922 0 0);
|
|
48
94
|
--primary-foreground: oklch(0.205 0 0);
|
|
49
95
|
--secondary: oklch(0.269 0 0);
|
|
@@ -56,30 +102,29 @@
|
|
|
56
102
|
--border: oklch(1 0 0 / 10%);
|
|
57
103
|
--input: oklch(1 0 0 / 15%);
|
|
58
104
|
--ring: oklch(0.556 0 0);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
105
|
+
--chart-1: oklch(0.87 0 0);
|
|
106
|
+
--chart-2: oklch(0.556 0 0);
|
|
107
|
+
--chart-3: oklch(0.439 0 0);
|
|
108
|
+
--chart-4: oklch(0.371 0 0);
|
|
109
|
+
--chart-5: oklch(0.269 0 0);
|
|
110
|
+
--sidebar: oklch(0.205 0 0);
|
|
111
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
112
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
113
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
114
|
+
--sidebar-accent: oklch(0.269 0 0);
|
|
115
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
116
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
117
|
+
--sidebar-ring: oklch(0.556 0 0);
|
|
70
118
|
}
|
|
71
119
|
|
|
72
120
|
@layer base {
|
|
73
|
-
html {
|
|
74
|
-
color-scheme: light dark;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
121
|
* {
|
|
78
|
-
@apply border-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
html,
|
|
122
|
+
@apply border-border outline-ring/50;
|
|
123
|
+
}
|
|
82
124
|
body {
|
|
83
|
-
@apply bg-
|
|
84
|
-
|
|
125
|
+
@apply bg-background text-foreground;
|
|
126
|
+
}
|
|
127
|
+
html {
|
|
128
|
+
@apply font-sans;
|
|
129
|
+
}
|
|
85
130
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
{
|
|
2
|
-
"include": ["**/*.ts", "**/*.tsx"],
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"strict": true,
|
|
5
|
-
"esModuleInterop": true,
|
|
6
|
-
"jsx": "react-jsx",
|
|
7
|
-
"module": "ESNext",
|
|
8
|
-
"moduleResolution": "Bundler",
|
|
9
|
-
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
10
|
-
"isolatedModules": true,
|
|
11
|
-
"resolveJsonModule": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"target": "ES2022",
|
|
14
|
-
"allowJs": true,
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
"forceConsistentCasingInFileNames": true,
|
|
17
|
-
"paths": {
|
|
18
|
-
"~/*": ["./src/*"]
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"exclude": ["node_modules"]
|
|
22
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"include": ["**/*.ts", "**/*.tsx"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"strict": true,
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"target": "ES2022",
|
|
14
|
+
"allowJs": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"paths": {
|
|
18
|
+
"~/*": ["./src/*"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"exclude": ["node_modules"]
|
|
22
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Instructions for AI coding agents working in {{projectName}}. Read this before making changes.
|
|
4
|
+
|
|
5
|
+
## Stack
|
|
6
|
+
|
|
7
|
+
{{#if (eq framework 'express')}}
|
|
8
|
+
- Express 5 REST API in TypeScript, compiled to CommonJS with `tsc`
|
|
9
|
+
{{/if}}
|
|
10
|
+
{{#if (eq framework 'nestjs')}}
|
|
11
|
+
- NestJS 12 REST API in TypeScript, using ES modules
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{#if (eq framework 'nextjs')}}
|
|
14
|
+
- Next.js 16 with the App Router, React 19, Tailwind CSS 4, and shadcn/ui on Base UI
|
|
15
|
+
{{/if}}
|
|
16
|
+
{{#if (eq framework 'tanstack')}}
|
|
17
|
+
- TanStack Start with Vite, Nitro, React 19, Tailwind CSS 4, and shadcn/ui on Base UI
|
|
18
|
+
{{/if}}
|
|
19
|
+
{{#if (eq database 'prisma')}}
|
|
20
|
+
- PostgreSQL through Prisma 7
|
|
21
|
+
{{/if}}
|
|
22
|
+
{{#if (eq database 'drizzle')}}
|
|
23
|
+
- PostgreSQL through Drizzle ORM
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{#if (eq database 'mongoose')}}
|
|
26
|
+
- MongoDB through Mongoose
|
|
27
|
+
{{/if}}
|
|
28
|
+
{{#if useAuth}}
|
|
29
|
+
- Better Auth: email and password, email verification, password reset, and GitHub and Google sign-in when their keys are set. Emails go through Resend when `RESEND_API_KEY` is set and are printed to the log otherwise
|
|
30
|
+
{{#if (eq framework 'express')}}
|
|
31
|
+
- Auth routes under `/api/auth` (`POST /api/auth/sign-up/email`, `POST /api/auth/sign-in/email`, ...). Clients without cookies send `Authorization: Bearer <token>`, using the `set-auth-token` header from sign-in
|
|
32
|
+
{{/if}}
|
|
33
|
+
{{#if (eq framework 'nestjs')}}
|
|
34
|
+
- Auth routes under `/api/auth` (`POST /api/auth/sign-up/email`, `POST /api/auth/sign-in/email`, ...). Clients without cookies send `Authorization: Bearer <token>`, using the `set-auth-token` header from sign-in
|
|
35
|
+
{{/if}}
|
|
36
|
+
{{/if}}
|
|
37
|
+
{{#if useRateLimit}}
|
|
38
|
+
- Rate limiting on every route except `/health`
|
|
39
|
+
{{/if}}
|
|
40
|
+
{{#if useDocker}}
|
|
41
|
+
- Docker: `Dockerfile` and `docker-compose.yml`
|
|
42
|
+
{{/if}}
|
|
43
|
+
{{#if useCi}}
|
|
44
|
+
- GitHub Actions CI in `.github/workflows/ci.yml`
|
|
45
|
+
{{/if}}
|
|
46
|
+
- Package manager: {{packageManager}}. Do not use another one or add its lockfile
|
|
47
|
+
- Node.js 24 or later
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
- Install: `{{packageManager}} install`
|
|
52
|
+
- Dev server: `{{docker.run}} dev`
|
|
53
|
+
- Build: `{{docker.run}} build`
|
|
54
|
+
- Type-check: `{{docker.run}} type:check`
|
|
55
|
+
- Lint: `{{docker.run}} lint`
|
|
56
|
+
{{#if (eq database 'prisma')}}
|
|
57
|
+
- After changing `prisma/schema.prisma`: `{{docker.run}} prisma:migrate` creates and applies a migration and regenerates the client
|
|
58
|
+
{{/if}}
|
|
59
|
+
{{#if (eq database 'drizzle')}}
|
|
60
|
+
- After changing the schema: `{{docker.run}} db:generate` writes a migration, then `{{docker.run}} db:migrate` applies it
|
|
61
|
+
{{/if}}
|
|
62
|
+
|
|
63
|
+
## Before you finish
|
|
64
|
+
|
|
65
|
+
Run type-check and lint, and fix every error they report. Run the build too when you changed config, dependencies, or anything the build reads. Do not report a task as done while any of them fails.
|
|
66
|
+
|
|
67
|
+
## Layout
|
|
68
|
+
|
|
69
|
+
{{#if (eq framework 'express')}}
|
|
70
|
+
- `src/index.ts`: creates the app, adds middleware, and mounts the routers
|
|
71
|
+
- `src/env.ts`: checks the environment variables with Zod at startup, so a missing one stops the server with a clear message
|
|
72
|
+
- `src/routes/`: one router per resource, mounted in `src/index.ts`
|
|
73
|
+
{{#if useAuth}}
|
|
74
|
+
- `src/lib/auth.ts`: the Better Auth server, mounted on `/api/auth` in `src/index.ts`
|
|
75
|
+
- `src/lib/email.ts`: sends the verification and password reset emails
|
|
76
|
+
- `src/middleware/requireAuth.ts`: add it to a route to require a session; `getSession(res)` returns it. `src/routes/me.ts` is an example
|
|
77
|
+
{{/if}}
|
|
78
|
+
{{#if useRateLimit}}
|
|
79
|
+
- `src/middleware/rateLimit.ts`: the rate limiters
|
|
80
|
+
{{/if}}
|
|
81
|
+
{{#if (eq database 'prisma')}}
|
|
82
|
+
- `src/lib/prisma.ts`: the shared Prisma client. Do not create another one
|
|
83
|
+
{{/if}}
|
|
84
|
+
{{#if (eq database 'drizzle')}}
|
|
85
|
+
- `src/lib/db.ts`, `src/lib/schema.ts`: the database client and the tables
|
|
86
|
+
{{/if}}
|
|
87
|
+
{{#if (eq database 'mongoose')}}
|
|
88
|
+
- `src/lib/db.ts`, `src/models/`: the connection and the Mongoose models
|
|
89
|
+
{{/if}}
|
|
90
|
+
{{/if}}
|
|
91
|
+
{{#if (eq framework 'nestjs')}}
|
|
92
|
+
- `src/main.ts`: starts the app
|
|
93
|
+
- `src/app.module.ts`: the root module. Register new modules and controllers here
|
|
94
|
+
- `src/env.ts`: checks the environment variables with Zod at startup, so a missing one stops the server with a clear message
|
|
95
|
+
- `src/health/`: `GET /health`
|
|
96
|
+
{{#if useAuth}}
|
|
97
|
+
- `src/auth/`: the Better Auth server (`auth.ts`), the emails it sends (`email.ts`), and the module that mounts it on `/api/auth` (`auth.module.ts`)
|
|
98
|
+
- Every route needs a session unless it has `@AllowAnonymous()` (or `@OptionalAuth()`). Read the session with `@Session()`, as `src/me/me.controller.ts` does
|
|
99
|
+
{{/if}}
|
|
100
|
+
{{#if (eq database 'prisma')}}
|
|
101
|
+
- `src/prisma/`: `PrismaService`, injected wherever the database is needed
|
|
102
|
+
{{/if}}
|
|
103
|
+
{{#if (eq database 'drizzle')}}
|
|
104
|
+
- `src/database/`: the database module and the tables in `schema.ts`
|
|
105
|
+
{{/if}}
|
|
106
|
+
{{#if (eq database 'mongoose')}}
|
|
107
|
+
- `src/users/user.schema.ts`: the Mongoose schema for users
|
|
108
|
+
{{/if}}
|
|
109
|
+
{{/if}}
|
|
110
|
+
{{#if (eq framework 'nextjs')}}
|
|
111
|
+
- `app/`: routes, layouts, and route handlers. Pages are Server Components unless they need state, effects, or event handlers
|
|
112
|
+
- `components/ui/`: shadcn/ui components built on Base UI (`@base-ui/react`). Add new ones with the shadcn CLI instead of writing them by hand. Use the `render` prop to change the rendered element, not Radix's `asChild`
|
|
113
|
+
- `lib/utils.ts`: the `cn()` class name helper
|
|
114
|
+
- `app/globals.css`: the shadcn theme. Style with its tokens (`bg-primary`, `text-muted-foreground`), not raw Tailwind colors, and space with `flex` + `gap-*`, not `space-y-*`
|
|
115
|
+
{{#if useAuth}}
|
|
116
|
+
- `lib/auth.ts`: the Better Auth server. `lib/auth-client.ts`: the client for components. `lib/email.ts`: sends the verification and password reset emails
|
|
117
|
+
- `lib/session.ts`: `getSession()` reads the session on the server, once per request
|
|
118
|
+
- `app/api/auth/[...all]/route.ts`: the Better Auth endpoints. Do not rename it
|
|
119
|
+
- `proxy.ts`: sends signed-out visitors from `/dashboard` to `/sign-in`. Add other protected paths to its `matcher`
|
|
120
|
+
{{/if}}
|
|
121
|
+
{{#if (eq database 'prisma')}}
|
|
122
|
+
- `lib/prisma.ts`: the shared Prisma client. Do not create another one
|
|
123
|
+
{{/if}}
|
|
124
|
+
{{#if (eq database 'drizzle')}}
|
|
125
|
+
- `lib/db.ts`, `lib/schema.ts`: the database client and the tables
|
|
126
|
+
{{/if}}
|
|
127
|
+
{{#if (eq database 'mongoose')}}
|
|
128
|
+
- `lib/db.ts`, `models/`: the connection and the Mongoose models
|
|
129
|
+
{{/if}}
|
|
130
|
+
{{/if}}
|
|
131
|
+
{{#if (eq framework 'tanstack')}}
|
|
132
|
+
- `src/routes/`: file-based routes. A new file becomes a route
|
|
133
|
+
- `src/routeTree.gen.ts`: generated by the dev server and the build. Never edit it
|
|
134
|
+
- `src/router.tsx`, `src/routes/__root.tsx`: the router and the root layout
|
|
135
|
+
- `src/components/ui/`: shadcn/ui components built on Base UI (`@base-ui/react`). Add new ones with the shadcn CLI instead of writing them by hand. Use the `render` prop to change the rendered element, not Radix's `asChild`
|
|
136
|
+
- `src/lib/utils.ts`: the `cn()` class name helper
|
|
137
|
+
- `src/styles/app.css`: the shadcn theme. Style with its tokens (`bg-primary`, `text-muted-foreground`), not raw Tailwind colors, and space with `flex` + `gap-*`, not `space-y-*`
|
|
138
|
+
{{#if useAuth}}
|
|
139
|
+
- `src/lib/auth.ts`: the Better Auth server. `src/lib/auth-client.ts`: the client for components. `src/lib/email.ts`: sends the verification and password reset emails
|
|
140
|
+
- `src/routes/api/auth/$.ts`: the Better Auth endpoints. Do not rename it
|
|
141
|
+
- `src/routes/dashboard.tsx`: an example of a protected route that redirects in `beforeLoad`
|
|
142
|
+
{{/if}}
|
|
143
|
+
{{#if (eq database 'prisma')}}
|
|
144
|
+
- `src/lib/prisma.ts`: the shared Prisma client. Do not create another one
|
|
145
|
+
{{/if}}
|
|
146
|
+
{{#if (eq database 'drizzle')}}
|
|
147
|
+
- `src/lib/db.ts`, `src/lib/schema.ts`: the database client and the tables
|
|
148
|
+
{{/if}}
|
|
149
|
+
{{#if (eq database 'mongoose')}}
|
|
150
|
+
- `src/lib/db.ts`, `src/models/`: the connection and the Mongoose models
|
|
151
|
+
{{/if}}
|
|
152
|
+
{{/if}}
|
|
153
|
+
|
|
154
|
+
## Rules
|
|
155
|
+
|
|
156
|
+
- TypeScript is strict. Do not use `any` or `@ts-ignore` to silence an error; fix the type
|
|
157
|
+
{{#if (eq framework 'nestjs')}}
|
|
158
|
+
- Relative imports end in `.js`, as ES modules require: `import { AuthModule } from "./auth/auth.module.js"`
|
|
159
|
+
{{/if}}
|
|
160
|
+
- Keep `.env` out of git. When you add an environment variable, add it to `.env.example` too{{#if (eq framework 'express')}}, and to `src/env.ts`{{/if}}{{#if (eq framework 'nestjs')}}, and to `src/env.ts`{{/if}}
|
|
161
|
+
{{#if (eq database 'prisma')}}
|
|
162
|
+
- The Prisma client is generated into {{#if (eq framework 'express')}}`src/generated/`{{/if}}{{#if (eq framework 'nestjs')}}`src/generated/`{{/if}}{{#if (eq framework 'nextjs')}}`generated/`{{/if}}{{#if (eq framework 'tanstack')}}`generated/`{{/if}}. Never edit or commit it
|
|
163
|
+
{{/if}}
|
|
164
|
+
- Match the existing code style. ESLint settings are in `eslint.config.mjs`{{#if (eq framework 'express')}} and Prettier settings in `.prettierrc`{{/if}}{{#if (eq framework 'nestjs')}} and Prettier settings in `.prettierrc`{{/if}}
|
|
165
|
+
{{#if (eq framework 'nextjs')}}
|
|
166
|
+
- Write Tailwind classes in their canonical form. Use the theme utility when one exists (`rounded-4xl`, not `rounded-[2rem]`), and in an arbitrary value write `_` only where CSS needs a space, never after a comma: `bg-[linear-gradient(180deg,#f8fafc_0%,#eef2ff_100%)]`. The Tailwind CSS VS Code extension warns about the long forms
|
|
167
|
+
{{/if}}
|
|
168
|
+
{{#if (eq framework 'tanstack')}}
|
|
169
|
+
- Write Tailwind classes in their canonical form. Use the theme utility when one exists (`rounded-4xl`, not `rounded-[2rem]`), and in an arbitrary value write `_` only where CSS needs a space, never after a comma: `bg-[linear-gradient(180deg,#f8fafc_0%,#eef2ff_100%)]`. The Tailwind CSS VS Code extension warns about the long forms
|
|
170
|
+
{{/if}}
|
|
171
|
+
- Add a dependency only when the task needs it, and install it with {{packageManager}}
|
|
172
|
+
|
|
173
|
+
## Production rules
|
|
174
|
+
|
|
175
|
+
- Validate every input from outside the app (request bodies, query strings, form data) with Zod before you use it{{#unless useAuth}}{{#if (eq framework 'nextjs')}} (add `zod` with {{packageManager}} first){{/if}}{{#if (eq framework 'tanstack')}} (add `zod` with {{packageManager}} first){{/if}}{{/unless}}
|
|
176
|
+
- Never log or return secrets, tokens, or passwords. Error responses get a short message and the right status code, never a stack trace
|
|
177
|
+
{{#unless (eq database 'none')}}
|
|
178
|
+
- Query the database through {{#if (eq database 'prisma')}}Prisma{{/if}}{{#if (eq database 'drizzle')}}Drizzle{{/if}}{{#if (eq database 'mongoose')}}Mongoose{{/if}}, never with SQL or queries built from strings
|
|
179
|
+
{{/unless}}
|
|
180
|
+
{{#if (eq framework 'express')}}
|
|
181
|
+
- Keep the security middleware in `src/index.ts` (`helmet`, `cors`{{#if useRateLimit}}, the rate limiter{{/if}}) in place. Set `CORS_ORIGIN` to your real origins in production
|
|
182
|
+
{{/if}}
|
|
183
|
+
{{#if (eq framework 'nestjs')}}
|
|
184
|
+
- Keep the security setup in `src/main.ts` and `src/app.module.ts` in place. Set `CORS_ORIGIN` to your real origins in production
|
|
185
|
+
{{/if}}
|
|
186
|
+
{{#if (eq framework 'nextjs')}}
|
|
187
|
+
- Server first: do not `await` data at the top of a page or layout, which holds back the whole page. Move each `await` into the component that needs the data and wrap that component in `<Suspense>` with a fallback, so the rest of the page is sent at once{{#if useAuth}}. `app/dashboard/page.tsx` shows the pattern with `getSession()`{{/if}}
|
|
188
|
+
- Code that reads secrets or the database stays on the server. Only variables prefixed with `NEXT_PUBLIC_` reach the browser, so never put a secret in one
|
|
189
|
+
{{/if}}
|
|
190
|
+
{{#if (eq framework 'tanstack')}}
|
|
191
|
+
- Code that reads secrets or the database runs in server functions or server routes. Only variables prefixed with `VITE_` reach the browser, so never put a secret in one
|
|
192
|
+
{{/if}}
|
|
193
|
+
{{#if useAuth}}
|
|
194
|
+
{{#if (eq framework 'nextjs')}}
|
|
195
|
+
- Check the session on the server in every protected page, route handler, and server action. Hiding a button in the UI does not protect anything
|
|
196
|
+
{{/if}}
|
|
197
|
+
{{#if (eq framework 'tanstack')}}
|
|
198
|
+
- Check the session on the server in every protected route and server function. Hiding a button in the UI does not protect anything
|
|
199
|
+
{{/if}}
|
|
200
|
+
{{/if}}
|
|
201
|
+
{{#if (eq framework 'express')}}
|
|
202
|
+
{{#if useAuth}}
|
|
203
|
+
- Check the session on the server in every protected route with `requireAuth`
|
|
204
|
+
{{/if}}
|
|
205
|
+
- Keep `GET /health` fast and free of auth{{#if useRateLimit}} and rate limiting{{/if}}, so hosts can check that the app is up
|
|
206
|
+
{{/if}}
|
|
207
|
+
{{#if (eq framework 'nestjs')}}
|
|
208
|
+
- Keep `GET /health` fast and free of auth{{#if useRateLimit}} and rate limiting{{/if}}, so hosts can check that the app is up
|
|
209
|
+
{{/if}}
|
|
210
|
+
- Keep changes small and focused on the task. Do not add layers, abstractions, or files the task does not need
|
|
211
|
+
|
|
212
|
+
## When you are unsure
|
|
213
|
+
|
|
214
|
+
The libraries here may be newer than what you know. When you are not sure how an API works, read the official docs for the version in `package.json` instead of guessing:
|
|
215
|
+
|
|
216
|
+
{{#if (eq framework 'express')}}
|
|
217
|
+
- Express 5: https://expressjs.com/en/5x/api.html
|
|
218
|
+
{{/if}}
|
|
219
|
+
{{#if (eq framework 'nestjs')}}
|
|
220
|
+
- NestJS: https://docs.nestjs.com
|
|
221
|
+
{{/if}}
|
|
222
|
+
{{#if (eq framework 'nextjs')}}
|
|
223
|
+
- Next.js: https://nextjs.org/docs
|
|
224
|
+
{{/if}}
|
|
225
|
+
{{#if (eq framework 'tanstack')}}
|
|
226
|
+
- TanStack Start: https://tanstack.com/start/latest/docs
|
|
227
|
+
{{/if}}
|
|
228
|
+
{{#if (eq database 'prisma')}}
|
|
229
|
+
- Prisma: https://www.prisma.io/docs
|
|
230
|
+
{{/if}}
|
|
231
|
+
{{#if (eq database 'drizzle')}}
|
|
232
|
+
- Drizzle: https://orm.drizzle.team/docs/overview
|
|
233
|
+
{{/if}}
|
|
234
|
+
{{#if (eq database 'mongoose')}}
|
|
235
|
+
- Mongoose: https://mongoosejs.com/docs
|
|
236
|
+
{{/if}}
|
|
237
|
+
{{#if useAuth}}
|
|
238
|
+
- Better Auth: https://www.better-auth.com/docs
|
|
239
|
+
{{#if (eq framework 'nestjs')}}
|
|
240
|
+
- NestJS Better Auth integration: https://github.com/ThallesP/nestjs-better-auth
|
|
241
|
+
{{/if}}
|
|
242
|
+
{{/if}}
|
|
243
|
+
- Zod: https://zod.dev
|
|
244
|
+
|
|
245
|
+
If the docs and this file disagree, follow the docs and say so.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "agents",
|
|
3
|
+
"name": "AI agent instructions",
|
|
4
|
+
"description": "An AGENTS.md that tells AI coding agents how this project is built, run, and checked, and a CLAUDE.md that points Claude Code to it",
|
|
5
|
+
"type": "feature",
|
|
6
|
+
"dependencies": {},
|
|
7
|
+
"devDependencies": {},
|
|
8
|
+
"scripts": {},
|
|
9
|
+
"envVars": {}
|
|
10
|
+
}
|