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,215 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # Note: This script runs AS PART of cloud-init (user_data), so we cannot wait for
5
+ # cloud-init to complete (that would cause a deadlock). The script starts immediately.
6
+
7
+ # Wait for any dpkg locks held by unattended-upgrades (runs on first boot).
8
+ # Without this, apt-get fails intermittently with "Could not get lock /var/lib/dpkg/lock".
9
+ for i in $(seq 1 30); do
10
+ if ! fuser /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; then
11
+ break
12
+ fi
13
+ echo "Waiting for dpkg lock to be released... ($i/30)"
14
+ sleep 10
15
+ done
16
+
17
+ # Update apt lists + install the packages we need. `apt-get upgrade` was
18
+ # removed from the critical path — unattended-upgrades handles security
19
+ # patches async. Saves 30-60s per deploy.
20
+ apt-get update -qq
21
+ apt-get install -y -qq curl jq docker.io docker-buildx
22
+
23
+ # Validate k3s version is set
24
+ K3S_TARGET_VERSION="${k3s_version}"
25
+ if [ -z "$K3S_TARGET_VERSION" ]; then
26
+ echo "ERROR: k3s_version not set"
27
+ exit 1
28
+ fi
29
+ echo "Installing k3s version: $K3S_TARGET_VERSION"
30
+
31
+ # IDENTICAL block in master-init.sh / worker-init.sh / supabase-init.sh — keep in sync.
32
+ # (Three-way duplication is acceptable here because the cloud-init scripts are
33
+ # rendered independently per role; extracting a shared snippet would require
34
+ # restructuring the renderScript() pipeline. Out of scope for Phase 1.)
35
+ # Configure containerd to mirror pulls for 10.0.1.1:5000 to the local registry
36
+ # we run on master. Cluster-autoscaler-spawned workers pull the app image from
37
+ # here on-demand (sideload only reaches workers that exist at sideload time).
38
+ # k3s only reads /etc/rancher/k3s/registries.yaml on agent start, so this MUST
39
+ # land before the k3s install step below.
40
+ #
41
+ # Plain http://10.0.1.1:5000 — the registry runs HTTP on the private network.
42
+ # Do NOT add `insecure_skip_verify: true` here: that flag only affects HTTPS
43
+ # endpoints, and recent k3s versions place it incorrectly when present
44
+ # (k3s-io/k3s#13215), which can break containerd config generation.
45
+ mkdir -p /etc/rancher/k3s
46
+ cat > /etc/rancher/k3s/registries.yaml << 'REGEOF'
47
+ mirrors:
48
+ "10.0.1.1:5000":
49
+ endpoint:
50
+ - "http://10.0.1.1:5000"
51
+ REGEOF
52
+
53
+ # Configure Floating IP on the OS so the kernel accepts packets destined for it.
54
+ # Hetzner routes the Floating IP to this server at the network level, but without
55
+ # a local address binding the kernel drops the packets.
56
+ # Use `ip addr add` instead of netplan — a separate netplan file that redefines
57
+ # ethernets.eth0 can override Hetzner's cloud-init config and drop the primary IP.
58
+ ip addr add ${floating_ip}/32 dev eth0 2>/dev/null || true
59
+
60
+ # Persist across reboots via a long-running systemd service (netplan-safe).
61
+ # Must be Type=simple (not oneshot) so it survives DHCP renewals — when networkd
62
+ # re-applies the cloud-init netplan config it can flush manually-added addresses.
63
+ # The loop re-adds the floating IP within 30 seconds if that happens.
64
+ cat > /etc/systemd/system/floating-ip.service << FIPEOF
65
+ [Unit]
66
+ Description=Maintain Hetzner Floating IP
67
+ After=network-online.target
68
+ Wants=network-online.target
69
+
70
+ [Service]
71
+ Type=simple
72
+ ExecStart=/bin/bash -c 'while true; do if ! ip addr show eth0 | grep -q "${floating_ip}"; then ip addr add ${floating_ip}/32 dev eth0 && echo "Floating IP re-added"; fi; sleep 30; done'
73
+ Restart=always
74
+ RestartSec=5
75
+
76
+ [Install]
77
+ WantedBy=multi-user.target
78
+ FIPEOF
79
+ systemctl daemon-reload
80
+ systemctl enable floating-ip.service
81
+
82
+ # Get node IPs for k3s configuration
83
+ PUBLIC_IP=$(curl -s --max-time 10 http://169.254.169.254/hetzner/v1/metadata/public-ipv4)
84
+
85
+ # Wait for the private network interface (10.0.x.x) to be assigned.
86
+ # Hetzner attaches the private network after the server boots, so the interface
87
+ # may not exist yet when cloud-init runs. grep exits 1 if no match, which kills
88
+ # the script under set -euo pipefail — so we retry with || true.
89
+ PRIVATE_IFACE=""
90
+ RETRY_COUNT=0
91
+ MAX_RETRIES=120
92
+ DHCP_TRIGGERED=false
93
+ echo "Waiting for private network interface..."
94
+ while [ -z "$PRIVATE_IFACE" ] && [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
95
+ PRIVATE_IFACE=$(ip -4 addr show | grep 'inet 10\.0\.' | awk '{print $NF}' || true)
96
+ if [ -z "$PRIVATE_IFACE" ]; then
97
+ # See worker-init.sh for the dhcpcd-race RCA. Same recovery applies here.
98
+ if [ "$DHCP_TRIGGERED" = "false" ] && [ $RETRY_COUNT -ge 6 ] && command -v dhcpcd >/dev/null 2>&1; then
99
+ CANDIDATE=$(ip -o link show 2>/dev/null | awk -F': ' '/^[0-9]+: en[a-z]+[0-9]+s[0-9]+/ {print $2}' | grep -v '^eth' | head -1 || true)
100
+ if [ -n "$CANDIDATE" ]; then
101
+ DHCP_TRIGGERED=true
102
+ echo "Private NIC $CANDIDATE has no lease after 30s — triggering dhcpcd"
103
+ ip link set "$CANDIDATE" up 2>&1 || true
104
+ dhcpcd -1 "$CANDIDATE" 2>&1 | sed 's/^/ dhcpcd: /' || true
105
+ fi
106
+ fi
107
+ if [ $((RETRY_COUNT % 12)) -eq 0 ]; then
108
+ echo "Private interface not ready yet... ($RETRY_COUNT/$MAX_RETRIES)"
109
+ fi
110
+ RETRY_COUNT=$((RETRY_COUNT + 1))
111
+ sleep 5
112
+ fi
113
+ done
114
+ if [ -z "$PRIVATE_IFACE" ]; then
115
+ echo "FATAL: Private network interface not found after $MAX_RETRIES retries"
116
+ echo "Hetzner private network may not be attached to this server."
117
+ exit 1
118
+ fi
119
+ echo "Private interface: $PRIVATE_IFACE"
120
+ PRIVATE_IP=$(ip -4 addr show "$PRIVATE_IFACE" 2>/dev/null | grep -oP 'inet \K[\d.]+' || echo "")
121
+
122
+ # Install k3s master with pre-shared token.
123
+ # --node-ip must be the PUBLIC IP so Hetzner CCM can match it against the Hetzner API
124
+ # and remove the node.cloudprovider.kubernetes.io/uninitialized taint.
125
+ # --flannel-iface routes pod-to-pod traffic over the private network.
126
+ #
127
+ # The k3s install script itself fetches https://github.com/k3s-io/k3s/releases/... and
128
+ # GitHub routinely returns 504 for brief windows. The outer curl has --retry 3, but
129
+ # GitHub failures happen inside the install script where we can't hand --retry through.
130
+ # Wrap the whole pipeline in a bash retry loop — up to 5 attempts with 20s backoff —
131
+ # so a transient CDN hiccup doesn't kill a fresh provision.
132
+ K3S_INSTALL_OK=false
133
+ for attempt in 1 2 3 4 5; do
134
+ if curl -sfL --max-time 120 --retry 3 --retry-delay 10 https://get.k3s.io | INSTALL_K3S_VERSION="${k3s_version}" sh -s - server \
135
+ --cluster-init \
136
+ --token "${k3s_token}" \
137
+ --tls-san "$PUBLIC_IP" \
138
+ --tls-san "${floating_ip}" \
139
+ --node-ip "$PUBLIC_IP" \
140
+ --node-external-ip "$PUBLIC_IP" \
141
+ --advertise-address "$PUBLIC_IP" \
142
+ --flannel-iface "$PRIVATE_IFACE" \
143
+ --disable traefik \
144
+ --disable servicelb \
145
+ --disable-cloud-controller \
146
+ --flannel-backend=wireguard-native \
147
+ --kubelet-arg="cloud-provider=external" \
148
+ --write-kubeconfig-mode=644; then
149
+ K3S_INSTALL_OK=true
150
+ break
151
+ fi
152
+ echo "k3s install attempt $attempt failed (likely transient GitHub/CDN issue), retrying in 20s..."
153
+ sleep 20
154
+ done
155
+ if [ "$K3S_INSTALL_OK" != "true" ]; then
156
+ echo "k3s install failed after 5 attempts — check GitHub CDN status" >&2
157
+ exit 1
158
+ fi
159
+
160
+ # Wait for k3s to be ready (max 3 minutes — if it hasn't started by then, something is wrong)
161
+ K3S_READY=false
162
+ for i in $(seq 1 36); do
163
+ if kubectl get nodes 2>/dev/null | grep -q "Ready"; then
164
+ K3S_READY=true
165
+ break
166
+ fi
167
+ echo "Waiting for k3s to be ready... ($i/36)"
168
+ sleep 5
169
+ done
170
+ if [ "$K3S_READY" != "true" ]; then
171
+ echo "FATAL: k3s did not become ready within 3 minutes"
172
+ echo "k3s service status:"
173
+ systemctl status k3s --no-pager 2>&1 || true
174
+ journalctl -u k3s --no-pager -n 20 2>&1 || true
175
+ exit 1
176
+ fi
177
+
178
+ # Marker for vibecarbon's deployK3s waiter — set AFTER hcloud Secret + CCM/CSI
179
+ # install below complete (see end of script). Keeps the early-readiness signal
180
+ # distinct from "fully provisioned and ready for app install."
181
+
182
+ # Create secret for Hetzner Cloud Controller Manager
183
+ kubectl -n kube-system create secret generic hcloud \
184
+ --from-literal=token="${hcloud_token}" \
185
+ --from-literal=network="${network_id}" \
186
+ --dry-run=client -o yaml | kubectl apply -f -
187
+
188
+ # Create secret for Hetzner CSI Driver
189
+ kubectl -n kube-system create secret generic hcloud-csi \
190
+ --from-literal=token="${hcloud_token}" \
191
+ --dry-run=client -o yaml | kubectl apply -f -
192
+
193
+ # Install Hetzner Cloud Controller Manager
194
+ # Use ccm.yaml (not ccm-networks.yaml) since k3s manages pod networking via flannel
195
+ # Retry up to 3 times — kubectl apply can fail if API server is briefly unavailable
196
+ for i in 1 2 3; do
197
+ kubectl apply -f https://github.com/hetznercloud/hcloud-cloud-controller-manager/releases/download/v1.20.0/ccm.yaml && break
198
+ echo "CCM install attempt $i failed, retrying in 10s..."
199
+ sleep 10
200
+ done
201
+
202
+ # Install Hetzner CSI Driver
203
+ for i in 1 2 3; do
204
+ kubectl apply -f https://raw.githubusercontent.com/hetznercloud/csi-driver/v2.9.0/deploy/kubernetes/hcloud-csi.yml && break
205
+ echo "CSI install attempt $i failed, retrying in 10s..."
206
+ sleep 10
207
+ done
208
+
209
+ echo "k3s master installation complete!"
210
+
211
+ # Final marker: vibecarbon's deployK3s polls for /tmp/k3s-ready before fetching
212
+ # kubeconfig + applying app manifests. Written here so the marker only fires
213
+ # after k3s + hcloud secrets + CCM + CSI are all in place — i.e., the cluster
214
+ # is ready for real workloads, not just "k3s daemon is up."
215
+ touch /tmp/k3s-ready
@@ -0,0 +1,167 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # Note: This script runs AS PART of cloud-init (user_data), so we cannot wait for
5
+ # cloud-init to complete (that would cause a deadlock). The script starts immediately.
6
+
7
+ # Wait for any dpkg locks held by unattended-upgrades (runs on first boot).
8
+ for i in $(seq 1 30); do
9
+ if ! fuser /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; then
10
+ break
11
+ fi
12
+ echo "Waiting for dpkg lock to be released... ($i/30)"
13
+ sleep 10
14
+ done
15
+
16
+ # Update apt lists + install just what we need. `apt-get upgrade` was removed
17
+ # from this path — we don't need every security update applied before the node
18
+ # joins the cluster (unattended-upgrades handles that async in the background),
19
+ # and it used to add 30-60s to every deploy.
20
+ apt-get update -qq
21
+ apt-get install -y -qq curl jq
22
+
23
+ # Validate k3s version is set
24
+ K3S_TARGET_VERSION="${k3s_version}"
25
+ if [ -z "$K3S_TARGET_VERSION" ]; then
26
+ echo "ERROR: k3s_version not set"
27
+ exit 1
28
+ fi
29
+ echo "Installing k3s version: $K3S_TARGET_VERSION"
30
+
31
+ # IDENTICAL block in master-init.sh / worker-init.sh / supabase-init.sh — keep in sync.
32
+ # (Three-way duplication is acceptable here because the cloud-init scripts are
33
+ # rendered independently per role; extracting a shared snippet would require
34
+ # restructuring the renderScript() pipeline. Out of scope for Phase 1.)
35
+ # Configure containerd to mirror pulls for 10.0.1.1:5000 to the local registry
36
+ # running on master. Cluster-autoscaler-spawned workers pull the app image from
37
+ # here on-demand (sideload only reaches workers that exist at sideload time).
38
+ # k3s only reads /etc/rancher/k3s/registries.yaml on agent start, so this MUST
39
+ # land before the k3s install step below.
40
+ #
41
+ # Plain http://10.0.1.1:5000 — the registry runs HTTP on the private network.
42
+ # Do NOT add `insecure_skip_verify: true` here: that flag only affects HTTPS
43
+ # endpoints, and recent k3s versions place it incorrectly when present
44
+ # (k3s-io/k3s#13215), which can break containerd config generation.
45
+ mkdir -p /etc/rancher/k3s
46
+ cat > /etc/rancher/k3s/registries.yaml << 'REGEOF'
47
+ mirrors:
48
+ "10.0.1.1:5000":
49
+ endpoint:
50
+ - "http://10.0.1.1:5000"
51
+ REGEOF
52
+
53
+ # Get node IPs for k3s configuration
54
+ PUBLIC_IP=$(curl -s --max-time 10 http://169.254.169.254/hetzner/v1/metadata/public-ipv4)
55
+
56
+ # Wait for the private network interface (10.0.x.x) to be assigned.
57
+ # Hetzner attaches the private network after the server boots, so the interface
58
+ # may not exist yet when cloud-init runs. grep exits 1 if no match, which kills
59
+ # the script under set -euo pipefail — so we retry with || true.
60
+ #
61
+ # This must happen BEFORE the master-readyz probe below, because that probe
62
+ # uses the master's private IP (10.0.1.1) — unreachable until our private NIC
63
+ # is up. See worker-init.sh for the full RCA.
64
+ PRIVATE_IFACE=""
65
+ RETRY_COUNT=0
66
+ MAX_RETRIES=120
67
+ DHCP_TRIGGERED=false
68
+ echo "Waiting for private network interface..."
69
+ while [ -z "$PRIVATE_IFACE" ] && [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
70
+ PRIVATE_IFACE=$(ip -4 addr show | grep 'inet 10\.0\.' | awk '{print $NF}' || true)
71
+ if [ -z "$PRIVATE_IFACE" ]; then
72
+ if [ "$DHCP_TRIGGERED" = "false" ] && [ $RETRY_COUNT -ge 6 ] && command -v dhcpcd >/dev/null 2>&1; then
73
+ CANDIDATE=$(ip -o link show 2>/dev/null | awk -F': ' '/^[0-9]+: en[a-z]+[0-9]+s[0-9]+/ {print $2}' | grep -v '^eth' | head -1 || true)
74
+ if [ -n "$CANDIDATE" ]; then
75
+ DHCP_TRIGGERED=true
76
+ echo "Private NIC $CANDIDATE has no lease after 30s — triggering dhcpcd"
77
+ ip link set "$CANDIDATE" up 2>&1 || true
78
+ dhcpcd -1 "$CANDIDATE" 2>&1 | sed 's/^/ dhcpcd: /' || true
79
+ fi
80
+ fi
81
+ if [ $((RETRY_COUNT % 12)) -eq 0 ]; then
82
+ echo "Private interface not ready yet... ($RETRY_COUNT/$MAX_RETRIES)"
83
+ fi
84
+ RETRY_COUNT=$((RETRY_COUNT + 1))
85
+ sleep 5
86
+ fi
87
+ done
88
+ if [ -z "$PRIVATE_IFACE" ]; then
89
+ echo "FATAL: Private network interface not found after $MAX_RETRIES retries"
90
+ exit 1
91
+ fi
92
+ echo "Private interface: $PRIVATE_IFACE"
93
+ PRIVATE_IP=$(ip -4 addr show "$PRIVATE_IFACE" 2>/dev/null | grep -oP 'inet \K[\d.]+' || echo "")
94
+
95
+ # Wait for master k3s API to be ready before joining (uses private IP — must
96
+ # come AFTER private-NIC bring-up above).
97
+ MAX_RETRIES=120
98
+ RETRY_COUNT=0
99
+
100
+ echo "Waiting for master k3s API to be ready..."
101
+ while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
102
+ if curl -sk --max-time 5 "https://${master_ip}:6443/readyz" >/dev/null 2>&1; then
103
+ echo "Master k3s API is ready!"
104
+ break
105
+ fi
106
+
107
+ if [ $((RETRY_COUNT % 12)) -eq 0 ]; then
108
+ echo "Master not ready yet... ($RETRY_COUNT/$MAX_RETRIES)"
109
+ fi
110
+ RETRY_COUNT=$((RETRY_COUNT + 1))
111
+ sleep 5
112
+ done
113
+
114
+ if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
115
+ echo "Warning: Master may not be fully ready, attempting to join anyway..."
116
+ fi
117
+
118
+ # Install k3s agent as dedicated Supabase node.
119
+ # --node-ip must be the PUBLIC IP so Hetzner CCM can match it (see master-init.sh).
120
+ # Bash retry loop around the whole pipeline — the k3s install script fetches
121
+ # from github.com which returns transient 504s under load. 5 attempts, 20s backoff.
122
+ K3S_INSTALL_OK=false
123
+ for attempt in 1 2 3 4 5; do
124
+ if curl -sfL --max-time 120 --retry 3 --retry-delay 10 https://get.k3s.io | INSTALL_K3S_VERSION="${k3s_version}" K3S_URL="https://${master_ip}:6443" K3S_TOKEN="${k3s_token}" sh -s - agent \
125
+ --node-ip "$PUBLIC_IP" \
126
+ --node-external-ip "$PUBLIC_IP" \
127
+ --flannel-iface "$PRIVATE_IFACE" \
128
+ --kubelet-arg="cloud-provider=external" \
129
+ --node-label="dedicated=supabase" \
130
+ --node-label="node-pool=supabase-pool" \
131
+ --node-taint="dedicated=supabase:NoSchedule"; then
132
+ K3S_INSTALL_OK=true
133
+ break
134
+ fi
135
+ echo "k3s supabase install attempt $attempt failed (likely transient GitHub/CDN issue), retrying in 20s..."
136
+ sleep 20
137
+ done
138
+ if [ "$K3S_INSTALL_OK" != "true" ]; then
139
+ echo "k3s supabase install failed after 5 attempts — check GitHub CDN status" >&2
140
+ exit 1
141
+ fi
142
+
143
+ echo "k3s supabase node installation complete!"
144
+
145
+ # Pre-warm containerd image cache in the background so the Supabase HelmRelease
146
+ # doesn't pay the full ~400MB postgres pull on its critical path. We only
147
+ # pre-pull stable-name images that supabase-community pins conservatively;
148
+ # version drift just means a cache miss (not wrong data).
149
+ #
150
+ # Runs async so the node can be marked Ready immediately — the main deploy
151
+ # doesn't block on this. If the pull is still in-flight when the chart
152
+ # schedules a pod, containerd deduplicates the concurrent pulls anyway.
153
+ nohup bash -c '
154
+ for i in $(seq 1 60); do
155
+ [ -S /run/k3s/containerd/containerd.sock ] && break
156
+ sleep 5
157
+ done
158
+ # Heaviest base images in the Supabase stack (~400MB combined). Pinned
159
+ # tags match supabase-community chart defaults at time of authoring.
160
+ for img in \
161
+ docker.io/supabase/postgres:15.1.1.78 \
162
+ docker.io/library/kong:2.8.1 \
163
+ ; do
164
+ /usr/local/bin/k3s crictl pull "$img" 2>&1 || echo "Pre-pull skipped: $img"
165
+ done
166
+ ' > /var/log/supabase-image-prewarm.log 2>&1 &
167
+
@@ -0,0 +1,147 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # Note: This script runs AS PART of cloud-init (user_data), so we cannot wait for
5
+ # cloud-init to complete (that would cause a deadlock). The script starts immediately.
6
+
7
+ # Wait for any dpkg locks held by unattended-upgrades (runs on first boot).
8
+ for i in $(seq 1 30); do
9
+ if ! fuser /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; then
10
+ break
11
+ fi
12
+ echo "Waiting for dpkg lock to be released... ($i/30)"
13
+ sleep 10
14
+ done
15
+
16
+ # Update apt lists + install the packages we need. `apt-get upgrade` was
17
+ # removed from the critical path — unattended-upgrades handles security
18
+ # patches async. Saves 30-60s per deploy.
19
+ apt-get update -qq
20
+ apt-get install -y -qq curl jq
21
+
22
+ # Validate k3s version is set
23
+ K3S_TARGET_VERSION="${k3s_version}"
24
+ if [ -z "$K3S_TARGET_VERSION" ]; then
25
+ echo "ERROR: k3s_version not set"
26
+ exit 1
27
+ fi
28
+ echo "Installing k3s version: $K3S_TARGET_VERSION"
29
+
30
+ # IDENTICAL block in master-init.sh / worker-init.sh / supabase-init.sh — keep in sync.
31
+ # (Three-way duplication is acceptable here because the cloud-init scripts are
32
+ # rendered independently per role; extracting a shared snippet would require
33
+ # restructuring the renderScript() pipeline. Out of scope for Phase 1.)
34
+ # Configure containerd to mirror pulls for 10.0.1.1:5000 to the local registry
35
+ # running on master. Cluster-autoscaler-spawned workers pull the app image from
36
+ # here on-demand (sideload only reaches workers that exist at sideload time).
37
+ # k3s only reads /etc/rancher/k3s/registries.yaml on agent start, so this MUST
38
+ # land before the k3s install step below.
39
+ #
40
+ # Plain http://10.0.1.1:5000 — the registry runs HTTP on the private network.
41
+ # Do NOT add `insecure_skip_verify: true` here: that flag only affects HTTPS
42
+ # endpoints, and recent k3s versions place it incorrectly when present
43
+ # (k3s-io/k3s#13215), which can break containerd config generation.
44
+ mkdir -p /etc/rancher/k3s
45
+ cat > /etc/rancher/k3s/registries.yaml << 'REGEOF'
46
+ mirrors:
47
+ "10.0.1.1:5000":
48
+ endpoint:
49
+ - "http://10.0.1.1:5000"
50
+ REGEOF
51
+
52
+ # Get node IPs for k3s configuration
53
+ PUBLIC_IP=$(curl -s --max-time 10 http://169.254.169.254/hetzner/v1/metadata/public-ipv4)
54
+
55
+ # Wait for the private network interface (10.0.x.x) to be assigned.
56
+ # Hetzner attaches the private network after the server boots, so the interface
57
+ # may not exist yet when cloud-init runs. grep exits 1 if no match, which kills
58
+ # the script under set -euo pipefail — so we retry with || true.
59
+ #
60
+ # This must happen BEFORE the master-readyz probe below, because that probe
61
+ # uses the master's private IP (10.0.1.1) — unreachable until our private NIC
62
+ # is up. Workers stuck in master-readyz with no private NIC was the failure
63
+ # mode in k8s-ha 2026-05-01 deploy run (yir52p, primary-worker-1): hung 600s
64
+ # in "Master not ready yet..." while enp7s0 sat in state DOWN with no IP.
65
+ PRIVATE_IFACE=""
66
+ RETRY_COUNT=0
67
+ MAX_RETRIES=120
68
+ DHCP_TRIGGERED=false
69
+ echo "Waiting for private network interface..."
70
+ while [ -z "$PRIVATE_IFACE" ] && [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
71
+ PRIVATE_IFACE=$(ip -4 addr show | grep 'inet 10\.0\.' | awk '{print $NF}' || true)
72
+ if [ -z "$PRIVATE_IFACE" ]; then
73
+ # After 30s with no 10.0.x.x address, actively trigger dhcpcd on any
74
+ # unmanaged enp* NIC. Hetzner ships dhcpcd-base + auto-starts dhcpcd at
75
+ # boot, but it races with the post-boot Hetzner private-network
76
+ # attachment. When dhcpcd loses the race the interface stays DOWN and no
77
+ # IP is ever requested — running `dhcpcd -1 <iface>` once obtains the
78
+ # lease idempotently. Skip if already triggered or dhcpcd missing.
79
+ if [ "$DHCP_TRIGGERED" = "false" ] && [ $RETRY_COUNT -ge 6 ] && command -v dhcpcd >/dev/null 2>&1; then
80
+ CANDIDATE=$(ip -o link show 2>/dev/null | awk -F': ' '/^[0-9]+: en[a-z]+[0-9]+s[0-9]+/ {print $2}' | grep -v '^eth' | head -1 || true)
81
+ if [ -n "$CANDIDATE" ]; then
82
+ DHCP_TRIGGERED=true
83
+ echo "Private NIC $CANDIDATE has no lease after 30s — triggering dhcpcd"
84
+ ip link set "$CANDIDATE" up 2>&1 || true
85
+ dhcpcd -1 "$CANDIDATE" 2>&1 | sed 's/^/ dhcpcd: /' || true
86
+ fi
87
+ fi
88
+ if [ $((RETRY_COUNT % 12)) -eq 0 ]; then
89
+ echo "Private interface not ready yet... ($RETRY_COUNT/$MAX_RETRIES)"
90
+ fi
91
+ RETRY_COUNT=$((RETRY_COUNT + 1))
92
+ sleep 5
93
+ fi
94
+ done
95
+ if [ -z "$PRIVATE_IFACE" ]; then
96
+ echo "FATAL: Private network interface not found after $MAX_RETRIES retries"
97
+ exit 1
98
+ fi
99
+ echo "Private interface: $PRIVATE_IFACE"
100
+ PRIVATE_IP=$(ip -4 addr show "$PRIVATE_IFACE" 2>/dev/null | grep -oP 'inet \K[\d.]+' || echo "")
101
+
102
+ # Wait for master k3s API to be ready before joining (uses private IP — must
103
+ # come AFTER private-NIC bring-up above).
104
+ MAX_RETRIES=120
105
+ RETRY_COUNT=0
106
+
107
+ echo "Waiting for master k3s API to be ready..."
108
+ while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
109
+ if curl -sk --max-time 5 "https://${master_ip}:6443/readyz" >/dev/null 2>&1; then
110
+ echo "Master k3s API is ready!"
111
+ break
112
+ fi
113
+
114
+ if [ $((RETRY_COUNT % 12)) -eq 0 ]; then
115
+ echo "Master not ready yet... ($RETRY_COUNT/$MAX_RETRIES)"
116
+ fi
117
+ RETRY_COUNT=$((RETRY_COUNT + 1))
118
+ sleep 5
119
+ done
120
+
121
+ if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
122
+ echo "Warning: Master may not be fully ready, attempting to join anyway..."
123
+ fi
124
+
125
+ # Install k3s agent with pre-shared token.
126
+ # --node-ip must be the PUBLIC IP so Hetzner CCM can match it (see master-init.sh).
127
+ # Bash retry loop around the whole pipeline — the k3s install script fetches
128
+ # from github.com which returns transient 504s under load. 5 attempts, 20s backoff.
129
+ K3S_INSTALL_OK=false
130
+ for attempt in 1 2 3 4 5; do
131
+ if curl -sfL --max-time 120 --retry 3 --retry-delay 10 https://get.k3s.io | INSTALL_K3S_VERSION="${k3s_version}" K3S_URL="https://${master_ip}:6443" K3S_TOKEN="${k3s_token}" sh -s - agent \
132
+ --node-ip "$PUBLIC_IP" \
133
+ --node-external-ip "$PUBLIC_IP" \
134
+ --flannel-iface "$PRIVATE_IFACE" \
135
+ --kubelet-arg="cloud-provider=external"; then
136
+ K3S_INSTALL_OK=true
137
+ break
138
+ fi
139
+ echo "k3s worker install attempt $attempt failed (likely transient GitHub/CDN issue), retrying in 20s..."
140
+ sleep 20
141
+ done
142
+ if [ "$K3S_INSTALL_OK" != "true" ]; then
143
+ echo "k3s worker install failed after 5 attempts — check GitHub CDN status" >&2
144
+ exit 1
145
+ fi
146
+
147
+ echo "k3s worker installation complete!"
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "base-maia",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/client/index.css",
9
+ "baseColor": "gray",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "aliases": {
15
+ "components": "@/components",
16
+ "utils": "@/lib/utils",
17
+ "ui": "@/components/ui",
18
+ "lib": "@/lib",
19
+ "hooks": "@/hooks"
20
+ },
21
+ "menuColor": "default",
22
+ "menuAccent": "bold",
23
+ "registries": {}
24
+ }
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Authentication Guide
3
+ description: A complete guide to authentication features including OAuth, magic links, and MFA.
4
+ date: "2025-01-20"
5
+ author: Team
6
+ ---
7
+
8
+ # Authentication Guide
9
+
10
+ Your application comes with a full authentication system powered by Supabase Auth.
11
+
12
+ ## Supported Methods
13
+
14
+ - **Email & Password** — Traditional sign-up and sign-in
15
+ - **OAuth Providers** — Google, Microsoft, GitHub, Apple, Discord
16
+ - **Magic Links** — Passwordless sign-in via email
17
+ - **Multi-Factor Authentication** — TOTP-based MFA for added security
18
+
19
+ ## Enabling OAuth Providers
20
+
21
+ OAuth providers are configured in your Supabase dashboard and toggled via environment variables:
22
+
23
+ ```bash
24
+ GITHUB_ENABLED=true
25
+ APPLE_ENABLED=true
26
+ DISCORD_ENABLED=true
27
+ MAGIC_LINK_ENABLED=true
28
+ ```
29
+
30
+ The sign-in page automatically shows buttons for enabled providers.
31
+
32
+ ## Row-Level Security
33
+
34
+ All database access is secured with Row-Level Security (RLS) policies. Users can only access data they're authorized to see, enforced at the database level.
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Getting Started
3
+ description: Learn how to set up your project and start building your SaaS application.
4
+ date: "2025-01-15"
5
+ author: Team
6
+ ---
7
+
8
+ # Getting Started
9
+
10
+ Welcome to your new SaaS application! This guide will help you get up and running quickly.
11
+
12
+ ## Prerequisites
13
+
14
+ Before you begin, make sure you have:
15
+
16
+ - **Node.js 22+** installed
17
+ - **Docker** running for local development
18
+ - **pnpm** as your package manager
19
+
20
+ ## Quick Start
21
+
22
+ 1. Start the development environment:
23
+
24
+ ```bash
25
+ pnpm dev:start
26
+ ```
27
+
28
+ This command will:
29
+ - Start Docker containers (Supabase, PostgreSQL, etc.)
30
+ - Run database migrations
31
+ - Launch the API server and Vite dev server
32
+
33
+ 2. Open your browser to `http://app.localhost`
34
+
35
+ 3. Sign in with your admin credentials
36
+
37
+ ## Next Steps
38
+
39
+ - Configure your [Stripe billing](/settings/billing) to start accepting payments
40
+ - Set up [OAuth providers](/settings/security) for social login
41
+ - Invite your [team members](/dashboard) to collaborate
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: "Initial Release"
3
+ description: "The first release of {{PROJECT_NAME}} with core features including authentication, billing, and infrastructure."
4
+ date: "2025-01-15"
5
+ version: "0.1.0"
6
+ ---
7
+
8
+ ## What's New
9
+
10
+ ### Authentication
11
+ - Email/password sign-up and sign-in
12
+ - OAuth providers (Google, Microsoft, GitHub, Apple, Discord)
13
+ - Magic link authentication
14
+ - Multi-factor authentication (TOTP)
15
+ - Account lockout protection
16
+
17
+ ### Billing
18
+ - Stripe integration with subscription management
19
+ - Free, Startup, and Pro plans
20
+ - Customer portal for self-service billing
21
+ - Webhook-driven subscription lifecycle
22
+
23
+ ### Infrastructure
24
+ - Self-hosted Supabase (PostgreSQL, Auth, REST API, Realtime, Storage)
25
+ - Docker Compose for local development
26
+ - Kubernetes manifests with Kustomize overlays
27
+ - High-availability deployment with PostgreSQL replication
28
+ - Traefik reverse proxy with automatic SSL
29
+
30
+ ### Admin Panel
31
+ - Super admin dashboard with service health monitoring
32
+ - User and organization management
33
+ - System-wide notification management
34
+ - User impersonation for support
35
+
36
+ ### Developer Experience
37
+ - Full TypeScript across client and server
38
+ - Biome for linting and formatting
39
+ - Vitest test suite
40
+ - AI editor rules (Claude Code, Cursor, Windsurf, Copilot)