@usequark/quark-create-app 1.23.11

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 (237) hide show
  1. package/README.md +210 -0
  2. package/package.json +56 -0
  3. package/src/dependabot-config.test.js +128 -0
  4. package/src/deploy/adapters/iac.js +203 -0
  5. package/src/deploy/adapters/index.js +27 -0
  6. package/src/deploy/adapters/railway.js +508 -0
  7. package/src/deploy/adapters/railway.test.js +318 -0
  8. package/src/deploy/contract.js +59 -0
  9. package/src/deploy/deploy.integration.test.js +183 -0
  10. package/src/deploy/deploy.js +430 -0
  11. package/src/deploy/deploy.test.js +105 -0
  12. package/src/deploy/discovery.js +115 -0
  13. package/src/deploy/discovery.test.js +141 -0
  14. package/src/deploy/index.js +38 -0
  15. package/src/deploy/inspect.js +130 -0
  16. package/src/index.js +2920 -0
  17. package/src/mobile-template.test.js +232 -0
  18. package/src/prepare-hooks.test.js +535 -0
  19. package/src/scaffold-guards.test.js +140 -0
  20. package/src/scaffold-output.test.js +228 -0
  21. package/src/template-scripts.test.js +160 -0
  22. package/src/utils.js +77 -0
  23. package/src/utils.test.js +95 -0
  24. package/src/worker-dockerfile.test.js +85 -0
  25. package/templates/base-project/.cursor/rules/quark.mdc +172 -0
  26. package/templates/base-project/.dockerignore +14 -0
  27. package/templates/base-project/.env.railway.example +87 -0
  28. package/templates/base-project/.github/copilot-instructions.md +65 -0
  29. package/templates/base-project/.github/dependabot.yml +31 -0
  30. package/templates/base-project/.github/skills/project-context/SKILL.md +109 -0
  31. package/templates/base-project/.github/workflows/ci.yml +116 -0
  32. package/templates/base-project/.github/workflows/dependabot-auto-merge.yml +22 -0
  33. package/templates/base-project/.github/workflows/install-windows.yml +27 -0
  34. package/templates/base-project/.github/workflows/release.yml +67 -0
  35. package/templates/base-project/.railway/railway.ts +40 -0
  36. package/templates/base-project/CLAUDE.md +163 -0
  37. package/templates/base-project/MAIN.md +21 -0
  38. package/templates/base-project/README.md +164 -0
  39. package/templates/base-project/apps/web/.env.example +99 -0
  40. package/templates/base-project/apps/web/Dockerfile +38 -0
  41. package/templates/base-project/apps/web/biome.json +8 -0
  42. package/templates/base-project/apps/web/jsconfig.json +9 -0
  43. package/templates/base-project/apps/web/next.config.js +154 -0
  44. package/templates/base-project/apps/web/package.json +42 -0
  45. package/templates/base-project/apps/web/postcss.config.mjs +7 -0
  46. package/templates/base-project/apps/web/public/.well-known/security.txt +3 -0
  47. package/templates/base-project/apps/web/public/quark.svg +47 -0
  48. package/templates/base-project/apps/web/scripts/prepare-standalone.mjs +71 -0
  49. package/templates/base-project/apps/web/src/app/_components/AsciiPanel.js +103 -0
  50. package/templates/base-project/apps/web/src/app/_components/HealthIndicator.js +85 -0
  51. package/templates/base-project/apps/web/src/app/_components/HomeThemeToggle.js +63 -0
  52. package/templates/base-project/apps/web/src/app/_components/QuarkAnimation.js +168 -0
  53. package/templates/base-project/apps/web/src/app/_components/SyncedPanels.js +212 -0
  54. package/templates/base-project/apps/web/src/app/_components/UmamiReplayRecorder.js +198 -0
  55. package/templates/base-project/apps/web/src/app/_components/UmamiWebVitals.js +39 -0
  56. package/templates/base-project/apps/web/src/app/api/auth/[...nextauth]/route.js +7 -0
  57. package/templates/base-project/apps/web/src/app/api/auth/apple/route.js +82 -0
  58. package/templates/base-project/apps/web/src/app/api/auth/google/route.js +59 -0
  59. package/templates/base-project/apps/web/src/app/api/auth/refresh/route.js +48 -0
  60. package/templates/base-project/apps/web/src/app/api/auth/register/route.js +63 -0
  61. package/templates/base-project/apps/web/src/app/api/auth/token/route.js +44 -0
  62. package/templates/base-project/apps/web/src/app/api/csrf/route.js +40 -0
  63. package/templates/base-project/apps/web/src/app/api/device/register/route.js +57 -0
  64. package/templates/base-project/apps/web/src/app/api/error-handler.js +23 -0
  65. package/templates/base-project/apps/web/src/app/api/files/[id]/route.js +89 -0
  66. package/templates/base-project/apps/web/src/app/api/files/route.js +120 -0
  67. package/templates/base-project/apps/web/src/app/api/health/route.js +160 -0
  68. package/templates/base-project/apps/web/src/app/api/users/[id]/route.js +54 -0
  69. package/templates/base-project/apps/web/src/app/api/users/me/route.js +67 -0
  70. package/templates/base-project/apps/web/src/app/api/users/route.js +45 -0
  71. package/templates/base-project/apps/web/src/app/auth/error/page.js +83 -0
  72. package/templates/base-project/apps/web/src/app/auth/forgot-password/page.js +58 -0
  73. package/templates/base-project/apps/web/src/app/auth/provider-loading.js +25 -0
  74. package/templates/base-project/apps/web/src/app/auth/register/RegisterPageClient.js +340 -0
  75. package/templates/base-project/apps/web/src/app/auth/register/page.js +17 -0
  76. package/templates/base-project/apps/web/src/app/auth/signin/SignInPageClient.js +230 -0
  77. package/templates/base-project/apps/web/src/app/auth/signin/page.js +10 -0
  78. package/templates/base-project/apps/web/src/app/favicon.ico +0 -0
  79. package/templates/base-project/apps/web/src/app/global-error.js +58 -0
  80. package/templates/base-project/apps/web/src/app/globals.css +1166 -0
  81. package/templates/base-project/apps/web/src/app/icon.svg +47 -0
  82. package/templates/base-project/apps/web/src/app/layout.js +57 -0
  83. package/templates/base-project/apps/web/src/app/manifest.js +12 -0
  84. package/templates/base-project/apps/web/src/app/not-found.js +39 -0
  85. package/templates/base-project/apps/web/src/app/page.js +262 -0
  86. package/templates/base-project/apps/web/src/app/robots.js +23 -0
  87. package/templates/base-project/apps/web/src/app/sitemap.js +14 -0
  88. package/templates/base-project/apps/web/src/lib/analytics/umami-before-send.js +29 -0
  89. package/templates/base-project/apps/web/src/lib/analytics/umami-config.js +95 -0
  90. package/templates/base-project/apps/web/src/lib/analytics/umami-csp.js +24 -0
  91. package/templates/base-project/apps/web/src/lib/analytics/umami-marketing.js +131 -0
  92. package/templates/base-project/apps/web/src/lib/analytics/umami-replay.js +204 -0
  93. package/templates/base-project/apps/web/src/lib/analytics/umami-web-vitals.js +237 -0
  94. package/templates/base-project/apps/web/src/lib/analytics/umami.js +57 -0
  95. package/templates/base-project/apps/web/src/lib/auth-middleware.js +82 -0
  96. package/templates/base-project/apps/web/src/lib/auth-signup.js +5 -0
  97. package/templates/base-project/apps/web/src/lib/auth.js +191 -0
  98. package/templates/base-project/apps/web/src/lib/csrf-cookie.js +11 -0
  99. package/templates/base-project/apps/web/src/lib/jwt.js +84 -0
  100. package/templates/base-project/apps/web/src/lib/load-crm-config.js +35 -0
  101. package/templates/base-project/apps/web/src/lib/normalize-auth-request.js +33 -0
  102. package/templates/base-project/apps/web/src/lib/proxy-auth.js +80 -0
  103. package/templates/base-project/apps/web/src/lib/seo/indexing.js +25 -0
  104. package/templates/base-project/apps/web/src/lib/seo/site-metadata.js +74 -0
  105. package/templates/base-project/apps/web/src/lib/sitemap-entries.js +22 -0
  106. package/templates/base-project/apps/web/src/preflight.js +55 -0
  107. package/templates/base-project/apps/web/src/proxy.js +328 -0
  108. package/templates/base-project/biome.json +52 -0
  109. package/templates/base-project/docker-compose.override.yml +17 -0
  110. package/templates/base-project/docker-compose.yml +37 -0
  111. package/templates/base-project/docs/FIRST_FEATURE.md +74 -0
  112. package/templates/base-project/docs/START_HERE.md +70 -0
  113. package/templates/base-project/docs/adr/README.md +42 -0
  114. package/templates/base-project/package.json +58 -0
  115. package/templates/base-project/packages/db/package.json +38 -0
  116. package/templates/base-project/packages/db/prisma/migrations/20260202061128_initial/migration.sql +202 -0
  117. package/templates/base-project/packages/db/prisma/migrations/migration_lock.toml +3 -0
  118. package/templates/base-project/packages/db/prisma/schema.prisma +161 -0
  119. package/templates/base-project/packages/db/prisma/seed.js +152 -0
  120. package/templates/base-project/packages/db/prisma.config.js +27 -0
  121. package/templates/base-project/packages/db/src/client.js +75 -0
  122. package/templates/base-project/packages/db/src/connection.js +44 -0
  123. package/templates/base-project/packages/db/src/context.js +275 -0
  124. package/templates/base-project/packages/db/src/index.js +5 -0
  125. package/templates/base-project/packages/db/src/ping.js +66 -0
  126. package/templates/base-project/packages/db/src/queries.js +292 -0
  127. package/templates/base-project/packages/db/src/schemas.js +30 -0
  128. package/templates/base-project/packages/db/src/umami.js +299 -0
  129. package/templates/base-project/pnpm-workspace.yaml +20 -0
  130. package/templates/base-project/scripts/check-loading.mjs +49 -0
  131. package/templates/base-project/scripts/check-standards.mjs +186 -0
  132. package/templates/base-project/scripts/clean-workspace.mjs +479 -0
  133. package/templates/base-project/scripts/dev-preflight.mjs +48 -0
  134. package/templates/base-project/scripts/doctor.js +408 -0
  135. package/templates/base-project/scripts/prepare.js +490 -0
  136. package/templates/base-project/scripts/run-tests.mjs +71 -0
  137. package/templates/base-project/skills/add-dashboard/SKILL.md +28 -0
  138. package/templates/base-project/skills/add-endpoint/SKILL.md +29 -0
  139. package/templates/base-project/skills/add-model/SKILL.md +28 -0
  140. package/templates/base-project/skills/ecommerce/SKILL.md +224 -0
  141. package/templates/base-project/skills/ecommerce-cart/SKILL.md +193 -0
  142. package/templates/base-project/skills/ecommerce-catalog/SKILL.md +179 -0
  143. package/templates/base-project/skills/ecommerce-checkout/SKILL.md +195 -0
  144. package/templates/base-project/skills/i18n/SKILL.md +211 -0
  145. package/templates/base-project/skills/payment/SKILL.md +280 -0
  146. package/templates/base-project/skills/quark-skills/SKILL.md +37 -0
  147. package/templates/base-project/turbo.json +143 -0
  148. package/templates/config/package.json +20 -0
  149. package/templates/config/src/app-url.js +134 -0
  150. package/templates/config/src/environment.js +284 -0
  151. package/templates/config/src/index.js +16 -0
  152. package/templates/config/src/load-config.js +157 -0
  153. package/templates/config/src/rate-limit.js +136 -0
  154. package/templates/config/src/redis.js +43 -0
  155. package/templates/config/src/validate-env.js +532 -0
  156. package/templates/jobs/README.md +52 -0
  157. package/templates/jobs/package.json +9 -0
  158. package/templates/jobs/src/definitions.js +13 -0
  159. package/templates/jobs/src/index.js +1 -0
  160. package/templates/mobile/.env.example +16 -0
  161. package/templates/mobile/CHECKLIST.md +40 -0
  162. package/templates/mobile/README.md +130 -0
  163. package/templates/mobile/app/(app)/_layout.tsx +83 -0
  164. package/templates/mobile/app/(app)/index.tsx +147 -0
  165. package/templates/mobile/app/(app)/profile.tsx +204 -0
  166. package/templates/mobile/app/(app)/settings.tsx +80 -0
  167. package/templates/mobile/app/(auth)/_layout.tsx +10 -0
  168. package/templates/mobile/app/(auth)/sign-in.tsx +140 -0
  169. package/templates/mobile/app/(auth)/sign-up.tsx +178 -0
  170. package/templates/mobile/app/+not-found.tsx +32 -0
  171. package/templates/mobile/app/_layout.tsx +18 -0
  172. package/templates/mobile/app.json +47 -0
  173. package/templates/mobile/assets/adaptive-icon.png +0 -0
  174. package/templates/mobile/assets/icon.png +0 -0
  175. package/templates/mobile/assets/notification-icon.png +0 -0
  176. package/templates/mobile/assets/splash.png +0 -0
  177. package/templates/mobile/biome.json +27 -0
  178. package/templates/mobile/components/AuthGate.tsx +19 -0
  179. package/templates/mobile/components/ThemeProvider.tsx +23 -0
  180. package/templates/mobile/eas.json +29 -0
  181. package/templates/mobile/hooks/use-auth.ts +127 -0
  182. package/templates/mobile/lib/api-client.ts +138 -0
  183. package/templates/mobile/lib/api.ts +83 -0
  184. package/templates/mobile/lib/auth-providers-google.ts +74 -0
  185. package/templates/mobile/lib/auth-providers.ts +74 -0
  186. package/templates/mobile/lib/auth.ts +100 -0
  187. package/templates/mobile/lib/config.ts +14 -0
  188. package/templates/mobile/lib/errors.ts +46 -0
  189. package/templates/mobile/lib/notifications.ts +77 -0
  190. package/templates/mobile/lib/storage.ts +25 -0
  191. package/templates/mobile/lib/theme-tokens.ts +16 -0
  192. package/templates/mobile/package.json +37 -0
  193. package/templates/mobile/tsconfig.json +10 -0
  194. package/templates/pwa/app/_components/PWARegister.js +15 -0
  195. package/templates/pwa/app/manifest.js +32 -0
  196. package/templates/pwa/public/sw.js +72 -0
  197. package/templates/ui/README.md +44 -0
  198. package/templates/ui/package.json +21 -0
  199. package/templates/ui/src/badge.js +23 -0
  200. package/templates/ui/src/button.js +111 -0
  201. package/templates/ui/src/card.js +128 -0
  202. package/templates/ui/src/checkbox.js +20 -0
  203. package/templates/ui/src/container.js +13 -0
  204. package/templates/ui/src/dialog.js +137 -0
  205. package/templates/ui/src/error-banner.js +15 -0
  206. package/templates/ui/src/footer.js +239 -0
  207. package/templates/ui/src/form-field.integration-test.js +142 -0
  208. package/templates/ui/src/form-field.js +50 -0
  209. package/templates/ui/src/index.js +24 -0
  210. package/templates/ui/src/input.js +11 -0
  211. package/templates/ui/src/label.js +14 -0
  212. package/templates/ui/src/lightbox.integration-test.js +167 -0
  213. package/templates/ui/src/lightbox.js +243 -0
  214. package/templates/ui/src/logo.js +52 -0
  215. package/templates/ui/src/navbar.js +602 -0
  216. package/templates/ui/src/password-input.js +31 -0
  217. package/templates/ui/src/rich-text.js +514 -0
  218. package/templates/ui/src/select.js +317 -0
  219. package/templates/ui/src/skeleton.js +10 -0
  220. package/templates/ui/src/spinner.js +31 -0
  221. package/templates/ui/src/table.js +169 -0
  222. package/templates/ui/src/textarea.js +11 -0
  223. package/templates/ui/src/theme-constants.js +24 -0
  224. package/templates/ui/src/theme.js +196 -0
  225. package/templates/ui/src/toast.js +206 -0
  226. package/templates/worker/Dockerfile +64 -0
  227. package/templates/worker/README.md +56 -0
  228. package/templates/worker/package.json +36 -0
  229. package/templates/worker/src/config/pricing.js +46 -0
  230. package/templates/worker/src/handlers/email-job-validation.js +36 -0
  231. package/templates/worker/src/handlers/email.js +98 -0
  232. package/templates/worker/src/handlers/files.js +59 -0
  233. package/templates/worker/src/handlers/index.js +20 -0
  234. package/templates/worker/src/handlers/push-notification.js +234 -0
  235. package/templates/worker/src/index.js +505 -0
  236. package/templates/worker/src/lib/railway.js +438 -0
  237. package/templates/worker/src/lib/tokens.js +81 -0
