create-skit 0.1.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.
Files changed (195) hide show
  1. package/README.md +36 -0
  2. package/bin/create-skit.mjs +1064 -0
  3. package/lib/module-application.mjs +281 -0
  4. package/lib/module-resolver.mjs +179 -0
  5. package/modules/README.md +22 -0
  6. package/modules/ai-dx/files/AGENTS.md +116 -0
  7. package/modules/ai-dx/files/ARCHITECTURE.md +103 -0
  8. package/modules/ai-dx/module.json +14 -0
  9. package/modules/ai-dx-claude/files/CLAUDE.md +8 -0
  10. package/modules/ai-dx-claude/module.json +13 -0
  11. package/modules/ai-dx-cursor/files/.cursor/rules/auth.mdc +53 -0
  12. package/modules/ai-dx-cursor/files/.cursor/rules/database.mdc +48 -0
  13. package/modules/ai-dx-cursor/files/.cursor/rules/env.mdc +43 -0
  14. package/modules/ai-dx-cursor/files/.cursor/rules/nextjs.mdc +58 -0
  15. package/modules/ai-dx-cursor/files/.cursor/rules/project.mdc +33 -0
  16. package/modules/ai-dx-cursor/files/.cursor/rules/testing.mdc +55 -0
  17. package/modules/ai-dx-cursor/module.json +18 -0
  18. package/modules/ai-dx-gemini/files/.gemini/GEMINI.md +5 -0
  19. package/modules/ai-dx-gemini/module.json +13 -0
  20. package/modules/auth-core/module.json +8 -0
  21. package/modules/auth-github/module.json +20 -0
  22. package/modules/billing-polar/module.json +20 -0
  23. package/modules/billing-stripe/module.json +23 -0
  24. package/modules/dashboard-shell/files/src/app/globals.css +756 -0
  25. package/modules/dashboard-shell/files/src/app/settings/page.tsx +67 -0
  26. package/modules/dashboard-shell/module.json +11 -0
  27. package/modules/db-pg/module.json +21 -0
  28. package/modules/db-postgresjs/module.json +21 -0
  29. package/modules/deploy-docker/files/.dockerignore +19 -0
  30. package/modules/deploy-docker/files/Dockerfile +25 -0
  31. package/modules/deploy-docker/module.json +11 -0
  32. package/modules/email-resend/module.json +21 -0
  33. package/modules/quality-baseline/module.json +8 -0
  34. package/modules/testing-baseline/module.json +8 -0
  35. package/package.json +40 -0
  36. package/presets/README.md +12 -0
  37. package/presets/blank.json +67 -0
  38. package/presets/dashboard.json +67 -0
  39. package/templates/base-web/.env.example +17 -0
  40. package/templates/base-web/.github/workflows/ci.yml +34 -0
  41. package/templates/base-web/.husky/pre-commit +3 -0
  42. package/templates/base-web/.husky/pre-push +3 -0
  43. package/templates/base-web/.prettierignore +3 -0
  44. package/templates/base-web/README.md +42 -0
  45. package/templates/base-web/drizzle.config.ts +16 -0
  46. package/templates/base-web/eslint.config.mjs +127 -0
  47. package/templates/base-web/manifest.json +5 -0
  48. package/templates/base-web/next-env.d.ts +4 -0
  49. package/templates/base-web/next.config.ts +5 -0
  50. package/templates/base-web/package.json +75 -0
  51. package/templates/base-web/playwright.config.ts +21 -0
  52. package/templates/base-web/prettier.config.mjs +9 -0
  53. package/templates/base-web/proxy.ts +23 -0
  54. package/templates/base-web/src/app/api/auth/[...all]/route.ts +5 -0
  55. package/templates/base-web/src/app/api/billing/checkout/route.ts +26 -0
  56. package/templates/base-web/src/app/api/billing/portal/route.ts +25 -0
  57. package/templates/base-web/src/app/api/email/test/route.ts +28 -0
  58. package/templates/base-web/src/app/api/webhooks/polar/route.ts +5 -0
  59. package/templates/base-web/src/app/api/webhooks/stripe/route.ts +5 -0
  60. package/templates/base-web/src/app/billing/page.tsx +55 -0
  61. package/templates/base-web/src/app/dashboard/page.tsx +15 -0
  62. package/templates/base-web/src/app/email/page.tsx +46 -0
  63. package/templates/base-web/src/app/error.tsx +27 -0
  64. package/templates/base-web/src/app/globals.css +534 -0
  65. package/templates/base-web/src/app/layout.tsx +19 -0
  66. package/templates/base-web/src/app/llms-full.txt/route.ts +158 -0
  67. package/templates/base-web/src/app/llms.txt/route.ts +59 -0
  68. package/templates/base-web/src/app/loading.tsx +24 -0
  69. package/templates/base-web/src/app/not-found.tsx +16 -0
  70. package/templates/base-web/src/app/page.tsx +5 -0
  71. package/templates/base-web/src/app/sign-in/page.tsx +14 -0
  72. package/templates/base-web/src/app/sign-up/page.tsx +14 -0
  73. package/templates/base-web/src/components/auth/email-auth-form.test.tsx +40 -0
  74. package/templates/base-web/src/components/auth/email-auth-form.tsx +128 -0
  75. package/templates/base-web/src/components/auth/sign-out-button.tsx +29 -0
  76. package/templates/base-web/src/db/index.ts +16 -0
  77. package/templates/base-web/src/db/schema/auth.ts +4 -0
  78. package/templates/base-web/src/db/schema/index.ts +2 -0
  79. package/templates/base-web/src/db/schema/projects.ts +17 -0
  80. package/templates/base-web/src/db/seeds/index.ts +32 -0
  81. package/templates/base-web/src/lib/auth-client.ts +5 -0
  82. package/templates/base-web/src/lib/auth-session.ts +21 -0
  83. package/templates/base-web/src/lib/auth.ts +23 -0
  84. package/templates/base-web/src/lib/billing/index.ts +37 -0
  85. package/templates/base-web/src/lib/billing/providers/polar.ts +80 -0
  86. package/templates/base-web/src/lib/billing/providers/stripe.ts +77 -0
  87. package/templates/base-web/src/lib/billing/types.ts +25 -0
  88. package/templates/base-web/src/lib/email/index.ts +19 -0
  89. package/templates/base-web/src/lib/email/templates.test.ts +12 -0
  90. package/templates/base-web/src/lib/email/templates.ts +40 -0
  91. package/templates/base-web/src/lib/env.ts +83 -0
  92. package/templates/base-web/tests/e2e/home.spec.ts +8 -0
  93. package/templates/base-web/tsconfig.json +34 -0
  94. package/templates/base-web/vitest.config.ts +19 -0
  95. package/templates/blank/.env.example +16 -0
  96. package/templates/blank/.github/workflows/ci.yml +34 -0
  97. package/templates/blank/.husky/pre-commit +3 -0
  98. package/templates/blank/.husky/pre-push +3 -0
  99. package/templates/blank/.prettierignore +3 -0
  100. package/templates/blank/drizzle.config.ts +16 -0
  101. package/templates/blank/eslint.config.mjs +127 -0
  102. package/templates/blank/next-env.d.ts +4 -0
  103. package/templates/blank/next.config.ts +5 -0
  104. package/templates/blank/package.json +75 -0
  105. package/templates/blank/playwright.config.ts +21 -0
  106. package/templates/blank/prettier.config.mjs +9 -0
  107. package/templates/blank/proxy.ts +28 -0
  108. package/templates/blank/src/app/api/auth/[...all]/route.ts +5 -0
  109. package/templates/blank/src/app/api/billing/checkout/route.ts +26 -0
  110. package/templates/blank/src/app/api/billing/portal/route.ts +25 -0
  111. package/templates/blank/src/app/api/email/test/route.ts +28 -0
  112. package/templates/blank/src/app/api/webhooks/polar/route.ts +5 -0
  113. package/templates/blank/src/app/api/webhooks/stripe/route.ts +5 -0
  114. package/templates/blank/src/app/billing/page.tsx +70 -0
  115. package/templates/blank/src/app/email/page.tsx +46 -0
  116. package/templates/blank/src/app/globals.css +394 -0
  117. package/templates/blank/src/app/layout.tsx +19 -0
  118. package/templates/blank/src/app/page.tsx +23 -0
  119. package/templates/blank/src/app/sign-in/page.tsx +18 -0
  120. package/templates/blank/src/app/sign-up/page.tsx +18 -0
  121. package/templates/blank/src/components/auth/email-auth-form.test.tsx +39 -0
  122. package/templates/blank/src/components/auth/email-auth-form.tsx +109 -0
  123. package/templates/blank/src/components/auth/sign-out-button.tsx +29 -0
  124. package/templates/blank/src/db/index.ts +16 -0
  125. package/templates/blank/src/db/schema/auth.ts +4 -0
  126. package/templates/blank/src/db/schema/index.ts +2 -0
  127. package/templates/blank/src/db/schema/projects.ts +17 -0
  128. package/templates/blank/src/db/seeds/index.ts +28 -0
  129. package/templates/blank/src/lib/auth-client.ts +5 -0
  130. package/templates/blank/src/lib/auth-session.ts +11 -0
  131. package/templates/blank/src/lib/auth.ts +23 -0
  132. package/templates/blank/src/lib/billing/index.ts +37 -0
  133. package/templates/blank/src/lib/billing/providers/polar.ts +80 -0
  134. package/templates/blank/src/lib/billing/providers/stripe.ts +77 -0
  135. package/templates/blank/src/lib/billing/types.ts +25 -0
  136. package/templates/blank/src/lib/email/index.ts +19 -0
  137. package/templates/blank/src/lib/email/templates.test.ts +15 -0
  138. package/templates/blank/src/lib/email/templates.ts +40 -0
  139. package/templates/blank/src/lib/env.ts +80 -0
  140. package/templates/blank/tsconfig.json +34 -0
  141. package/templates/blank/vitest.config.ts +19 -0
  142. package/templates/dashboard/.env.example +16 -0
  143. package/templates/dashboard/.github/workflows/ci.yml +34 -0
  144. package/templates/dashboard/.husky/pre-commit +3 -0
  145. package/templates/dashboard/.husky/pre-push +3 -0
  146. package/templates/dashboard/.prettierignore +3 -0
  147. package/templates/dashboard/drizzle.config.ts +16 -0
  148. package/templates/dashboard/eslint.config.mjs +127 -0
  149. package/templates/dashboard/next-env.d.ts +4 -0
  150. package/templates/dashboard/next.config.ts +5 -0
  151. package/templates/dashboard/package.json +75 -0
  152. package/templates/dashboard/playwright.config.ts +21 -0
  153. package/templates/dashboard/prettier.config.mjs +9 -0
  154. package/templates/dashboard/proxy.ts +36 -0
  155. package/templates/dashboard/src/app/api/auth/[...all]/route.ts +5 -0
  156. package/templates/dashboard/src/app/api/billing/checkout/route.ts +26 -0
  157. package/templates/dashboard/src/app/api/billing/portal/route.ts +25 -0
  158. package/templates/dashboard/src/app/api/email/test/route.ts +28 -0
  159. package/templates/dashboard/src/app/api/webhooks/polar/route.ts +5 -0
  160. package/templates/dashboard/src/app/api/webhooks/stripe/route.ts +5 -0
  161. package/templates/dashboard/src/app/billing/layout.tsx +22 -0
  162. package/templates/dashboard/src/app/billing/page.tsx +73 -0
  163. package/templates/dashboard/src/app/dashboard/layout.tsx +22 -0
  164. package/templates/dashboard/src/app/dashboard/page.tsx +104 -0
  165. package/templates/dashboard/src/app/email/layout.tsx +22 -0
  166. package/templates/dashboard/src/app/email/page.tsx +54 -0
  167. package/templates/dashboard/src/app/globals.css +1357 -0
  168. package/templates/dashboard/src/app/layout.tsx +25 -0
  169. package/templates/dashboard/src/app/page.tsx +154 -0
  170. package/templates/dashboard/src/app/settings/layout.tsx +22 -0
  171. package/templates/dashboard/src/app/settings/page.tsx +85 -0
  172. package/templates/dashboard/src/app/sign-in/page.tsx +47 -0
  173. package/templates/dashboard/src/app/sign-up/page.tsx +47 -0
  174. package/templates/dashboard/src/components/auth/email-auth-form.test.tsx +39 -0
  175. package/templates/dashboard/src/components/auth/email-auth-form.tsx +160 -0
  176. package/templates/dashboard/src/components/auth/sign-out-button.tsx +29 -0
  177. package/templates/dashboard/src/components/dashboard/shell.tsx +158 -0
  178. package/templates/dashboard/src/db/index.ts +16 -0
  179. package/templates/dashboard/src/db/schema/auth.ts +4 -0
  180. package/templates/dashboard/src/db/schema/index.ts +2 -0
  181. package/templates/dashboard/src/db/schema/projects.ts +17 -0
  182. package/templates/dashboard/src/db/seeds/index.ts +28 -0
  183. package/templates/dashboard/src/lib/auth-client.ts +5 -0
  184. package/templates/dashboard/src/lib/auth-session.ts +11 -0
  185. package/templates/dashboard/src/lib/auth.ts +41 -0
  186. package/templates/dashboard/src/lib/billing/index.ts +37 -0
  187. package/templates/dashboard/src/lib/billing/providers/polar.ts +80 -0
  188. package/templates/dashboard/src/lib/billing/providers/stripe.ts +77 -0
  189. package/templates/dashboard/src/lib/billing/types.ts +25 -0
  190. package/templates/dashboard/src/lib/email/index.ts +19 -0
  191. package/templates/dashboard/src/lib/email/templates.test.ts +15 -0
  192. package/templates/dashboard/src/lib/email/templates.ts +40 -0
  193. package/templates/dashboard/src/lib/env.ts +88 -0
  194. package/templates/dashboard/tsconfig.json +34 -0
  195. package/templates/dashboard/vitest.config.ts +19 -0
