Let users size the database workload from the deploy wizard the same way
Redis/RabbitMQ are configured: a resource card (CPU request/limit, memory
request/limit, storage) on the Resources step, stored in
optionalServiceResources.database.
- entity/DTO: add `database` to optionalServiceResources
- k8s: resolveDatabaseResources() applies user-selected resources on both
the Helm and K8s-API deploy paths (was hardcoded 100m/256Mi→500m/512Mi)
- billing: bill database CPU/RAM as a separate line on top of the app's
resources; merge it through the upgrade path too
- wizard: db resource card on the Resources step, disk moved into the card,
cost preview + review summary include the database resources
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Removing a custom domain left the Ingress with a stale custom-domain rule
and no preview host, so the platform preview URL 404'd. updateIngress now
resolves the app's stable preview number from its latest deployment and
re-emits the preview host (with cert-manager TLS) whenever no verified
custom domain is set, and removeCustomDomain re-applies the Ingress.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ingress / preview URLs:
- Default the app Ingress class and ACME HTTP-01 solver to Traefik
(k3s default) via a new INGRESS_CLASS env, instead of hardcoding nginx —
fixes 404s on clusters without ingress-nginx.
- Only put public, real-TLD hosts (custom domain + preview) in the TLS
block; the internal *.apps.cloudhost.local host no longer poisons the
Let's Encrypt order, so certs actually issue.
- Make the per-app preview number stable across redeploys so URLs stop
breaking, and let PREVIEW_BASE_DOMAIN configure the base domain.
Registry pulls:
- Point the k3s registries.yaml mirror endpoint at the registry NodePort on
loopback so node containerd never depends on cluster DNS (image pulls
survive node restarts).
Builds:
- Pin the Kaniko image, use IfNotPresent pull policy, drop the dead build
queue/processor, and retry transient Kubernetes API errors while polling
build jobs.
Logs & apps list:
- fluent-bit reads log files from head so startup output reaches
Elasticsearch.
- Order joined deployments newest-first so the apps list shows the latest
deployment status.
Allocation:
- Reserve in-flight (pending/building) capacity and stop globally degrading
the cluster on a single allocation failure, so concurrent deploys don't
starve or wrongly report "no healthy cluster".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce a catalog-driven Tools Management section under Clusters so
admins can install/uninstall infrastructure tools per cluster: cert-manager
(Helm/jetstack), ClusterIssuer (email + HTTP01 form, depends on cert-manager),
and central Elasticsearch. Cluster creation no longer auto-installs Elastic
or the cloudhost-node-cluster-dns DaemonSet; build bootstrap stays automatic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Build hosts as <userPrefix>-<deploymentNumber>-preview.<rootDomain> from FRONTEND_URL, wire them through ingress/TLS, and open them from the preview API.
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto port-forward using the registered cluster kubeconfig, default to loopback outside Kubernetes, route log APIs by app cluster, and document platform env settings.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove external registry Ingress (repo.3fase.ir) and route Kaniko push and app pulls through the internal ClusterIP registry. Add RegistryService, ensure StorageClass and pull secrets on deploy, make Elasticsearch install/repair more resilient, and add per-cluster Deploy Elastic controls in admin UI.
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto-reconnect Elasticsearch port-forward after cluster or API restarts, poll log status in the UI, and apply storage changes through billing upgrade for all workloads. Add Redis/RabbitMQ PVC resize, Helm ES credentials for Fluent Bit, and fix deploy progress overlay behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce product types for managed PostgreSQL, Redis, and RabbitMQ with a dedicated dashboard, Helm-only deploy pipeline, external access, snapshots with progress, and prorated resource or storage upgrades matching application billing rules. PVCs use an expandable StorageClass with automatic migration when legacy disks cannot resize in place.
Co-authored-by: Cursor <cursoragent@cursor.com>
Deployment success now reflects readiness across the application, database, and enabled add-on workloads so scheduling or resource failures do not appear as a running app.
Co-authored-by: Cursor <cursoragent@cursor.com>
Users pick per-service CPU/memory/storage at deploy; admins manage unit rates and deploy defaults. PATCH sends only fields accepted by the pricing-catalog DTO.
Co-authored-by: Cursor <cursoragent@cursor.com>
Deploy cloudhost-logging on cluster registration, ship app and optional service logs to ES with owner isolation, and fix Kibana 8.12 auth via kibana_system.
Co-authored-by: Cursor <cursoragent@cursor.com>
Users can open temporary NodePort access with auto-revoke via Bull jobs and a dashboard UI to manage active grants.
Co-authored-by: Cursor <cursoragent@cursor.com>
Read live deployment replica counts from K8s before scaling to zero,
store them on the application as suspendedReplicas, and use that snapshot
when resuming so Start restores the pre-stop replica layout.
Co-authored-by: Cursor <cursoragent@cursor.com>
Use suspendApplication on stop so app, database, Redis, and RabbitMQ
deployments scale to zero. Start uses resumeApplication to bring the
full stack back. Deployment status is updated to stopped/running.
Co-authored-by: Cursor <cursoragent@cursor.com>
Inject APP_URL for Laravel/PHP apps when missing: on create from the
platform subdomain, on custom-domain verification from the verified host,
and at deploy time as a safety net. Never overwrites user-provided values.
Co-authored-by: Cursor <cursoragent@cursor.com>
Laravel images no longer bake config:cache at build time, which ignored
K8s DB env vars. Add DB_CONNECTION, clear config on boot, generate APP_KEY
when missing, run migrations, and rebuild caches at container start.
Co-authored-by: Cursor <cursoragent@cursor.com>
Set Laravel DB env vars in Helm and Kubernetes, fix default port to 80 with a storage-aware entrypoint, and let users upload a .env file during deploy.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace port-forward/netcat PVC upload with kubectl cp for integrity
- Add build cancellation API and session cleanup; deploy catches cancel
- Default port 80 for WordPress, PHP, and Laravel on create
- Build progress modal with cancel; Helm/K8s adjustments for deployments
- Update build and kubernetes specs
Co-authored-by: Cursor <cursoragent@cursor.com>
Add admin endpoints for stack deploy/status and user-facing logs
query API. Register controllers and service in KubernetesModule.
Co-authored-by: Cursor <cursoragent@cursor.com>
Deploy and manage central Elasticsearch + Kibana via K8s API, with
health checks, credentials, and per-user log query helpers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Users can assign a custom domain to their app with automatic SSL via
cert-manager. Includes DNS verification flow (CNAME check), Persian
instructions, admin-configurable pricing via PlatformSetting, and
integration into the deploy wizard cost calculation.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add helm/kubectl binaries and chart directory to backend Dockerfile
- Extend Helm templates for MongoDB/MariaDB database support (env vars, probes, ports)
- Add Redis and RabbitMQ Helm templates (deployment, service, secret, PVC)
- Add generic app-storage PVC and Fluent Bit sidecar with ES authentication
- Fix imagePullSecrets in K8s API fallback, prevent secret regeneration on redeploy
- Clean up Redis/RabbitMQ/FluentBit resources on app deletion without removing shared secrets
- Fix HelmService chartPath resolution for production Docker builds
Co-authored-by: Cursor <cursoragent@cursor.com>
- Job containers now sleep 120s after completing dump/archive
- This allows exec to retrieve files before container exits
- Wait for DUMP_DONE/ARCHIVE_DONE marker before attempting exec
- Cleanup job immediately after retrieval
- Fix Helm registry-pull-secret ownership conflict with lookup
- deployApplication now tries Helm first, falls back to direct K8s API
- Restored all private methods: ensureNamespace, applySecret, applyDeployment,
applyService, applyIngress, applyWordPressPvc, deployDatabase, createDbSecret, createPVC
- Added ManifestContext interface
- Added DATABASE_URL env var, PGDATA, health probes for DB, ingressClassName
- Add revisionHistoryLimit: 10 and change-cause annotation to K8s deployments
- Add getDeploymentRevisions() to list ReplicaSet revision history
- Add rollbackDeploymentRevision() using K8s API (instant, no rebuild)
- Refactor snapshot rollback: use K8s revision for app, keep file-based DB/wp-content restore
- Add GET /snapshots/applications/:appId/revisions endpoint
- Add POST /snapshots/applications/:appId/revisions/:rev/rollback endpoint
- Add K8sRevision and K8sRevisionData types to frontend
- Redesign UI with two tabs: K8s Revisions (instant) + File Snapshots (full backup)
- K8s Revisions tab shows deployment history with one-click instant rollback
- File Snapshots tab retains download, DB restore, and wp-content restore
- Add AppSnapshot entity with type (pre_deploy/manual), status tracking, and file paths
- Add SnapshotsService with create, capture, rollback, prune (max 10), and download logic
- Add SnapshotsController with REST endpoints for CRUD, rollback, and file downloads
- Add K8s methods: exportDatabaseDump, archiveWpContent, restoreWpContent
- Auto-create pre-deploy snapshots before each deployment for rollback safety
- Support downloading current live state (source, wp-content, database) without snapshots
- Add snapshot management UI in app detail page with create, rollback, download, delete
- Wire circular dependencies with forwardRef between Deployments and Snapshots modules
- Add dbStorageSize column to Application entity (default: 1Gi)
- Add dbStorageSize to CreateApplicationDto, frontend types
- Use dynamic storage size in K8s deployDatabase instead of hardcoded 5Gi
- Deploy page: storage size selector with +/- buttons (min 1GB, max 100GB)
- Auto-suggest storage based on DB dump file size (3x dump size, min 1GB)
- Show DB storage in Review step
- App detail: Database Storage section with expand button
- GET /applications/:id/db-storage — read current PVC size from K8s
- PATCH /applications/:id/db-storage — expand PVC (only increase, no shrink)
- PVC resize uses JSON patch on K8s API
Backend:
- Add runtimeVersion, phpVersion, dbVersion columns to Application entity
- Add version fields to CreateApplicationDto with validation
- Node.js Dockerfile: use selected version (22/20/18/16) instead of hardcoded 20
- Laravel Dockerfile: use selected PHP version (8.4/8.3/8.2/8.1) instead of 8.3
- WordPress Dockerfile: use selected WP version (6.7/6.6/6.5/6.4) + PHP version
- K8s deployDatabase(): use selected DB version instead of hardcoded postgres:16/mysql:8.0
- K8s restoreDatabaseDump(): match DB image version for restore jobs
- Add dbVersion to ManifestContext interface
Frontend:
- Add runtimeVersion, phpVersion, dbVersion to Application and CreateApplicationDto
- Deploy page: Node.js version dropdown (22/20/18/16)
- Deploy page: Laravel PHP version dropdown (8.4/8.3/8.2/8.1)
- Deploy page: WordPress version + PHP version dropdowns
- Deploy page: PostgreSQL version dropdown (17/16/15/14)
- Deploy page: MySQL version dropdown (9.0/8.4/8.0/5.7)
- Deploy page: auto-set default versions on runtime/DB selection
- Review step: show selected versions
- App detail page: display runtime + DB versions in config and header
Backend:
- Add WORDPRESS to AppRuntime enum
- Add wordpressDockerfile() using wordpress:6-php8.3-apache base image
with custom theme/plugin/wp-content merge support
- Add WordPress-specific K8s env vars (WORDPRESS_DB_HOST, WORDPRESS_DB_USER,
WORDPRESS_DB_PASSWORD, WORDPRESS_DB_NAME, WORDPRESS_TABLE_PREFIX)
- Create wp-content PersistentVolumeClaim (2Gi) for WordPress deployments
- Mount wp-content PVC in deployment container at /var/www/html/wp-content
Frontend:
- Add 'wordpress' to runtime type unions (Application, CreateApplicationDto)
- Add WordPress runtime card in deploy page (port 80, blue icon)
- Auto-select MySQL database when WordPress is chosen, disable other DB options
- Show Persian hint 'وردپرس به MySQL نیاز دارد' when WordPress selected
- Update all runtime icon colors across dashboard, apps, admin/apps pages
to show blue-600 for WordPress
Backend:
- Add dbUsername/dbPassword columns to Application entity
- Add optional DB credential fields to CreateApplicationDto
- Auto-generate dbPassword (crypto.randomBytes) and default dbUsername='appuser'
when databaseType != 'none' on app creation
- Store both username and password in K8s DB secret (was password-only)
- Read DB_USER/POSTGRES_USER/MYSQL_USER from secretKeyRef instead of hardcoded
- New restoreDatabaseDump() in KubernetesService: creates K8s Job with
psql/mysql client to restore uploaded SQL dump, waits for completion,
returns logs
- New POST /applications/:id/db-upload endpoint with 500MB file limit
Frontend:
- Add dbUsername/dbPassword to Application and CreateApplicationDto types
- Deploy page: show username/password fields when database is selected,
with generate-random-password button and show/hide toggle
- App detail page: new Database section with connection info (host, port,
db name, username, password with copy-to-clipboard), SQL dump upload
area with drag-and-drop, and restore output logs display
Security:
- Database remains ClusterIP only (no external exposure)
- Credentials stored in K8s Secrets (base64-encoded)
- Dump file uploaded as temporary K8s Secret, auto-cleaned after restore
Most user apps (e.g. Next.js) don't have a /health endpoint, causing
liveness/readiness probes to fail with 404 and crash-loop the pods.
TCP socket probes just check if the port is open, which works universally.
- Backend: getPreviewInfo() in KubernetesService auto-patches ClusterIP
service to NodePort for direct external access
- Backend: GET /applications/:id/preview endpoint returns access URL
with nodePort, host IP (extracted from kubeconfig), and ingress URL
- Frontend: '🌐 Preview' button on app detail page (visible when running)
opens the deployed app in a new browser tab via NodePort URL
- Tested: service patched to NodePort 30107 successfully
- Backend: getResourceUsage() method in KubernetesService fetches real-time
CPU/Memory metrics from K8s metrics-server API per pod
- Backend: updateResources() method patches live K8s deployments with new
CPU/Memory requests+limits and replica count
- Backend: GET /applications/:id/resources endpoint for monitoring
- Backend: PATCH /applications/:id/resources endpoint for scaling
- Backend: ScaleResourcesDto with validation for resource fields
- Frontend: Resource monitoring card with per-pod CPU/Memory progress bars
(color-coded: green < 50%, yellow < 80%, red > 80%)
- Frontend: Pod status table showing phase, readiness, restarts
- Frontend: Scaling controls for CPU request/limit, memory request/limit,
and replicas with +/- buttons
- Frontend: Auto-refresh metrics every 5 seconds when monitoring is open
- Frontend: parseCpuToMillicores/parseMemoryToMi helpers for metric parsing