@@ -0,0 +1,172 @@
1
+ ---
2
+ description: Quark project conventions for __QUARK_PROJECT_NAME__. Covers all layers: UI, backend, database, auth, jobs, testing, and deployment.
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Quark Project: __QUARK_PROJECT_NAME__
7
+
8
+ Package scope: `@__QUARK_SCOPE__` - use this for ALL workspace packages.
9
+ Scaffolded: __QUARK_SCAFFOLD_DATE__
10
+
11
+ ---
12
+
13
+ ## Non-Negotiable Rules
14
+
15
+ 1. **ESM only.** Always `import`/`export`. Never `require()` or `module.exports`.
16
+ 2. **No authored TypeScript.** Plain `.js` and `.jsx` files only - no repo-authored `.ts`, `.tsx`, or type annotations. Generated code is the only exception.
17
+ 3. **Validate everything at boundaries.** Server Actions and API routes must use Zod. No raw `req.body` access without parsing.
18
+ 4. **Use AppError at runtime boundaries.** Throw `AppError` / `ValidationError` / `NotFoundError` from `@techstream/quark-core/errors` in application/runtime code. Native `Error` is reserved for library, bootstrap, CLI, and test code.
19
+ 5. **Log with createLogger in runtime code.** Use `createLogger(name)` from `@techstream/quark-core` for application/runtime code. Console output is reserved for bootstrap, CLI, and test code.
20
+ 6. **DB models always have timestamps.** Every Prisma model: `createdAt DateTime @default(now())` + `updatedAt DateTime @updatedAt`.
21
+ 7. **Workspace import scope.** Use `@__QUARK_SCOPE__/*` for local packages. Never `@techstream/quark-db`, `@techstream/quark-config`, etc.
22
+ 8. **Co-located tests.** `feature.test.js` lives next to `feature.js`. Tests use `node --test` - no Jest, no Vitest.
23
+
24
+ ---
25
+
26
+ ## Import Reference
27
+
28
+ ```javascript
29
+ // ✅ Workspace packages - always @__QUARK_SCOPE__/*:
30
+ import { prisma, user, post } from "@__QUARK_SCOPE__/db";
31
+ import { loadConfig } from "@__QUARK_SCOPE__/config";
32
+ import { Button, Card, Input } from "@__QUARK_SCOPE__/ui";
33
+ import { JOB_TYPES } from "@__QUARK_SCOPE__/jobs";
34
+
35
+ // ✅ Published runtime - @techstream/quark-core:
36
+ import { AppError, ValidationError, NotFoundError } from "@techstream/quark-core/errors";
37
+ import { createLogger, getCurrentSession } from "@techstream/quark-core";
38
+ import { createQueue, addJob } from "@techstream/quark-core";
39
+ import { metrics, cache, storage } from "@techstream/quark-core";
40
+
41
+ // ❌ Never:
42
+ import { Button } from "@/components/ui/button"; // wrong path convention
43
+ import { prisma } from "@techstream/quark-db"; // wrong scope for workspace pkg
44
+ import something from "@techstream/quark-config"; // wrong scope for workspace pkg
45
+ ```
46
+
47
+ ---
48
+
49
+ ## UI & Design System
50
+
51
+ - Styling: **Tailwind CSS utility classes only**. No inline styles, no CSS modules.
52
+ - Components from `@__QUARK_SCOPE__/ui`. All accept `className` for overrides.
53
+ - Available: `Button`, `Input`, `Label`, `Textarea`, `Select`, `Checkbox`, `Badge`, `Card`/`CardHeader`/`CardTitle`/`CardContent`/`CardFooter`, `Table`/`TableHeader`/`TableBody`/`TableRow`/`TableHead`/`TableCell`, `Skeleton`, `QuarkLogo` *(server)*, `Dialog` *(client)*, `Toast`/`useToast` *(client)*, `ThemeProvider`/`useTheme` *(client)*.
54
+ - Loading states → `<Skeleton>` + `<Suspense>` boundaries.
55
+ - User feedback → `useToast()` (mark component `"use client"`).
56
+ - Modals → `<Dialog>` (mark parent `"use client"`).
57
+ - Default to **Server Components**. Only add `"use client"` when necessary.
58
+
59
+ ---
60
+
61
+ ## Server Action Pattern
62
+
63
+ ```javascript
64
+ "use server";
65
+ import { z } from "zod";
66
+ import { ValidationError, AppError } from "@techstream/quark-core/errors";
67
+ import { getCurrentSession, createLogger } from "@techstream/quark-core";
68
+ import { prisma } from "@__QUARK_SCOPE__/db";
69
+
70
+ const log = createLogger("action:example");
71
+ const schema = z.object({ title: z.string().min(1).max(255) });
72
+
73
+ export async function createExample(formData) {
74
+ const session = await getCurrentSession();
75
+ if (!session) throw new AppError("Unauthorized", 401);
76
+
77
+ const parsed = schema.safeParse(Object.fromEntries(formData));
78
+ if (!parsed.success) throw new ValidationError(parsed.error.flatten());
79
+
80
+ const result = await prisma.example.create({ data: parsed.data });
81
+ log.info("created", { id: result.id });
82
+ return result;
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## API Route Pattern
89
+
90
+ ```javascript
91
+ import { NextResponse } from "next/server";
92
+ import { AppError } from "@techstream/quark-core/errors";
93
+ import { createLogger } from "@techstream/quark-core";
94
+
95
+ const log = createLogger("api:example");
96
+
97
+ export async function GET(request) {
98
+ try {
99
+ return NextResponse.json({ data });
100
+ } catch (error) {
101
+ log.error("request failed", { error });
102
+ if (error instanceof AppError)
103
+ return NextResponse.json({ error: error.message }, { status: error.statusCode });
104
+ return NextResponse.json({ error: "Internal server error" }, { status: 500 });
105
+ }
106
+ }
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Database
112
+
113
+ - Schema: `packages/db/prisma/schema.prisma`
114
+ - Query helpers: `packages/db/src/queries.js` - add functions here, don't call `prisma.*` directly in components or actions.
115
+ - Always run `pnpm db:generate` after schema changes, then `pnpm db:migrate`.
116
+
117
+ ---
118
+
119
+ ## Auth
120
+
121
+ ```javascript
122
+ import { getCurrentSession } from "@techstream/quark-core";
123
+
124
+ const session = await getCurrentSession(); // null if unauthenticated
125
+ if (!session) redirect("/login"); // Server Component
126
+ if (!session) throw new AppError("Unauthorized", 401); // Server Action / API
127
+ if (session.user.role !== "ADMIN") throw new AppError("Forbidden", 403);
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Background Jobs
133
+
134
+ ```javascript
135
+ // Dispatch (from Server Action or API route):
136
+ import { createQueue, addJob } from "@techstream/quark-core";
137
+ import { JOB_TYPES } from "@__QUARK_SCOPE__/jobs";
138
+ const queue = createQueue("default");
139
+ await addJob(queue, JOB_TYPES.MY_JOB, { userId });
140
+
141
+ // Handle (apps/worker/src/handlers/):
142
+ import { createLogger } from "@techstream/quark-core";
143
+ const log = createLogger("job:my-job");
144
+ export async function handleMyJob({ data }) { log.info("processing", data); }
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Testing
150
+
151
+ ```javascript
152
+ import { test } from "node:test";
153
+ import assert from "node:assert";
154
+
155
+ test("feature", async (t) => {
156
+ await t.test("does X", async () => {
157
+ assert.strictEqual(actual, expected);
158
+ });
159
+ });
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Environment
165
+
166
+ New env vars must be registered in `packages/config/src/validate-env.js` before use. Load config via `loadConfig()` from `@__QUARK_SCOPE__/config`.
167
+
168
+ ---
169
+
170
+ ## Deployment
171
+
172
+ Railway: two services (`web` + `worker`). Migrations auto-run on deploy via `preDeploy` in `.railway/railway.ts`. Env vars managed in Railway dashboard - never committed.
@@ -0,0 +1,14 @@
1
+ node_modules
2
+ .git
3
+ .next
4
+ dist
5
+ coverage
6
+ .turbo
7
+ .env
8
+ .env.*
9
+ !.env.example
10
+ *.log
11
+ .DS_Store
12
+ .idea
13
+ .vscode
14
+ docs
@@ -0,0 +1,87 @@
1
+ # Default Railway runtime variables for __QUARK_PROJECT_NAME__.
2
+ # Copy these values into Railway shared/service variables as a starting point.
3
+ # Railway does not read docker-compose.yml or the local .env example.
4
+ # Add managed PostgreSQL and Redis services in Railway first, then wire the
5
+ # placeholders below with Railway service references or pasted connection
6
+ # strings before the first deploy.
7
+ # Railway injects PORT automatically, so do not set it manually here.
8
+
9
+ # --- Core runtime ---
10
+ NODE_ENV=production
11
+ # Forces the standalone Next.js server to bind on Railway's network interface.
12
+ HOSTNAME=0.0.0.0
13
+ APP_NAME=__QUARK_PROJECT_NAME__
14
+ APP_DESCRIPTION=Update this before production deployment.
15
+ # APP_URL must be an absolute public URL with https://
16
+ APP_URL=https://__QUARK_PROJECT_NAME__.railway.app
17
+ ALLOW_INDEXING=false
18
+ AUTH_ALLOW_SIGNUP=false
19
+
20
+ # --- Auth ---
21
+ # Generate with: openssl rand -base64 32
22
+ # AUTH_SECRET is an alternative name; the deploy CLI auto-sets both.
23
+ # Must be at least 32 characters or startup validation fails.
24
+ NEXTAUTH_SECRET=CHANGE_ME_TO_A_32_CHARACTERS_OR_LONGER_SECRET
25
+
26
+ # APP_URL is the canonical public URL. NEXTAUTH_URL is derived automatically.
27
+ # Uncomment only if you need to override it explicitly.
28
+ # NEXTAUTH_URL=https://__QUARK_PROJECT_NAME__.railway.app
29
+
30
+ # --- Managed infrastructure ---
31
+ # `quark deploy railway` automatically sets DATABASE_URL and REDIS_URL using
32
+ # Railway service references (${{Postgres.DATABASE_URL}}, ${{Redis.REDIS_URL}}).
33
+ # You only need to set these manually if you are not using the CLI deploy flow.
34
+ # DATABASE_URL=postgresql://user:pass@host:5432/db
35
+ # REDIS_URL=redis://user:pass@host:6379
36
+
37
+ # --- Worker ---
38
+ WORKER_CONCURRENCY=5
39
+
40
+ # --- Optional remote seed defaults ---
41
+ # Used only when you intentionally run `pnpm db:seed` against Railway.
42
+ # Remove these after the first seed if you do not want bootstrap admin
43
+ # credentials stored in Railway long term.
44
+ SEED_PROFILE=minimal
45
+ ADMIN_EMAIL=admin@example.com
46
+ ADMIN_PASSWORD=CHANGE_ME_TO_STRONG_ADMIN_PASSWORD
47
+ # ADMIN_NAME=Admin
48
+
49
+ # --- Storage ---
50
+ # Local storage is ephemeral on Railway. Keep this only if uploaded files do not
51
+ # need to survive redeploys or reschedules. For durable uploads, switch to s3.
52
+ STORAGE_PROVIDER=local
53
+ # STORAGE_PROVIDER=s3
54
+ # S3_BUCKET=your-bucket-name
55
+ # S3_REGION=auto
56
+ # S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
57
+ # S3_ACCESS_KEY_ID=your-access-key
58
+ # S3_SECRET_ACCESS_KEY=your-secret-key
59
+ # S3_PUBLIC_URL=https://your-public-bucket-domain.com
60
+
61
+ # --- Email ---
62
+ # Configure a real provider before enabling email in Railway.
63
+ # EMAIL_PROVIDER=smtp
64
+ # EMAIL_FROM=__QUARK_PROJECT_NAME__ <noreply@yourdomain.com>
65
+ # SMTP_HOST=smtp.example.com
66
+ # SMTP_PORT=587
67
+ # SMTP_SECURE=true
68
+ # SMTP_USER=your_smtp_user
69
+ # SMTP_PASSWORD=your_smtp_password
70
+ # RESEND_API_KEY=re_xxxxxxxxxxxxx
71
+ # ZEPTOMAIL_TOKEN=Zoho-enczapikey your_zeptomail_api_key
72
+ # ZEPTOMAIL_URL=https://api.zeptomail.com
73
+ # ZEPTOMAIL_BOUNCE_EMAIL=bounce@yourdomain.com
74
+
75
+ # --- Optional analytics ---
76
+ # NEXT_PUBLIC_UMAMI_URL=https://umami.example.com
77
+ # NEXT_PUBLIC_UMAMI_WEBSITE_ID=00000000-0000-0000-0000-000000000000
78
+ # NEXT_PUBLIC_UMAMI_REPLAY_ENABLED=false
79
+
80
+ # --- Optional tuning ---
81
+ # LOG_LEVEL=info
82
+ # CACHE_TTL=600
83
+ # RATE_LIMIT_MAX=100
84
+ # RATE_LIMIT_WINDOW_MS=900000
85
+ # API_BODY_SIZE_LIMIT=2097152
86
+ # UPLOAD_SIZE_LIMIT=10485760
87
+ # ASSET_CDN_URL=https://cdn.yourdomain.com
@@ -0,0 +1,65 @@
1
+ <skills>
2
+ <skill>
3
+ <name>project-context</name>
4
+ <description>Project-specific context and conventions. This skill evolves with your project - update it as your architecture grows.</description>
5
+ <file>.github/skills/project-context/SKILL.md</file>
6
+ </skill>
7
+ </skills>
8
+
9
+ # __QUARK_PROJECT_NAME__ - Project Conventions
10
+
11
+ > Scaffolded with Quark on __QUARK_SCAFFOLD_DATE__. Package scope: `@__QUARK_SCOPE__`
12
+ > Also see `CLAUDE.md` at the project root for the full context reference.
13
+
14
+ ## Non-Negotiable Rules
15
+
16
+ - **ESM only** - `import`/`export` everywhere. Never `require()`.
17
+ - **No authored TypeScript** - `.js` and `.jsx` only. Generated code may emit typed artifacts, but project code should not add `.ts` or `.tsx` sources.
18
+ - **Validate at every boundary** - Zod schemas on all Server Actions and API routes.
19
+ - **Errors** - `AppError` / `ValidationError` from `@techstream/quark-core/errors` in app/runtime code. Native `Error` is acceptable in library, bootstrap, CLI, and test code.
20
+ - **Logging** - `createLogger(name)` from `@techstream/quark-core` in app/runtime code. Console output is acceptable in bootstrap, CLI, and test code.
21
+ - **DB models** - Always add `createdAt` and `updatedAt` to every Prisma model.
22
+ - **Workspace imports** - Use `@__QUARK_SCOPE__/*` for local packages (`db`, `config`, `ui`, `jobs`). Never `@techstream/quark-db` etc.
23
+ - **Tests** - Co-located `*.test.js`, run with `node --test`.
24
+
25
+ ## Import Patterns
26
+
27
+ ```javascript
28
+ // Workspace packages:
29
+ import { prisma, user } from "@__QUARK_SCOPE__/db";
30
+ import { loadConfig } from "@__QUARK_SCOPE__/config";
31
+ import { Button, Card, Input } from "@__QUARK_SCOPE__/ui";
32
+ import { JOB_TYPES } from "@__QUARK_SCOPE__/jobs";
33
+
34
+ // Published runtime:
35
+ import { AppError, ValidationError } from "@techstream/quark-core/errors";
36
+ import { createLogger, getCurrentSession, createQueue, addJob } from "@techstream/quark-core";
37
+ ```
38
+
39
+ ## UI & Design System
40
+
41
+ Components from `@__QUARK_SCOPE__/ui` - Tailwind-only, Server Component safe:
42
+ `Button`, `Input`, `Label`, `Textarea`, `Select`, `Checkbox`, `Badge`,
43
+ `Card`/`CardHeader`/`CardTitle`/`CardContent`/`CardFooter`,
44
+ `Table`/`TableHeader`/`TableBody`/`TableRow`/`TableHead`/`TableCell`,
45
+ `Skeleton`, `ErrorBanner`, `Footer`, `Navbar`/`MobileNavbar`, `RichText`,
46
+ `QuarkLogo` *(server)*, `Dialog` *(client)*, `Toast`/`useToast` *(client)*,
47
+ `ThemeProvider`/`useTheme` *(client)* - dark/light mode context.
48
+
49
+ All accept `className`. Never import from `@/components/ui/*`.
50
+ Inspect `apps/web/src/app/page.js` and `packages/ui/README.md` before creating bespoke public-page layout primitives.
51
+
52
+ ## Standard Patterns
53
+
54
+ ```javascript
55
+ // Server Action:
56
+ "use server";
57
+ const parsed = schema.safeParse(Object.fromEntries(formData));
58
+ if (!parsed.success) throw new ValidationError(parsed.error.flatten());
59
+ const session = await getCurrentSession();
60
+ if (!session) throw new AppError("Unauthorized", 401);
61
+
62
+ // New env var: register in packages/config/src/validate-env.js first.
63
+ // New DB model: schema.prisma → pnpm db:generate → pnpm db:migrate.
64
+ // New job: define type in packages/jobs/src/index.js, handler in apps/worker/src/handlers/.
65
+ ```
@@ -0,0 +1,31 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: npm
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+
8
+ # Split by semver update type. A single "production" group bundles patch,
9
+ # minor and major bumps into one PR, so a breaking change hides behind a
10
+ # wall of safe patches and gets rubber-stamped. Majors get their own PR.
11
+ groups:
12
+ production-majors:
13
+ dependency-type: production
14
+ update-types: ["major"]
15
+ development-majors:
16
+ dependency-type: development
17
+ update-types: ["major"]
18
+ production-minor:
19
+ dependency-type: production
20
+ update-types: ["minor"]
21
+ production-patch:
22
+ dependency-type: production
23
+ update-types: ["patch"]
24
+ development-minor:
25
+ dependency-type: development
26
+ update-types: ["minor"]
27
+ development-patch:
28
+ dependency-type: development
29
+ update-types: ["patch"]
30
+
31
+ open-pull-requests-limit: 10
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: project-context
3
+ description: Project-specific context and conventions. This skill evolves with your project - update it as your architecture grows.
4
+ ---
5
+
6
+ # Project Context
7
+
8
+ ## Overview
9
+
10
+ This is a Quark-based full-stack JavaScript application.
11
+
12
+ | Property | Value |
13
+ |---|---|
14
+ | **Scope** | `@__QUARK_SCOPE__` |
15
+ | **Framework** | Quark (scaffolded from `@techstream/quark-create-app`) |
16
+ | **Scaffolded** | __QUARK_SCAFFOLD_DATE__ |
17
+
18
+ ## Project Structure
19
+
20
+ ```
21
+ __QUARK_PROJECT_NAME__/
22
+ ├── apps/
23
+ │ ├── web/ # Next.js (App Router, Server Actions)
24
+ __QUARK_OPTIONAL_APPS__├── packages/
25
+ │ ├── db/ # Prisma schema, client, queries
26
+ │ ├── config/ # Environment validation & shared config
27
+ __QUARK_OPTIONAL_PACKAGES__├── docker-compose.yml
28
+ ├── .env # Local environment (git-ignored)
29
+ └── .env.example # Template for environment variables
30
+ ```
31
+
32
+ ## Tech Stack
33
+
34
+ | Layer | Technology |
35
+ |---|---|
36
+ | Runtime | Node.js 22, ES Modules |
37
+ | Package manager | pnpm (workspaces) |
38
+ | Monorepo | Turborepo |
39
+ | Web | Next.js 16 (App Router) |
40
+ | Database | PostgreSQL 16 + Prisma 7 |
41
+ | Queue | BullMQ + Redis 7 |
42
+ | Auth | NextAuth v5 |
43
+ | Validation | Zod 4 |
44
+ | UI | Tailwind CSS + `@__QUARK_SCOPE__/ui` components |
45
+ | Email | Nodemailer |
46
+ | Linting | Biome |
47
+ | Testing | Node.js built-in test runner |
48
+
49
+ ## Coding Conventions
50
+
51
+ - **ESM only** - use `import`/`export`, never `require`.
52
+ - **No authored TypeScript** - plain `.js` and `.jsx` files. Generated code may emit typed artifacts, but project code should not add `.ts` or `.tsx` sources.
53
+ - **Imports:** Use `@techstream/quark-core` for published utilities. Use `@__QUARK_SCOPE__/*` for local packages (db, config, ui, jobs).
54
+ - **Tests:** Co-located `*.test.js` files, run with `node --test`.
55
+ - **Validation:** Zod schemas for all Server Actions and API routes.
56
+ - **Errors:** Use `AppError` / `ValidationError` from `@techstream/quark-core/errors` in app/runtime code. Native `Error` is acceptable in library, bootstrap, CLI, and test code.
57
+ - **Logging:** Use `createLogger(name)` from `@techstream/quark-core` in app/runtime code. Console output is acceptable in bootstrap, CLI, and test code.
58
+ - **Database models:** Always include `createdAt`/`updatedAt`.
59
+ - **Environment:** All env vars validated in `packages/config/src/validate-env.js`.
60
+ - **Analytics:** Optional Umami support lives in `apps/web/src/lib/analytics/*`. The public env contract uses only `NEXT_PUBLIC_UMAMI_URL`, `NEXT_PUBLIC_UMAMI_WEBSITE_ID`, and `NEXT_PUBLIC_UMAMI_REPLAY_ENABLED`; replay uses a local rrweb recorder, and dormant helpers exist for dashboard-generated Umami Links, Pixels, and marketing-email snippets.
61
+
62
+ ## Common Commands
63
+
64
+ ```bash
65
+ pnpm dev # Start all apps in dev mode
66
+ pnpm build # Build everything
67
+ pnpm test # Run all tests
68
+ pnpm lint # Lint with Biome
69
+ pnpm db:generate # Regenerate Prisma client
70
+ pnpm db:push # Push schema changes
71
+ pnpm db:migrate # Run database migrations
72
+ docker compose up -d # Start infrastructure
73
+ ```
74
+
75
+ ## Key Files to Know
76
+
77
+ - `packages/db/prisma/schema.prisma` - Database schema (edit this to add models)
78
+ - `packages/db/src/queries.js` - Database query functions
79
+ - `packages/config/src/validate-env.js` - Environment variable validation
80
+ - `apps/web/src/app/` - Next.js App Router pages and API routes
81
+ - `apps/web/src/lib/auth.js` - Authentication configuration
82
+ - `apps/web/src/lib/seo/site-metadata.js` - `getSiteMetadata()` (root layout) and `getPageMetadata()` for per-page titles; see the `seo` skill for the page-title convention
83
+ - `apps/web/src/lib/analytics/umami-config.js` - Optional Umami URL and replay gating
84
+ - `apps/worker/src/handlers/` - Background job handlers
85
+
86
+ ## Updating Quark Core
87
+
88
+ ```bash
89
+ npx @techstream/quark-create-app update # Update core infrastructure
90
+ pnpm update @techstream/quark-core # Or update directly
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Maintaining This Skill
96
+
97
+ > **Important:** When you make changes that affect this project's architecture,
98
+ > conventions, or structure - such as adding new packages, models, API patterns,
99
+ > environment variables, deployment targets, or team conventions - **update this
100
+ > skill file** to reflect those changes. This ensures future AI interactions
101
+ > always have accurate, up-to-date context.
102
+ >
103
+ > Examples of when to update this file:
104
+ > - Adding a new Prisma model or database table
105
+ > - Introducing a new API route pattern or middleware
106
+ > - Adding or removing a workspace package
107
+ > - Changing deployment infrastructure or CI/CD steps
108
+ > - Establishing new coding conventions or architectural decisions
109
+ > - Adding third-party integrations or services
@@ -0,0 +1,116 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths-ignore:
7
+ - "**/*.md"
8
+ - "docs/**"
9
+ pull_request:
10
+ branches: [main]
11
+ paths-ignore:
12
+ - "**/*.md"
13
+ - "docs/**"
14
+ workflow_dispatch:
15
+
16
+ concurrency:
17
+ group: ci-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ permissions:
21
+ contents: read
22
+
23
+ jobs:
24
+ lint:
25
+ name: Lint
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+
30
+ - uses: pnpm/action-setup@v4
31
+
32
+ - uses: actions/setup-node@v4
33
+ with:
34
+ node-version: 22
35
+ cache: pnpm
36
+
37
+ - run: pnpm install --frozen-lockfile
38
+
39
+ - run: pnpm lint
40
+
41
+ - run: pnpm standards
42
+
43
+ test:
44
+ runs-on: ubuntu-latest
45
+ name: Test
46
+ services:
47
+ postgres:
48
+ image: postgres:16-alpine
49
+ env:
50
+ POSTGRES_USER: postgres
51
+ POSTGRES_PASSWORD: postgres
52
+ POSTGRES_DB: app_test
53
+ ports:
54
+ - 5432:5432
55
+ options: >-
56
+ --health-cmd="pg_isready -U postgres"
57
+ --health-interval=5s
58
+ --health-timeout=5s
59
+ --health-retries=5
60
+ redis:
61
+ image: redis:7-alpine
62
+ ports:
63
+ - 6379:6379
64
+ options: >-
65
+ --health-cmd="redis-cli ping"
66
+ --health-interval=5s
67
+ --health-timeout=5s
68
+ --health-retries=5
69
+ env:
70
+ POSTGRES_USER: postgres
71
+ POSTGRES_PASSWORD: postgres
72
+ POSTGRES_HOST: localhost
73
+ POSTGRES_PORT: "5432"
74
+ POSTGRES_DB: app_test
75
+ REDIS_HOST: localhost
76
+ REDIS_PORT: "6379"
77
+ NEXTAUTH_SECRET: ci-test-secret-must-be-at-least-32-characters-long
78
+ NODE_ENV: test
79
+ steps:
80
+ - uses: actions/checkout@v4
81
+
82
+ - uses: pnpm/action-setup@v4
83
+
84
+ - uses: actions/setup-node@v4
85
+ with:
86
+ node-version: 22
87
+ cache: pnpm
88
+
89
+ - run: pnpm install --frozen-lockfile
90
+
91
+ - run: pnpm db:generate
92
+
93
+ - run: pnpm test
94
+
95
+ build:
96
+ name: Build
97
+ needs: [lint, test]
98
+ runs-on: ubuntu-latest
99
+
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+
103
+ - uses: pnpm/action-setup@v4
104
+
105
+ - uses: actions/setup-node@v4
106
+ with:
107
+ node-version: 22
108
+ cache: pnpm
109
+
110
+ - run: pnpm install --frozen-lockfile
111
+
112
+ - run: pnpm db:generate
113
+
114
+ - run: pnpm doctor:ci
115
+
116
+ - run: pnpm build
@@ -0,0 +1,22 @@
1
+ name: Auto-merge Dependabot
2
+
3
+ on: pull_request
4
+
5
+ permissions:
6
+ contents: write
7
+ pull-requests: write
8
+
9
+ jobs:
10
+ auto-merge:
11
+ if: github.actor == 'dependabot[bot]'
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: dependabot/fetch-metadata@v2
15
+ id: meta
16
+
17
+ - name: Auto-merge patch updates
18
+ if: steps.meta.outputs.update-type == 'version-update:semver-patch'
19
+ run: gh pr merge "$PR_URL" --auto --squash
20
+ env:
21
+ PR_URL: ${{ github.event.pull_request.html_url }}
22
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,27 @@
1
+ name: Install (Windows)
2
+
3
+ # Windows runners bill at 2x the Linux rate. This workflow only proves that
4
+ # `pnpm install` resolves the lockfile, which the Linux CI jobs already cover,
5
+ # so it runs on demand only rather than on every push and pull request.
6
+ on:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ install-windows:
14
+ name: Install (Windows)
15
+ runs-on: windows-latest
16
+ timeout-minutes: 10
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - uses: pnpm/action-setup@v4
21
+
22
+ - uses: actions/setup-node@v4
23
+ with:
24
+ node-version: 22
25
+ cache: pnpm
26
+
27
+ - run: pnpm install --frozen-lockfile