@@ -0,0 +1,67 @@
1
+ import { redirect } from "next/navigation";
2
+
3
+ import { getSession } from "@/lib/auth-session";
4
+
5
+ export default async function SettingsPage() {
6
+ const session = await getSession();
7
+
8
+ if (!session) {
9
+ redirect("/sign-in");
10
+ }
11
+
12
+ return (
13
+ <main className="dashboard">
14
+ <aside className="sidebar">
15
+ <div>
16
+ <p className="brand">Skit</p>
17
+ <h1 className="workspace-title">Settings</h1>
18
+ <p className="workspace-subtitle">
19
+ Manage your account, notifications, and workspace preferences.
20
+ </p>
21
+ </div>
22
+
23
+ <div className="sidebar-section">
24
+ <p className="sidebar-label">Signed in as</p>
25
+ <div className="pill">
26
+ <span className="status-dot" />
27
+ {session.user.email}
28
+ </div>
29
+ </div>
30
+
31
+ <div className="sidebar-spacer" />
32
+ </aside>
33
+
34
+ <section className="content">
35
+ <div className="settings-grid">
36
+ <article className="settings-card">
37
+ <p className="eyebrow">Profile</p>
38
+ <h2>Identity and session</h2>
39
+ <p>
40
+ Better Auth is wired in. Add avatar upload, password rotation, and audit
41
+ log surfaces here without changing the route structure later.
42
+ </p>
43
+ </article>
44
+
45
+ <article className="settings-card">
46
+ <p className="eyebrow">Billing</p>
47
+ <h2>Plan and seat management</h2>
48
+ <p>
49
+ This is the natural place for subscription state, invoices, and workspace
50
+ access management once billing moves past the starter baseline.
51
+ </p>
52
+ </article>
53
+
54
+ <article className="settings-card settings-card-wide">
55
+ <p className="eyebrow">Ops note</p>
56
+ <h2>Keep settings boring and reliable</h2>
57
+ <p>
58
+ The page is intentionally structured as stable product infrastructure rather
59
+ than visual filler. Add account, organization, and compliance controls here
60
+ as real features land.
61
+ </p>
62
+ </article>
63
+ </div>
64
+ </section>
65
+ </main>
66
+ );
67
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "dashboard-shell",
3
+ "kind": "ui",
4
+ "description": "Dashboard-oriented app shell and example UI.",
5
+ "dependsOn": ["auth-core", "testing-baseline"],
6
+ "conflictsWith": [],
7
+ "replaces": [],
8
+ "template": {
9
+ "copyFiles": ["src/app/globals.css", "src/app/settings/page.tsx"]
10
+ }
11
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "db-pg",
3
+ "kind": "database",
4
+ "description": "Drizzle ORM with node-postgres.",
5
+ "dependsOn": ["quality-baseline"],
6
+ "conflictsWith": ["db-postgresjs"],
7
+ "replaces": [],
8
+ "template": {
9
+ "tokenReplacements": {
10
+ "__DATABASE_DRIVER__": "pg",
11
+ "__DATABASE_DEPENDENCIES__": " \"pg\": \"8.16.x\",",
12
+ "__DATABASE_DEV_DEPENDENCIES__": " \"@types/pg\": \"^8.15.5\",",
13
+ "__DRIZZLE_DRIVER_IMPORT__": "drizzle-orm/node-postgres",
14
+ "__DATABASE_CLIENT_IMPORT__": "import { Pool } from \"pg\";",
15
+ "__DATABASE_GLOBAL_BLOCK__": "const globalForDb = globalThis as typeof globalThis & {\n __pandaPool?: Pool;\n};",
16
+ "__DATABASE_CLIENT_EXPRESSION__": "globalForDb.__pandaPool ??\n new Pool({\n connectionString: env.DATABASE_URL\n })",
17
+ "__DATABASE_DEV_CACHE__": " globalForDb.__pandaPool = client;",
18
+ "__DATABASE_DRIZZLE_EXPRESSION__": "drizzle({\n client\n})"
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "db-postgresjs",
3
+ "kind": "database",
4
+ "description": "Drizzle ORM with postgres.js.",
5
+ "dependsOn": ["quality-baseline"],
6
+ "conflictsWith": ["db-pg"],
7
+ "replaces": [],
8
+ "template": {
9
+ "tokenReplacements": {
10
+ "__DATABASE_DRIVER__": "postgres.js",
11
+ "__DATABASE_DEPENDENCIES__": " \"postgres\": \"^3.4.7\",",
12
+ "__DATABASE_DEV_DEPENDENCIES__": "",
13
+ "__DRIZZLE_DRIVER_IMPORT__": "drizzle-orm/postgres-js",
14
+ "__DATABASE_CLIENT_IMPORT__": "import postgres from \"postgres\";",
15
+ "__DATABASE_GLOBAL_BLOCK__": "const globalForDb = globalThis as typeof globalThis & {\n __pandaClient?: ReturnType<typeof postgres>;\n};",
16
+ "__DATABASE_CLIENT_EXPRESSION__": "globalForDb.__pandaClient ??\n postgres(env.DATABASE_URL, {\n prepare: false\n })",
17
+ "__DATABASE_DEV_CACHE__": " globalForDb.__pandaClient = client;",
18
+ "__DATABASE_DRIZZLE_EXPRESSION__": "drizzle(client)"
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,19 @@
1
+ .git
2
+ .github
3
+ .husky
4
+ .next
5
+ .turbo
6
+ .tmp
7
+ coverage
8
+ node_modules
9
+ npm-debug.log*
10
+ pnpm-debug.log*
11
+ yarn-debug.log*
12
+ yarn-error.log*
13
+ playwright-report
14
+ test-results
15
+ .env
16
+ .env.local
17
+ .env.development.local
18
+ .env.test.local
19
+ .env.production.local
@@ -0,0 +1,25 @@
1
+ FROM __DOCKER_BASE_IMAGE__ AS deps
2
+ WORKDIR /app
3
+ COPY package.json ./
4
+ COPY tsconfig.json ./
5
+ COPY next.config.ts ./
6
+ COPY eslint.config.mjs ./
7
+ COPY prettier.config.mjs ./
8
+ COPY playwright.config.ts ./
9
+ COPY vitest.config.ts ./
10
+ COPY drizzle.config.ts ./
11
+ COPY . .
12
+ __DOCKER_SETUP__
13
+ RUN __DOCKER_INSTALL_COMMAND__
14
+
15
+ FROM deps AS builder
16
+ WORKDIR /app
17
+ RUN __DOCKER_BUILD_COMMAND__
18
+
19
+ FROM __DOCKER_BASE_IMAGE__ AS runner
20
+ WORKDIR /app
21
+ ENV NODE_ENV=production
22
+ COPY --from=builder /app ./
23
+ __DOCKER_SETUP__
24
+ EXPOSE 3000
25
+ CMD ["/bin/sh", "-c", "__DOCKER_START_COMMAND__"]
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "deploy-docker",
3
+ "kind": "deploy",
4
+ "description": "Docker deployment baseline with Dockerfile and .dockerignore.",
5
+ "dependsOn": ["quality-baseline"],
6
+ "conflictsWith": [],
7
+ "replaces": [],
8
+ "template": {
9
+ "copyFiles": ["Dockerfile", ".dockerignore"]
10
+ }
11
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "email-resend",
3
+ "kind": "email",
4
+ "description": "Resend transactional email integration.",
5
+ "dependsOn": ["auth-core"],
6
+ "conflictsWith": [],
7
+ "replaces": [],
8
+ "template": {
9
+ "emailProvider": "resend",
10
+ "packageDependencies": [
11
+ " \"resend\": \"6.0.3\","
12
+ ],
13
+ "email": {
14
+ "imports": [
15
+ "import { Resend } from \"resend\";"
16
+ ],
17
+ "setup": "let resendClient: Resend | null = null;\n\nfunction getEmailClient() {\n if (!env.RESEND_API_KEY) {\n throw new Error(\"RESEND_API_KEY is required for email sending.\");\n }\n\n resendClient ??= new Resend(env.RESEND_API_KEY);\n return resendClient;\n}",
18
+ "sendImplementation": " const resend = getEmailClient();\n\n return resend.emails.send({\n from: getFromAddress(),\n to: input.to,\n subject: input.template.subject,\n text: input.template.text,\n html: input.template.html\n });"
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "quality-baseline",
3
+ "kind": "developer-experience",
4
+ "description": "ESLint, Prettier, Husky, and repo quality defaults.",
5
+ "dependsOn": [],
6
+ "conflictsWith": [],
7
+ "replaces": []
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "testing-baseline",
3
+ "kind": "developer-experience",
4
+ "description": "Vitest, Playwright, and CI testing defaults.",
5
+ "dependsOn": ["quality-baseline"],
6
+ "conflictsWith": [],
7
+ "replaces": []
8
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "create-skit",
3
+ "version": "0.1.0",
4
+ "description": "Opinionated SaaS starter CLI for Next.js 16.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "create-skit": "./bin/create-skit.mjs"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "lib",
13
+ "modules",
14
+ "presets",
15
+ "templates",
16
+ "README.md"
17
+ ],
18
+ "keywords": [
19
+ "nextjs",
20
+ "starter",
21
+ "saas",
22
+ "cli",
23
+ "scaffold"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/jocage/skit.git",
28
+ "directory": "apps/cli"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "homepage": "https://github.com/jocage/skit",
34
+ "bugs": {
35
+ "url": "https://github.com/jocage/skit/issues"
36
+ },
37
+ "scripts": {
38
+ "prepack": "node ../../scripts/sync-cli-package-assets.mjs"
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ # Presets
2
+
3
+ Presets are curated bundles of modules.
4
+
5
+ Current presets:
6
+
7
+ - `blank`
8
+ - `dashboard`
9
+
10
+ For now, the CLI still copies the matching verified template, but preset resolution already determines the module manifest written into generated apps.
11
+
12
+ Each preset now also tracks its `overrideFiles` relative to `templates/base-web`, which makes the shared-vs-specific boundary explicit before full preset assembly is introduced.
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "blank",
3
+ "base": "base-web",
4
+ "template": "blank",
5
+ "tokenReplacements": {
6
+ "__TEMPLATE_NAME__": "blank",
7
+ "__AUTH_PROVIDER_ENV_EXAMPLE__": "",
8
+ "__AUTH_PROVIDER_ENV_SCHEMA__": "",
9
+ "__AUTH_PROVIDER_ENV_VALUES__": "",
10
+ "__AUTH_SOCIAL_PROVIDERS_BLOCK__": "",
11
+ "__AUTH_SOCIAL_BUTTON_HANDLER__": "",
12
+ "__AUTH_SOCIAL_BUTTON__": "",
13
+ "__AUTH_SOCIAL_TEST_ASSERTION__": "",
14
+ "__AUTH_SCREEN_CLASS__": "shell auth-shell",
15
+ "__AUTH_PANEL_CLASS__": "auth-card",
16
+ "__SIGN_OUT_BUTTON_CLASS__": "subtle-button",
17
+ "__AUTH_FORM_CLASS__": "auth-card",
18
+ "__AUTH_FORM_COPY_CLASS__": "auth-copy",
19
+ "__AUTH_FORM_FIELDS_CLASS__": "auth-fields",
20
+ "__AUTH_FORM_SIGN_IN_EYEBROW__": "Welcome back",
21
+ "__AUTH_FORM_SIGN_IN_HEADING__": "Sign in to your workspace",
22
+ "__AUTH_FORM_SIGN_IN_LEDE__": "Use your email and password to continue into the starter app shell.",
23
+ "__AUTH_FORM_SIGN_UP_HEADING__": "Create your account",
24
+ "__AUTH_FORM_SIGN_UP_LEDE__": "Start from a minimal SaaS baseline with auth, billing, and strong project structure.",
25
+ "__AUTH_FORM_TEST_MODE__": "sign-in",
26
+ "__AUTH_FORM_TEST_HEADING__": "sign in to your workspace",
27
+ "__AUTH_FORM_TEST_LABEL__": "email",
28
+ "__EMAIL_TEMPLATE_TEST_IMPORT__": "createWelcomeEmailTemplate",
29
+ "__EMAIL_TEMPLATE_TEST_SUITE__": "createWelcomeEmailTemplate",
30
+ "__EMAIL_TEMPLATE_TEST_CASE__": "includes the app name in the subject",
31
+ "__EMAIL_TEMPLATE_TEST_FACTORY__": "createWelcomeEmailTemplate({\n appName: \"Skit\",\n recipientName: \"Ada\"\n })",
32
+ "__EMAIL_TEMPLATE_EXPECT_SUBJECT__": "Skit",
33
+ "__EMAIL_TEMPLATE_EXPECT_TEXT__": "Ada",
34
+ "__PROTECTED_ROUTE_CONDITION__": "pathname.startsWith(\"/dashboard\") ||\n pathname.startsWith(\"/billing\") ||\n pathname.startsWith(\"/email\")",
35
+ "__PROTECTED_ROUTE_MATCHERS__": "\"/dashboard/:path*\", \"/billing/:path*\", \"/email/:path*\"",
36
+ "__README_STATE_COPY__": "initial minimal shell for the starter",
37
+ "__README_HIGHLIGHT_BULLET__": "simple polished landing screen",
38
+ "__README_PROTECTED_ROUTES_BULLET__": "protected `/dashboard` route and auth handler",
39
+ "__HOME_MAIN_CLASS__": "shell",
40
+ "__HOME_SECTION_CLASS__": "hero",
41
+ "__HOME_HEADING__": "Your SaaS starts here.",
42
+ "__HOME_LEDE__": "Auth, database, billing, email — pre-wired and ready. Extend the blank baseline with real product features instead of rebuilding infrastructure.",
43
+ "__HOME_PAGE_CONTENT__": "(\n <>\n <header className=\"blank-header\">\n <span className=\"blank-logo\">__PROJECT_NAME__</span>\n <nav className=\"blank-nav\">\n <Link href=\"/sign-in\">Sign in</Link>\n <Link href=\"/sign-up\" className=\"blank-nav-cta\">Get started</Link>\n </nav>\n </header>\n <main className=\"shell\">\n <section className=\"hero\">\n <p className=\"eyebrow\">Skit</p>\n <h1>Your SaaS starts here.</h1>\n <p className=\"lede\">\n Auth, database, billing, email — pre-wired and ready.\n Extend the blank baseline with real product features.\n </p>\n <div className=\"hero-actions\">\n <Link href=\"/sign-up\">Create account</Link>\n <Link href=\"/dashboard\">Open dashboard</Link>\n </div>\n </section>\n </main>\n </>\n )",
44
+ "__BILLING_REDIRECT_IMPORT__": "import { redirect } from \"next/navigation\";\n",
45
+ "__BILLING_SESSION_SETUP__": "",
46
+ "__BILLING_AUTH_GUARD__": " if (!session) {\n redirect(\"/sign-in\");\n }",
47
+ "__BILLING_DEMO_BANNER__": "",
48
+ "__BILLING_PROVIDER_CARD__": " <form\n key={provider}\n action=\"/api/billing/checkout\"\n method=\"post\"\n className=\"billing-card\"\n >\n <input type=\"hidden\" name=\"provider\" value={provider} />\n <h2>{provider === \"stripe\" ? \"Stripe\" : \"Polar\"}</h2>\n <p>\n {provider === \"stripe\"\n ? \"Create a subscription checkout session using the configured Stripe price.\"\n : \"Create a Polar checkout session using the configured product identifier.\"}\n </p>\n <button type=\"submit\" className=\"auth-button\">\n {provider === \"stripe\" ? \"Start Stripe checkout\" : \"Start Polar checkout\"}\n </button>\n </form>",
49
+ "__EMAIL_REDIRECT_IMPORT__": "import { redirect } from \"next/navigation\";\n",
50
+ "__EMAIL_SESSION_SETUP__": "",
51
+ "__EMAIL_AUTH_GUARD__": " if (!session) {\n redirect(\"/sign-in\");\n }\n\n const displayEmailRecipient = session.user.email;\n const emailSendingDisabled = false;",
52
+ "__EMAIL_DEMO_BANNER__": "",
53
+ "__DASHBOARD_REDIRECT_IMPORT__": "import { redirect } from \"next/navigation\";\n",
54
+ "__DASHBOARD_SESSION_SETUP__": "",
55
+ "__DASHBOARD_AUTH_GUARD__": " if (!session) {\n redirect(\"/sign-in\");\n }",
56
+ "__DASHBOARD_PAGE_PRELUDE__": "",
57
+ "__DASHBOARD_PAGE_CONTENT__": "(\n <main className=\"shell\">\n <section className=\"hero\">\n <p className=\"eyebrow\">Protected area</p>\n <h1>Hello {session.user.name ?? session.user.email}</h1>\n <p className=\"lede\">\n This is the first protected route in the blank starter. It proves the auth\n flow, route guarding, and session wiring are in place.\n </p>\n <div className=\"hero-actions\">\n <Link href=\"/\">Go home</Link>\n <Link href=\"/billing\">Billing</Link>\n <Link href=\"/email\">Email</Link>\n <SignOutButton />\n </div>\n </section>\n </main>\n )",
58
+ "__HOME_E2E_TEST_NAME__": "home page renders starter links",
59
+ "__HOME_E2E_HEADING__": "your saas starts here",
60
+ "__HOME_E2E_LINK__": "create account",
61
+ "__AUTH_LLMS_EXTRA__": "",
62
+ "__BILLING_LLMS_LINE__": "Stripe / Polar billing (provider abstraction)",
63
+ "__EMAIL_LLMS_LINE__": "Resend transactional email"
64
+ },
65
+ "overrideFiles": [],
66
+ "modules": ["quality-baseline", "testing-baseline", "auth-core"]
67
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "dashboard",
3
+ "base": "base-web",
4
+ "template": "dashboard",
5
+ "tokenReplacements": {
6
+ "__TEMPLATE_NAME__": "dashboard",
7
+ "__AUTH_PROVIDER_ENV_EXAMPLE__": "",
8
+ "__AUTH_PROVIDER_ENV_SCHEMA__": "",
9
+ "__AUTH_PROVIDER_ENV_VALUES__": "",
10
+ "__AUTH_SOCIAL_PROVIDERS_BLOCK__": "",
11
+ "__AUTH_SOCIAL_BUTTON_HANDLER__": "",
12
+ "__AUTH_SOCIAL_BUTTON__": "",
13
+ "__AUTH_SOCIAL_TEST_ASSERTION__": "",
14
+ "__AUTH_SCREEN_CLASS__": "auth-screen",
15
+ "__AUTH_PANEL_CLASS__": "auth-panel",
16
+ "__SIGN_OUT_BUTTON_CLASS__": "ghost-button",
17
+ "__AUTH_FORM_CLASS__": "auth-panel",
18
+ "__AUTH_FORM_COPY_CLASS__": "",
19
+ "__AUTH_FORM_FIELDS_CLASS__": "auth-grid",
20
+ "__AUTH_FORM_SIGN_IN_EYEBROW__": "Access dashboard",
21
+ "__AUTH_FORM_SIGN_IN_HEADING__": "Sign in",
22
+ "__AUTH_FORM_SIGN_IN_LEDE__": "Use your email and password to continue into the app.",
23
+ "__AUTH_FORM_SIGN_UP_HEADING__": "Create your operator account",
24
+ "__AUTH_FORM_SIGN_UP_LEDE__": "Create an account to access the protected dashboard shell.",
25
+ "__AUTH_FORM_TEST_MODE__": "sign-up",
26
+ "__AUTH_FORM_TEST_HEADING__": "create your operator account",
27
+ "__AUTH_FORM_TEST_LABEL__": "password",
28
+ "__EMAIL_TEMPLATE_TEST_IMPORT__": "createBillingUpdatePlaceholderTemplate",
29
+ "__EMAIL_TEMPLATE_TEST_SUITE__": "createBillingUpdatePlaceholderTemplate",
30
+ "__EMAIL_TEMPLATE_TEST_CASE__": "mentions the billing provider",
31
+ "__EMAIL_TEMPLATE_TEST_FACTORY__": "createBillingUpdatePlaceholderTemplate({\n appName: \"Skit\",\n provider: \"stripe\"\n })",
32
+ "__EMAIL_TEMPLATE_EXPECT_SUBJECT__": "billing",
33
+ "__EMAIL_TEMPLATE_EXPECT_TEXT__": "stripe",
34
+ "__PROTECTED_ROUTE_CONDITION__": "pathname.startsWith(\"/settings\") ||\n pathname.startsWith(\"/billing\") ||\n pathname.startsWith(\"/email\")",
35
+ "__PROTECTED_ROUTE_MATCHERS__": "\"/settings/:path*\", \"/billing/:path*\", \"/email/:path*\"",
36
+ "__README_STATE_COPY__": "initial dashboard-oriented shell for the starter",
37
+ "__README_HIGHLIGHT_BULLET__": "modern SaaS marketing page plus public demo dashboard shell",
38
+ "__README_PROTECTED_ROUTES_BULLET__": "public demo `/dashboard` plus protected account surfaces like `/settings`, `/billing`, and `/email`",
39
+ "__HOME_MAIN_CLASS__": "landing",
40
+ "__HOME_SECTION_CLASS__": "landing-panel",
41
+ "__HOME_HEADING__": "Launch faster with a modular SaaS base.",
42
+ "__HOME_LEDE__": "This template now ships with a public demo dashboard, Better Auth wiring, database scaffolding, and the first product surfaces already in place.",
43
+ "__HOME_PAGE_CONTENT__": "(\n <main className=\"landing-page\">\n <nav className=\"marketing-nav\">\n <div className=\"logo\">launch<em>frame</em></div>\n <div className=\"marketing-nav-links\">\n <Link href=\"/sign-in\">Sign in</Link>\n <Link href=\"/sign-up\" className=\"nav-cta\">Get started</Link>\n </div>\n </nav>\n\n <div className=\"marketing-shell\">\n <section className=\"marketing-hero\">\n <span className=\"badge-pill\">Ship faster in 2026</span>\n <h1>Build your SaaS <em>without the boilerplate.</em></h1>\n <p className=\"lede\">\n Auth, billing, email, database — all wired up and ready.\n Stop rebuilding infrastructure and start shipping your product.\n </p>\n <div className=\"hero-actions\">\n <Link href=\"/dashboard\">Explore the live demo</Link>\n <Link href=\"/sign-up\">Start from this baseline</Link>\n <Link href=\"/sign-in\">Sign in</Link>\n </div>\n </section>\n\n <section className=\"bento-section\">\n <p className=\"eyebrow\">Everything included</p>\n <h2>Production-ready from day one</h2>\n <div className=\"bento-grid\">\n <div className=\"bento-card span-2\">\n <span className=\"bento-icon\">🔐</span>\n <h3>Authentication</h3>\n <p>Email/password auth with Better Auth. Session management, protected routes, and middleware — all pre-configured.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">Better Auth</span><span className=\"bento-tag\">Server sessions</span><span className=\"bento-tag\">Edge middleware</span></div>\n </div>\n <div className=\"bento-card\">\n <span className=\"bento-icon\">💳</span>\n <h3>Billing</h3>\n <p>Stripe and Polar checkout flows with a provider abstraction you can extend.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">Stripe</span><span className=\"bento-tag\">Polar</span></div>\n </div>\n <div className=\"bento-card\">\n <span className=\"bento-icon\">🗄️</span>\n <h3>Database</h3>\n <p>Drizzle ORM with migrations, seeds, and a typed schema ready for your models.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">Drizzle</span><span className=\"bento-tag\">PostgreSQL</span></div>\n </div>\n <div className=\"bento-card span-2\">\n <span className=\"bento-icon\">📧</span>\n <h3>Transactional email</h3>\n <p>Resend integration with HTML templates for welcome emails, password resets, and billing notifications.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">Resend</span><span className=\"bento-tag\">HTML templates</span></div>\n </div>\n <div className=\"bento-card\">\n <span className=\"bento-icon\">🧪</span>\n <h3>Testing</h3>\n <p>Vitest for unit tests, Playwright for E2E. Pre-commit hooks enforce quality.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">Vitest</span><span className=\"bento-tag\">Playwright</span></div>\n </div>\n <div className=\"bento-card\">\n <span className=\"bento-icon\">⚡</span>\n <h3>Next.js 16</h3>\n <p>App Router, React 19, server components, and the latest compiler out of the box.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">App Router</span><span className=\"bento-tag\">React 19</span></div>\n </div>\n <div className=\"bento-card\">\n <span className=\"bento-icon\">🤖</span>\n <h3>Agent-friendly</h3>\n <p>AGENTS.md, explicit placeholders, and a flat file tree that AI coding assistants love.</p>\n <div className=\"bento-tags\"><span className=\"bento-tag\">Cursor</span><span className=\"bento-tag\">Copilot</span></div>\n </div>\n </div>\n </section>\n\n <section className=\"pricing-section\">\n <p className=\"eyebrow\">Pricing</p>\n <h2>Simple, transparent pricing</h2>\n <p className=\"lede\">Start free, scale as you grow. No hidden fees, cancel anytime.</p>\n <div className=\"pricing-grid\">\n <div className=\"pricing-card\">\n <p className=\"plan-name\">Starter</p>\n <div className=\"plan-price\"><strong>$0</strong><span>/month</span></div>\n <p className=\"plan-desc\">For side projects and experiments.</p>\n <ul className=\"pricing-features\">\n <li>Up to 100 users</li>\n <li>Basic analytics</li>\n <li>Community support</li>\n <li>1 project</li>\n </ul>\n <Link href=\"/sign-up\" className=\"pricing-cta\">Get started free</Link>\n </div>\n <div className=\"pricing-card featured\">\n <p className=\"plan-name\">Pro</p>\n <div className=\"plan-price\"><strong>$29</strong><span>/month</span></div>\n <p className=\"plan-desc\">For growing products that need more.</p>\n <ul className=\"pricing-features\">\n <li>Unlimited users</li>\n <li>Advanced analytics</li>\n <li>Priority support</li>\n <li>Unlimited projects</li>\n <li>Custom domain</li>\n </ul>\n <Link href=\"/sign-up\" className=\"pricing-cta\">Start 14-day trial</Link>\n </div>\n <div className=\"pricing-card\">\n <p className=\"plan-name\">Enterprise</p>\n <div className=\"plan-price\"><strong>Custom</strong></div>\n <p className=\"plan-desc\">For teams with specific needs.</p>\n <ul className=\"pricing-features\">\n <li>Everything in Pro</li>\n <li>SSO &amp; SAML</li>\n <li>Dedicated support</li>\n <li>SLA guarantee</li>\n <li>Custom integrations</li>\n </ul>\n <Link href=\"/sign-up\" className=\"pricing-cta\">Contact sales</Link>\n </div>\n </div>\n </section>\n\n <section className=\"cta-section\">\n <h2>Ready to ship?</h2>\n <p>Generate your project in seconds. Everything is yours to customize — no vendor lock-in, no hidden abstractions.</p>\n <div className=\"hero-actions\">\n <Link href=\"/dashboard\">Open live dashboard</Link>\n <Link href=\"/sign-up\">Create account</Link>\n </div>\n </section>\n\n <footer className=\"marketing-footer\">\n <p>Built with Skit — open source SaaS starter for Next.js</p>\n </footer>\n </div>\n </main>\n )",
44
+ "__DASHBOARD_REDIRECT_IMPORT__": "",
45
+ "__DASHBOARD_SESSION_SETUP__": " const displayUser = session?.user ?? {\n email: \"eugene@jocage.com\",\n name: \"Demo Workspace\"\n };",
46
+ "__DASHBOARD_AUTH_GUARD__": "",
47
+ "__BILLING_REDIRECT_IMPORT__": "",
48
+ "__BILLING_SESSION_SETUP__": " const displayBillingUser = session?.user ?? {\n email: \"eugene@jocage.com\",\n name: \"Demo Workspace\"\n };",
49
+ "__BILLING_AUTH_GUARD__": "",
50
+ "__BILLING_DEMO_BANNER__": " {!session ? (\n <p className=\"demo-banner\">\n Demo mode is active. Checkout buttons stay visible for product context, but\n real billing flows should be tested after auth and provider credentials are configured.\n </p>\n ) : null}",
51
+ "__BILLING_PROVIDER_CARD__": " <form\n key={provider}\n action=\"/api/billing/checkout\"\n method=\"post\"\n className=\"billing-card\"\n >\n <input type=\"hidden\" name=\"provider\" value={provider} />\n <h2>{provider === \"stripe\" ? \"Stripe\" : \"Polar\"}</h2>\n <p>\n {provider === \"stripe\"\n ? \"Create a subscription checkout session using the configured Stripe price.\"\n : \"Create a Polar checkout session using the configured product identifier.\"}\n </p>\n <p className=\"billing-caption\">\n Viewing as <strong>{displayBillingUser.name ?? displayBillingUser.email}</strong>\n </p>\n <button type=\"submit\" className=\"auth-button\" disabled={!session}>\n {!session\n ? provider === \"stripe\"\n ? \"Sign in to test Stripe\"\n : \"Sign in to test Polar\"\n : provider === \"stripe\"\n ? \"Start Stripe checkout\"\n : \"Start Polar checkout\"}\n </button>\n </form>",
52
+ "__EMAIL_REDIRECT_IMPORT__": "",
53
+ "__EMAIL_SESSION_SETUP__": " const displayEmailRecipient = session?.user?.email ?? \"eugene@jocage.com\";\n const emailSendingDisabled = !session;",
54
+ "__EMAIL_AUTH_GUARD__": "",
55
+ "__EMAIL_DEMO_BANNER__": " {!session ? (\n <p className=\"demo-banner\">\n Demo mode is active. The email surface stays visible, but actual send actions\n unlock after sign-in and provider configuration.\n </p>\n ) : null}",
56
+ "__DASHBOARD_PAGE_PRELUDE__": "const stats = [\n { label: \"MRR\", value: \"$12.4k\", change: \"+8.2%\", tone: \"positive\" },\n { label: \"Trials\", value: \"184\", change: \"+14.9%\", tone: \"positive\" },\n { label: \"Activation\", value: \"62%\", change: \"+5.1%\", tone: \"positive\" },\n { label: \"Churn\", value: \"2.1%\", change: \"Watchlist\", tone: \"warning\" }\n];\n\nconst activity = [\n {\n title: \"Polar and Stripe adapters are already wired\",\n description: \"Swap providers without rewriting your app surface.\",\n stamp: \"Now\",\n badge: \"BL\"\n },\n {\n title: \"Better Auth baseline is live\",\n description: \"Email auth flows, protected routes, and session helpers are in place.\",\n stamp: \"Auth\",\n badge: \"AU\"\n },\n {\n title: \"Vitest + Playwright gates are included\",\n description: \"You start with verification, not just templates and good intentions.\",\n stamp: \"QA\",\n badge: \"TS\"\n }\n];\n\nconst pipeline = [\n { label: \"Lead capture\", value: \"1,284\", detail: \"+11% week over week\" },\n { label: \"Qualified trials\", value: \"312\", detail: \"42 from referral channels\" },\n { label: \"Activated workspaces\", value: \"116\", detail: \"62% activation rate\" }\n];",
57
+ "__DASHBOARD_PAGE_CONTENT__": "(\n <main className=\"dashboard\">\n <aside className=\"sidebar\">\n <div>\n <p className=\"brand\">Skit</p>\n <h1 className=\"workspace-title\">Control room</h1>\n <p className=\"workspace-subtitle\">\n Start with a product shell that already understands auth, billing, email,\n and deployment paths.\n </p>\n </div>\n\n <div className=\"sidebar-section\">\n <p className=\"sidebar-label\">Workspace</p>\n <div className=\"pill\">\n <span className=\"status-dot\" />\n {displayUser.name ?? displayUser.email}\n </div>\n </div>\n\n <nav className=\"nav\">\n <Link href=\"/dashboard\">\n Overview <span>01</span>\n </Link>\n <Link href=\"/billing\">\n Billing <span>02</span>\n </Link>\n <Link href=\"/email\">\n Email <span>03</span>\n </Link>\n <Link href=\"/settings\">\n Settings <span>04</span>\n </Link>\n <Link href=\"/\">\n Home <span>05</span>\n </Link>\n </nav>\n\n <div className=\"sidebar-note\">\n <strong>Starter principle</strong>\n <p>\n Keep the generated app sharp, predictable, and easy to extend with both\n human and agent workflows.\n </p>\n </div>\n\n {session ? (\n <SignOutButton />\n ) : (\n <Link href=\"/sign-in\" className=\"ghost-button\">\n Sign in for the full app\n </Link>\n )}\n </aside>\n\n <section className=\"content\">\n <header className=\"header\">\n <article className=\"hero-panel\">\n <p className=\"eyebrow\">Dashboard starter</p>\n <h2>Ship the first real screen on day zero.</h2>\n <p className=\"lede\">\n This is not a toy admin mockup. It is the first protected surface of a\n modular SaaS app, with auth, billing, email, and database boundaries\n already mapped out.\n </p>\n <div className=\"hero-actions\">\n <Link href=\"/billing\">Open billing</Link>\n <Link href=\"/settings\">Open settings</Link>\n <Link href=\"/email\">Send a test email</Link>\n </div>\n </article>\n\n <article className=\"insight-panel\">\n <p className=\"eyebrow\">Why it matters</p>\n <h3>Clean foundations beat feature theater.</h3>\n <ul className=\"insight-list\">\n <li>\n <strong>Composable modules</strong>\n <span>DB, billing, deploy target, and dashboard shell are resolved intentionally.</span>\n </li>\n <li>\n <strong>AI-first repo shape</strong>\n <span>Thin routes, clear boundaries, and generated manifests keep agent work predictable.</span>\n </li>\n <li>\n <strong>Verified output</strong>\n <span>Smoke profiles exist so the starter stays real, not aspirational.</span>\n </li>\n </ul>\n </article>\n </header>\n\n <section className=\"stats\">\n {stats.map((item) => (\n <article key={item.label} className=\"card\">\n <p>{item.label}</p>\n <strong>{item.value}</strong>\n <span className={`metric-trend ${item.tone}`}>{item.change}</span>\n </article>\n ))}\n </section>\n\n <section className=\"panel-grid\">\n <article className=\"panel\">\n <p className=\"eyebrow\">Recent activity</p>\n <h3>What this starter already gives you</h3>\n <div className=\"activity-list\">\n {activity.map((item) => (\n <div key={item.title} className=\"activity-item\">\n <div className=\"activity-badge\">{item.badge}</div>\n <div>\n <strong>{item.title}</strong>\n <p>{item.description}</p>\n </div>\n <span>{item.stamp}</span>\n </div>\n ))}\n </div>\n </article>\n\n <aside className=\"mini-grid\">\n <article className=\"mini-card\">\n <p className=\"eyebrow\">Auth</p>\n <strong>Ready when you need real accounts</strong>\n <p>Auth exists, but the demo dashboard no longer blocks first-run product exploration.</p>\n </article>\n <article className=\"mini-card\">\n <p className=\"eyebrow\">Deploy</p>\n <strong>Vercel or Docker</strong>\n <p>The generator keeps deploy target selection explicit instead of burying it in docs.</p>\n </article>\n <article className=\"mini-card\">\n <p className=\"eyebrow\">Billing</p>\n <strong>Provider abstraction first</strong>\n <p>Stripe and Polar stay behind one app-facing contract from the beginning.</p>\n </article>\n </aside>\n </section>\n\n <section className=\"pipeline-panel\">\n <div className=\"pipeline-header\">\n <div>\n <p className=\"eyebrow\">Growth pipeline</p>\n <h3>Demo data that feels like a product, not a lorem ipsum card set.</h3>\n </div>\n <span className=\"pill\">\n <span className=\"status-dot\" />\n Demo mode\n </span>\n </div>\n <div className=\"pipeline-grid\">\n {pipeline.map((item) => (\n <article key={item.label} className=\"pipeline-card\">\n <p>{item.label}</p>\n <strong>{item.value}</strong>\n <span>{item.detail}</span>\n </article>\n ))}\n </div>\n </section>\n </section>\n </main>\n )",
58
+ "__HOME_E2E_TEST_NAME__": "home page renders skit landing",
59
+ "__HOME_E2E_HEADING__": "build your saas",
60
+ "__HOME_E2E_LINK__": "explore the live demo",
61
+ "__AUTH_LLMS_EXTRA__": "",
62
+ "__BILLING_LLMS_LINE__": "Stripe / Polar billing (provider abstraction)",
63
+ "__EMAIL_LLMS_LINE__": "Resend transactional email"
64
+ },
65
+ "overrideFiles": [],
66
+ "modules": ["quality-baseline", "testing-baseline", "auth-core", "dashboard-shell"]
67
+ }
@@ -0,0 +1,17 @@
1
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
2
+ BETTER_AUTH_URL=http://localhost:3000
3
+ DATABASE_URL=postgresql://postgres:postgres@localhost:5432/__PROJECT_NAME__
4
+ BETTER_AUTH_SECRET=replace-me
5
+ __AUTH_PROVIDER_ENV_EXAMPLE__
6
+ RESEND_API_KEY=re_xxx
7
+ EMAIL_FROM=Panda Starter <onboarding@example.com>
8
+ STRIPE_SECRET_KEY=sk_test_xxx
9
+ STRIPE_PRICE_ID=price_xxx
10
+ STRIPE_WEBHOOK_SECRET=whsec_xxx
11
+ POLAR_ACCESS_TOKEN=polar_pat_xxx
12
+ POLAR_ORGANIZATION_ID=org_xxx
13
+ POLAR_PRODUCT_ID=prod_xxx
14
+ POLAR_SERVER=sandbox
15
+ POLAR_WEBHOOK_SECRET=polar_whsec_xxx
16
+ BILLING_PROVIDER=__BILLING_PROVIDER__
17
+ EMAIL_PROVIDER=__EMAIL_PROVIDER__
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+
8
+ jobs:
9
+ quality:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Setup Node
16
+ uses: actions/setup-node@v4
17
+ with:
18
+ node-version: 22
19
+ cache: __CI_CACHE__
20
+
21
+ - name: Install
22
+ run: __CI_INSTALL_COMMAND__
23
+
24
+ - name: Lint
25
+ run: __CI_RUN_LINT__
26
+
27
+ - name: Typecheck
28
+ run: __CI_RUN_TYPECHECK__
29
+
30
+ - name: Unit tests
31
+ run: __CI_RUN_TEST__
32
+
33
+ - name: Build
34
+ run: __CI_RUN_BUILD__
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+
3
+ npm run lint-staged && npm run typecheck
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+
3
+ npm run test
@@ -0,0 +1,3 @@
1
+ .next
2
+ coverage
3
+ node_modules
@@ -0,0 +1,42 @@
1
+ # __PROJECT_NAME__
2
+
3
+ Generated with Skit using the `__TEMPLATE_NAME__` template.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ __INSTALL_COMMAND__
9
+ __RUN_DEV_COMMAND__
10
+ ```
11
+
12
+ Generated settings:
13
+
14
+ - package manager: `__PACKAGE_MANAGER_NAME__`
15
+ - database driver: `__DATABASE_DRIVER__`
16
+ - billing provider: `__BILLING_PROVIDER__`
17
+ - email provider: `__EMAIL_PROVIDER__`
18
+ - deploy target: `__DEPLOY_TARGET__`
19
+ - demo seed data: `__SEED_DEMO_DATA__`
20
+
21
+ ## Current State
22
+
23
+ This is the __README_STATE_COPY__.
24
+
25
+ Included:
26
+
27
+ - Next.js 16 app shell
28
+ - strict TypeScript baseline
29
+ - __README_HIGHLIGHT_BULLET__
30
+ - flat ESLint config with strict rules
31
+ - Prettier config
32
+ - validated env entrypoint with Zod
33
+ - Drizzle ORM baseline with PostgreSQL via `__DATABASE_DRIVER__`
34
+ - migration and seed scripts
35
+ - Better Auth baseline with email/password sign-in and sign-up
36
+ - __README_PROTECTED_ROUTES_BULLET__
37
+ - billing provider abstraction with `__BILLING_PROVIDER__` as the configured default
38
+ - billing page and webhook route skeletons
39
+ - `__EMAIL_PROVIDER__` email service layer and email template placeholders
40
+ - protected `/email` page for test sends
41
+ - Vitest and Playwright baseline with example tests
42
+ - GitHub Actions CI workflow for lint, typecheck, test, and build
@@ -0,0 +1,16 @@
1
+ import { defineConfig } from "drizzle-kit";
2
+
3
+ if (!process.env.DATABASE_URL) {
4
+ throw new Error("DATABASE_URL is required to use Drizzle.");
5
+ }
6
+
7
+ export default defineConfig({
8
+ schema: "./src/db/schema/index.ts",
9
+ out: "./src/db/migrations",
10
+ dialect: "postgresql",
11
+ dbCredentials: {
12
+ url: process.env.DATABASE_URL
13
+ },
14
+ verbose: true,
15
+ strict: true
16
+ });