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.
- package/LICENSE +663 -0
- package/README.md +188 -0
- package/carbon/.claude/hooks/task-completed-gate.sh +19 -0
- package/carbon/.claude/hooks/teammate-idle-gate.sh +29 -0
- package/carbon/.claude/settings.json +29 -0
- package/carbon/.cursor/rules/vibecarbon.mdc +6 -0
- package/carbon/.dockerignore +57 -0
- package/carbon/.env.example +219 -0
- package/carbon/.github/copilot-instructions.md +3 -0
- package/carbon/.github/workflows/deploy.yml +346 -0
- package/carbon/.github/workflows/vibecarbon-build.yml +81 -0
- package/carbon/.windsurfrules +74 -0
- package/carbon/AGENTS.md +422 -0
- package/carbon/CLAUDE.md +3 -0
- package/carbon/DEVELOPMENT.md +187 -0
- package/carbon/Dockerfile +98 -0
- package/carbon/LICENSE +21 -0
- package/carbon/PRODUCTION.md +364 -0
- package/carbon/README.md +193 -0
- package/carbon/TESTING.md +138 -0
- package/carbon/backup/Dockerfile +75 -0
- package/carbon/backup/backup.sh +95 -0
- package/carbon/backup/compose-backup.sh +140 -0
- package/carbon/biome.json +83 -0
- package/carbon/cloud-init/docker-ce-setup.yaml +55 -0
- package/carbon/cloud-init/k3s/master-init.sh +215 -0
- package/carbon/cloud-init/k3s/supabase-init.sh +167 -0
- package/carbon/cloud-init/k3s/worker-init.sh +147 -0
- package/carbon/components.json +24 -0
- package/carbon/content/blog/authentication-guide.mdx +34 -0
- package/carbon/content/blog/getting-started.mdx +41 -0
- package/carbon/content/changelog/v0-1-0.mdx +40 -0
- package/carbon/content/docs/analytics.mdx +90 -0
- package/carbon/content/docs/authentication.mdx +231 -0
- package/carbon/content/docs/background-jobs.mdx +116 -0
- package/carbon/content/docs/cli.mdx +630 -0
- package/carbon/content/docs/database.mdx +236 -0
- package/carbon/content/docs/deployment.mdx +227 -0
- package/carbon/content/docs/development.mdx +238 -0
- package/carbon/content/docs/environments.mdx +84 -0
- package/carbon/content/docs/getting-started.mdx +112 -0
- package/carbon/content/docs/legal/privacy-policy.mdx +89 -0
- package/carbon/content/docs/legal/terms-of-service.mdx +99 -0
- package/carbon/content/docs/optional-services.mdx +160 -0
- package/carbon/db/Dockerfile +23 -0
- package/carbon/docker-compose.dev-init.yml +5 -0
- package/carbon/docker-compose.metabase.override.yml +14 -0
- package/carbon/docker-compose.metabase.prod.yml +28 -0
- package/carbon/docker-compose.metabase.yml +84 -0
- package/carbon/docker-compose.n8n.override.yml +14 -0
- package/carbon/docker-compose.n8n.prod.yml +31 -0
- package/carbon/docker-compose.n8n.yml +97 -0
- package/carbon/docker-compose.observability.override.yml +18 -0
- package/carbon/docker-compose.observability.prod.yml +28 -0
- package/carbon/docker-compose.observability.yml +125 -0
- package/carbon/docker-compose.override.yml +28 -0
- package/carbon/docker-compose.prod.yml +294 -0
- package/carbon/docker-compose.yml +508 -0
- package/carbon/docker-entrypoint.sh +12 -0
- package/carbon/ha/activate-standby.sh +52 -0
- package/carbon/ha/primary-init.sql +36 -0
- package/carbon/ha/standby-init.sh +74 -0
- package/carbon/k8s/LICENSE +99 -0
- package/carbon/k8s/README.md +272 -0
- package/carbon/k8s/base/app/deployment.yaml +130 -0
- package/carbon/k8s/base/app/hpa.yaml +44 -0
- package/carbon/k8s/base/app/kustomization.yaml +10 -0
- package/carbon/k8s/base/app/network-policy.yaml +124 -0
- package/carbon/k8s/base/app/pdb.yaml +14 -0
- package/carbon/k8s/base/app/rbac.yaml +36 -0
- package/carbon/k8s/base/app/service.yaml +16 -0
- package/carbon/k8s/base/backup/cronjob.yaml +120 -0
- package/carbon/k8s/base/backup/kustomization.yaml +7 -0
- package/carbon/k8s/base/backup/network-policy.yaml +31 -0
- package/carbon/k8s/base/backup/rbac.yaml +7 -0
- package/carbon/k8s/base/cluster-autoscaler/deployment.yaml +103 -0
- package/carbon/k8s/base/cluster-autoscaler/kustomization.yaml +17 -0
- package/carbon/k8s/base/cluster-autoscaler/rbac.yaml +109 -0
- package/carbon/k8s/base/config/configmap.yaml +48 -0
- package/carbon/k8s/base/config/kustomization.yaml +8 -0
- package/carbon/k8s/base/hetzner-ccm/kustomization.yaml +9 -0
- package/carbon/k8s/base/hetzner-csi/kustomization.yaml +9 -0
- package/carbon/k8s/base/kustomization.yaml +43 -0
- package/carbon/k8s/base/namespace.yaml +7 -0
- package/carbon/k8s/base/network-policies.yaml +95 -0
- package/carbon/k8s/base/registry/kustomization.yaml +5 -0
- package/carbon/k8s/base/registry/local-registry.yaml +193 -0
- package/carbon/k8s/base/traefik/certificate.yaml +21 -0
- package/carbon/k8s/base/traefik/configmap.yaml +13 -0
- package/carbon/k8s/base/traefik/deployment.yaml +165 -0
- package/carbon/k8s/base/traefik/ingressroute.yaml +141 -0
- package/carbon/k8s/base/traefik/kustomization.yaml +11 -0
- package/carbon/k8s/base/traefik/middleware.yaml +109 -0
- package/carbon/k8s/base/traefik/network-policy.yaml +92 -0
- package/carbon/k8s/base/traefik/service.yaml +38 -0
- package/carbon/k8s/flux/README.md +49 -0
- package/carbon/k8s/flux/clusters/primary/vibecarbon.yaml +128 -0
- package/carbon/k8s/flux/clusters/standby/vibecarbon.yaml +83 -0
- package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-release.yaml +38 -0
- package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-repository.yaml +16 -0
- package/carbon/k8s/gitops/cert-manager-webhook-hetzner/kustomization.yaml +10 -0
- package/carbon/k8s/gitops/supabase/helm-release.yaml +66 -0
- package/carbon/k8s/gitops/supabase/helm-repository.yaml +18 -0
- package/carbon/k8s/gitops/supabase/kustomization.yaml +33 -0
- package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-cloudflare.yaml +51 -0
- package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-hetzner.yaml +59 -0
- package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-manual.yaml +43 -0
- package/carbon/k8s/infra/cert-manager-resources/kustomization.yaml +15 -0
- package/carbon/k8s/infra/kustomization.yaml +21 -0
- package/carbon/k8s/infra/traefik-crds/kustomization.yaml +10 -0
- package/carbon/k8s/overlays/local/configmap.yaml +23 -0
- package/carbon/k8s/overlays/local/ingressroute-studio.yaml +104 -0
- package/carbon/k8s/overlays/local/kustomization.yaml +215 -0
- package/carbon/k8s/overlays/local/namespace.yaml +8 -0
- package/carbon/k8s/overlays/local/secrets.yaml +32 -0
- package/carbon/k8s/overlays/production/kustomization.yaml +34 -0
- package/carbon/k8s/test-local.sh +318 -0
- package/carbon/k8s/values/supabase.values.yaml +133 -0
- package/carbon/package.json +154 -0
- package/carbon/runtime.Dockerfile +17 -0
- package/carbon/scripts/_dev-jwt.mjs +45 -0
- package/carbon/scripts/check-rls.ts +53 -0
- package/carbon/scripts/dev-init.js +191 -0
- package/carbon/scripts/dev.js +191 -0
- package/carbon/scripts/docker-down.js +63 -0
- package/carbon/scripts/docker-logs.js +59 -0
- package/carbon/scripts/docker-up.js +222 -0
- package/carbon/scripts/generate-dev-configs.sh +131 -0
- package/carbon/scripts/generate-rss.ts +116 -0
- package/carbon/scripts/generate-sitemap.ts +102 -0
- package/carbon/scripts/k8s-apply.js +71 -0
- package/carbon/scripts/k8s-delete.js +75 -0
- package/carbon/scripts/lib/manifest.js +176 -0
- package/carbon/scripts/secret-scan.mjs +278 -0
- package/carbon/scripts/validate-dev-configs.sh +101 -0
- package/carbon/src/client/App.tsx +202 -0
- package/carbon/src/client/assets/hyperformant-dark.svg +29 -0
- package/carbon/src/client/assets/hyperformant-light.svg +29 -0
- package/carbon/src/client/assets/logos/aider.svg +1 -0
- package/carbon/src/client/assets/logos/antigravity.svg +1 -0
- package/carbon/src/client/assets/logos/bolt.svg +1 -0
- package/carbon/src/client/assets/logos/claude-code.svg +1 -0
- package/carbon/src/client/assets/logos/copilot.svg +1 -0
- package/carbon/src/client/assets/logos/cursor.svg +1 -0
- package/carbon/src/client/assets/logos/gemini-cli.svg +1 -0
- package/carbon/src/client/assets/logos/lovable.svg +1 -0
- package/carbon/src/client/assets/logos/openai-codex.svg +1 -0
- package/carbon/src/client/assets/logos/v0.svg +1 -0
- package/carbon/src/client/assets/logos/windsurf.svg +1 -0
- package/carbon/src/client/assets/vibecarbon-icon.svg +19 -0
- package/carbon/src/client/assets/vibecarbon-logo-dark.svg +29 -0
- package/carbon/src/client/assets/vibecarbon-logo-light.svg +29 -0
- package/carbon/src/client/components/AIIntegrationSection.tsx +120 -0
- package/carbon/src/client/components/AppSidebar.tsx +760 -0
- package/carbon/src/client/components/ArchitectureSection.tsx +46 -0
- package/carbon/src/client/components/CTAFooter.tsx +59 -0
- package/carbon/src/client/components/ComparisonSection.tsx +132 -0
- package/carbon/src/client/components/ContentPanel.tsx +66 -0
- package/carbon/src/client/components/ContentSkeleton.tsx +21 -0
- package/carbon/src/client/components/ErrorBoundary.tsx +46 -0
- package/carbon/src/client/components/FAQSection.tsx +76 -0
- package/carbon/src/client/components/FileUpload.tsx +210 -0
- package/carbon/src/client/components/HeaderActions.tsx +17 -0
- package/carbon/src/client/components/Hero.tsx +608 -0
- package/carbon/src/client/components/ImpersonationBanner.tsx +31 -0
- package/carbon/src/client/components/LanguageSwitcher.tsx +67 -0
- package/carbon/src/client/components/Logo.tsx +87 -0
- package/carbon/src/client/components/LogoStrip.tsx +76 -0
- package/carbon/src/client/components/MetricsStrip.tsx +48 -0
- package/carbon/src/client/components/Nav.tsx +195 -0
- package/carbon/src/client/components/NewsletterSignup.tsx +147 -0
- package/carbon/src/client/components/NotificationDrawer.tsx +171 -0
- package/carbon/src/client/components/PageHeader.tsx +24 -0
- package/carbon/src/client/components/PlanGate.tsx +36 -0
- package/carbon/src/client/components/PricingSection.tsx +371 -0
- package/carbon/src/client/components/SEO.tsx +34 -0
- package/carbon/src/client/components/SmoothScroll.tsx +45 -0
- package/carbon/src/client/components/TechStackSection.tsx +165 -0
- package/carbon/src/client/components/WorkflowSection.tsx +604 -0
- package/carbon/src/client/components/admin/DockerLogs.tsx +276 -0
- package/carbon/src/client/components/admin/PerformanceMetrics.tsx +230 -0
- package/carbon/src/client/components/admin/ServiceCard.tsx +45 -0
- package/carbon/src/client/components/admin/ServicesStatus.tsx +296 -0
- package/carbon/src/client/components/architecture/ArchitectureDiagram.tsx +413 -0
- package/carbon/src/client/components/auth/AuthProvider.tsx +466 -0
- package/carbon/src/client/components/effects/FilmGrainOverlay.tsx +35 -0
- package/carbon/src/client/components/effects/FresnelEdge.tsx +49 -0
- package/carbon/src/client/components/effects/GlowTracker.tsx +46 -0
- package/carbon/src/client/components/effects/SparkBurst.tsx +145 -0
- package/carbon/src/client/components/effects/VGlowEffect.tsx +83 -0
- package/carbon/src/client/components/effects/index.ts +2 -0
- package/carbon/src/client/components/layouts/SidebarLayout.tsx +20 -0
- package/carbon/src/client/components/scroll/ScrollSection.tsx +76 -0
- package/carbon/src/client/components/scroll/ScrollytellingProvider.tsx +81 -0
- package/carbon/src/client/components/scroll/index.ts +2 -0
- package/carbon/src/client/components/ui/accordion.tsx +71 -0
- package/carbon/src/client/components/ui/alert-dialog.tsx +162 -0
- package/carbon/src/client/components/ui/alert.tsx +73 -0
- package/carbon/src/client/components/ui/aspect-ratio.tsx +22 -0
- package/carbon/src/client/components/ui/avatar.tsx +91 -0
- package/carbon/src/client/components/ui/badge.tsx +50 -0
- package/carbon/src/client/components/ui/breadcrumb.tsx +100 -0
- package/carbon/src/client/components/ui/button-group.tsx +78 -0
- package/carbon/src/client/components/ui/button.tsx +120 -0
- package/carbon/src/client/components/ui/calendar.tsx +182 -0
- package/carbon/src/client/components/ui/card.tsx +85 -0
- package/carbon/src/client/components/ui/carousel.tsx +227 -0
- package/carbon/src/client/components/ui/chart.tsx +357 -0
- package/carbon/src/client/components/ui/checkbox.tsx +27 -0
- package/carbon/src/client/components/ui/collapsible.tsx +15 -0
- package/carbon/src/client/components/ui/command.tsx +178 -0
- package/carbon/src/client/components/ui/context-menu.tsx +233 -0
- package/carbon/src/client/components/ui/dialog.tsx +132 -0
- package/carbon/src/client/components/ui/drawer.tsx +118 -0
- package/carbon/src/client/components/ui/dropdown-menu.tsx +242 -0
- package/carbon/src/client/components/ui/empty.tsx +94 -0
- package/carbon/src/client/components/ui/field.tsx +226 -0
- package/carbon/src/client/components/ui/hover-card.tsx +44 -0
- package/carbon/src/client/components/ui/input-group.tsx +146 -0
- package/carbon/src/client/components/ui/input-otp.tsx +83 -0
- package/carbon/src/client/components/ui/input.tsx +20 -0
- package/carbon/src/client/components/ui/item.tsx +188 -0
- package/carbon/src/client/components/ui/kbd.tsx +26 -0
- package/carbon/src/client/components/ui/label.tsx +21 -0
- package/carbon/src/client/components/ui/menubar.tsx +250 -0
- package/carbon/src/client/components/ui/navigation-menu.tsx +155 -0
- package/carbon/src/client/components/ui/pagination.tsx +102 -0
- package/carbon/src/client/components/ui/popover.tsx +75 -0
- package/carbon/src/client/components/ui/progress.tsx +66 -0
- package/carbon/src/client/components/ui/radio-group.tsx +36 -0
- package/carbon/src/client/components/ui/resizable.tsx +46 -0
- package/carbon/src/client/components/ui/scroll-area.tsx +48 -0
- package/carbon/src/client/components/ui/select.tsx +186 -0
- package/carbon/src/client/components/ui/separator.tsx +21 -0
- package/carbon/src/client/components/ui/sheet.tsx +124 -0
- package/carbon/src/client/components/ui/sidebar.tsx +702 -0
- package/carbon/src/client/components/ui/skeleton.tsx +13 -0
- package/carbon/src/client/components/ui/slider.tsx +57 -0
- package/carbon/src/client/components/ui/sonner.tsx +45 -0
- package/carbon/src/client/components/ui/spinner.tsx +15 -0
- package/carbon/src/client/components/ui/switch.tsx +30 -0
- package/carbon/src/client/components/ui/table.tsx +89 -0
- package/carbon/src/client/components/ui/tabs.tsx +73 -0
- package/carbon/src/client/components/ui/textarea.tsx +18 -0
- package/carbon/src/client/components/ui/toggle-group.tsx +87 -0
- package/carbon/src/client/components/ui/toggle.tsx +44 -0
- package/carbon/src/client/components/ui/tooltip.tsx +56 -0
- package/carbon/src/client/hooks/api/index.ts +14 -0
- package/carbon/src/client/hooks/api/useAuthSettings.ts +80 -0
- package/carbon/src/client/hooks/api/useSubscription.ts +87 -0
- package/carbon/src/client/hooks/use-mobile.ts +21 -0
- package/carbon/src/client/hooks/useMousePosition.ts +91 -0
- package/carbon/src/client/hooks/useNotifications.tsx +124 -0
- package/carbon/src/client/hooks/useOrganizationMembers.ts +127 -0
- package/carbon/src/client/hooks/useOrganizations.tsx +230 -0
- package/carbon/src/client/hooks/usePackageManager.ts +69 -0
- package/carbon/src/client/hooks/useReducedMotion.ts +20 -0
- package/carbon/src/client/hooks/useRunningServices.ts +114 -0
- package/carbon/src/client/hooks/useScrollProgress.ts +56 -0
- package/carbon/src/client/index.css +467 -0
- package/carbon/src/client/index.html +56 -0
- package/carbon/src/client/lib/admin-services.ts +151 -0
- package/carbon/src/client/lib/api.ts +32 -0
- package/carbon/src/client/lib/blog.ts +35 -0
- package/carbon/src/client/lib/changelog.ts +33 -0
- package/carbon/src/client/lib/docs-search.ts +101 -0
- package/carbon/src/client/lib/docs.ts +37 -0
- package/carbon/src/client/lib/i18n.ts +32 -0
- package/carbon/src/client/lib/supabase.ts +72 -0
- package/carbon/src/client/lib/tailwind-colors.ts +357 -0
- package/carbon/src/client/lib/theme.ts +117 -0
- package/carbon/src/client/lib/utils.ts +22 -0
- package/carbon/src/client/locales/de.json +529 -0
- package/carbon/src/client/locales/en.json +461 -0
- package/carbon/src/client/locales/es.json +529 -0
- package/carbon/src/client/locales/fr.json +529 -0
- package/carbon/src/client/locales/pt.json +529 -0
- package/carbon/src/client/main.tsx +56 -0
- package/carbon/src/client/mdx.d.ts +13 -0
- package/carbon/src/client/pages/ApiDocs.tsx +76 -0
- package/carbon/src/client/pages/AuthCallback.tsx +34 -0
- package/carbon/src/client/pages/Blog.tsx +167 -0
- package/carbon/src/client/pages/Changelog.tsx +171 -0
- package/carbon/src/client/pages/Charts.tsx +388 -0
- package/carbon/src/client/pages/Checkout.tsx +227 -0
- package/carbon/src/client/pages/Contact.tsx +174 -0
- package/carbon/src/client/pages/Dashboard.tsx +368 -0
- package/carbon/src/client/pages/Docs.tsx +372 -0
- package/carbon/src/client/pages/ForgotPassword.tsx +111 -0
- package/carbon/src/client/pages/Home.tsx +187 -0
- package/carbon/src/client/pages/Legal.tsx +100 -0
- package/carbon/src/client/pages/Login.tsx +408 -0
- package/carbon/src/client/pages/MFAVerify.tsx +156 -0
- package/carbon/src/client/pages/NotFound.tsx +21 -0
- package/carbon/src/client/pages/Onboarding.tsx +246 -0
- package/carbon/src/client/pages/ResetPassword.tsx +200 -0
- package/carbon/src/client/pages/UIComponents.tsx +390 -0
- package/carbon/src/client/pages/admin/ContactSubmissions.tsx +220 -0
- package/carbon/src/client/pages/admin/Dashboard.tsx +24 -0
- package/carbon/src/client/pages/admin/Infrastructure.tsx +257 -0
- package/carbon/src/client/pages/admin/Jobs.tsx +225 -0
- package/carbon/src/client/pages/admin/Logs.tsx +18 -0
- package/carbon/src/client/pages/admin/Newsletter.tsx +300 -0
- package/carbon/src/client/pages/admin/Notifications.tsx +603 -0
- package/carbon/src/client/pages/admin/Organizations.tsx +306 -0
- package/carbon/src/client/pages/admin/Settings.tsx +314 -0
- package/carbon/src/client/pages/admin/Theme.tsx +465 -0
- package/carbon/src/client/pages/admin/Users.tsx +365 -0
- package/carbon/src/client/pages/api-docs.css +156 -0
- package/carbon/src/client/pages/organizations/Details.tsx +200 -0
- package/carbon/src/client/pages/organizations/Members.tsx +402 -0
- package/carbon/src/client/pages/settings/Billing.tsx +473 -0
- package/carbon/src/client/pages/settings/Profile.tsx +160 -0
- package/carbon/src/client/pages/settings/Security.tsx +341 -0
- package/carbon/src/client/public/favicon.svg +19 -0
- package/carbon/src/client/public/robots.txt +8 -0
- package/carbon/src/server/billing/index.ts +104 -0
- package/carbon/src/server/billing/provider.ts +81 -0
- package/carbon/src/server/billing/providers/paddle.ts +314 -0
- package/carbon/src/server/billing/providers/polar.ts +325 -0
- package/carbon/src/server/billing/providers/stripe.ts +233 -0
- package/carbon/src/server/emails/templates.ts +116 -0
- package/carbon/src/server/index.ts +554 -0
- package/carbon/src/server/lib/auth.ts +6 -0
- package/carbon/src/server/lib/email.ts +64 -0
- package/carbon/src/server/lib/env.ts +112 -0
- package/carbon/src/server/lib/errors.ts +21 -0
- package/carbon/src/server/lib/logger.ts +17 -0
- package/carbon/src/server/lib/rate-limiter.ts +288 -0
- package/carbon/src/server/lib/request.ts +34 -0
- package/carbon/src/server/lib/stripe.ts +42 -0
- package/carbon/src/server/lib/supabase.ts +65 -0
- package/carbon/src/server/middleware/requirePlan.ts +80 -0
- package/carbon/src/server/routes/_internal/services-status.ts +958 -0
- package/carbon/src/server/routes/_internal/verify-role.ts +185 -0
- package/carbon/src/server/routes/health.ts +48 -0
- package/carbon/src/server/routes/v1/admin/contact.ts +128 -0
- package/carbon/src/server/routes/v1/admin/jobs.ts +171 -0
- package/carbon/src/server/routes/v1/admin/newsletter.ts +237 -0
- package/carbon/src/server/routes/v1/auth.ts +390 -0
- package/carbon/src/server/routes/v1/billing.ts +718 -0
- package/carbon/src/server/routes/v1/contact.ts +93 -0
- package/carbon/src/server/routes/v1/index.ts +1333 -0
- package/carbon/src/server/routes/v1/newsletter.ts +181 -0
- package/carbon/src/server/routes/v1/performance.ts +157 -0
- package/carbon/src/server/routes/v1/stats.ts +170 -0
- package/carbon/src/server/routes/v1/theme.ts +106 -0
- package/carbon/src/server/routes/webhooks/billing.ts +376 -0
- package/carbon/src/server/routes/webhooks/stripe.ts +276 -0
- package/carbon/src/server/types.ts +11 -0
- package/carbon/src/shared/pricing.ts +155 -0
- package/carbon/src/shared/types.ts +338 -0
- package/carbon/supabase/migrations/00001_init.sql +717 -0
- package/carbon/supabase/migrations/00002_theme_settings.sql +13 -0
- package/carbon/supabase/migrations/00003_pg_cron.sql +121 -0
- package/carbon/supabase/migrations/00004_contact_newsletter.sql +81 -0
- package/carbon/supabase/migrations/00005_localization_languages.sql +22 -0
- package/carbon/supabase/seed.sql +16 -0
- package/carbon/tests/_helpers/app.ts +45 -0
- package/carbon/tests/_helpers/env.ts +37 -0
- package/carbon/tests/_helpers/factories.ts +69 -0
- package/carbon/tests/_helpers/jwt.ts +23 -0
- package/carbon/tests/_helpers/setup-integration.ts +20 -0
- package/carbon/tests/_helpers/setup-rtl.ts +12 -0
- package/carbon/tests/component/ErrorBoundary.test.tsx +53 -0
- package/carbon/tests/component/use-auth-settings.test.tsx +119 -0
- package/carbon/tests/integration/server/routes/contact.test.ts +162 -0
- package/carbon/tests/integration/server/routes/health.test.ts +61 -0
- package/carbon/tests/structural/i18n-parity.test.ts +42 -0
- package/carbon/tests/unit/client/utils.test.ts +49 -0
- package/carbon/tests/unit/shared/pricing.test.ts +93 -0
- package/carbon/tsconfig.json +27 -0
- package/carbon/tsconfig.server.json +27 -0
- package/carbon/tsconfig.test.json +9 -0
- package/carbon/vite.config.ts +110 -0
- package/carbon/vitest.config.ts +74 -0
- package/carbon/volumes/db/jwt.sql +57 -0
- package/carbon/volumes/db/metabase-init.sh +29 -0
- package/carbon/volumes/db/n8n-init.sh +25 -0
- package/carbon/volumes/db/realtime.sql +33 -0
- package/carbon/volumes/db/roles.sql +93 -0
- package/carbon/volumes/db/set-passwords.sh +12 -0
- package/carbon/volumes/db/super-admin.dev.sql +113 -0
- package/carbon/volumes/db/super-admin.generated.sql +113 -0
- package/carbon/volumes/db/super-admin.sql +114 -0
- package/carbon/volumes/grafana/dashboards/logs.json +179 -0
- package/carbon/volumes/grafana/dashboards/overview.json +523 -0
- package/carbon/volumes/grafana/dashboards/postgresql.json +337 -0
- package/carbon/volumes/grafana/dashboards.dev/logs.json +179 -0
- package/carbon/volumes/grafana/dashboards.dev/overview.json +156 -0
- package/carbon/volumes/grafana/dashboards.dev/postgresql.json +337 -0
- package/carbon/volumes/grafana/provisioning/dashboards/dashboards.dev.yml +16 -0
- package/carbon/volumes/grafana/provisioning/dashboards/dashboards.yml +16 -0
- package/carbon/volumes/grafana/provisioning/datasources/datasources.yml +43 -0
- package/carbon/volumes/kong/docker-entrypoint.sh +9 -0
- package/carbon/volumes/kong/kong.yml +208 -0
- package/carbon/volumes/loki/loki-config.yml +58 -0
- package/carbon/volumes/n8n/hooks.js +131 -0
- package/carbon/volumes/n8n/scripts/setup.sh +66 -0
- package/carbon/volumes/prometheus/prometheus.yml +43 -0
- package/carbon/volumes/promtail/promtail-config.yml +64 -0
- package/carbon/volumes/traefik/middlewares.dev.yml +83 -0
- package/carbon/volumes/traefik/middlewares.yml +95 -0
- package/carbon/volumes/traefik/vite-dev.yml +20 -0
- package/package.json +95 -0
- package/src/access.js +354 -0
- package/src/activate.js +187 -0
- package/src/add.js +718 -0
- package/src/backup.js +786 -0
- package/src/cli.js +350 -0
- package/src/configure.js +967 -0
- package/src/console.js +155 -0
- package/src/create.js +1499 -0
- package/src/deploy.js +311 -0
- package/src/destroy.js +2033 -0
- package/src/diagnose.js +735 -0
- package/src/down.js +80 -0
- package/src/failover.js +1032 -0
- package/src/lib/backup-s3.js +179 -0
- package/src/lib/build.js +33 -0
- package/src/lib/checksum.js +28 -0
- package/src/lib/ci-setup.js +666 -0
- package/src/lib/cli/help.js +129 -0
- package/src/lib/cli/parse-flags.js +160 -0
- package/src/lib/cli/select-action.js +65 -0
- package/src/lib/cli/select-environment.js +108 -0
- package/src/lib/cli/tty-guard.js +75 -0
- package/src/lib/cloudflare.js +447 -0
- package/src/lib/colors.js +52 -0
- package/src/lib/command.js +361 -0
- package/src/lib/config.js +359 -0
- package/src/lib/cost.js +103 -0
- package/src/lib/deploy/bundle.js +231 -0
- package/src/lib/deploy/compose/acme-verify.js +121 -0
- package/src/lib/deploy/compose/build-args.js +78 -0
- package/src/lib/deploy/compose/ha.js +1874 -0
- package/src/lib/deploy/compose/index.js +1294 -0
- package/src/lib/deploy/compose/reconcile.js +74 -0
- package/src/lib/deploy/github.js +382 -0
- package/src/lib/deploy/image.js +191 -0
- package/src/lib/deploy/index.js +119 -0
- package/src/lib/deploy/k8s/LICENSE +99 -0
- package/src/lib/deploy/k8s/gitops-deploy.js +298 -0
- package/src/lib/deploy/k8s/ha/index.js +1000 -0
- package/src/lib/deploy/k8s/index.js +62 -0
- package/src/lib/deploy/k8s/k3s.js +2515 -0
- package/src/lib/deploy/orchestrator.js +1401 -0
- package/src/lib/deploy/prompts.js +545 -0
- package/src/lib/deploy/remote-build.js +130 -0
- package/src/lib/deploy/state.js +120 -0
- package/src/lib/deploy/utils.js +328 -0
- package/src/lib/deploy-logger.js +93 -0
- package/src/lib/dns-propagation.js +48 -0
- package/src/lib/environment.js +58 -0
- package/src/lib/fetch-retry.js +103 -0
- package/src/lib/github-environments.js +335 -0
- package/src/lib/hetzner-dns.js +377 -0
- package/src/lib/hetzner-guided-setup.js +275 -0
- package/src/lib/host-keys.js +37 -0
- package/src/lib/iac/cloud-init.js +52 -0
- package/src/lib/iac/index.js +325 -0
- package/src/lib/iac/programs/hetzner-compose.js +130 -0
- package/src/lib/iac/programs/hetzner-k8s.js +320 -0
- package/src/lib/kubectl.js +81 -0
- package/src/lib/licensing/index.js +259 -0
- package/src/lib/licensing/tiers.js +181 -0
- package/src/lib/licensing/validator.js +171 -0
- package/src/lib/merge-package-json.js +90 -0
- package/src/lib/operator-ip.js +381 -0
- package/src/lib/package-manager.js +111 -0
- package/src/lib/perf.js +71 -0
- package/src/lib/project-guard.js +39 -0
- package/src/lib/project.js +334 -0
- package/src/lib/providers/base.js +276 -0
- package/src/lib/providers/hetzner-s3.js +656 -0
- package/src/lib/providers/hetzner.js +755 -0
- package/src/lib/providers/index.js +164 -0
- package/src/lib/s3.js +510 -0
- package/src/lib/secret-scan.js +583 -0
- package/src/lib/secrets.js +63 -0
- package/src/lib/server-types.js +195 -0
- package/src/lib/shell.js +91 -0
- package/src/lib/ssh.js +241 -0
- package/src/lib/tracker.js +242 -0
- package/src/lib/upgrade-policy.js +170 -0
- package/src/lib/validators.js +105 -0
- package/src/lib/version.js +5 -0
- package/src/remove.js +292 -0
- package/src/reset.js +97 -0
- package/src/restore.js +871 -0
- package/src/scale.js +1734 -0
- package/src/shell.js +222 -0
- package/src/status.js +981 -0
- package/src/up.js +264 -0
- package/src/upgrade.js +721 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Database"
|
|
3
|
+
description: "Work with Supabase PostgreSQL, migrations, and row-level security."
|
|
4
|
+
order: 5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Your application uses self-hosted Supabase with PostgreSQL. All database operations go through Supabase's client libraries, which provide built-in support for row-level security (RLS).
|
|
10
|
+
|
|
11
|
+
## Schema Overview
|
|
12
|
+
|
|
13
|
+
The initial migration (`supabase/migrations/00001_init.sql`) creates the following tables:
|
|
14
|
+
|
|
15
|
+
| Table | Purpose |
|
|
16
|
+
|-------|---------|
|
|
17
|
+
| `organizations` | Multi-tenant orgs with name, slug, and plan (FREE, STARTER, PRO, ENTERPRISE) |
|
|
18
|
+
| `memberships` | User-org relationships with role (OWNER, ADMIN, MEMBER) |
|
|
19
|
+
| `customers` | Billing customer records, linked to a user or organization (any provider) |
|
|
20
|
+
| `subscriptions` | Billing subscription data (status, period, cancellation) |
|
|
21
|
+
| `notifications` | System-wide or org-specific notifications with scheduling |
|
|
22
|
+
| `notification_dismissals` | Tracks which notifications each user has dismissed |
|
|
23
|
+
| `failed_login_attempts` | Brute force protection (email, IP, timestamp) |
|
|
24
|
+
| `app_settings` | Key-value store for global config (e.g., MFA enforcement) |
|
|
25
|
+
| `cron_job_history` | Background job execution tracking (pg_cron, see [Background Jobs](/docs/background-jobs)) |
|
|
26
|
+
| `contact_submissions` | Contact form submissions (name, email, subject, message, status) |
|
|
27
|
+
| `newsletter_subscribers` | Newsletter subscribers with double opt-in (email, status, confirmation token) |
|
|
28
|
+
|
|
29
|
+
## Migrations
|
|
30
|
+
|
|
31
|
+
SQL migrations live in `supabase/migrations/`. Run them with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pnpm db:migrate
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Conventions
|
|
38
|
+
|
|
39
|
+
- **Naming**: Use zero-padded sequential numbering — `00001_init.sql`, `00002_my_feature.sql`
|
|
40
|
+
- **RLS**: Always enable RLS on new tables and add policies
|
|
41
|
+
- **Timestamps**: Include `created_at` and `updated_at` columns with `TIMESTAMPTZ DEFAULT NOW()`
|
|
42
|
+
- **Triggers**: Always add the `update_updated_at()` trigger for auto-updating `updated_at`
|
|
43
|
+
- **Indexes**: Add indexes for foreign keys and frequently queried columns
|
|
44
|
+
|
|
45
|
+
### Creating a New Table
|
|
46
|
+
|
|
47
|
+
Create a migration file with the table, index, RLS policies, and trigger:
|
|
48
|
+
|
|
49
|
+
```sql
|
|
50
|
+
-- supabase/migrations/00002_my_table.sql
|
|
51
|
+
|
|
52
|
+
CREATE TABLE IF NOT EXISTS my_table (
|
|
53
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
54
|
+
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
55
|
+
name TEXT NOT NULL,
|
|
56
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
57
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_my_table_user_id ON my_table(user_id);
|
|
61
|
+
|
|
62
|
+
-- Enable RLS
|
|
63
|
+
ALTER TABLE my_table ENABLE ROW LEVEL SECURITY;
|
|
64
|
+
|
|
65
|
+
-- CRUD policies
|
|
66
|
+
CREATE POLICY "Users can view their own items"
|
|
67
|
+
ON my_table FOR SELECT
|
|
68
|
+
USING (user_id = (SELECT auth.uid()));
|
|
69
|
+
|
|
70
|
+
CREATE POLICY "Users can create their own items"
|
|
71
|
+
ON my_table FOR INSERT
|
|
72
|
+
WITH CHECK (user_id = (SELECT auth.uid()));
|
|
73
|
+
|
|
74
|
+
CREATE POLICY "Users can update their own items"
|
|
75
|
+
ON my_table FOR UPDATE
|
|
76
|
+
USING (user_id = (SELECT auth.uid()));
|
|
77
|
+
|
|
78
|
+
CREATE POLICY "Users can delete their own items"
|
|
79
|
+
ON my_table FOR DELETE
|
|
80
|
+
USING (user_id = (SELECT auth.uid()));
|
|
81
|
+
|
|
82
|
+
-- Auto-update updated_at
|
|
83
|
+
CREATE TRIGGER my_table_updated_at
|
|
84
|
+
BEFORE UPDATE ON my_table
|
|
85
|
+
FOR EACH ROW
|
|
86
|
+
EXECUTE FUNCTION update_updated_at();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Row-Level Security
|
|
90
|
+
|
|
91
|
+
Every table has RLS enabled. Policies use helper functions defined in the initial migration:
|
|
92
|
+
|
|
93
|
+
### RLS Helper Functions
|
|
94
|
+
|
|
95
|
+
| Function | Returns | Description |
|
|
96
|
+
|----------|---------|-------------|
|
|
97
|
+
| `get_user_org_ids()` | `SETOF UUID` | Org IDs where the user is a member (any role) |
|
|
98
|
+
| `get_user_admin_org_ids()` | `SETOF UUID` | Org IDs where the user is OWNER or ADMIN |
|
|
99
|
+
| `get_user_owner_org_ids()` | `SETOF UUID` | Org IDs where the user is OWNER |
|
|
100
|
+
| `get_user_customer_ids()` | `SETOF UUID` | Customer IDs for the user or their orgs |
|
|
101
|
+
| `is_super_admin()` | `BOOLEAN` | `true` if user's `app_metadata.role` is `super_admin` |
|
|
102
|
+
|
|
103
|
+
All helper functions use `SECURITY DEFINER` so they can read the `memberships` table regardless of the calling user's permissions.
|
|
104
|
+
|
|
105
|
+
### Common Policy Patterns
|
|
106
|
+
|
|
107
|
+
**User-owned data** — rows belong to a specific user:
|
|
108
|
+
|
|
109
|
+
```sql
|
|
110
|
+
CREATE POLICY "Users can view their own items"
|
|
111
|
+
ON my_table FOR SELECT
|
|
112
|
+
USING (user_id = (SELECT auth.uid()));
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Organization data** — rows belong to an org the user is a member of:
|
|
116
|
+
|
|
117
|
+
```sql
|
|
118
|
+
CREATE POLICY "Members can view org data"
|
|
119
|
+
ON my_table FOR SELECT
|
|
120
|
+
USING (organization_id IN (SELECT get_user_org_ids()));
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Admin-only writes** — only org owners/admins can modify:
|
|
124
|
+
|
|
125
|
+
```sql
|
|
126
|
+
CREATE POLICY "Admins can update org data"
|
|
127
|
+
ON my_table FOR UPDATE
|
|
128
|
+
USING (organization_id IN (SELECT get_user_admin_org_ids()));
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Super admin access** — full access for super admins:
|
|
132
|
+
|
|
133
|
+
```sql
|
|
134
|
+
CREATE POLICY "Super admins can do anything"
|
|
135
|
+
ON my_table FOR ALL
|
|
136
|
+
USING (is_super_admin());
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Client-Side Queries
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { supabase } from '@/lib/supabase';
|
|
143
|
+
|
|
144
|
+
// Fetch data (RLS enforced automatically)
|
|
145
|
+
const { data: items, error: fetchError } = await supabase
|
|
146
|
+
.from('my_table')
|
|
147
|
+
.select('*');
|
|
148
|
+
|
|
149
|
+
// Insert data
|
|
150
|
+
const { data: newItem, error: insertError } = await supabase
|
|
151
|
+
.from('my_table')
|
|
152
|
+
.insert({ name: 'New item' })
|
|
153
|
+
.select()
|
|
154
|
+
.single();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Server-Side Queries
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// User-context (respects RLS)
|
|
161
|
+
const supabase = c.get('supabase');
|
|
162
|
+
const { data } = await supabase.from('my_table').select('*');
|
|
163
|
+
|
|
164
|
+
// Admin operations (bypasses RLS)
|
|
165
|
+
import { supabaseAdmin } from '@/server/lib/supabase';
|
|
166
|
+
const { data } = await supabaseAdmin.from('my_table').select('*');
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## TanStack Query
|
|
170
|
+
|
|
171
|
+
Use TanStack Query for client-side data fetching with caching, deduplication, and automatic refetching.
|
|
172
|
+
|
|
173
|
+
### Fetching Data
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { useQuery } from '@tanstack/react-query';
|
|
177
|
+
import { supabase } from '@/lib/supabase';
|
|
178
|
+
|
|
179
|
+
export function useItems() {
|
|
180
|
+
return useQuery({
|
|
181
|
+
queryKey: ['items'],
|
|
182
|
+
queryFn: async () => {
|
|
183
|
+
const { data, error } = await supabase.from('items').select('*');
|
|
184
|
+
if (error) throw error;
|
|
185
|
+
return data;
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Mutations with Cache Invalidation
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
195
|
+
import { supabase } from '@/lib/supabase';
|
|
196
|
+
|
|
197
|
+
export function useCreateItem() {
|
|
198
|
+
const queryClient = useQueryClient();
|
|
199
|
+
|
|
200
|
+
return useMutation({
|
|
201
|
+
mutationFn: async (item: { name: string }) => {
|
|
202
|
+
const { data, error } = await supabase
|
|
203
|
+
.from('items')
|
|
204
|
+
.insert(item)
|
|
205
|
+
.select()
|
|
206
|
+
.single();
|
|
207
|
+
if (error) throw error;
|
|
208
|
+
return data;
|
|
209
|
+
},
|
|
210
|
+
onSuccess: () => {
|
|
211
|
+
queryClient.invalidateQueries({ queryKey: ['items'] });
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Usage in Components
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
function ItemList() {
|
|
221
|
+
const { data: items, isLoading, error } = useItems();
|
|
222
|
+
const createItem = useCreateItem();
|
|
223
|
+
|
|
224
|
+
if (isLoading) return <p>Loading...</p>;
|
|
225
|
+
if (error) return <p>Error: {error.message}</p>;
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<div>
|
|
229
|
+
{items?.map((item) => <p key={item.id}>{item.name}</p>)}
|
|
230
|
+
<button onClick={() => createItem.mutate({ name: 'New item' })}>
|
|
231
|
+
Add Item
|
|
232
|
+
</button>
|
|
233
|
+
</div>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Deployment"
|
|
3
|
+
description: "Deploy your application to production with Docker or Kubernetes."
|
|
4
|
+
order: 6
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
> **Deployment requires a Diamond or Fullerene license.** `create` and local development (`up`, `down`) are always free. See [Getting Started](/docs/getting-started) for licensing details.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Your application can be deployed using Docker Compose, Compose HA, or Kubernetes — all available with a Diamond or Fullerene license. Fullerene is the commercial license for agencies and enterprise.
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
**Always required (all deploy modes):**
|
|
16
|
+
- **GitHub CLI** (`gh`) — authenticated with `read:packages` + `delete_repo` scopes. Images are built by GitHub Actions and published to ghcr.io; deploy waits for the tagged image to appear before provisioning the cluster.
|
|
17
|
+
- **Pulumi** (`curl -fsSL https://get.pulumi.com | sh`) — drives Hetzner VM provisioning.
|
|
18
|
+
- A **domain name** with DNS access (Cloudflare or Hetzner DNS).
|
|
19
|
+
- **SMTP credentials** for transactional email (auth confirmations, magic links, invitations).
|
|
20
|
+
- (Optional) **Stripe API keys** for billing.
|
|
21
|
+
|
|
22
|
+
**Additional for `-mode k8s` / `-mode k8s-ha`:**
|
|
23
|
+
- **kubectl** — applies manifests + waits for the app rollout.
|
|
24
|
+
- **docker** + **ssh** — image is built locally and sideloaded to each k3s node via `docker save | ssh node 'k3s ctr images import -'`. No registry round-trip on the deploy path.
|
|
25
|
+
|
|
26
|
+
**Optional:**
|
|
27
|
+
- `helm` — only required if you layer GitOps on top via [`vibecarbon configure cicd <env>`](/docs/cli#configure-cicd-env-subcommand) (Flux-managed Helm releases). The default deploy path doesn't use it.
|
|
28
|
+
|
|
29
|
+
## Build
|
|
30
|
+
|
|
31
|
+
Build the client and server for production:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pnpm build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This produces:
|
|
38
|
+
- `dist/client/` — Static assets (Vite build with hashed filenames)
|
|
39
|
+
- `dist/server/` — Bundled API server (esbuild output)
|
|
40
|
+
|
|
41
|
+
The `Dockerfile` uses a multi-stage build: a Node.js build stage compiles both client and server, then copies the output into a slim runtime image.
|
|
42
|
+
|
|
43
|
+
## Docker Compose
|
|
44
|
+
|
|
45
|
+
For a single-server deployment:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The production overlay (`docker-compose.prod.yml`) adds:
|
|
52
|
+
- Production environment variables (`NODE_ENV=production`)
|
|
53
|
+
- Resource limits for containers
|
|
54
|
+
- Restart policies (`unless-stopped`)
|
|
55
|
+
- Traefik SSL configuration with Let's Encrypt
|
|
56
|
+
- Host-based routing for your domain
|
|
57
|
+
|
|
58
|
+
Verify the deployment:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
curl -s https://your-domain.com/api/health | jq
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Kubernetes
|
|
65
|
+
|
|
66
|
+
For production deployments with auto-scaling and monitoring (requires Diamond or Fullerene license):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Bare command opens a guided prompt for env, mode, region, etc.
|
|
70
|
+
npx vibecarbon deploy
|
|
71
|
+
|
|
72
|
+
# Or seed env + mode for a scripted deploy
|
|
73
|
+
npx vibecarbon deploy prod -mode k8s
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This command:
|
|
77
|
+
1. Builds the app and sideloads images to every k3s node via SSH (no registry round-trip)
|
|
78
|
+
2. Applies Kubernetes manifests with Kustomize overlays
|
|
79
|
+
3. Configures Traefik ingress with automatic SSL
|
|
80
|
+
4. Sets up monitoring (Grafana, Prometheus, Loki) if observability is enabled
|
|
81
|
+
|
|
82
|
+
The `k8s/` directory structure:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
k8s/
|
|
86
|
+
├── base/ # Shared manifests
|
|
87
|
+
│ ├── app/ # App deployment, service, ingress
|
|
88
|
+
│ ├── supabase/ # Supabase services
|
|
89
|
+
│ └── kustomization.yaml
|
|
90
|
+
└── overlays/
|
|
91
|
+
├── staging/ # Staging-specific config
|
|
92
|
+
└── production/ # Production-specific config
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Node Scaling
|
|
96
|
+
|
|
97
|
+
Worker nodes are bounds-controlled at deploy time — the default is `min=1, max=3` (cluster-autoscaler scales 0..(max-min) workers on top of the static floor). Worker bounds and server types are configured interactively during `vibecarbon deploy` or in `.vibecarbon.json`; they don't have CLI flags (the design principle is "things you set once and forget belong in the config file").
|
|
98
|
+
|
|
99
|
+
To re-tune bounds or worker server types on an existing cluster, run `npx vibecarbon scale` — the wizard walks you through what's changeable for your topology. Power users can seed a server-type change with `-type` (e.g. `npx vibecarbon scale prod -type cx33 -y`). Pod-level autoscaling (HPA) is configured for the app and rest services and scales pods within the existing worker pool based on CPU.
|
|
100
|
+
|
|
101
|
+
> **Note**: k3s masters have no `NoSchedule` taint by default, so all application pods run on the master node when no workers are present.
|
|
102
|
+
|
|
103
|
+
### High Availability
|
|
104
|
+
|
|
105
|
+
**Compose HA** — multi-region Docker Compose with PostgreSQL streaming replication:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npx vibecarbon deploy prod -mode compose-ha
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
This adds:
|
|
112
|
+
- PostgreSQL streaming replication across regions
|
|
113
|
+
- DNS-based health checks with one-command failover (`vibecarbon failover`)
|
|
114
|
+
- Primary + standby VPS architecture
|
|
115
|
+
|
|
116
|
+
**Kubernetes HA** — full K8s clusters per region:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx vibecarbon deploy prod -mode k8s-ha
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This additionally includes:
|
|
123
|
+
- Kubernetes HPA (pod-level autoscaling) per region
|
|
124
|
+
- Cluster Autoscaler (VPS-level autoscaling) per region
|
|
125
|
+
- Health monitoring across replicas
|
|
126
|
+
|
|
127
|
+
## Environment Variables
|
|
128
|
+
|
|
129
|
+
Production requires these environment variables in `.env.production` or your deployment secrets:
|
|
130
|
+
|
|
131
|
+
| Variable | Required | Description |
|
|
132
|
+
|----------|----------|-------------|
|
|
133
|
+
| `SUPABASE_URL` | Yes | Your Supabase API URL |
|
|
134
|
+
| `SUPABASE_ANON_KEY` | Yes | Public anonymous key |
|
|
135
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Yes | Server-side service role key |
|
|
136
|
+
| `SITE_URL` | Yes | Your production URL (e.g., `https://app.example.com`) |
|
|
137
|
+
| `DOMAIN` | Yes | Your root domain (e.g., `example.com`) |
|
|
138
|
+
| `SMTP_HOST` | Yes | SMTP server hostname |
|
|
139
|
+
| `SMTP_PORT` | No | SMTP port (default: 587) |
|
|
140
|
+
| `SMTP_USER` | Yes | SMTP username |
|
|
141
|
+
| `SMTP_PASS` | Yes | SMTP password |
|
|
142
|
+
| `SMTP_SENDER_NAME` | No | Display name for outgoing emails |
|
|
143
|
+
| `SMTP_ADMIN_EMAIL` | No | Admin contact email for system notifications |
|
|
144
|
+
| `BILLING_PROVIDER` | No | Payment provider: `stripe` (default), `paddle`, or `polar` |
|
|
145
|
+
| `STRIPE_SECRET_KEY` | No | Stripe API key (required if using Stripe) |
|
|
146
|
+
| `STRIPE_WEBHOOK_SECRET` | No | Stripe webhook signing secret |
|
|
147
|
+
| `STRIPE_PRICE_STARTER` | No | Stripe price ID for the Startup plan |
|
|
148
|
+
| `STRIPE_PRICE_PRO` | No | Stripe price ID for the Pro plan |
|
|
149
|
+
| `PADDLE_API_KEY` | No | Paddle API key (required if using Paddle) |
|
|
150
|
+
| `PADDLE_WEBHOOK_SECRET` | No | Paddle webhook signing secret |
|
|
151
|
+
| `PADDLE_ENVIRONMENT` | No | `sandbox` or `production` (default: sandbox) |
|
|
152
|
+
| `PADDLE_PRICE_STARTER` | No | Paddle price ID for the Startup plan |
|
|
153
|
+
| `PADDLE_PRICE_PRO` | No | Paddle price ID for the Pro plan |
|
|
154
|
+
| `POLAR_ACCESS_TOKEN` | No | Polar access token (required if using Polar) |
|
|
155
|
+
| `POLAR_WEBHOOK_SECRET` | No | Polar webhook signing secret |
|
|
156
|
+
| `POLAR_ORGANIZATION_ID` | No | Polar organization ID |
|
|
157
|
+
| `POLAR_PRICE_STARTER` | No | Polar product ID for the Startup plan |
|
|
158
|
+
| `POLAR_PRICE_PRO` | No | Polar product ID for the Pro plan |
|
|
159
|
+
| `VITE_PLAUSIBLE_DOMAIN` | No | Plausible analytics domain (e.g., `myapp.com`) |
|
|
160
|
+
| `VITE_PLAUSIBLE_SCRIPT_URL` | No | Plausible script URL (default: Plausible Cloud) |
|
|
161
|
+
| `REDIS_URL` | No | Redis connection URL (for distributed rate limiting) |
|
|
162
|
+
|
|
163
|
+
## SMTP Configuration
|
|
164
|
+
|
|
165
|
+
SMTP credentials are shared between Supabase Auth (for email confirmation, password reset, magic links) and the application's email service (for welcome emails, team invitations, billing notifications).
|
|
166
|
+
|
|
167
|
+
**Required variables**: `SMTP_HOST`, `SMTP_USER`, `SMTP_PASS`
|
|
168
|
+
|
|
169
|
+
**Optional variables**: `SMTP_PORT` (defaults to 587), `SMTP_SENDER_NAME`, `SMTP_ADMIN_EMAIL`
|
|
170
|
+
|
|
171
|
+
Without SMTP configured:
|
|
172
|
+
- Email confirmation is disabled — users can sign in immediately after sign-up
|
|
173
|
+
- Magic link authentication is unavailable
|
|
174
|
+
- Team invitation emails won't send (invitations still work via shareable link)
|
|
175
|
+
- Transactional emails (welcome, billing) are skipped silently
|
|
176
|
+
|
|
177
|
+
## DNS Configuration
|
|
178
|
+
|
|
179
|
+
Point your domain to the server's IP address:
|
|
180
|
+
|
|
181
|
+
| Record | Name | Value |
|
|
182
|
+
|--------|------|-------|
|
|
183
|
+
| A | `app.example.com` | `<server-ip>` |
|
|
184
|
+
| A | `api.example.com` | `<server-ip>` |
|
|
185
|
+
|
|
186
|
+
If you have optional services enabled, add records for their subdomains too (e.g., `grafana.example.com`, `n8n.example.com`).
|
|
187
|
+
|
|
188
|
+
SSL certificates are handled automatically by Traefik via Let's Encrypt — no manual certificate management required.
|
|
189
|
+
|
|
190
|
+
## Backup & Restore
|
|
191
|
+
|
|
192
|
+
Create and manage database backups with the CLI:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Interactive — prompts for env and action
|
|
196
|
+
npx vibecarbon backup
|
|
197
|
+
|
|
198
|
+
# Create a backup for a specific env
|
|
199
|
+
npx vibecarbon backup prod
|
|
200
|
+
|
|
201
|
+
# List existing backups
|
|
202
|
+
npx vibecarbon backup prod -l
|
|
203
|
+
|
|
204
|
+
# Restore from a backup (interactive picker)
|
|
205
|
+
npx vibecarbon restore prod
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Backups include the full PostgreSQL database (schema, data, and auth tables).
|
|
209
|
+
|
|
210
|
+
## Monitoring
|
|
211
|
+
|
|
212
|
+
Add the observability stack for metrics, dashboards, and log aggregation:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
npx vibecarbon add observability
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
This enables:
|
|
219
|
+
- **Prometheus** — Metrics collection from all services
|
|
220
|
+
- **Grafana** — Pre-built dashboards for API performance, database metrics, and container health
|
|
221
|
+
- **Loki** — Centralized log aggregation with Grafana integration
|
|
222
|
+
|
|
223
|
+
Access Grafana at `https://grafana.your-domain.com` (requires `super_admin` role in production).
|
|
224
|
+
|
|
225
|
+
## SSL Certificates
|
|
226
|
+
|
|
227
|
+
Traefik automatically obtains and renews SSL certificates via Let's Encrypt. No manual certificate management required.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Development"
|
|
3
|
+
description: "Day-to-day development workflow, commands, and how to add pages, routes, and content."
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## CLI Commands
|
|
8
|
+
|
|
9
|
+
If you installed Vibecarbon globally, you can manage your dev environment with these commands:
|
|
10
|
+
|
|
11
|
+
| Command | Purpose |
|
|
12
|
+
|---------|---------|
|
|
13
|
+
| `npx vibecarbon up` | Full cold start — Docker, migrations, and dev servers |
|
|
14
|
+
| `npx vibecarbon down` | Stop all Docker services |
|
|
15
|
+
| `npx vibecarbon reset` | Remove containers, volumes, and built images (run `npx vibecarbon up` to restart) |
|
|
16
|
+
|
|
17
|
+
These are wrappers around the `pnpm` scripts listed below — use whichever you prefer.
|
|
18
|
+
|
|
19
|
+
## Dev Commands
|
|
20
|
+
|
|
21
|
+
| Command | Purpose |
|
|
22
|
+
|---------|---------|
|
|
23
|
+
| `pnpm dev:start` | Full cold start — Docker, migrations, and dev servers |
|
|
24
|
+
| `pnpm dev` | Start API + Vite (assumes Docker is already running) |
|
|
25
|
+
| `pnpm dev:reset` | Remove containers, volumes, and built images (run `pnpm dev:start` to restart) |
|
|
26
|
+
| `pnpm docker:up` | Start Supabase and infrastructure services |
|
|
27
|
+
| `pnpm docker:down` | Stop all Docker services |
|
|
28
|
+
| `pnpm db:migrate` | Run SQL migrations from `supabase/migrations/` |
|
|
29
|
+
| `pnpm build` | Build client (Vite) and server (esbuild) for production |
|
|
30
|
+
| `pnpm lint` | Biome linting and formatting check |
|
|
31
|
+
| `pnpm lint:fix` | Auto-fix lint and formatting issues |
|
|
32
|
+
| `pnpm typecheck` | TypeScript type checking |
|
|
33
|
+
| `pnpm test` | Run vitest tests |
|
|
34
|
+
| `pnpm start` | Run production server (`node dist/server/index.js`) |
|
|
35
|
+
| `pnpm stripe:listen` | Forward Stripe webhooks to local API |
|
|
36
|
+
| `pnpm docker:logs` | Tail logs from all Docker containers |
|
|
37
|
+
|
|
38
|
+
## How It Works
|
|
39
|
+
|
|
40
|
+
`pnpm dev:start` runs three phases in sequence:
|
|
41
|
+
|
|
42
|
+
1. **Docker startup** — Starts PostgreSQL, Kong, GoTrue, PostgREST, Realtime, Storage, Studio, and Traefik. Blocks until all services are healthy.
|
|
43
|
+
2. **Migrations** — Executes all SQL files in `supabase/migrations/` to set up the schema, RLS policies, and initial admin user.
|
|
44
|
+
3. **Dev servers** — Spawns two processes in parallel:
|
|
45
|
+
- **Hono API** on port 3000 via `tsx watch` (auto-restarts on file changes)
|
|
46
|
+
- **Vite** on port 5173 with full HMR (instant browser updates)
|
|
47
|
+
|
|
48
|
+
Vite proxies all `/api/*` requests to the Hono server, so the client can call `fetch('/api/v1/...')` without worrying about ports or CORS.
|
|
49
|
+
|
|
50
|
+
## Development URLs
|
|
51
|
+
|
|
52
|
+
Traefik routes `*.localhost` subdomains to each service:
|
|
53
|
+
|
|
54
|
+
| Service | URL |
|
|
55
|
+
|---------|-----|
|
|
56
|
+
| App | http://app.localhost |
|
|
57
|
+
| Supabase Studio | http://studio.localhost |
|
|
58
|
+
| Traefik Dashboard | http://traefik.localhost |
|
|
59
|
+
|
|
60
|
+
Optional services (n8n, Metabase, Grafana) get their own subdomains when enabled — see [Optional Services](/docs/optional-services).
|
|
61
|
+
|
|
62
|
+
## Hot Reloading
|
|
63
|
+
|
|
64
|
+
**Client changes** (React components, CSS, MDX) update instantly in the browser via Vite HMR. Component state is preserved.
|
|
65
|
+
|
|
66
|
+
**Server changes** (API routes, middleware) trigger a full process restart via `tsx watch`. The API is briefly unavailable during restart.
|
|
67
|
+
|
|
68
|
+
**Database changes** require running `pnpm db:migrate` manually — migrations are not watched.
|
|
69
|
+
|
|
70
|
+
## Debugging
|
|
71
|
+
|
|
72
|
+
**Container logs** — Run `pnpm docker:logs` to tail logs from all Docker services. Useful for debugging Supabase Auth errors, PostgREST issues, or Kong routing problems.
|
|
73
|
+
|
|
74
|
+
**Supabase Studio** — Open [http://studio.localhost](http://studio.localhost) to browse your database, inspect tables, view RLS policies, and manage auth users directly.
|
|
75
|
+
|
|
76
|
+
**React DevTools** — Vite's dev server supports React DevTools out of the box. Install the browser extension for component inspection and state debugging.
|
|
77
|
+
|
|
78
|
+
## Adding a Page
|
|
79
|
+
|
|
80
|
+
1. Create a component in `src/client/pages/`:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
export default function MyPage() {
|
|
84
|
+
return <h1>My Page</h1>;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
2. Add a route in `src/client/App.tsx`:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<Route
|
|
92
|
+
path="/my-page"
|
|
93
|
+
element={
|
|
94
|
+
<ProtectedRoute>
|
|
95
|
+
<MyPage />
|
|
96
|
+
</ProtectedRoute>
|
|
97
|
+
}
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Wrap with `<ProtectedRoute>` to require authentication, or omit it for public pages.
|
|
102
|
+
|
|
103
|
+
## Adding an API Route
|
|
104
|
+
|
|
105
|
+
1. Create a route file in `src/server/routes/v1/`:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { Hono } from 'hono';
|
|
109
|
+
import { z } from 'zod';
|
|
110
|
+
import type { HonoVariables } from '../../types';
|
|
111
|
+
|
|
112
|
+
const items = new Hono<{ Variables: HonoVariables }>();
|
|
113
|
+
|
|
114
|
+
const createSchema = z.object({
|
|
115
|
+
name: z.string().min(1).max(100),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
items.get('/', async (c) => {
|
|
119
|
+
const user = c.get('user');
|
|
120
|
+
if (!user) return c.json({ error: 'Unauthorized' }, 401);
|
|
121
|
+
|
|
122
|
+
const supabase = c.get('supabase');
|
|
123
|
+
const { data, error } = await supabase.from('items').select('*');
|
|
124
|
+
if (error) return c.json({ error: 'Failed to fetch items' }, 500);
|
|
125
|
+
return c.json(data);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
items.post('/', async (c) => {
|
|
129
|
+
const user = c.get('user');
|
|
130
|
+
if (!user) return c.json({ error: 'Unauthorized' }, 401);
|
|
131
|
+
|
|
132
|
+
const body = await c.req.json();
|
|
133
|
+
const result = createSchema.safeParse(body);
|
|
134
|
+
if (!result.success) {
|
|
135
|
+
return c.json({ error: result.error.issues.map((e) => e.message).join(', ') }, 400);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const supabase = c.get('supabase');
|
|
139
|
+
const { data, error } = await supabase
|
|
140
|
+
.from('items')
|
|
141
|
+
.insert(result.data)
|
|
142
|
+
.select()
|
|
143
|
+
.single();
|
|
144
|
+
if (error) return c.json({ error: 'Failed to create item' }, 500);
|
|
145
|
+
return c.json({ item: data }, 201);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
export { items };
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
2. Mount in `src/server/index.ts`:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { items } from './routes/v1/items';
|
|
155
|
+
app.route('/api/v1/items', items);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The Vite proxy forwards `/api/*` to the Hono server automatically.
|
|
159
|
+
|
|
160
|
+
## Adding MDX Content
|
|
161
|
+
|
|
162
|
+
MDX files in `content/` are auto-discovered at build time. Drop a file in the right directory and it appears on the site.
|
|
163
|
+
|
|
164
|
+
**Blog post** — `content/blog/my-post.mdx`:
|
|
165
|
+
|
|
166
|
+
```markdown
|
|
167
|
+
---
|
|
168
|
+
title: "My Post"
|
|
169
|
+
description: "A short summary."
|
|
170
|
+
date: "2025-01-15"
|
|
171
|
+
author: "Your Name"
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
Post content with **markdown** and JSX.
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Documentation page** — `content/docs/my-page.mdx`:
|
|
178
|
+
|
|
179
|
+
```markdown
|
|
180
|
+
---
|
|
181
|
+
title: "My Page"
|
|
182
|
+
description: "What this page covers."
|
|
183
|
+
order: 7
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
Page content here.
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Changelog entry** — `content/changelog/v1-1-0.mdx`:
|
|
190
|
+
|
|
191
|
+
```markdown
|
|
192
|
+
---
|
|
193
|
+
title: "v1.1.0"
|
|
194
|
+
description: "What changed."
|
|
195
|
+
date: "2025-01-15"
|
|
196
|
+
version: "1.1.0"
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Features
|
|
200
|
+
- New feature
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The `order` field controls sidebar position in docs. Blog and changelog entries sort by `date` (newest first).
|
|
204
|
+
|
|
205
|
+
## Running Multiple Projects
|
|
206
|
+
|
|
207
|
+
To run two Vibecarbon projects simultaneously, set a port offset in `.env.local`:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
DEV_PORT_OFFSET=100
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
This shifts all ports by 100 (Vite → 5273, API → 3100, Kong → 8100, etc.). You can also override individual ports:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
DEV_VITE_PORT=5273
|
|
217
|
+
DEV_API_PORT=3100
|
|
218
|
+
DEV_KONG_PORT=8100
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Resetting the Environment
|
|
222
|
+
|
|
223
|
+
If your database gets into a bad state or you want a clean slate:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
pnpm dev:reset # Remove containers, volumes, and built images
|
|
227
|
+
pnpm dev:start # Cold start: Docker + migrations + dev servers
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`dev:reset` removes all Docker containers, volumes (including database data), and locally-built images. It does **not** restart services — run `pnpm dev:start` afterward to start fresh.
|
|
231
|
+
|
|
232
|
+
To stop services without losing data:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
pnpm docker:down # Stop services, data preserved in volumes
|
|
236
|
+
pnpm docker:up # Restart services with existing data
|
|
237
|
+
pnpm dev # Start dev servers
|
|
238
|
+
```
|