vibecarbon 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 (495) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +188 -0
  3. package/carbon/.claude/hooks/task-completed-gate.sh +19 -0
  4. package/carbon/.claude/hooks/teammate-idle-gate.sh +29 -0
  5. package/carbon/.claude/settings.json +29 -0
  6. package/carbon/.cursor/rules/vibecarbon.mdc +6 -0
  7. package/carbon/.dockerignore +57 -0
  8. package/carbon/.env.example +219 -0
  9. package/carbon/.github/copilot-instructions.md +3 -0
  10. package/carbon/.github/workflows/deploy.yml +346 -0
  11. package/carbon/.github/workflows/vibecarbon-build.yml +81 -0
  12. package/carbon/.windsurfrules +74 -0
  13. package/carbon/AGENTS.md +422 -0
  14. package/carbon/CLAUDE.md +3 -0
  15. package/carbon/DEVELOPMENT.md +187 -0
  16. package/carbon/Dockerfile +98 -0
  17. package/carbon/LICENSE +21 -0
  18. package/carbon/PRODUCTION.md +364 -0
  19. package/carbon/README.md +193 -0
  20. package/carbon/TESTING.md +138 -0
  21. package/carbon/backup/Dockerfile +75 -0
  22. package/carbon/backup/backup.sh +95 -0
  23. package/carbon/backup/compose-backup.sh +140 -0
  24. package/carbon/biome.json +83 -0
  25. package/carbon/cloud-init/docker-ce-setup.yaml +55 -0
  26. package/carbon/cloud-init/k3s/master-init.sh +215 -0
  27. package/carbon/cloud-init/k3s/supabase-init.sh +167 -0
  28. package/carbon/cloud-init/k3s/worker-init.sh +147 -0
  29. package/carbon/components.json +24 -0
  30. package/carbon/content/blog/authentication-guide.mdx +34 -0
  31. package/carbon/content/blog/getting-started.mdx +41 -0
  32. package/carbon/content/changelog/v0-1-0.mdx +40 -0
  33. package/carbon/content/docs/analytics.mdx +90 -0
  34. package/carbon/content/docs/authentication.mdx +231 -0
  35. package/carbon/content/docs/background-jobs.mdx +116 -0
  36. package/carbon/content/docs/cli.mdx +630 -0
  37. package/carbon/content/docs/database.mdx +236 -0
  38. package/carbon/content/docs/deployment.mdx +227 -0
  39. package/carbon/content/docs/development.mdx +238 -0
  40. package/carbon/content/docs/environments.mdx +84 -0
  41. package/carbon/content/docs/getting-started.mdx +112 -0
  42. package/carbon/content/docs/legal/privacy-policy.mdx +89 -0
  43. package/carbon/content/docs/legal/terms-of-service.mdx +99 -0
  44. package/carbon/content/docs/optional-services.mdx +160 -0
  45. package/carbon/db/Dockerfile +23 -0
  46. package/carbon/docker-compose.dev-init.yml +5 -0
  47. package/carbon/docker-compose.metabase.override.yml +14 -0
  48. package/carbon/docker-compose.metabase.prod.yml +28 -0
  49. package/carbon/docker-compose.metabase.yml +84 -0
  50. package/carbon/docker-compose.n8n.override.yml +14 -0
  51. package/carbon/docker-compose.n8n.prod.yml +31 -0
  52. package/carbon/docker-compose.n8n.yml +97 -0
  53. package/carbon/docker-compose.observability.override.yml +18 -0
  54. package/carbon/docker-compose.observability.prod.yml +28 -0
  55. package/carbon/docker-compose.observability.yml +125 -0
  56. package/carbon/docker-compose.override.yml +28 -0
  57. package/carbon/docker-compose.prod.yml +294 -0
  58. package/carbon/docker-compose.yml +508 -0
  59. package/carbon/docker-entrypoint.sh +12 -0
  60. package/carbon/ha/activate-standby.sh +52 -0
  61. package/carbon/ha/primary-init.sql +36 -0
  62. package/carbon/ha/standby-init.sh +74 -0
  63. package/carbon/k8s/LICENSE +99 -0
  64. package/carbon/k8s/README.md +272 -0
  65. package/carbon/k8s/base/app/deployment.yaml +130 -0
  66. package/carbon/k8s/base/app/hpa.yaml +44 -0
  67. package/carbon/k8s/base/app/kustomization.yaml +10 -0
  68. package/carbon/k8s/base/app/network-policy.yaml +124 -0
  69. package/carbon/k8s/base/app/pdb.yaml +14 -0
  70. package/carbon/k8s/base/app/rbac.yaml +36 -0
  71. package/carbon/k8s/base/app/service.yaml +16 -0
  72. package/carbon/k8s/base/backup/cronjob.yaml +120 -0
  73. package/carbon/k8s/base/backup/kustomization.yaml +7 -0
  74. package/carbon/k8s/base/backup/network-policy.yaml +31 -0
  75. package/carbon/k8s/base/backup/rbac.yaml +7 -0
  76. package/carbon/k8s/base/cluster-autoscaler/deployment.yaml +103 -0
  77. package/carbon/k8s/base/cluster-autoscaler/kustomization.yaml +17 -0
  78. package/carbon/k8s/base/cluster-autoscaler/rbac.yaml +109 -0
  79. package/carbon/k8s/base/config/configmap.yaml +48 -0
  80. package/carbon/k8s/base/config/kustomization.yaml +8 -0
  81. package/carbon/k8s/base/hetzner-ccm/kustomization.yaml +9 -0
  82. package/carbon/k8s/base/hetzner-csi/kustomization.yaml +9 -0
  83. package/carbon/k8s/base/kustomization.yaml +43 -0
  84. package/carbon/k8s/base/namespace.yaml +7 -0
  85. package/carbon/k8s/base/network-policies.yaml +95 -0
  86. package/carbon/k8s/base/registry/kustomization.yaml +5 -0
  87. package/carbon/k8s/base/registry/local-registry.yaml +193 -0
  88. package/carbon/k8s/base/traefik/certificate.yaml +21 -0
  89. package/carbon/k8s/base/traefik/configmap.yaml +13 -0
  90. package/carbon/k8s/base/traefik/deployment.yaml +165 -0
  91. package/carbon/k8s/base/traefik/ingressroute.yaml +141 -0
  92. package/carbon/k8s/base/traefik/kustomization.yaml +11 -0
  93. package/carbon/k8s/base/traefik/middleware.yaml +109 -0
  94. package/carbon/k8s/base/traefik/network-policy.yaml +92 -0
  95. package/carbon/k8s/base/traefik/service.yaml +38 -0
  96. package/carbon/k8s/flux/README.md +49 -0
  97. package/carbon/k8s/flux/clusters/primary/vibecarbon.yaml +128 -0
  98. package/carbon/k8s/flux/clusters/standby/vibecarbon.yaml +83 -0
  99. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-release.yaml +38 -0
  100. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-repository.yaml +16 -0
  101. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/kustomization.yaml +10 -0
  102. package/carbon/k8s/gitops/supabase/helm-release.yaml +66 -0
  103. package/carbon/k8s/gitops/supabase/helm-repository.yaml +18 -0
  104. package/carbon/k8s/gitops/supabase/kustomization.yaml +33 -0
  105. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-cloudflare.yaml +51 -0
  106. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-hetzner.yaml +59 -0
  107. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-manual.yaml +43 -0
  108. package/carbon/k8s/infra/cert-manager-resources/kustomization.yaml +15 -0
  109. package/carbon/k8s/infra/kustomization.yaml +21 -0
  110. package/carbon/k8s/infra/traefik-crds/kustomization.yaml +10 -0
  111. package/carbon/k8s/overlays/local/configmap.yaml +23 -0
  112. package/carbon/k8s/overlays/local/ingressroute-studio.yaml +104 -0
  113. package/carbon/k8s/overlays/local/kustomization.yaml +215 -0
  114. package/carbon/k8s/overlays/local/namespace.yaml +8 -0
  115. package/carbon/k8s/overlays/local/secrets.yaml +32 -0
  116. package/carbon/k8s/overlays/production/kustomization.yaml +34 -0
  117. package/carbon/k8s/test-local.sh +318 -0
  118. package/carbon/k8s/values/supabase.values.yaml +133 -0
  119. package/carbon/package.json +154 -0
  120. package/carbon/runtime.Dockerfile +17 -0
  121. package/carbon/scripts/_dev-jwt.mjs +45 -0
  122. package/carbon/scripts/check-rls.ts +53 -0
  123. package/carbon/scripts/dev-init.js +191 -0
  124. package/carbon/scripts/dev.js +191 -0
  125. package/carbon/scripts/docker-down.js +63 -0
  126. package/carbon/scripts/docker-logs.js +59 -0
  127. package/carbon/scripts/docker-up.js +222 -0
  128. package/carbon/scripts/generate-dev-configs.sh +131 -0
  129. package/carbon/scripts/generate-rss.ts +116 -0
  130. package/carbon/scripts/generate-sitemap.ts +102 -0
  131. package/carbon/scripts/k8s-apply.js +71 -0
  132. package/carbon/scripts/k8s-delete.js +75 -0
  133. package/carbon/scripts/lib/manifest.js +176 -0
  134. package/carbon/scripts/secret-scan.mjs +278 -0
  135. package/carbon/scripts/validate-dev-configs.sh +101 -0
  136. package/carbon/src/client/App.tsx +202 -0
  137. package/carbon/src/client/assets/hyperformant-dark.svg +29 -0
  138. package/carbon/src/client/assets/hyperformant-light.svg +29 -0
  139. package/carbon/src/client/assets/logos/aider.svg +1 -0
  140. package/carbon/src/client/assets/logos/antigravity.svg +1 -0
  141. package/carbon/src/client/assets/logos/bolt.svg +1 -0
  142. package/carbon/src/client/assets/logos/claude-code.svg +1 -0
  143. package/carbon/src/client/assets/logos/copilot.svg +1 -0
  144. package/carbon/src/client/assets/logos/cursor.svg +1 -0
  145. package/carbon/src/client/assets/logos/gemini-cli.svg +1 -0
  146. package/carbon/src/client/assets/logos/lovable.svg +1 -0
  147. package/carbon/src/client/assets/logos/openai-codex.svg +1 -0
  148. package/carbon/src/client/assets/logos/v0.svg +1 -0
  149. package/carbon/src/client/assets/logos/windsurf.svg +1 -0
  150. package/carbon/src/client/assets/vibecarbon-icon.svg +19 -0
  151. package/carbon/src/client/assets/vibecarbon-logo-dark.svg +29 -0
  152. package/carbon/src/client/assets/vibecarbon-logo-light.svg +29 -0
  153. package/carbon/src/client/components/AIIntegrationSection.tsx +120 -0
  154. package/carbon/src/client/components/AppSidebar.tsx +760 -0
  155. package/carbon/src/client/components/ArchitectureSection.tsx +46 -0
  156. package/carbon/src/client/components/CTAFooter.tsx +59 -0
  157. package/carbon/src/client/components/ComparisonSection.tsx +132 -0
  158. package/carbon/src/client/components/ContentPanel.tsx +66 -0
  159. package/carbon/src/client/components/ContentSkeleton.tsx +21 -0
  160. package/carbon/src/client/components/ErrorBoundary.tsx +46 -0
  161. package/carbon/src/client/components/FAQSection.tsx +76 -0
  162. package/carbon/src/client/components/FileUpload.tsx +210 -0
  163. package/carbon/src/client/components/HeaderActions.tsx +17 -0
  164. package/carbon/src/client/components/Hero.tsx +608 -0
  165. package/carbon/src/client/components/ImpersonationBanner.tsx +31 -0
  166. package/carbon/src/client/components/LanguageSwitcher.tsx +67 -0
  167. package/carbon/src/client/components/Logo.tsx +87 -0
  168. package/carbon/src/client/components/LogoStrip.tsx +76 -0
  169. package/carbon/src/client/components/MetricsStrip.tsx +48 -0
  170. package/carbon/src/client/components/Nav.tsx +195 -0
  171. package/carbon/src/client/components/NewsletterSignup.tsx +147 -0
  172. package/carbon/src/client/components/NotificationDrawer.tsx +171 -0
  173. package/carbon/src/client/components/PageHeader.tsx +24 -0
  174. package/carbon/src/client/components/PlanGate.tsx +36 -0
  175. package/carbon/src/client/components/PricingSection.tsx +371 -0
  176. package/carbon/src/client/components/SEO.tsx +34 -0
  177. package/carbon/src/client/components/SmoothScroll.tsx +45 -0
  178. package/carbon/src/client/components/TechStackSection.tsx +165 -0
  179. package/carbon/src/client/components/WorkflowSection.tsx +604 -0
  180. package/carbon/src/client/components/admin/DockerLogs.tsx +276 -0
  181. package/carbon/src/client/components/admin/PerformanceMetrics.tsx +230 -0
  182. package/carbon/src/client/components/admin/ServiceCard.tsx +45 -0
  183. package/carbon/src/client/components/admin/ServicesStatus.tsx +296 -0
  184. package/carbon/src/client/components/architecture/ArchitectureDiagram.tsx +413 -0
  185. package/carbon/src/client/components/auth/AuthProvider.tsx +466 -0
  186. package/carbon/src/client/components/effects/FilmGrainOverlay.tsx +35 -0
  187. package/carbon/src/client/components/effects/FresnelEdge.tsx +49 -0
  188. package/carbon/src/client/components/effects/GlowTracker.tsx +46 -0
  189. package/carbon/src/client/components/effects/SparkBurst.tsx +145 -0
  190. package/carbon/src/client/components/effects/VGlowEffect.tsx +83 -0
  191. package/carbon/src/client/components/effects/index.ts +2 -0
  192. package/carbon/src/client/components/layouts/SidebarLayout.tsx +20 -0
  193. package/carbon/src/client/components/scroll/ScrollSection.tsx +76 -0
  194. package/carbon/src/client/components/scroll/ScrollytellingProvider.tsx +81 -0
  195. package/carbon/src/client/components/scroll/index.ts +2 -0
  196. package/carbon/src/client/components/ui/accordion.tsx +71 -0
  197. package/carbon/src/client/components/ui/alert-dialog.tsx +162 -0
  198. package/carbon/src/client/components/ui/alert.tsx +73 -0
  199. package/carbon/src/client/components/ui/aspect-ratio.tsx +22 -0
  200. package/carbon/src/client/components/ui/avatar.tsx +91 -0
  201. package/carbon/src/client/components/ui/badge.tsx +50 -0
  202. package/carbon/src/client/components/ui/breadcrumb.tsx +100 -0
  203. package/carbon/src/client/components/ui/button-group.tsx +78 -0
  204. package/carbon/src/client/components/ui/button.tsx +120 -0
  205. package/carbon/src/client/components/ui/calendar.tsx +182 -0
  206. package/carbon/src/client/components/ui/card.tsx +85 -0
  207. package/carbon/src/client/components/ui/carousel.tsx +227 -0
  208. package/carbon/src/client/components/ui/chart.tsx +357 -0
  209. package/carbon/src/client/components/ui/checkbox.tsx +27 -0
  210. package/carbon/src/client/components/ui/collapsible.tsx +15 -0
  211. package/carbon/src/client/components/ui/command.tsx +178 -0
  212. package/carbon/src/client/components/ui/context-menu.tsx +233 -0
  213. package/carbon/src/client/components/ui/dialog.tsx +132 -0
  214. package/carbon/src/client/components/ui/drawer.tsx +118 -0
  215. package/carbon/src/client/components/ui/dropdown-menu.tsx +242 -0
  216. package/carbon/src/client/components/ui/empty.tsx +94 -0
  217. package/carbon/src/client/components/ui/field.tsx +226 -0
  218. package/carbon/src/client/components/ui/hover-card.tsx +44 -0
  219. package/carbon/src/client/components/ui/input-group.tsx +146 -0
  220. package/carbon/src/client/components/ui/input-otp.tsx +83 -0
  221. package/carbon/src/client/components/ui/input.tsx +20 -0
  222. package/carbon/src/client/components/ui/item.tsx +188 -0
  223. package/carbon/src/client/components/ui/kbd.tsx +26 -0
  224. package/carbon/src/client/components/ui/label.tsx +21 -0
  225. package/carbon/src/client/components/ui/menubar.tsx +250 -0
  226. package/carbon/src/client/components/ui/navigation-menu.tsx +155 -0
  227. package/carbon/src/client/components/ui/pagination.tsx +102 -0
  228. package/carbon/src/client/components/ui/popover.tsx +75 -0
  229. package/carbon/src/client/components/ui/progress.tsx +66 -0
  230. package/carbon/src/client/components/ui/radio-group.tsx +36 -0
  231. package/carbon/src/client/components/ui/resizable.tsx +46 -0
  232. package/carbon/src/client/components/ui/scroll-area.tsx +48 -0
  233. package/carbon/src/client/components/ui/select.tsx +186 -0
  234. package/carbon/src/client/components/ui/separator.tsx +21 -0
  235. package/carbon/src/client/components/ui/sheet.tsx +124 -0
  236. package/carbon/src/client/components/ui/sidebar.tsx +702 -0
  237. package/carbon/src/client/components/ui/skeleton.tsx +13 -0
  238. package/carbon/src/client/components/ui/slider.tsx +57 -0
  239. package/carbon/src/client/components/ui/sonner.tsx +45 -0
  240. package/carbon/src/client/components/ui/spinner.tsx +15 -0
  241. package/carbon/src/client/components/ui/switch.tsx +30 -0
  242. package/carbon/src/client/components/ui/table.tsx +89 -0
  243. package/carbon/src/client/components/ui/tabs.tsx +73 -0
  244. package/carbon/src/client/components/ui/textarea.tsx +18 -0
  245. package/carbon/src/client/components/ui/toggle-group.tsx +87 -0
  246. package/carbon/src/client/components/ui/toggle.tsx +44 -0
  247. package/carbon/src/client/components/ui/tooltip.tsx +56 -0
  248. package/carbon/src/client/hooks/api/index.ts +14 -0
  249. package/carbon/src/client/hooks/api/useAuthSettings.ts +80 -0
  250. package/carbon/src/client/hooks/api/useSubscription.ts +87 -0
  251. package/carbon/src/client/hooks/use-mobile.ts +21 -0
  252. package/carbon/src/client/hooks/useMousePosition.ts +91 -0
  253. package/carbon/src/client/hooks/useNotifications.tsx +124 -0
  254. package/carbon/src/client/hooks/useOrganizationMembers.ts +127 -0
  255. package/carbon/src/client/hooks/useOrganizations.tsx +230 -0
  256. package/carbon/src/client/hooks/usePackageManager.ts +69 -0
  257. package/carbon/src/client/hooks/useReducedMotion.ts +20 -0
  258. package/carbon/src/client/hooks/useRunningServices.ts +114 -0
  259. package/carbon/src/client/hooks/useScrollProgress.ts +56 -0
  260. package/carbon/src/client/index.css +467 -0
  261. package/carbon/src/client/index.html +56 -0
  262. package/carbon/src/client/lib/admin-services.ts +151 -0
  263. package/carbon/src/client/lib/api.ts +32 -0
  264. package/carbon/src/client/lib/blog.ts +35 -0
  265. package/carbon/src/client/lib/changelog.ts +33 -0
  266. package/carbon/src/client/lib/docs-search.ts +101 -0
  267. package/carbon/src/client/lib/docs.ts +37 -0
  268. package/carbon/src/client/lib/i18n.ts +32 -0
  269. package/carbon/src/client/lib/supabase.ts +72 -0
  270. package/carbon/src/client/lib/tailwind-colors.ts +357 -0
  271. package/carbon/src/client/lib/theme.ts +117 -0
  272. package/carbon/src/client/lib/utils.ts +22 -0
  273. package/carbon/src/client/locales/de.json +529 -0
  274. package/carbon/src/client/locales/en.json +461 -0
  275. package/carbon/src/client/locales/es.json +529 -0
  276. package/carbon/src/client/locales/fr.json +529 -0
  277. package/carbon/src/client/locales/pt.json +529 -0
  278. package/carbon/src/client/main.tsx +56 -0
  279. package/carbon/src/client/mdx.d.ts +13 -0
  280. package/carbon/src/client/pages/ApiDocs.tsx +76 -0
  281. package/carbon/src/client/pages/AuthCallback.tsx +34 -0
  282. package/carbon/src/client/pages/Blog.tsx +167 -0
  283. package/carbon/src/client/pages/Changelog.tsx +171 -0
  284. package/carbon/src/client/pages/Charts.tsx +388 -0
  285. package/carbon/src/client/pages/Checkout.tsx +227 -0
  286. package/carbon/src/client/pages/Contact.tsx +174 -0
  287. package/carbon/src/client/pages/Dashboard.tsx +368 -0
  288. package/carbon/src/client/pages/Docs.tsx +372 -0
  289. package/carbon/src/client/pages/ForgotPassword.tsx +111 -0
  290. package/carbon/src/client/pages/Home.tsx +187 -0
  291. package/carbon/src/client/pages/Legal.tsx +100 -0
  292. package/carbon/src/client/pages/Login.tsx +408 -0
  293. package/carbon/src/client/pages/MFAVerify.tsx +156 -0
  294. package/carbon/src/client/pages/NotFound.tsx +21 -0
  295. package/carbon/src/client/pages/Onboarding.tsx +246 -0
  296. package/carbon/src/client/pages/ResetPassword.tsx +200 -0
  297. package/carbon/src/client/pages/UIComponents.tsx +390 -0
  298. package/carbon/src/client/pages/admin/ContactSubmissions.tsx +220 -0
  299. package/carbon/src/client/pages/admin/Dashboard.tsx +24 -0
  300. package/carbon/src/client/pages/admin/Infrastructure.tsx +257 -0
  301. package/carbon/src/client/pages/admin/Jobs.tsx +225 -0
  302. package/carbon/src/client/pages/admin/Logs.tsx +18 -0
  303. package/carbon/src/client/pages/admin/Newsletter.tsx +300 -0
  304. package/carbon/src/client/pages/admin/Notifications.tsx +603 -0
  305. package/carbon/src/client/pages/admin/Organizations.tsx +306 -0
  306. package/carbon/src/client/pages/admin/Settings.tsx +314 -0
  307. package/carbon/src/client/pages/admin/Theme.tsx +465 -0
  308. package/carbon/src/client/pages/admin/Users.tsx +365 -0
  309. package/carbon/src/client/pages/api-docs.css +156 -0
  310. package/carbon/src/client/pages/organizations/Details.tsx +200 -0
  311. package/carbon/src/client/pages/organizations/Members.tsx +402 -0
  312. package/carbon/src/client/pages/settings/Billing.tsx +473 -0
  313. package/carbon/src/client/pages/settings/Profile.tsx +160 -0
  314. package/carbon/src/client/pages/settings/Security.tsx +341 -0
  315. package/carbon/src/client/public/favicon.svg +19 -0
  316. package/carbon/src/client/public/robots.txt +8 -0
  317. package/carbon/src/server/billing/index.ts +104 -0
  318. package/carbon/src/server/billing/provider.ts +81 -0
  319. package/carbon/src/server/billing/providers/paddle.ts +314 -0
  320. package/carbon/src/server/billing/providers/polar.ts +325 -0
  321. package/carbon/src/server/billing/providers/stripe.ts +233 -0
  322. package/carbon/src/server/emails/templates.ts +116 -0
  323. package/carbon/src/server/index.ts +554 -0
  324. package/carbon/src/server/lib/auth.ts +6 -0
  325. package/carbon/src/server/lib/email.ts +64 -0
  326. package/carbon/src/server/lib/env.ts +112 -0
  327. package/carbon/src/server/lib/errors.ts +21 -0
  328. package/carbon/src/server/lib/logger.ts +17 -0
  329. package/carbon/src/server/lib/rate-limiter.ts +288 -0
  330. package/carbon/src/server/lib/request.ts +34 -0
  331. package/carbon/src/server/lib/stripe.ts +42 -0
  332. package/carbon/src/server/lib/supabase.ts +65 -0
  333. package/carbon/src/server/middleware/requirePlan.ts +80 -0
  334. package/carbon/src/server/routes/_internal/services-status.ts +958 -0
  335. package/carbon/src/server/routes/_internal/verify-role.ts +185 -0
  336. package/carbon/src/server/routes/health.ts +48 -0
  337. package/carbon/src/server/routes/v1/admin/contact.ts +128 -0
  338. package/carbon/src/server/routes/v1/admin/jobs.ts +171 -0
  339. package/carbon/src/server/routes/v1/admin/newsletter.ts +237 -0
  340. package/carbon/src/server/routes/v1/auth.ts +390 -0
  341. package/carbon/src/server/routes/v1/billing.ts +718 -0
  342. package/carbon/src/server/routes/v1/contact.ts +93 -0
  343. package/carbon/src/server/routes/v1/index.ts +1333 -0
  344. package/carbon/src/server/routes/v1/newsletter.ts +181 -0
  345. package/carbon/src/server/routes/v1/performance.ts +157 -0
  346. package/carbon/src/server/routes/v1/stats.ts +170 -0
  347. package/carbon/src/server/routes/v1/theme.ts +106 -0
  348. package/carbon/src/server/routes/webhooks/billing.ts +376 -0
  349. package/carbon/src/server/routes/webhooks/stripe.ts +276 -0
  350. package/carbon/src/server/types.ts +11 -0
  351. package/carbon/src/shared/pricing.ts +155 -0
  352. package/carbon/src/shared/types.ts +338 -0
  353. package/carbon/supabase/migrations/00001_init.sql +717 -0
  354. package/carbon/supabase/migrations/00002_theme_settings.sql +13 -0
  355. package/carbon/supabase/migrations/00003_pg_cron.sql +121 -0
  356. package/carbon/supabase/migrations/00004_contact_newsletter.sql +81 -0
  357. package/carbon/supabase/migrations/00005_localization_languages.sql +22 -0
  358. package/carbon/supabase/seed.sql +16 -0
  359. package/carbon/tests/_helpers/app.ts +45 -0
  360. package/carbon/tests/_helpers/env.ts +37 -0
  361. package/carbon/tests/_helpers/factories.ts +69 -0
  362. package/carbon/tests/_helpers/jwt.ts +23 -0
  363. package/carbon/tests/_helpers/setup-integration.ts +20 -0
  364. package/carbon/tests/_helpers/setup-rtl.ts +12 -0
  365. package/carbon/tests/component/ErrorBoundary.test.tsx +53 -0
  366. package/carbon/tests/component/use-auth-settings.test.tsx +119 -0
  367. package/carbon/tests/integration/server/routes/contact.test.ts +162 -0
  368. package/carbon/tests/integration/server/routes/health.test.ts +61 -0
  369. package/carbon/tests/structural/i18n-parity.test.ts +42 -0
  370. package/carbon/tests/unit/client/utils.test.ts +49 -0
  371. package/carbon/tests/unit/shared/pricing.test.ts +93 -0
  372. package/carbon/tsconfig.json +27 -0
  373. package/carbon/tsconfig.server.json +27 -0
  374. package/carbon/tsconfig.test.json +9 -0
  375. package/carbon/vite.config.ts +110 -0
  376. package/carbon/vitest.config.ts +74 -0
  377. package/carbon/volumes/db/jwt.sql +57 -0
  378. package/carbon/volumes/db/metabase-init.sh +29 -0
  379. package/carbon/volumes/db/n8n-init.sh +25 -0
  380. package/carbon/volumes/db/realtime.sql +33 -0
  381. package/carbon/volumes/db/roles.sql +93 -0
  382. package/carbon/volumes/db/set-passwords.sh +12 -0
  383. package/carbon/volumes/db/super-admin.dev.sql +113 -0
  384. package/carbon/volumes/db/super-admin.generated.sql +113 -0
  385. package/carbon/volumes/db/super-admin.sql +114 -0
  386. package/carbon/volumes/grafana/dashboards/logs.json +179 -0
  387. package/carbon/volumes/grafana/dashboards/overview.json +523 -0
  388. package/carbon/volumes/grafana/dashboards/postgresql.json +337 -0
  389. package/carbon/volumes/grafana/dashboards.dev/logs.json +179 -0
  390. package/carbon/volumes/grafana/dashboards.dev/overview.json +156 -0
  391. package/carbon/volumes/grafana/dashboards.dev/postgresql.json +337 -0
  392. package/carbon/volumes/grafana/provisioning/dashboards/dashboards.dev.yml +16 -0
  393. package/carbon/volumes/grafana/provisioning/dashboards/dashboards.yml +16 -0
  394. package/carbon/volumes/grafana/provisioning/datasources/datasources.yml +43 -0
  395. package/carbon/volumes/kong/docker-entrypoint.sh +9 -0
  396. package/carbon/volumes/kong/kong.yml +208 -0
  397. package/carbon/volumes/loki/loki-config.yml +58 -0
  398. package/carbon/volumes/n8n/hooks.js +131 -0
  399. package/carbon/volumes/n8n/scripts/setup.sh +66 -0
  400. package/carbon/volumes/prometheus/prometheus.yml +43 -0
  401. package/carbon/volumes/promtail/promtail-config.yml +64 -0
  402. package/carbon/volumes/traefik/middlewares.dev.yml +83 -0
  403. package/carbon/volumes/traefik/middlewares.yml +95 -0
  404. package/carbon/volumes/traefik/vite-dev.yml +20 -0
  405. package/package.json +95 -0
  406. package/src/access.js +354 -0
  407. package/src/activate.js +187 -0
  408. package/src/add.js +718 -0
  409. package/src/backup.js +786 -0
  410. package/src/cli.js +350 -0
  411. package/src/configure.js +967 -0
  412. package/src/console.js +155 -0
  413. package/src/create.js +1499 -0
  414. package/src/deploy.js +311 -0
  415. package/src/destroy.js +2033 -0
  416. package/src/diagnose.js +735 -0
  417. package/src/down.js +80 -0
  418. package/src/failover.js +1032 -0
  419. package/src/lib/backup-s3.js +179 -0
  420. package/src/lib/build.js +33 -0
  421. package/src/lib/checksum.js +28 -0
  422. package/src/lib/ci-setup.js +666 -0
  423. package/src/lib/cli/help.js +129 -0
  424. package/src/lib/cli/parse-flags.js +160 -0
  425. package/src/lib/cli/select-action.js +65 -0
  426. package/src/lib/cli/select-environment.js +108 -0
  427. package/src/lib/cli/tty-guard.js +75 -0
  428. package/src/lib/cloudflare.js +447 -0
  429. package/src/lib/colors.js +52 -0
  430. package/src/lib/command.js +361 -0
  431. package/src/lib/config.js +359 -0
  432. package/src/lib/cost.js +103 -0
  433. package/src/lib/deploy/bundle.js +231 -0
  434. package/src/lib/deploy/compose/acme-verify.js +121 -0
  435. package/src/lib/deploy/compose/build-args.js +78 -0
  436. package/src/lib/deploy/compose/ha.js +1874 -0
  437. package/src/lib/deploy/compose/index.js +1294 -0
  438. package/src/lib/deploy/compose/reconcile.js +74 -0
  439. package/src/lib/deploy/github.js +382 -0
  440. package/src/lib/deploy/image.js +191 -0
  441. package/src/lib/deploy/index.js +119 -0
  442. package/src/lib/deploy/k8s/LICENSE +99 -0
  443. package/src/lib/deploy/k8s/gitops-deploy.js +298 -0
  444. package/src/lib/deploy/k8s/ha/index.js +1000 -0
  445. package/src/lib/deploy/k8s/index.js +62 -0
  446. package/src/lib/deploy/k8s/k3s.js +2515 -0
  447. package/src/lib/deploy/orchestrator.js +1401 -0
  448. package/src/lib/deploy/prompts.js +545 -0
  449. package/src/lib/deploy/remote-build.js +130 -0
  450. package/src/lib/deploy/state.js +120 -0
  451. package/src/lib/deploy/utils.js +328 -0
  452. package/src/lib/deploy-logger.js +93 -0
  453. package/src/lib/dns-propagation.js +48 -0
  454. package/src/lib/environment.js +58 -0
  455. package/src/lib/fetch-retry.js +103 -0
  456. package/src/lib/github-environments.js +335 -0
  457. package/src/lib/hetzner-dns.js +377 -0
  458. package/src/lib/hetzner-guided-setup.js +275 -0
  459. package/src/lib/host-keys.js +37 -0
  460. package/src/lib/iac/cloud-init.js +52 -0
  461. package/src/lib/iac/index.js +325 -0
  462. package/src/lib/iac/programs/hetzner-compose.js +130 -0
  463. package/src/lib/iac/programs/hetzner-k8s.js +320 -0
  464. package/src/lib/kubectl.js +81 -0
  465. package/src/lib/licensing/index.js +259 -0
  466. package/src/lib/licensing/tiers.js +181 -0
  467. package/src/lib/licensing/validator.js +171 -0
  468. package/src/lib/merge-package-json.js +90 -0
  469. package/src/lib/operator-ip.js +381 -0
  470. package/src/lib/package-manager.js +111 -0
  471. package/src/lib/perf.js +71 -0
  472. package/src/lib/project-guard.js +39 -0
  473. package/src/lib/project.js +334 -0
  474. package/src/lib/providers/base.js +276 -0
  475. package/src/lib/providers/hetzner-s3.js +656 -0
  476. package/src/lib/providers/hetzner.js +755 -0
  477. package/src/lib/providers/index.js +164 -0
  478. package/src/lib/s3.js +510 -0
  479. package/src/lib/secret-scan.js +583 -0
  480. package/src/lib/secrets.js +63 -0
  481. package/src/lib/server-types.js +195 -0
  482. package/src/lib/shell.js +91 -0
  483. package/src/lib/ssh.js +241 -0
  484. package/src/lib/tracker.js +242 -0
  485. package/src/lib/upgrade-policy.js +170 -0
  486. package/src/lib/validators.js +105 -0
  487. package/src/lib/version.js +5 -0
  488. package/src/remove.js +292 -0
  489. package/src/reset.js +97 -0
  490. package/src/restore.js +871 -0
  491. package/src/scale.js +1734 -0
  492. package/src/shell.js +222 -0
  493. package/src/status.js +981 -0
  494. package/src/up.js +264 -0
  495. package/src/upgrade.js +721 -0
