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,604 @@
1
+ import { motion, useInView } from 'framer-motion';
2
+ import {
3
+ Activity,
4
+ Check,
5
+ Cloud,
6
+ Copy,
7
+ Database,
8
+ FileCode,
9
+ Folder,
10
+ FolderOpen,
11
+ Globe,
12
+ Layers,
13
+ Server,
14
+ Terminal,
15
+ Zap,
16
+ } from 'lucide-react';
17
+ import { useRef, useState } from 'react';
18
+ import { useTranslation } from 'react-i18next';
19
+ import vibecarbonIcon from '../assets/vibecarbon-icon.svg';
20
+
21
+ // Clean command box with prominent copy button
22
+ export function CommandBox({
23
+ command,
24
+ description,
25
+ delay = 0,
26
+ }: {
27
+ command: string;
28
+ description?: string;
29
+ delay?: number;
30
+ }) {
31
+ const [copied, setCopied] = useState(false);
32
+
33
+ const handleCopy = async () => {
34
+ await navigator.clipboard.writeText(command);
35
+ setCopied(true);
36
+ setTimeout(() => setCopied(false), 2000);
37
+ };
38
+
39
+ return (
40
+ <motion.div
41
+ initial={{ opacity: 0, y: 20 }}
42
+ whileInView={{ opacity: 1, y: 0 }}
43
+ viewport={{ once: true }}
44
+ transition={{ duration: 0.5, delay }}
45
+ className="group"
46
+ >
47
+ {description && <p className="text-sm text-muted-foreground mb-2 ml-1">{description}</p>}
48
+ <div className="relative flex items-center bg-muted/80 dark:bg-black/40 border border-border dark:border-white/10 rounded-xl overflow-hidden hover:border-primary/30 transition-colors">
49
+ <div className="flex-1 flex items-center gap-3 px-5 py-4 font-mono text-sm md:text-base">
50
+ <span className="text-primary font-bold">$</span>
51
+ <span className="text-foreground">{command}</span>
52
+ </div>
53
+ <button
54
+ type="button"
55
+ onClick={handleCopy}
56
+ className="flex items-center gap-2 px-5 self-stretch bg-black/[0.03] hover:bg-black/[0.06] dark:bg-white/5 dark:hover:bg-white/10 border-l border-border dark:border-white/10 transition-all cursor-pointer"
57
+ aria-label="Copy command"
58
+ >
59
+ {copied ? (
60
+ <>
61
+ <Check className="w-4 h-4 text-primary" />
62
+ <span className="text-xs text-primary font-medium hidden sm:inline">Copied!</span>
63
+ </>
64
+ ) : (
65
+ <>
66
+ <Copy className="w-4 h-4 text-muted-foreground group-hover:text-foreground transition-colors" />
67
+ <span className="text-xs text-muted-foreground group-hover:text-foreground font-medium hidden sm:inline transition-colors">
68
+ Copy
69
+ </span>
70
+ </>
71
+ )}
72
+ </button>
73
+ </div>
74
+ </motion.div>
75
+ );
76
+ }
77
+
78
+ // Step number indicator
79
+ function StepNumber({ number, color }: { number: number; color: 'teal' | 'magenta' }) {
80
+ return (
81
+ <div
82
+ className={`flex items-center justify-center w-12 h-12 rounded-2xl text-2xl font-black ${
83
+ color === 'teal'
84
+ ? 'bg-primary/20 text-primary border border-primary/30'
85
+ : 'bg-secondary-accent/20 text-secondary-accent border border-secondary-accent/30'
86
+ }`}
87
+ style={{
88
+ boxShadow:
89
+ color === 'teal'
90
+ ? '0 0 20px oklch(0.82 0.14 192 / 0.25)'
91
+ : '0 0 20px oklch(0.65 0.26 350 / 0.25)',
92
+ }}
93
+ >
94
+ {number}
95
+ </div>
96
+ );
97
+ }
98
+
99
+ // Create Visual: Project scaffolding animation
100
+ function CreateVisual() {
101
+ const ref = useRef<HTMLDivElement>(null);
102
+ const isInView = useInView(ref, { once: true, margin: '-50px' });
103
+
104
+ const structure = [
105
+ { name: 'my-app/', icon: FolderOpen, level: 0, delay: 0.2 },
106
+ { name: 'src/', icon: FolderOpen, level: 1, delay: 0.3 },
107
+ { name: 'client/', icon: Folder, level: 2, delay: 0.4 },
108
+ { name: 'server/', icon: Folder, level: 2, delay: 0.5 },
109
+ { name: 'shared/', icon: Folder, level: 2, delay: 0.6 },
110
+ { name: 'supabase/', icon: FolderOpen, level: 1, delay: 0.7 },
111
+ { name: 'migrations/', icon: Folder, level: 2, delay: 0.8 },
112
+ { name: 'k8s/', icon: FolderOpen, level: 1, delay: 0.9 },
113
+ { name: 'docker-compose.yml', icon: Layers, level: 1, delay: 1.0 },
114
+ { name: 'package.json', icon: FileCode, level: 1, delay: 1.1 },
115
+ ];
116
+
117
+ return (
118
+ <div ref={ref} className="relative">
119
+ {/* Behind-card glow */}
120
+ <div className="absolute -inset-[40px] -z-10 pointer-events-none">
121
+ <div
122
+ className="absolute inset-0"
123
+ style={{
124
+ background:
125
+ 'radial-gradient(ellipse 70% 60% at 50% 60%, rgb(0, 180, 200) 0%, rgb(0, 100, 140) 25%, rgba(0, 130, 160, 0) 65%)',
126
+ filter: 'blur(50px)',
127
+ opacity: 0.4,
128
+ }}
129
+ />
130
+ <div
131
+ className="absolute inset-[20%]"
132
+ style={{
133
+ background:
134
+ 'radial-gradient(ellipse 80% 70% at 50% 55%, rgb(100, 255, 240) 0%, rgba(0, 200, 210, 0) 60%)',
135
+ filter: 'blur(30px)',
136
+ opacity: 0.2,
137
+ }}
138
+ />
139
+ </div>
140
+
141
+ <div className="relative bg-muted dark:bg-black/60 backdrop-blur-xl border border-border dark:border-white/10 rounded-2xl overflow-hidden">
142
+ {/* Glowing top edge */}
143
+ <div className="absolute inset-x-0 -top-px h-px bg-gradient-to-r from-transparent via-primary/80 to-transparent" />
144
+ {/* Spotlight from above */}
145
+ <div
146
+ className="absolute inset-x-0 top-0 h-[250px] pointer-events-none"
147
+ style={{
148
+ background:
149
+ 'radial-gradient(ellipse 80% 60% at 50% 0%, oklch(0.82 0.14 192 / 0.25) 0%, transparent 100%)',
150
+ }}
151
+ />
152
+ {/* Particle dots */}
153
+ <div className="spotlight-particles absolute inset-0 pointer-events-none opacity-50" />
154
+
155
+ {/* Terminal header */}
156
+ <div className="relative flex items-center gap-2 px-4 py-3 border-b border-border dark:border-white/10 bg-black/[0.03] dark:bg-white/5">
157
+ <div className="flex gap-1.5">
158
+ <div className="w-3 h-3 rounded-full bg-red-500/70" />
159
+ <div className="w-3 h-3 rounded-full bg-yellow-500/70" />
160
+ <div className="w-3 h-3 rounded-full bg-green-500/70" />
161
+ </div>
162
+ <span className="text-xs text-muted-foreground ml-2 font-mono">Terminal</span>
163
+ </div>
164
+
165
+ <div className="relative p-5">
166
+ {/* Command */}
167
+ <motion.div
168
+ initial={{ opacity: 0 }}
169
+ animate={isInView ? { opacity: 1 } : { opacity: 0 }}
170
+ transition={{ duration: 0.3, delay: 0.1 }}
171
+ className="font-mono text-sm mb-4 flex items-center gap-2"
172
+ >
173
+ <span className="text-primary">$</span>
174
+ <span className="text-foreground">npx vibecarbon create</span>
175
+ </motion.div>
176
+
177
+ {/* File structure */}
178
+ <div className="space-y-0.5 font-mono text-sm">
179
+ {structure.map((item) => (
180
+ <motion.div
181
+ key={item.name}
182
+ initial={{ opacity: 0, x: -20 }}
183
+ animate={isInView ? { opacity: 1, x: 0 } : { opacity: 0, x: -20 }}
184
+ transition={{ duration: 0.3, delay: item.delay }}
185
+ className="flex items-center gap-2"
186
+ style={{ paddingLeft: `${item.level * 20}px` }}
187
+ >
188
+ <item.icon
189
+ className={`w-4 h-4 flex-shrink-0 ${
190
+ item.name.endsWith('/') ? 'text-primary' : 'text-secondary-accent'
191
+ }`}
192
+ />
193
+ <span className="text-foreground/80">{item.name}</span>
194
+ </motion.div>
195
+ ))}
196
+ </div>
197
+
198
+ {/* Success */}
199
+ <motion.div
200
+ initial={{ opacity: 0, y: 10 }}
201
+ animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 10 }}
202
+ transition={{ duration: 0.4, delay: 1.3 }}
203
+ className="mt-4 pt-4 border-t border-border dark:border-white/10 flex items-center gap-2"
204
+ >
205
+ <div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
206
+ <span className="text-green-600 dark:text-green-400 text-sm font-medium">
207
+ Project created successfully
208
+ </span>
209
+ </motion.div>
210
+ </div>
211
+ </div>
212
+ </div>
213
+ );
214
+ }
215
+
216
+ // Build Visual: Dev environment running
217
+ function BuildVisual() {
218
+ const ref = useRef<HTMLDivElement>(null);
219
+ const isInView = useInView(ref, { once: true, margin: '-50px' });
220
+
221
+ const services = [
222
+ { name: 'Vite', port: '5173', status: 'ready', icon: Zap, color: 'text-secondary-accent' },
223
+ { name: 'API', port: '3000', status: 'ready', icon: Server, color: 'text-primary' },
224
+ { name: 'Supabase', port: '8000', status: 'ready', icon: Database, color: 'text-green-400' },
225
+ { name: 'Studio', port: '3001', status: 'ready', icon: Globe, color: 'text-blue-400' },
226
+ ];
227
+
228
+ return (
229
+ <div ref={ref} className="relative">
230
+ {/* Behind-card glow */}
231
+ <div className="absolute -inset-[40px] -z-10 pointer-events-none">
232
+ <div
233
+ className="absolute inset-0"
234
+ style={{
235
+ background:
236
+ 'radial-gradient(ellipse 70% 60% at 50% 60%, rgb(200, 60, 180) 0%, rgb(140, 30, 120) 25%, rgba(160, 40, 140, 0) 65%)',
237
+ filter: 'blur(50px)',
238
+ opacity: 0.35,
239
+ }}
240
+ />
241
+ <div
242
+ className="absolute inset-[20%]"
243
+ style={{
244
+ background:
245
+ 'radial-gradient(ellipse 80% 70% at 50% 55%, rgb(255, 140, 220) 0%, rgba(200, 60, 180, 0) 60%)',
246
+ filter: 'blur(30px)',
247
+ opacity: 0.15,
248
+ }}
249
+ />
250
+ </div>
251
+
252
+ <div className="relative bg-muted dark:bg-black/60 backdrop-blur-xl border border-border dark:border-white/10 rounded-2xl overflow-hidden">
253
+ {/* Glowing top edge */}
254
+ <div className="absolute inset-x-0 -top-px h-px bg-gradient-to-r from-transparent via-secondary-accent/80 to-transparent" />
255
+ {/* Spotlight from above */}
256
+ <div
257
+ className="absolute inset-x-0 top-0 h-[250px] pointer-events-none"
258
+ style={{
259
+ background:
260
+ 'radial-gradient(ellipse 80% 60% at 50% 0%, oklch(0.65 0.26 350 / 0.25) 0%, transparent 100%)',
261
+ }}
262
+ />
263
+ {/* Particle dots */}
264
+ <div className="spotlight-particles absolute inset-0 pointer-events-none opacity-50" />
265
+
266
+ {/* Header */}
267
+ <div className="relative flex items-center justify-between px-4 py-3 border-b border-border dark:border-white/10 bg-black/[0.03] dark:bg-white/5">
268
+ <div className="flex items-center gap-2">
269
+ <Terminal className="w-4 h-4 text-secondary-accent" />
270
+ <span className="text-xs text-muted-foreground font-mono">Development Server</span>
271
+ </div>
272
+ <div className="flex items-center gap-2">
273
+ <Activity className="w-3 h-3 text-green-600 dark:text-green-400 animate-pulse" />
274
+ <span className="text-xs text-green-600 dark:text-green-400">Running</span>
275
+ </div>
276
+ </div>
277
+
278
+ <div className="relative p-5 space-y-3">
279
+ {services.map((service, index) => (
280
+ <motion.div
281
+ key={service.name}
282
+ initial={{ opacity: 0, x: -20 }}
283
+ animate={isInView ? { opacity: 1, x: 0 } : { opacity: 0, x: -20 }}
284
+ transition={{ duration: 0.4, delay: 0.2 + index * 0.15 }}
285
+ className="flex items-center justify-between p-3 bg-black/[0.03] dark:bg-white/5 rounded-xl border border-border/50 dark:border-white/5"
286
+ >
287
+ <div className="flex items-center gap-3">
288
+ <service.icon className={`w-5 h-5 ${service.color}`} />
289
+ <span className="text-foreground font-medium">{service.name}</span>
290
+ </div>
291
+ <div className="flex items-center gap-3">
292
+ <span className="text-muted-foreground font-mono text-sm">:{service.port}</span>
293
+ <div className="flex items-center gap-1.5">
294
+ <div className="w-2 h-2 rounded-full bg-green-500" />
295
+ <span className="text-xs text-green-600 dark:text-green-400">
296
+ {service.status}
297
+ </span>
298
+ </div>
299
+ </div>
300
+ </motion.div>
301
+ ))}
302
+
303
+ {/* Hot reload indicator */}
304
+ <motion.div
305
+ initial={{ opacity: 0 }}
306
+ animate={isInView ? { opacity: 1 } : { opacity: 0 }}
307
+ transition={{ duration: 0.4, delay: 0.9 }}
308
+ className="pt-3 border-t border-border dark:border-white/10 flex items-center justify-center gap-2 text-sm text-muted-foreground"
309
+ >
310
+ <Zap className="w-4 h-4 text-secondary-accent" />
311
+ <span>
312
+ Hot reload active at <span className="text-primary font-mono">localhost:5173</span>
313
+ </span>
314
+ </motion.div>
315
+ </div>
316
+ </div>
317
+ </div>
318
+ );
319
+ }
320
+
321
+ // Deploy Visual: Production infrastructure
322
+ function DeployVisual() {
323
+ const ref = useRef<HTMLDivElement>(null);
324
+ const isInView = useInView(ref, { once: true, margin: '-50px' });
325
+
326
+ return (
327
+ <div ref={ref} className="relative">
328
+ {/* Behind-card glow */}
329
+ <div className="absolute -inset-[40px] -z-10 pointer-events-none">
330
+ <div
331
+ className="absolute inset-0"
332
+ style={{
333
+ background:
334
+ 'radial-gradient(ellipse 70% 60% at 50% 60%, rgb(0, 180, 200) 0%, rgb(0, 100, 140) 25%, rgba(0, 130, 160, 0) 65%)',
335
+ filter: 'blur(50px)',
336
+ opacity: 0.4,
337
+ }}
338
+ />
339
+ <div
340
+ className="absolute inset-[20%]"
341
+ style={{
342
+ background:
343
+ 'radial-gradient(ellipse 80% 70% at 50% 55%, rgb(100, 255, 240) 0%, rgba(0, 200, 210, 0) 60%)',
344
+ filter: 'blur(30px)',
345
+ opacity: 0.2,
346
+ }}
347
+ />
348
+ </div>
349
+
350
+ <div className="relative bg-muted dark:bg-black/60 backdrop-blur-xl border border-border dark:border-white/10 rounded-2xl overflow-hidden">
351
+ {/* Glowing top edge */}
352
+ <div className="absolute inset-x-0 -top-px h-px bg-gradient-to-r from-transparent via-primary/80 to-transparent" />
353
+ {/* Spotlight from above */}
354
+ <div
355
+ className="absolute inset-x-0 top-0 h-[250px] pointer-events-none"
356
+ style={{
357
+ background:
358
+ 'radial-gradient(ellipse 80% 60% at 50% 0%, oklch(0.82 0.14 192 / 0.25) 0%, transparent 100%)',
359
+ }}
360
+ />
361
+ {/* Particle dots */}
362
+ <div className="spotlight-particles absolute inset-0 pointer-events-none opacity-50" />
363
+
364
+ {/* Header */}
365
+ <div className="relative flex items-center justify-between px-4 py-3 border-b border-border dark:border-white/10 bg-black/[0.03] dark:bg-white/5">
366
+ <div className="flex items-center gap-2">
367
+ <Cloud className="w-4 h-4 text-primary" />
368
+ <span className="text-xs text-muted-foreground font-mono">
369
+ Production Infrastructure
370
+ </span>
371
+ </div>
372
+ <span className="text-xs text-primary font-medium">Kubernetes</span>
373
+ </div>
374
+
375
+ <div className="relative p-5">
376
+ {/* Infrastructure diagram */}
377
+ <div className="flex flex-col items-center gap-3">
378
+ {/* Load Balancer */}
379
+ <motion.div
380
+ initial={{ opacity: 0, y: -20 }}
381
+ animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: -20 }}
382
+ transition={{ duration: 0.4, delay: 0.2 }}
383
+ className="w-full max-w-xs p-3 bg-gradient-to-r from-primary/20 to-primary/10 border border-primary/30 rounded-xl flex items-center justify-between"
384
+ >
385
+ <div className="flex items-center gap-2">
386
+ <Globe className="w-5 h-5 text-primary" />
387
+ <span className="font-medium text-sm">Load Balancer</span>
388
+ </div>
389
+ <div className="flex items-center gap-1.5">
390
+ <div className="w-2 h-2 rounded-full bg-green-500" />
391
+ <span className="text-xs text-foreground/70">Healthy</span>
392
+ </div>
393
+ </motion.div>
394
+
395
+ {/* Connection line */}
396
+ <motion.div
397
+ initial={{ scaleY: 0 }}
398
+ animate={isInView ? { scaleY: 1 } : { scaleY: 0 }}
399
+ transition={{ duration: 0.2, delay: 0.4 }}
400
+ className="w-px h-4 bg-gradient-to-b from-primary/50 to-secondary-accent/50 origin-top"
401
+ />
402
+
403
+ {/* App Pods */}
404
+ <motion.div
405
+ initial={{ opacity: 0, scale: 0.9 }}
406
+ animate={isInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.9 }}
407
+ transition={{ duration: 0.4, delay: 0.5 }}
408
+ className="flex flex-wrap justify-center gap-2"
409
+ >
410
+ {[1, 2, 3].map((i) => (
411
+ <div
412
+ key={i}
413
+ className="p-2.5 bg-black/[0.03] dark:bg-white/5 border border-border/50 dark:border-white/10 rounded-lg flex items-center gap-2"
414
+ >
415
+ <Server className="w-4 h-4 text-secondary-accent" />
416
+ <span className="text-xs font-mono">pod-{i}</span>
417
+ <div className="w-1.5 h-1.5 rounded-full bg-green-500" />
418
+ </div>
419
+ ))}
420
+ </motion.div>
421
+
422
+ {/* Connection line */}
423
+ <motion.div
424
+ initial={{ scaleY: 0 }}
425
+ animate={isInView ? { scaleY: 1 } : { scaleY: 0 }}
426
+ transition={{ duration: 0.2, delay: 0.7 }}
427
+ className="w-px h-4 bg-gradient-to-b from-secondary-accent/50 to-primary/50 origin-top"
428
+ />
429
+
430
+ {/* Database */}
431
+ <motion.div
432
+ initial={{ opacity: 0, y: 20 }}
433
+ animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
434
+ transition={{ duration: 0.4, delay: 0.8 }}
435
+ className="w-full max-w-xs p-3 bg-gradient-to-r from-secondary-accent/20 to-secondary-accent/10 border border-secondary-accent/30 rounded-xl flex items-center justify-between"
436
+ >
437
+ <div className="flex items-center gap-2">
438
+ <Database className="w-5 h-5 text-secondary-accent" />
439
+ <span className="font-medium text-sm">PostgreSQL HA</span>
440
+ </div>
441
+ <div className="flex items-center gap-1.5">
442
+ <div className="w-2 h-2 rounded-full bg-green-500" />
443
+ <span className="text-xs text-foreground/70">Primary</span>
444
+ </div>
445
+ </motion.div>
446
+ </div>
447
+
448
+ {/* Status bar */}
449
+ <motion.div
450
+ initial={{ opacity: 0 }}
451
+ animate={isInView ? { opacity: 1 } : { opacity: 0 }}
452
+ transition={{ duration: 0.4, delay: 1.0 }}
453
+ className="mt-4 pt-4 border-t border-border dark:border-white/10 flex items-center justify-between text-xs"
454
+ >
455
+ <div className="flex items-center gap-4">
456
+ <span className="text-muted-foreground">
457
+ Autoscaling: <span className="text-primary">Active</span>
458
+ </span>
459
+ <span className="text-muted-foreground">
460
+ High availability: <span className="text-primary">Ready</span>
461
+ </span>
462
+ </div>
463
+ <span className="text-foreground/70 flex items-center gap-1.5">
464
+ <span className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
465
+ All systems operational
466
+ </span>
467
+ </motion.div>
468
+ </div>
469
+ </div>
470
+ </div>
471
+ );
472
+ }
473
+
474
+ // Workflow step component
475
+ function WorkflowStep({
476
+ step,
477
+ title,
478
+ subtitle,
479
+ command,
480
+ visual,
481
+ color,
482
+ reverse = false,
483
+ }: {
484
+ step: number;
485
+ title: string;
486
+ subtitle: string;
487
+ command: string;
488
+ visual: React.ReactNode;
489
+ color: 'teal' | 'magenta';
490
+ reverse?: boolean;
491
+ }) {
492
+ const ref = useRef<HTMLDivElement>(null);
493
+ const isInView = useInView(ref, { once: true, margin: '-100px' });
494
+
495
+ return (
496
+ <div
497
+ ref={ref}
498
+ className={`flex flex-col ${reverse ? 'lg:flex-row-reverse' : 'lg:flex-row'} gap-12 lg:gap-20 items-center lg:items-start`}
499
+ >
500
+ {/* Text content */}
501
+ <div className="w-full lg:w-1/2 space-y-6">
502
+ <motion.div
503
+ initial={{ opacity: 0, y: 20 }}
504
+ animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
505
+ transition={{ duration: 0.5 }}
506
+ className="flex items-center gap-4"
507
+ >
508
+ <StepNumber number={step} color={color} />
509
+ <div>
510
+ <h2
511
+ className={`text-4xl md:text-6xl font-black tracking-tight ${
512
+ color === 'teal' ? 'text-primary' : 'text-secondary-accent'
513
+ }`}
514
+ >
515
+ {title}
516
+ </h2>
517
+ </div>
518
+ </motion.div>
519
+
520
+ <motion.p
521
+ initial={{ opacity: 0 }}
522
+ animate={isInView ? { opacity: 1 } : { opacity: 0 }}
523
+ transition={{ duration: 0.5, delay: 0.1 }}
524
+ className="text-lg text-muted-foreground max-w-md"
525
+ >
526
+ {subtitle}
527
+ </motion.p>
528
+
529
+ <CommandBox command={command} delay={0.2} />
530
+ </div>
531
+
532
+ {/* Visual */}
533
+ <div className="w-full lg:w-1/2">{visual}</div>
534
+ </div>
535
+ );
536
+ }
537
+
538
+ export function WorkflowSection() {
539
+ const { t } = useTranslation();
540
+ return (
541
+ <section className="relative py-24 md:py-36 overflow-hidden">
542
+ <div className="mx-auto max-w-7xl px-6">
543
+ {/* Section header */}
544
+ <motion.div
545
+ initial={{ opacity: 0, y: 20 }}
546
+ whileInView={{ opacity: 1, y: 0 }}
547
+ viewport={{ once: true }}
548
+ transition={{ duration: 0.5 }}
549
+ className="text-center mb-10"
550
+ >
551
+ <motion.div
552
+ className="flex justify-center mb-6"
553
+ animate={{ y: [0, -6, 0] }}
554
+ transition={{ duration: 3, repeat: Infinity, ease: 'easeInOut' }}
555
+ >
556
+ <img
557
+ src={vibecarbonIcon}
558
+ alt=""
559
+ width={56}
560
+ height={56}
561
+ className="drop-shadow-[0_0_12px_oklch(0.82_0.14_192/0.6)]"
562
+ />
563
+ </motion.div>
564
+ <h2 className="text-3xl md:text-4xl font-black tracking-tight mb-4">
565
+ {t('landing.workflow.headline')}
566
+ </h2>
567
+ <p className="text-lg text-muted-foreground max-w-2xl mx-auto">
568
+ {t('landing.workflow.subheading')}
569
+ </p>
570
+ </motion.div>
571
+
572
+ {/* Steps */}
573
+ <div className="space-y-14">
574
+ <WorkflowStep
575
+ step={1}
576
+ title={t('landing.workflow.create.label')}
577
+ subtitle={t('landing.workflow.create.description')}
578
+ command="npx vibecarbon create"
579
+ visual={<CreateVisual />}
580
+ color="teal"
581
+ />
582
+
583
+ <WorkflowStep
584
+ step={2}
585
+ title={t('landing.workflow.develop.label')}
586
+ subtitle={t('landing.workflow.develop.description')}
587
+ command="npx vibecarbon up"
588
+ visual={<BuildVisual />}
589
+ color="magenta"
590
+ />
591
+
592
+ <WorkflowStep
593
+ step={3}
594
+ title={t('landing.workflow.deploy.label')}
595
+ subtitle={t('landing.workflow.deploy.description')}
596
+ command="npx vibecarbon deploy"
597
+ visual={<DeployVisual />}
598
+ color="teal"
599
+ />
600
+ </div>
601
+ </div>
602
+ </section>
603
+ );
604
+ }