Per docs/PROVISIONING-PLAN.md Phase 1. Catalyst-Zero (the running deployment on Contabo k3s, namespaces catalyst/sme/marketplace/website) source code now lives in this public repo. Cutover to public-repo CI builds happens in Phase 2.
What moved (from openova-private → openova):
- apps/console/ → core/console/ (Astro+Svelte UI)
- apps/admin/ → core/admin/ (Astro+Svelte UI, includes canonical voucher/billing/tenants admin surface)
- apps/marketplace/ → core/marketplace/ (Astro+Svelte UI, 5-step Plan→Apps→Addons→Checkout→Review flow)
- website/marketplace-api/ → core/marketplace-api/ (Go backend with handlers/, provisioner/, store/)
- clusters/contabo-mkt/apps/catalyst/ → products/catalyst/chart/templates/ (catalyst-{ui,api} K8s manifests)
- clusters/contabo-mkt/apps/sme/services/ → products/catalyst/chart/templates/sme-services/ (15 manifests)
- clusters/contabo-mkt/apps/marketplace-api/ → products/catalyst/chart/templates/marketplace-api/
- 5 CI workflows (catalyst-build, marketplace-api-build, sme-{admin,console,marketplace}-build) → .github/workflows/, renamed to drop "sme-" prefix
Image refs updated:
- ghcr.io/openova-io/openova-private/catalyst-{ui,api} → ghcr.io/openova-io/openova/catalyst-{ui,api}
- ghcr.io/openova-io/openova-private/sme-{admin,console,marketplace} → ghcr.io/openova-io/openova/{admin,console,marketplace}
- ghcr.io/openova-io/openova-private/marketplace-api → ghcr.io/openova-io/openova/marketplace-api
Workflow path updates:
- paths: 'apps/{X}/**' → 'core/{X}/**'
- context: apps/{X} → core/{X}
- deploy paths: clusters/contabo-mkt/apps/{X}/.../{X}.yaml → products/catalyst/chart/templates/.../{X}.yaml
- deploy commit: git add clusters/ → git add products/
Deferred to follow-up phase:
- 8 legacy SME backend services (auth, billing, catalog, domain, gateway, notification, provisioning, tenant) keep their ghcr.io/openova-io/openova-private/sme-* image refs because their source code in openova-private/services/ has not yet been migrated to public repo. Tracked via TODO in core/README.md migration history.
- sme-services-build.yaml NOT migrated (matches deferred services).
Documentation updates:
- core/README.md rewritten to describe what's actually in this directory now (4 deployed modules, not the old Go-monorepo placeholder design)
- products/catalyst/README.md created with migration status table
- products/catalyst/chart/Chart.yaml created (umbrella bp-catalyst-platform chart)
- docs/IMPLEMENTATION-STATUS.md §1 + §2.1 + §6 updated: console/admin/marketplace/marketplace-api/catalyst-{ui,api} all flipped from 📐 to 🚧 (deployed but not yet wired to unified Catalyst contract); openova Sovereign description rewritten to make Catalyst-Zero status explicit; omantel target updated to omantel.omani.works on Hetzner.
Verification:
- 99 source files copied (verified via git ls-files count)
- All image refs updated except the 8 deferred legacy SME backend services (verified via grep openova-private)
- Workflow naming reflects unified Catalyst (no more "sme-" prefix)
Phase 2 next: trigger public-repo CI builds, GHCR images published under openova/ namespace, Flux source on Catalyst-Zero repointed to this repo, rolling update of Contabo pods to new image SHAs. Catalyst-Zero becomes self-built from the public repo.
81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/openova-io/openova-private/website/marketplace-api/store"
|
|
)
|
|
|
|
// runProvisioning simulates the async provisioning workflow.
|
|
// In production, this commits manifests to Git and polls Flux reconciliation status.
|
|
func (h *Handler) runProvisioning(p *store.Provision) {
|
|
sizeLabels := map[string]string{"xs": "XS", "s": "S", "m": "M", "l": "L"}
|
|
|
|
for i := range p.Steps {
|
|
now := time.Now()
|
|
p.Steps[i].Status = store.StatusProvisioning
|
|
p.Steps[i].StartedAt = &now
|
|
p.UpdatedAt = now
|
|
h.Store.UpdateProvision(p)
|
|
|
|
// Simulate work — in production this would be:
|
|
// 1. Git commit (vcluster.yaml, resource-quota.yaml, helmrelease.yaml)
|
|
// 2. Wait for Flux reconciliation webhook
|
|
// 3. Verify pod readiness
|
|
duration := 3*time.Second + time.Duration(i)*time.Second
|
|
time.Sleep(duration)
|
|
|
|
done := time.Now()
|
|
p.Steps[i].Status = store.StatusCompleted
|
|
p.Steps[i].DoneAt = &done
|
|
p.Steps[i].Message = "Done"
|
|
p.UpdatedAt = done
|
|
h.Store.UpdateProvision(p)
|
|
|
|
log.Printf("Provision %s: step %d/%d completed (%s)", p.ID, i+1, len(p.Steps), p.Steps[i].Name)
|
|
}
|
|
|
|
p.Status = store.StatusCompleted
|
|
p.UpdatedAt = time.Now()
|
|
h.Store.UpdateProvision(p)
|
|
|
|
// Create tenant record
|
|
tenant := &store.Tenant{
|
|
ID: p.TenantID,
|
|
CompanyName: p.CompanyName,
|
|
Email: p.Email,
|
|
Subdomain: p.Subdomain,
|
|
VClusterName: "vc-" + p.Subdomain,
|
|
VClusterStatus: "running",
|
|
Size: p.Size,
|
|
SizeLabel: sizeLabels[p.Size],
|
|
Apps: make([]store.App, 0, len(p.Apps)),
|
|
Domains: []store.Domain{
|
|
{
|
|
Domain: p.Subdomain + ".openova.cloud",
|
|
Type: "subdomain",
|
|
TLSReady: true,
|
|
CreatedAt: time.Now().Format(time.RFC3339),
|
|
},
|
|
},
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
for _, appSlug := range p.Apps {
|
|
tenant.Apps = append(tenant.Apps, store.App{
|
|
Slug: appSlug,
|
|
Name: appSlug, // In production, resolve from catalog
|
|
Status: "running",
|
|
URL: "https://" + appSlug + "." + p.Subdomain + ".openova.cloud",
|
|
Version: "latest",
|
|
DeployedAt: time.Now().Format(time.RFC3339),
|
|
Healthy: true,
|
|
})
|
|
}
|
|
|
|
h.Store.CreateTenant(tenant)
|
|
|
|
log.Printf("Provision %s completed: tenant %s created with %d apps", p.ID, p.TenantID, len(p.Apps))
|
|
}
|