@@ -0,0 +1,372 @@
1
+ import { BookOpen, ChevronRight, Menu, Search, X } from 'lucide-react';
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { Link, Navigate, useNavigate, useParams } from 'react-router-dom';
4
+ import { Wordmark } from '@/components/Logo';
5
+ import { Nav } from '@/components/Nav';
6
+ import { SEO } from '@/components/SEO';
7
+ import { Button } from '@/components/ui/button';
8
+ import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
9
+ import {
10
+ type PackageManager,
11
+ replacePackageManager,
12
+ usePackageManager,
13
+ } from '@/hooks/usePackageManager';
14
+ import { getPage, pages } from '@/lib/docs';
15
+ import { type SearchResult, searchDocs } from '@/lib/docs-search';
16
+ import { cn } from '@/lib/utils';
17
+
18
+ function DocsSearch({ onNavigate }: { onNavigate?: () => void }) {
19
+ const [query, setQuery] = useState('');
20
+ const [results, setResults] = useState<SearchResult[]>([]);
21
+ const [isOpen, setIsOpen] = useState(false);
22
+ const inputRef = useRef<HTMLInputElement>(null);
23
+ const navigate = useNavigate();
24
+
25
+ const handleSearch = useCallback((value: string) => {
26
+ setQuery(value);
27
+ if (value.length >= 2) {
28
+ setResults(searchDocs(value));
29
+ setIsOpen(true);
30
+ } else {
31
+ setResults([]);
32
+ setIsOpen(false);
33
+ }
34
+ }, []);
35
+
36
+ const handleSelect = useCallback(
37
+ (slug: string) => {
38
+ navigate(`/docs/${slug}`);
39
+ setQuery('');
40
+ setIsOpen(false);
41
+ onNavigate?.();
42
+ },
43
+ [navigate, onNavigate]
44
+ );
45
+
46
+ // Cmd+K / Ctrl+K keyboard shortcut
47
+ useEffect(() => {
48
+ const handler = (e: KeyboardEvent) => {
49
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
50
+ e.preventDefault();
51
+ inputRef.current?.focus();
52
+ }
53
+ if (e.key === 'Escape') {
54
+ setIsOpen(false);
55
+ inputRef.current?.blur();
56
+ }
57
+ };
58
+ document.addEventListener('keydown', handler);
59
+ return () => document.removeEventListener('keydown', handler);
60
+ }, []);
61
+
62
+ return (
63
+ <div className="relative mb-4">
64
+ <div className="relative">
65
+ <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground" />
66
+ <input
67
+ ref={inputRef}
68
+ type="text"
69
+ value={query}
70
+ onChange={(e) => handleSearch(e.target.value)}
71
+ onFocus={() => query.length >= 2 && setIsOpen(true)}
72
+ onBlur={() => setTimeout(() => setIsOpen(false), 200)}
73
+ placeholder="Search docs..."
74
+ className="w-full rounded-md border border-border bg-muted/50 pl-8 pr-12 py-1.5 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary"
75
+ />
76
+ <kbd className="absolute right-2 top-1/2 -translate-y-1/2 hidden sm:inline-flex items-center gap-0.5 rounded border border-border bg-muted px-1.5 py-0.5 text-[10px] font-mono text-muted-foreground">
77
+ <span className="text-xs">⌘</span>K
78
+ </kbd>
79
+ </div>
80
+
81
+ {/* Results dropdown */}
82
+ {isOpen && results.length > 0 && (
83
+ <div className="absolute z-50 mt-1 w-full rounded-md border border-border bg-popover shadow-lg">
84
+ {results.map((result) => (
85
+ <button
86
+ key={result.slug}
87
+ type="button"
88
+ onMouseDown={() => handleSelect(result.slug)}
89
+ className="w-full px-3 py-2 text-left text-sm hover:bg-accent transition-colors first:rounded-t-md last:rounded-b-md"
90
+ >
91
+ <div className="font-medium">{result.title}</div>
92
+ <div className="text-xs text-muted-foreground truncate">{result.snippet}</div>
93
+ </button>
94
+ ))}
95
+ </div>
96
+ )}
97
+
98
+ {isOpen && query.length >= 2 && results.length === 0 && (
99
+ <div className="absolute z-50 mt-1 w-full rounded-md border border-border bg-popover p-3 shadow-lg">
100
+ <p className="text-sm text-muted-foreground">No results found.</p>
101
+ </div>
102
+ )}
103
+ </div>
104
+ );
105
+ }
106
+
107
+ function DocsSidebar({
108
+ currentSlug,
109
+ onNavigate,
110
+ }: {
111
+ currentSlug: string;
112
+ onNavigate?: () => void;
113
+ }) {
114
+ return (
115
+ <nav className="space-y-1">
116
+ <DocsSearch onNavigate={onNavigate} />
117
+ {pages.map((page) => (
118
+ <Link
119
+ key={page.slug}
120
+ to={`/docs/${page.slug}`}
121
+ onClick={onNavigate}
122
+ className={cn(
123
+ 'flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors',
124
+ page.slug === currentSlug
125
+ ? 'bg-primary/10 text-primary font-medium'
126
+ : 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
127
+ )}
128
+ >
129
+ {page.frontmatter.title}
130
+ </Link>
131
+ ))}
132
+ </nav>
133
+ );
134
+ }
135
+
136
+ export function DocsIndex() {
137
+ // Redirect to the first doc page
138
+ if (pages.length > 0) {
139
+ return <Navigate to={`/docs/${pages[0].slug}`} replace />;
140
+ }
141
+
142
+ return (
143
+ <div className="min-h-screen bg-background">
144
+ <Nav />
145
+ <main className="mx-auto max-w-3xl px-6 pt-32 pb-24 text-center">
146
+ <h1 className="mb-4 text-2xl font-bold">No documentation yet</h1>
147
+ <p className="text-muted-foreground">Check back soon!</p>
148
+ </main>
149
+ </div>
150
+ );
151
+ }
152
+
153
+ const PM_OPTIONS: PackageManager[] = ['pnpm', 'npm', 'bun'];
154
+
155
+ function PackageManagerSwitcher({
156
+ pm,
157
+ onChange,
158
+ }: {
159
+ pm: PackageManager;
160
+ onChange: (pm: PackageManager) => void;
161
+ }) {
162
+ return (
163
+ <ToggleGroup
164
+ value={[pm]}
165
+ onValueChange={(values) => {
166
+ const next = values[0] as PackageManager | undefined;
167
+ if (next) onChange(next);
168
+ }}
169
+ variant="outline"
170
+ size="sm"
171
+ className="shrink-0"
172
+ >
173
+ {PM_OPTIONS.map((option) => (
174
+ <ToggleGroupItem key={option} value={option} className="text-xs px-2.5">
175
+ {option}
176
+ </ToggleGroupItem>
177
+ ))}
178
+ </ToggleGroup>
179
+ );
180
+ }
181
+
182
+ export function DocsPage() {
183
+ const { slug } = useParams<{ slug: string }>();
184
+ const page = slug ? getPage(slug) : undefined;
185
+ const [sidebarOpen, setSidebarOpen] = useState(false);
186
+ const [pm, setPm] = usePackageManager();
187
+
188
+ const mdxComponents = useMemo(
189
+ () => ({
190
+ code: ((rawProps: unknown) => {
191
+ const { children, ...props } = rawProps as Record<string, unknown> & {
192
+ children?: React.ReactNode;
193
+ };
194
+ const content =
195
+ typeof children === 'string' && children.includes('pnpm')
196
+ ? replacePackageManager(children, pm)
197
+ : children;
198
+ return <code {...props}>{content}</code>;
199
+ }) as React.ComponentType<unknown>,
200
+ }),
201
+ [pm]
202
+ );
203
+
204
+ if (!page) {
205
+ return (
206
+ <div className="min-h-screen bg-background">
207
+ <Nav />
208
+ <main className="mx-auto max-w-3xl px-6 pt-32 pb-24 text-center">
209
+ <h1 className="mb-4 text-2xl font-bold">Page not found</h1>
210
+ <Button variant="outline" asChild>
211
+ <Link to="/docs" className="inline-flex items-center gap-2">
212
+ <BookOpen className="size-4 shrink-0" />
213
+ Browse docs
214
+ </Link>
215
+ </Button>
216
+ </main>
217
+ </div>
218
+ );
219
+ }
220
+
221
+ // Find prev/next pages
222
+ const currentIndex = pages.findIndex((p) => p.slug === slug);
223
+ const prevPage = currentIndex > 0 ? pages[currentIndex - 1] : null;
224
+ const nextPage = currentIndex < pages.length - 1 ? pages[currentIndex + 1] : null;
225
+
226
+ return (
227
+ <div className="min-h-screen bg-background">
228
+ <Nav />
229
+ <SEO title={page.frontmatter.title} description={page.frontmatter.description} />
230
+
231
+ <div className="mx-auto max-w-7xl px-6 pt-28 pb-24">
232
+ <div className="flex gap-10">
233
+ {/* Desktop sidebar */}
234
+ <aside className="hidden lg:block w-56 shrink-0 sticky top-28 h-[calc(100vh-8rem)] overflow-y-auto">
235
+ <h3 className="mb-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
236
+ Documentation
237
+ </h3>
238
+ <DocsSidebar currentSlug={slug || ''} />
239
+ </aside>
240
+
241
+ {/* Mobile sidebar toggle */}
242
+ <Button
243
+ variant="outline"
244
+ size="icon-sm"
245
+ className="fixed bottom-6 right-6 z-50 lg:hidden shadow-lg"
246
+ onClick={() => setSidebarOpen(!sidebarOpen)}
247
+ >
248
+ {sidebarOpen ? <X className="size-4" /> : <Menu className="size-4" />}
249
+ </Button>
250
+
251
+ {/* Mobile sidebar overlay */}
252
+ {sidebarOpen && (
253
+ <div
254
+ role="button"
255
+ tabIndex={0}
256
+ aria-label="Close sidebar"
257
+ className="fixed inset-0 z-40 bg-background/80 backdrop-blur-sm lg:hidden"
258
+ onClick={() => setSidebarOpen(false)}
259
+ onKeyDown={(e) => {
260
+ if (e.key === 'Enter' || e.key === ' ') setSidebarOpen(false);
261
+ }}
262
+ >
263
+ <aside
264
+ className="absolute left-0 top-20 bottom-0 w-64 bg-background border-r p-6 overflow-y-auto"
265
+ onClick={(e) => e.stopPropagation()}
266
+ onKeyDown={() => {}}
267
+ >
268
+ <h3 className="mb-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
269
+ Documentation
270
+ </h3>
271
+ <DocsSidebar currentSlug={slug || ''} onNavigate={() => setSidebarOpen(false)} />
272
+ </aside>
273
+ </div>
274
+ )}
275
+
276
+ {/* Main content */}
277
+ <main className="min-w-0 flex-1">
278
+ <header className="mb-10">
279
+ <div className="flex items-start justify-between gap-4">
280
+ <h1 className="mb-3 text-4xl font-black tracking-tight">
281
+ {page.frontmatter.title}
282
+ </h1>
283
+ <PackageManagerSwitcher pm={pm} onChange={setPm} />
284
+ </div>
285
+ {page.frontmatter.description && (
286
+ <p className="text-lg text-muted-foreground">{page.frontmatter.description}</p>
287
+ )}
288
+ </header>
289
+
290
+ <article className="prose prose-invert max-w-none">
291
+ <page.Component components={mdxComponents} />
292
+ </article>
293
+
294
+ {/* Prev / Next navigation */}
295
+ <div className="mt-16 border-t pt-8 flex items-center justify-between gap-4">
296
+ {prevPage ? (
297
+ <Link
298
+ to={`/docs/${prevPage.slug}`}
299
+ className="group flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
300
+ >
301
+ <ChevronRight className="size-4 rotate-180 group-hover:-translate-x-0.5 transition-transform" />
302
+ {prevPage.frontmatter.title}
303
+ </Link>
304
+ ) : (
305
+ <div />
306
+ )}
307
+ {nextPage && (
308
+ <Link
309
+ to={`/docs/${nextPage.slug}`}
310
+ className="group flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
311
+ >
312
+ {nextPage.frontmatter.title}
313
+ <ChevronRight className="size-4 group-hover:translate-x-0.5 transition-transform" />
314
+ </Link>
315
+ )}
316
+ </div>
317
+ </main>
318
+ </div>
319
+ </div>
320
+
321
+ <DocsFooter />
322
+ </div>
323
+ );
324
+ }
325
+
326
+ /** Default export for React.lazy() route-level code splitting */
327
+ export default function DocsRoute() {
328
+ const { slug } = useParams<{ slug: string }>();
329
+ return slug ? <DocsPage /> : <DocsIndex />;
330
+ }
331
+
332
+ function DocsFooter() {
333
+ return (
334
+ <footer className="border-t border-border py-8">
335
+ <div className="mx-auto flex max-w-7xl flex-col items-center justify-between gap-4 px-6 sm:flex-row">
336
+ <Wordmark size="sm" />
337
+ <div className="flex items-center gap-6">
338
+ <Link
339
+ to="/"
340
+ className="text-sm text-muted-foreground transition-colors hover:text-foreground"
341
+ >
342
+ Home
343
+ </Link>
344
+ <Link
345
+ to="/docs"
346
+ className="text-sm text-muted-foreground transition-colors hover:text-foreground"
347
+ >
348
+ Docs
349
+ </Link>
350
+ <Link
351
+ to="/blog"
352
+ className="text-sm text-muted-foreground transition-colors hover:text-foreground"
353
+ >
354
+ Blog
355
+ </Link>
356
+ <Link
357
+ to="/privacy"
358
+ className="text-sm text-muted-foreground transition-colors hover:text-foreground"
359
+ >
360
+ Privacy
361
+ </Link>
362
+ <Link
363
+ to="/terms"
364
+ className="text-sm text-muted-foreground transition-colors hover:text-foreground"
365
+ >
366
+ Terms
367
+ </Link>
368
+ </div>
369
+ </div>
370
+ </footer>
371
+ );
372
+ }
@@ -0,0 +1,111 @@
1
+ import { useState } from 'react';
2
+ import { Link } from 'react-router-dom';
3
+ import { Wordmark } from '../components/Logo';
4
+ import { Button } from '../components/ui/button';
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card';
6
+ import { Input } from '../components/ui/input';
7
+ import { supabase } from '../lib/supabase';
8
+
9
+ export default function ForgotPassword() {
10
+ const [email, setEmail] = useState('');
11
+ const [error, setError] = useState('');
12
+ const [success, setSuccess] = useState(false);
13
+ const [loading, setLoading] = useState(false);
14
+
15
+ const handleSubmit = async (e: React.FormEvent) => {
16
+ e.preventDefault();
17
+ setError('');
18
+ setLoading(true);
19
+
20
+ try {
21
+ const { error } = await supabase.auth.resetPasswordForEmail(email, {
22
+ redirectTo: `${window.location.origin}/reset-password`,
23
+ });
24
+
25
+ if (error) throw error;
26
+
27
+ // Always show success to prevent email enumeration
28
+ setSuccess(true);
29
+ } catch (_err) {
30
+ // Show generic message to prevent email enumeration
31
+ setError('Unable to send reset email. Please try again later.');
32
+ } finally {
33
+ setLoading(false);
34
+ }
35
+ };
36
+
37
+ return (
38
+ <div className="min-h-screen flex flex-col bg-background">
39
+ {/* Header */}
40
+ <header className="h-20">
41
+ <div className="mx-auto max-w-7xl h-full px-6 flex items-center">
42
+ <Link to="/" className="group">
43
+ <Wordmark size="lg" />
44
+ </Link>
45
+ </div>
46
+ </header>
47
+
48
+ {/* Main content */}
49
+ <div className="flex-1 flex items-center justify-center p-4">
50
+ <Card className="w-full max-w-md shadow-lg shadow-primary/5">
51
+ <CardHeader className="text-center">
52
+ <CardTitle className="text-2xl text-primary">Reset password</CardTitle>
53
+ <CardDescription>
54
+ {success
55
+ ? 'Check your email for a reset link'
56
+ : "Enter your email and we'll send you a reset link"}
57
+ </CardDescription>
58
+ </CardHeader>
59
+ <CardContent className="space-y-6">
60
+ {success ? (
61
+ <div className="space-y-4">
62
+ <div className="p-3 text-sm text-emerald-600 bg-emerald-50 dark:bg-emerald-950/30 dark:text-emerald-400 rounded-lg">
63
+ If an account exists with that email, you'll receive a password reset link
64
+ shortly.
65
+ </div>
66
+ <p className="text-center text-sm text-muted-foreground">
67
+ Didn't receive an email?{' '}
68
+ <button
69
+ type="button"
70
+ onClick={() => setSuccess(false)}
71
+ className="text-primary hover:underline font-medium cursor-pointer"
72
+ >
73
+ Try again
74
+ </button>
75
+ </p>
76
+ </div>
77
+ ) : (
78
+ <form onSubmit={handleSubmit} className="space-y-4">
79
+ {error && (
80
+ <div className="p-3 text-sm text-destructive bg-destructive/10 rounded-lg">
81
+ {error}
82
+ </div>
83
+ )}
84
+
85
+ <Input
86
+ type="email"
87
+ placeholder="Email"
88
+ value={email}
89
+ onChange={(e) => setEmail(e.target.value)}
90
+ required
91
+ autoFocus
92
+ />
93
+
94
+ <Button type="submit" disabled={loading} className="w-full">
95
+ {loading ? 'Sending...' : 'Send reset link'}
96
+ </Button>
97
+ </form>
98
+ )}
99
+
100
+ <p className="text-center text-sm text-muted-foreground">
101
+ Remember your password?{' '}
102
+ <Link to="/login" className="text-primary hover:underline font-medium">
103
+ Sign in
104
+ </Link>
105
+ </p>
106
+ </CardContent>
107
+ </Card>
108
+ </div>
109
+ </div>
110
+ );
111
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Vibecarbon marketing homepage.
3
+ *
4
+ * Route: /
5
+ */
6
+
7
+ import { motion } from 'framer-motion';
8
+ import { ExternalLink, Lock } from 'lucide-react';
9
+ import { useTranslation } from 'react-i18next';
10
+ import { Link } from 'react-router-dom';
11
+ import hyperformantLogo from '../assets/hyperformant-dark.svg';
12
+ import claudeLogo from '../assets/logos/claude-code.svg';
13
+ import geminiLogo from '../assets/logos/gemini-cli.svg';
14
+ import openaiLogo from '../assets/logos/openai-codex.svg';
15
+ import { AIIntegrationSection } from '../components/AIIntegrationSection';
16
+ import { ArchitectureSection } from '../components/ArchitectureSection';
17
+ import { ComparisonSection } from '../components/ComparisonSection';
18
+ import { CTAFooter } from '../components/CTAFooter';
19
+ import { FilmGrainOverlay } from '../components/effects/FilmGrainOverlay';
20
+ import { VGlowEffect } from '../components/effects/VGlowEffect';
21
+ import { FAQSection } from '../components/FAQSection';
22
+ import Hero from '../components/Hero';
23
+ import { LogoStrip } from '../components/LogoStrip';
24
+ import { MetricsStrip } from '../components/MetricsStrip';
25
+ import { NewsletterSignup } from '../components/NewsletterSignup';
26
+ import { PricingSection } from '../components/PricingSection';
27
+ import { SEO } from '../components/SEO';
28
+ import { ScrollSection } from '../components/scroll/ScrollSection';
29
+ import { ScrollytellingProvider } from '../components/scroll/ScrollytellingProvider';
30
+ import { TechStackSection } from '../components/TechStackSection';
31
+ import { WorkflowSection } from '../components/WorkflowSection';
32
+
33
+ function VibecarbonCTAFooter() {
34
+ const { t } = useTranslation();
35
+ return (
36
+ <CTAFooter
37
+ gradient="bg-gradient-to-br from-fuchsia-950 via-fuchsia-900/80 to-secondary-accent/60"
38
+ floatingElements={
39
+ <div className="absolute inset-0 flex items-end justify-center gap-4 pb-2">
40
+ {/* Shared glow behind the group */}
41
+ <div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[400px] h-[200px] rounded-full bg-primary/15 blur-[60px]" />
42
+ {[
43
+ { src: claudeLogo, scale: 1.2, delay: 0 },
44
+ { src: geminiLogo, scale: 1.0, delay: 0.3 },
45
+ { src: openaiLogo, scale: 1.1, delay: 0.6 },
46
+ ].map(({ src, scale, delay }, i) => (
47
+ <motion.div
48
+ key={src}
49
+ className="relative p-5 rounded-2xl bg-white/8 border border-white/15 backdrop-blur-md shadow-2xl"
50
+ style={{ scale }}
51
+ animate={{ y: [0, -10, 0], rotate: [0, i % 2 === 0 ? 3 : -3, 0] }}
52
+ transition={{
53
+ duration: 3.5 + i * 0.4,
54
+ repeat: Infinity,
55
+ ease: 'easeInOut',
56
+ delay,
57
+ }}
58
+ >
59
+ <img src={src} alt="" width={64} height={64} className="brightness-0 invert" />
60
+ </motion.div>
61
+ ))}
62
+ </div>
63
+ }
64
+ footerLinks={
65
+ <>
66
+ <div className="flex items-center gap-6">
67
+ <a
68
+ href="https://github.com/hyperformant/vibecarbon/"
69
+ target="_blank"
70
+ rel="noopener noreferrer"
71
+ className="text-sm text-white/60 transition-colors hover:text-white flex items-center gap-1"
72
+ >
73
+ GitHub
74
+ <ExternalLink className="size-3" />
75
+ </a>
76
+ <Link to="/docs" className="text-sm text-white/60 transition-colors hover:text-white">
77
+ {t('landing.footer.userDocs')}
78
+ </Link>
79
+ <Link
80
+ to="/api/docs"
81
+ className="text-sm text-white/60 transition-colors hover:text-white"
82
+ >
83
+ {t('landing.footer.apiDocs')}
84
+ </Link>
85
+ <Link to="/blog" className="text-sm text-white/60 transition-colors hover:text-white">
86
+ {t('landing.footer.blog')}
87
+ </Link>
88
+ <Link
89
+ to="/changelog"
90
+ className="text-sm text-white/60 transition-colors hover:text-white"
91
+ >
92
+ {t('landing.footer.changelog')}
93
+ </Link>
94
+ <Link
95
+ to="/contact"
96
+ className="text-sm text-white/60 transition-colors hover:text-white"
97
+ >
98
+ {t('landing.footer.contact')}
99
+ </Link>
100
+ <Link
101
+ to="/privacy"
102
+ className="text-sm text-white/60 transition-colors hover:text-white"
103
+ >
104
+ {t('landing.footer.privacy')}
105
+ </Link>
106
+ <Link to="/terms" className="text-sm text-white/60 transition-colors hover:text-white">
107
+ {t('landing.footer.terms')}
108
+ </Link>
109
+ </div>
110
+ <a
111
+ href="https://hyperformant.co/"
112
+ target="_blank"
113
+ rel="noopener noreferrer"
114
+ className="flex items-center gap-2 text-sm text-white/60 hover:text-white transition-colors"
115
+ >
116
+ <img src={hyperformantLogo} alt="Hyperformant" className="h-5" />
117
+ </a>
118
+ </>
119
+ }
120
+ >
121
+ <div className="mb-4 inline-flex items-center gap-2 rounded-full bg-white/20 px-4 py-1.5 text-sm font-medium text-white">
122
+ <Lock className="size-4" />
123
+ {t('landing.cta.badge')}
124
+ </div>
125
+
126
+ <h2 className="mb-4 text-3xl font-black tracking-tight text-white md:text-4xl">
127
+ {t('landing.cta.headline')}
128
+ </h2>
129
+
130
+ <p className="mb-8 text-lg text-white/80">{t('landing.cta.subheading')}</p>
131
+
132
+ <NewsletterSignup className="justify-center max-w-md mx-auto" />
133
+ </CTAFooter>
134
+ );
135
+ }
136
+
137
+ export default function VibecarbonHome() {
138
+ return (
139
+ <ScrollytellingProvider>
140
+ <div className="relative min-h-screen bg-background film-grain">
141
+ <SEO description="Professional grade vibecoding. Full-stack, security-hardened, auto-everything SaaS apps in minutes." />
142
+ <FilmGrainOverlay opacity={0.025} />
143
+ <VGlowEffect />
144
+
145
+ <ScrollSection id="hero" disableEffects>
146
+ <Hero />
147
+ </ScrollSection>
148
+
149
+ <LogoStrip />
150
+
151
+ <div className="bg-background">
152
+ <ScrollSection id="workflow">
153
+ <WorkflowSection />
154
+ </ScrollSection>
155
+
156
+ <MetricsStrip />
157
+
158
+ <ScrollSection id="comparison">
159
+ <ComparisonSection />
160
+ </ScrollSection>
161
+
162
+ <ScrollSection id="ai-integration">
163
+ <AIIntegrationSection />
164
+ </ScrollSection>
165
+
166
+ <ScrollSection id="tech-stack">
167
+ <TechStackSection />
168
+ </ScrollSection>
169
+
170
+ <ScrollSection id="architecture">
171
+ <ArchitectureSection />
172
+ </ScrollSection>
173
+
174
+ <ScrollSection id="pricing">
175
+ <PricingSection />
176
+ </ScrollSection>
177
+
178
+ <ScrollSection id="faq">
179
+ <FAQSection />
180
+ </ScrollSection>
181
+
182
+ <VibecarbonCTAFooter />
183
+ </div>
184
+ </div>
185
+ </ScrollytellingProvider>
186
+ );
187
+ }