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,508 @@
1
+ # Vibecarbon Docker Compose
2
+ # Supabase self-hosted + Hono API + Traefik reverse proxy
3
+
4
+ services:
5
+ # ===========================================
6
+ # REVERSE PROXY
7
+ # ===========================================
8
+ traefik:
9
+ image: traefik:v3.6.11
10
+ container_name: ${PROJECT_NAME}-traefik
11
+ restart: unless-stopped
12
+ security_opt:
13
+ - no-new-privileges:true
14
+ cap_drop:
15
+ - ALL
16
+ cap_add:
17
+ - NET_BIND_SERVICE
18
+ read_only: true
19
+ tmpfs:
20
+ - /tmp
21
+ command:
22
+ - "--api.dashboard=true"
23
+ - "--api.insecure=true"
24
+ - "--providers.docker=true"
25
+ - "--providers.docker.endpoint=unix:///var/run/docker.sock"
26
+ - "--providers.docker.exposedbydefault=false"
27
+ - "--providers.file.directory=/etc/traefik/dynamic"
28
+ - "--entrypoints.web.address=:80"
29
+ - "--log.level=INFO"
30
+ ports:
31
+ - "${DEV_TRAEFIK_PORT:-80}:80"
32
+ volumes:
33
+ - /var/run/docker.sock:/var/run/docker.sock:ro
34
+ - ./volumes/traefik:/etc/traefik/dynamic:ro
35
+ networks:
36
+ - vibecarbon-network
37
+ labels:
38
+ - "traefik.enable=true"
39
+ # Subdomain routing - auth added via prod overlay (docker-compose.prod.yml)
40
+ - "traefik.http.routers.dashboard.rule=Host(`traefik.${DOMAIN:-localhost}`)"
41
+ - "traefik.http.routers.dashboard.entrypoints=web"
42
+ - "traefik.http.routers.dashboard.service=api@internal"
43
+
44
+ # ===========================================
45
+ # APPLICATION
46
+ # ===========================================
47
+ app:
48
+ build:
49
+ context: .
50
+ args:
51
+ VITE_PROJECT_NAME: ${PROJECT_NAME}
52
+ VITE_SUPABASE_URL: ${SITE_URL}
53
+ VITE_SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
54
+ VITE_PLAUSIBLE_DOMAIN: ${VITE_PLAUSIBLE_DOMAIN:-}
55
+ VITE_PLAUSIBLE_SCRIPT_URL: ${VITE_PLAUSIBLE_SCRIPT_URL:-}
56
+ container_name: ${PROJECT_NAME}-app
57
+ restart: unless-stopped
58
+ security_opt:
59
+ - no-new-privileges:true
60
+ cap_drop:
61
+ - ALL
62
+ read_only: true
63
+ tmpfs:
64
+ - /tmp
65
+ environment:
66
+ - NODE_ENV=production
67
+ - SUPABASE_URL=http://kong:8000
68
+ - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
69
+ - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}
70
+ - SITE_URL=${SITE_URL:-http://localhost:5173}
71
+ depends_on:
72
+ # The Hono backend uses the Supabase JS client (calls flow through Kong)
73
+ # and never touches postgres directly, so we don't need `db: healthy`
74
+ # gating app startup. `service_started` on both lets the app boot in
75
+ # parallel with db's ~20-30s initial warmup.
76
+ db:
77
+ condition: service_started
78
+ kong:
79
+ condition: service_started
80
+ networks:
81
+ - vibecarbon-network
82
+ labels:
83
+ - "traefik.enable=true"
84
+ - "traefik.http.routers.app.rule=Host(`localhost`)"
85
+ - "traefik.http.routers.app.entrypoints=web"
86
+ - "traefik.http.services.app.loadbalancer.server.port=3000"
87
+
88
+ # ===========================================
89
+ # SUPABASE CORE SERVICES
90
+ # ===========================================
91
+
92
+ # PostgreSQL Database
93
+ db:
94
+ build:
95
+ context: ./db
96
+ image: ${PROJECT_NAME}-db:latest
97
+ # The db image is built locally from ./db (no registry to pull from).
98
+ # Without this, compose's default `pull_policy: missing` first attempts
99
+ # a Docker Hub pull, which 401s with "pull access denied for {image}"
100
+ # before falling back to the local build. Functional but scary noise on
101
+ # every `docker compose up` invocation.
102
+ pull_policy: build
103
+ container_name: ${PROJECT_NAME}-db
104
+ restart: unless-stopped
105
+ security_opt:
106
+ - no-new-privileges:true
107
+ healthcheck:
108
+ test: ["CMD", "pg_isready", "-U", "postgres", "-h", "localhost"]
109
+ interval: 5s
110
+ timeout: 5s
111
+ retries: 10
112
+ # First-time init runs all Supabase migrations + WAL-G init before the
113
+ # server accepts TCP connections (~60-150s under fanout-3 load — observed
114
+ # restore re-deploy failing at deploy.compose.up=160s while the same db
115
+ # eventually became healthy ~3min later, fanout9 e1 2026-05-01). Without
116
+ # start_period, retries × interval = 50s expires before first init
117
+ # completes, compose marks db unhealthy, and dependent services fail
118
+ # with "dependency failed to start". start_period suppresses the
119
+ # unhealthy verdict during initial boot.
120
+ start_period: 180s
121
+ command:
122
+ - postgres
123
+ - -c
124
+ - config_file=/etc/postgresql/postgresql.conf
125
+ - -c
126
+ - log_min_messages=fatal
127
+ - -c
128
+ - wal_level=replica
129
+ - -c
130
+ - archive_mode=on
131
+ - -c
132
+ - archive_command=/usr/local/bin/wal-g wal-push %p
133
+ - -c
134
+ - archive_timeout=60
135
+ - -c
136
+ # hot_standby=on lets a server in recovery mode (i.e. our standby)
137
+ # accept read-only psql connections. Required so failover's
138
+ # pg_promote() call can connect to the standby (psql connections
139
+ # otherwise return "database is not accepting connections / Hot
140
+ # standby mode is disabled" and pg_promote can't be invoked).
141
+ # No-op on the primary — hot_standby only affects standbys. PG15
142
+ # default is on, but supabase/postgres:15.8.1.085 ships with it
143
+ # off, so set it explicitly. RCA: compose-ha 2026-05-01 fanout13
144
+ # failover — pg_promote retried 5 times against an unreachable
145
+ # standby psql before aborting.
146
+ - hot_standby=on
147
+ environment:
148
+ POSTGRES_HOST: /var/run/postgresql
149
+ PGPORT: 5432
150
+ POSTGRES_PORT: 5432
151
+ PGPASSWORD: ${POSTGRES_PASSWORD}
152
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
153
+ PGDATABASE: postgres
154
+ POSTGRES_DB: postgres
155
+ JWT_SECRET: ${JWT_SECRET}
156
+ JWT_EXP: 3600
157
+ # WAL-G Configuration
158
+ # `:-` defaults so local dev (no .env-set S3 creds) doesn't trigger
159
+ # `WARN The "S3_*" variable is not set` for every compose invocation.
160
+ # WAL-G is dormant locally without these anyway; the warns were pure
161
+ # noise.
162
+ WALG_S3_PREFIX: s3://${S3_BACKUP_BUCKET:-${S3_BUCKET:-}}/backups/${PROJECT_NAME}/walg
163
+ AWS_ACCESS_KEY_ID: ${S3_ACCESS_KEY:-}
164
+ AWS_SECRET_ACCESS_KEY: ${S3_SECRET_KEY:-}
165
+ AWS_ENDPOINT: ${S3_ENDPOINT:-}
166
+ AWS_REGION: ${S3_REGION:-us-east-1}
167
+ WALG_COMPRESSION_METHOD: lz4
168
+ volumes:
169
+ - db_data:/var/lib/postgresql/data
170
+ - ./volumes/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/98-roles.sql:Z
171
+ - ./volumes/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:Z
172
+ - ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
173
+ - ./volumes/db/set-passwords.sh:/docker-entrypoint-initdb.d/zz-set-passwords.sh:Z
174
+ - ./supabase/migrations:/migrations:ro
175
+ networks:
176
+ - vibecarbon-network
177
+
178
+ # Kong API Gateway
179
+ kong:
180
+ image: kong:3.9.1
181
+ container_name: ${PROJECT_NAME}-kong
182
+ restart: unless-stopped
183
+ security_opt:
184
+ - no-new-privileges:true
185
+ cap_drop:
186
+ - ALL
187
+ cap_add:
188
+ - SETGID
189
+ - SETUID
190
+ read_only: true
191
+ tmpfs:
192
+ - /tmp
193
+ ports:
194
+ - "${DEV_KONG_PORT:-8000}:8000/tcp"
195
+ - "${DEV_KONG_SSL_PORT:-8443}:8443/tcp"
196
+ healthcheck:
197
+ test: ["CMD", "kong", "health"]
198
+ interval: 10s
199
+ timeout: 5s
200
+ retries: 5
201
+ entrypoint: /home/kong/docker-entrypoint.sh
202
+ environment:
203
+ KONG_DATABASE: "off"
204
+ KONG_PREFIX: /tmp/kong
205
+ KONG_DECLARATIVE_CONFIG: /tmp/kong.yml
206
+ KONG_DNS_ORDER: LAST,A,CNAME
207
+ KONG_PLUGINS: request-transformer,cors,key-auth,acl
208
+ KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: 160k
209
+ KONG_NGINX_PROXY_PROXY_BUFFERS: 64 160k
210
+ SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
211
+ SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
212
+ volumes:
213
+ - ./volumes/kong/kong.yml:/home/kong/kong.yml.template:ro
214
+ - ./volumes/kong/docker-entrypoint.sh:/home/kong/docker-entrypoint.sh:ro
215
+ # Kong runs in DB-less mode (KONG_DATABASE: "off") — config comes from
216
+ # the declarative kong.yml volume. No postgres dependency at all, so
217
+ # we intentionally don't list `db` here. Kong can boot in parallel
218
+ # with the database, shaving ~20s off the compose cold start.
219
+ networks:
220
+ - vibecarbon-network
221
+
222
+ # GoTrue Authentication
223
+ auth:
224
+ image: supabase/gotrue:v2.186.0
225
+ container_name: ${PROJECT_NAME}-auth
226
+ restart: unless-stopped
227
+ security_opt:
228
+ - no-new-privileges:true
229
+ cap_drop:
230
+ - ALL
231
+ read_only: true
232
+ tmpfs:
233
+ - /tmp
234
+ healthcheck:
235
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9999/health"]
236
+ interval: 5s
237
+ timeout: 5s
238
+ retries: 3
239
+ environment:
240
+ GOTRUE_API_HOST: 0.0.0.0
241
+ GOTRUE_API_PORT: 9999
242
+ API_EXTERNAL_URL: ${SITE_URL}
243
+ GOTRUE_DB_DRIVER: postgres
244
+ GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@db:5432/postgres
245
+ GOTRUE_SITE_URL: ${SITE_URL}
246
+ GOTRUE_URI_ALLOW_LIST: "${SITE_URL}/**,http://localhost:${DEV_VITE_PORT:-5173}/**,http://localhost:${DEV_API_PORT:-3000}/**"
247
+ GOTRUE_DISABLE_SIGNUP: "false"
248
+ GOTRUE_JWT_ADMIN_ROLES: service_role
249
+ GOTRUE_JWT_AUD: authenticated
250
+ GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
251
+ GOTRUE_JWT_EXP: 3600
252
+ GOTRUE_JWT_SECRET: ${JWT_SECRET}
253
+ GOTRUE_EXTERNAL_EMAIL_ENABLED: "true"
254
+ GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: "false"
255
+ GOTRUE_MAILER_AUTOCONFIRM: "true"
256
+ # MFA/TOTP
257
+ GOTRUE_MFA_ENABLED: "true"
258
+ # OAuth Providers
259
+ GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED:-false}
260
+ GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
261
+ GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_CLIENT_SECRET:-}
262
+ GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${SITE_URL}/auth/v1/callback
263
+ GOTRUE_EXTERNAL_AZURE_ENABLED: ${MICROSOFT_ENABLED:-false}
264
+ GOTRUE_EXTERNAL_AZURE_CLIENT_ID: ${MICROSOFT_CLIENT_ID:-}
265
+ GOTRUE_EXTERNAL_AZURE_SECRET: ${MICROSOFT_CLIENT_SECRET:-}
266
+ GOTRUE_EXTERNAL_AZURE_URL: https://login.microsoftonline.com/${MICROSOFT_TENANT_ID:-common}
267
+ GOTRUE_EXTERNAL_AZURE_REDIRECT_URI: ${SITE_URL}/auth/v1/callback
268
+ # SMTP (optional)
269
+ GOTRUE_SMTP_HOST: ${SMTP_HOST:-}
270
+ GOTRUE_SMTP_PORT: ${SMTP_PORT:-587}
271
+ GOTRUE_SMTP_USER: ${SMTP_USER:-}
272
+ GOTRUE_SMTP_PASS: ${SMTP_PASS:-}
273
+ GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL:-}
274
+ GOTRUE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME:-}
275
+ GOTRUE_MAILER_URLPATHS_INVITE: /auth/v1/verify
276
+ GOTRUE_MAILER_URLPATHS_CONFIRMATION: /auth/v1/verify
277
+ GOTRUE_MAILER_URLPATHS_RECOVERY: /auth/v1/verify
278
+ GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE: /auth/v1/verify
279
+ depends_on:
280
+ db:
281
+ condition: service_healthy
282
+ networks:
283
+ - vibecarbon-network
284
+
285
+ # PostgREST API
286
+ rest:
287
+ image: postgrest/postgrest:v14.6
288
+ container_name: ${PROJECT_NAME}-rest
289
+ restart: unless-stopped
290
+ security_opt:
291
+ - no-new-privileges:true
292
+ cap_drop:
293
+ - ALL
294
+ read_only: true
295
+ tmpfs:
296
+ - /tmp
297
+ environment:
298
+ PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@db:5432/postgres
299
+ PGRST_DB_SCHEMAS: public,storage,graphql_public
300
+ PGRST_DB_ANON_ROLE: anon
301
+ PGRST_JWT_SECRET: ${JWT_SECRET}
302
+ PGRST_DB_USE_LEGACY_GUCS: "false"
303
+ PGRST_APP_SETTINGS_JWT_SECRET: ${JWT_SECRET}
304
+ PGRST_APP_SETTINGS_JWT_EXP: 3600
305
+ command: postgrest
306
+ depends_on:
307
+ db:
308
+ condition: service_healthy
309
+ networks:
310
+ - vibecarbon-network
311
+
312
+ # Realtime Server
313
+ realtime:
314
+ image: supabase/realtime:v2.76.5
315
+ container_name: ${PROJECT_NAME}-realtime
316
+ restart: unless-stopped
317
+ cap_drop:
318
+ - ALL
319
+ cap_add:
320
+ - SETUID
321
+ - SETGID
322
+ read_only: true
323
+ tmpfs:
324
+ - /tmp
325
+ - /app/rel/realtime/tmp
326
+ - /app/rel/realtime/releases/2.76.5
327
+ healthcheck:
328
+ test: ["CMD-SHELL", "curl -so /dev/null -w '%{http_code}' http://localhost:4000/ | grep -qE '^[0-9]+$'"]
329
+ interval: 10s
330
+ timeout: 5s
331
+ retries: 5
332
+ start_period: 30s
333
+ environment:
334
+ PORT: 4000
335
+ DB_HOST: db
336
+ DB_PORT: 5432
337
+ DB_USER: supabase_admin
338
+ DB_PASSWORD: ${POSTGRES_PASSWORD}
339
+ DB_NAME: postgres
340
+ DB_AFTER_CONNECT_QUERY: "SET search_path TO _realtime"
341
+ DB_ENC_KEY: ${DB_ENC_KEY:-devdbencryptkey1}
342
+ API_JWT_SECRET: ${JWT_SECRET}
343
+ SECRET_KEY_BASE: ${REALTIME_SECRET:-realtimesecret}
344
+ ERL_AFLAGS: -proto_dist inet_tcp
345
+ DNS_NODES: "''"
346
+ RLIMIT_NOFILE: "10000"
347
+ APP_NAME: realtime
348
+ SEED_SELF_HOST: "true"
349
+ FLY_ALLOC_ID: fly123
350
+ FLY_APP_NAME: realtime
351
+ REPLICATION_MODE: RLS
352
+ REPLICATION_POLL_INTERVAL: 100
353
+ SECURE_CHANNELS: "true"
354
+ SLOT_NAME: supabase_realtime_rls
355
+ TEMPORARY_SLOT: "true"
356
+ depends_on:
357
+ db:
358
+ condition: service_healthy
359
+ networks:
360
+ - vibecarbon-network
361
+
362
+ # ===========================================
363
+ # SUPABASE STORAGE
364
+ # ===========================================
365
+
366
+ storage:
367
+ image: supabase/storage-api:v1.44.2
368
+ container_name: ${PROJECT_NAME}-storage
369
+ restart: unless-stopped
370
+ security_opt:
371
+ - no-new-privileges:true
372
+ cap_drop:
373
+ - ALL
374
+ read_only: true
375
+ tmpfs:
376
+ - /tmp
377
+ healthcheck:
378
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5000/status"]
379
+ interval: 5s
380
+ timeout: 5s
381
+ retries: 3
382
+ environment:
383
+ ANON_KEY: ${SUPABASE_ANON_KEY}
384
+ SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
385
+ POSTGREST_URL: http://rest:3000
386
+ PGRST_JWT_SECRET: ${JWT_SECRET}
387
+ DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD}@db:5432/postgres
388
+ FILE_SIZE_LIMIT: 52428800
389
+ STORAGE_BACKEND: s3
390
+ TENANT_ID: stub
391
+ REGION: ${S3_REGION:-stub}
392
+ GLOBAL_S3_BUCKET: ${S3_BUCKET:-stub}
393
+ GLOBAL_S3_ENDPOINT: ${S3_ENDPOINT:-}
394
+ GLOBAL_S3_FORCE_PATH_STYLE: "true"
395
+ AWS_ACCESS_KEY_ID: ${S3_ACCESS_KEY:-}
396
+ AWS_SECRET_ACCESS_KEY: ${S3_SECRET_KEY:-}
397
+ ENABLE_IMAGE_TRANSFORMATION: "true"
398
+ IMGPROXY_URL: http://imgproxy:5001
399
+ VAULT_ENC_KEY: ${VAULT_ENC_KEY:-vaultenckey}
400
+ volumes:
401
+ - storage_data:/var/lib/storage
402
+ depends_on:
403
+ db:
404
+ condition: service_healthy
405
+ rest:
406
+ condition: service_started
407
+ imgproxy:
408
+ condition: service_started
409
+ networks:
410
+ - vibecarbon-network
411
+
412
+ imgproxy:
413
+ image: darthsim/imgproxy:v3.30.1
414
+ container_name: ${PROJECT_NAME}-imgproxy
415
+ restart: unless-stopped
416
+ security_opt:
417
+ - no-new-privileges:true
418
+ cap_drop:
419
+ - ALL
420
+ read_only: true
421
+ tmpfs:
422
+ - /tmp
423
+ healthcheck:
424
+ test: ["CMD", "imgproxy", "health"]
425
+ interval: 5s
426
+ timeout: 5s
427
+ retries: 3
428
+ environment:
429
+ IMGPROXY_BIND: ":5001"
430
+ IMGPROXY_LOCAL_FILESYSTEM_ROOT: /
431
+ IMGPROXY_USE_ETAG: "true"
432
+ IMGPROXY_ENABLE_WEBP_DETECTION: "true"
433
+ volumes:
434
+ - storage_data:/var/lib/storage
435
+ networks:
436
+ - vibecarbon-network
437
+
438
+ # ===========================================
439
+ # SUPABASE MANAGEMENT
440
+ # ===========================================
441
+
442
+ meta:
443
+ image: supabase/postgres-meta:v0.95.2
444
+ container_name: ${PROJECT_NAME}-meta
445
+ restart: unless-stopped
446
+ security_opt:
447
+ - no-new-privileges:true
448
+ cap_drop:
449
+ - ALL
450
+ environment:
451
+ PG_META_PORT: 8080
452
+ PG_META_DB_HOST: db
453
+ PG_META_DB_PORT: 5432
454
+ PG_META_DB_NAME: postgres
455
+ PG_META_DB_USER: supabase_admin
456
+ PG_META_DB_PASSWORD: ${POSTGRES_PASSWORD}
457
+ PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY:-pgmetacryptokey}
458
+ depends_on:
459
+ db:
460
+ condition: service_healthy
461
+ networks:
462
+ - vibecarbon-network
463
+
464
+ studio:
465
+ image: supabase/studio:2026.03.16-sha-5528817
466
+ container_name: ${PROJECT_NAME}-studio
467
+ restart: unless-stopped
468
+ security_opt:
469
+ - no-new-privileges:true
470
+ cap_drop:
471
+ - ALL
472
+ healthcheck:
473
+ disable: true
474
+ environment:
475
+ STUDIO_PG_META_URL: http://meta:8080
476
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
477
+ DEFAULT_ORGANIZATION_NAME: ${PROJECT_NAME}
478
+ DEFAULT_PROJECT_NAME: ${PROJECT_NAME}
479
+ SUPABASE_URL: http://kong:8000
480
+ SUPABASE_PUBLIC_URL: ${SITE_URL}
481
+ SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
482
+ SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
483
+ AUTH_JWT_SECRET: ${JWT_SECRET}
484
+ LOGFLARE_API_KEY: ${LOGFLARE_API_KEY:-logflarekey}
485
+ LOGFLARE_URL: http://analytics:4000
486
+ NEXT_PUBLIC_ENABLE_LOGS: "false"
487
+ NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
488
+ labels:
489
+ - "traefik.enable=true"
490
+ # Subdomain routing - auth added via prod overlay (docker-compose.prod.yml)
491
+ - "traefik.http.routers.studio.rule=Host(`studio.${DOMAIN:-localhost}`)"
492
+ - "traefik.http.routers.studio.entrypoints=web"
493
+ - "traefik.http.services.studio.loadbalancer.server.port=3000"
494
+ depends_on:
495
+ db:
496
+ condition: service_healthy
497
+ meta:
498
+ condition: service_started
499
+ networks:
500
+ - vibecarbon-network
501
+
502
+ volumes:
503
+ db_data:
504
+ storage_data:
505
+
506
+ networks:
507
+ vibecarbon-network:
508
+ driver: bridge
@@ -0,0 +1,12 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ echo "Starting ${PROJECT_NAME}..."
5
+
6
+ # Note: Database migrations are handled by Supabase
7
+ # Run migrations manually with: docker compose exec db psql -U postgres -d postgres -f /migrations/init.sql
8
+
9
+ echo "Starting application..."
10
+
11
+ # Execute the main command
12
+ exec "$@"
@@ -0,0 +1,52 @@
1
+ #!/bin/bash
2
+ # Promote a standby PostgreSQL to primary and scale up services.
3
+ #
4
+ # This script runs ON the standby master node and uses kubectl to:
5
+ # 1. Promote PostgreSQL from standby to primary
6
+ # 2. Wait for the promotion to complete
7
+ # 3. Scale up Supabase and application services
8
+ #
9
+ # Optional env vars:
10
+ # NAMESPACE — Kubernetes namespace (default: vibecarbon)
11
+
12
+ set -euo pipefail
13
+
14
+ NAMESPACE="${NAMESPACE:-vibecarbon}"
15
+ PGDATA="/var/lib/postgresql/data"
16
+
17
+ # Find the postgres pod
18
+ POD=$(kubectl get pods -n "$NAMESPACE" -l app.kubernetes.io/name=supabase-db -o jsonpath='{.items[0].metadata.name}')
19
+ if [ -z "$POD" ]; then
20
+ echo "ERROR: No postgres pod found in namespace $NAMESPACE"
21
+ exit 1
22
+ fi
23
+
24
+ echo "Promoting standby: pod=$POD"
25
+
26
+ # 1. Promote PostgreSQL
27
+ echo "Promoting PostgreSQL standby to primary..."
28
+ kubectl exec -n "$NAMESPACE" "$POD" -- su postgres -c "pg_ctl promote -D $PGDATA" 2>/dev/null || true
29
+
30
+ # 2. Wait for promotion to complete
31
+ echo "Waiting for promotion..."
32
+ for i in $(seq 1 30); do
33
+ result=$(kubectl exec -n "$NAMESPACE" "$POD" -- psql -U supabase_admin -tAc 'SELECT pg_is_in_recovery()' 2>/dev/null || echo "t")
34
+ if [ "$result" = "f" ]; then
35
+ echo "PostgreSQL promoted successfully"
36
+ break
37
+ fi
38
+ if [ "$i" = "30" ]; then
39
+ echo "WARNING: Promotion not confirmed after 60 seconds"
40
+ fi
41
+ sleep 2
42
+ done
43
+
44
+ # 3. Scale up services
45
+ echo "Scaling up services..."
46
+ kubectl scale deployment app -n "$NAMESPACE" --replicas=2
47
+ kubectl scale deployment auth -n "$NAMESPACE" --replicas=2
48
+ kubectl scale deployment rest -n "$NAMESPACE" --replicas=2
49
+ kubectl scale deployment realtime -n "$NAMESPACE" --replicas=2
50
+ kubectl scale deployment storage -n "$NAMESPACE" --replicas=1
51
+
52
+ echo "Standby activation complete"
@@ -0,0 +1,36 @@
1
+ -- Configure primary PostgreSQL for streaming replication.
2
+ -- Run on the primary database before initializing the standby.
3
+ --
4
+ -- This script is idempotent: safe to run multiple times.
5
+
6
+ -- Create dedicated replication role (if not exists), or update its password on re-runs.
7
+ DO $$
8
+ BEGIN
9
+ IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'replicator') THEN
10
+ CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'repl_password';
11
+ ELSE
12
+ ALTER ROLE replicator WITH PASSWORD 'repl_password';
13
+ END IF;
14
+ END $$;
15
+
16
+ -- Enable WAL-level replication
17
+ ALTER SYSTEM SET wal_level = 'replica';
18
+ ALTER SYSTEM SET max_wal_senders = 5;
19
+ ALTER SYSTEM SET wal_keep_size = '512MB';
20
+
21
+ -- Create a physical replication slot for the standby. Without a slot, the
22
+ -- standby's follow position isn't persisted on primary; if it falls behind
23
+ -- by more than wal_keep_size (512MB), primary recycles WAL and streaming
24
+ -- breaks silently. The slot tells primary to hold WAL until the standby
25
+ -- confirms receipt. Idempotent: wrapped in a DO block that checks existence.
26
+ DO $$
27
+ BEGIN
28
+ IF NOT EXISTS (
29
+ SELECT 1 FROM pg_replication_slots WHERE slot_name = 'vibecarbon_standby_slot'
30
+ ) THEN
31
+ PERFORM pg_create_physical_replication_slot('vibecarbon_standby_slot');
32
+ END IF;
33
+ END $$;
34
+
35
+ -- Reload config (wal_level change requires restart, handled by caller)
36
+ SELECT pg_reload_conf();
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ # Initialize standby PostgreSQL as a streaming replica of the primary.
3
+ #
4
+ # This script runs ON the standby master node and uses kubectl to
5
+ # exec into the postgres pod. It:
6
+ # 1. Stops the standby database
7
+ # 2. Wipes data and runs pg_basebackup from the primary
8
+ # 3. Configures standby.signal and primary_conninfo
9
+ # 4. Restarts as a hot standby
10
+ #
11
+ # Required env vars:
12
+ # PRIMARY_HOST — IP address of the primary cluster (master node)
13
+ #
14
+ # Optional env vars:
15
+ # PRIMARY_PORT — PostgreSQL port on the primary (default: 5432, use 30432 for NodePort)
16
+ # REPL_PASSWORD — Replication user password (required; generated by vibecarbon create in .env.local)
17
+ # NAMESPACE — Kubernetes namespace (default: vibecarbon)
18
+
19
+ set -euo pipefail
20
+
21
+ : "${PRIMARY_HOST:?PRIMARY_HOST is required}"
22
+ PRIMARY_PORT="${PRIMARY_PORT:-5432}"
23
+ : "${REPL_PASSWORD:?REPL_PASSWORD is required — generate one in .env.local and export it before running standby-init.sh}"
24
+ NAMESPACE="${NAMESPACE:-vibecarbon}"
25
+ PGDATA="/var/lib/postgresql/data"
26
+
27
+ # Find the postgres pod
28
+ POD=$(kubectl get pods -n "$NAMESPACE" -l app.kubernetes.io/name=supabase-db -o jsonpath='{.items[0].metadata.name}')
29
+ if [ -z "$POD" ]; then
30
+ echo "ERROR: No postgres pod found in namespace $NAMESPACE"
31
+ exit 1
32
+ fi
33
+
34
+ echo "Standby init: pod=$POD, primary=$PRIMARY_HOST:$PRIMARY_PORT"
35
+
36
+ # 1. Stop postgres on standby
37
+ echo "Stopping standby PostgreSQL..."
38
+ kubectl exec -n "$NAMESPACE" "$POD" -- su postgres -c "pg_ctl stop -D $PGDATA -m fast" 2>/dev/null || true
39
+ sleep 5
40
+
41
+ # 2. Wipe data and run pg_basebackup from primary
42
+ echo "Running pg_basebackup from primary ($PRIMARY_HOST:$PRIMARY_PORT)..."
43
+ kubectl exec -n "$NAMESPACE" "$POD" -- bash -c "
44
+ rm -rf ${PGDATA}/*
45
+ PGPASSWORD='${REPL_PASSWORD}' pg_basebackup -h ${PRIMARY_HOST} -p ${PRIMARY_PORT} -U replicator -D ${PGDATA} -Fp -Xs -P -R
46
+ "
47
+
48
+ # 3. Configure standby signal and primary connection info
49
+ echo "Configuring standby.signal and primary_conninfo..."
50
+ kubectl exec -n "$NAMESPACE" "$POD" -- bash -c "
51
+ touch ${PGDATA}/standby.signal
52
+ echo \"primary_conninfo = 'host=${PRIMARY_HOST} port=${PRIMARY_PORT} user=replicator password=${REPL_PASSWORD}'\" >> ${PGDATA}/postgresql.auto.conf
53
+ chown -R postgres:postgres ${PGDATA}
54
+ "
55
+
56
+ # 4. Start postgres as hot standby
57
+ echo "Starting standby PostgreSQL..."
58
+ kubectl exec -n "$NAMESPACE" "$POD" -- su postgres -c "pg_ctl start -D $PGDATA -l /var/log/postgresql/postgresql.log"
59
+
60
+ # 5. Verify recovery mode
61
+ echo "Verifying standby is in recovery mode..."
62
+ sleep 5
63
+ for i in $(seq 1 15); do
64
+ result=$(kubectl exec -n "$NAMESPACE" "$POD" -- psql -U supabase_admin -tAc 'SELECT pg_is_in_recovery()' 2>/dev/null || echo "")
65
+ if [ "$result" = "t" ]; then
66
+ echo "Standby is in recovery mode — streaming replication active"
67
+ exit 0
68
+ fi
69
+ echo " Waiting for standby to enter recovery mode (attempt $i/15)..."
70
+ sleep 2
71
+ done
72
+
73
+ echo "WARNING: Could not confirm standby is in recovery mode"
74
+ exit 1