Close billing, tenancy, migration, build, and CI/CD gaps identified in the
audit: wallet/gateway guards, full-UUID namespaces, idempotent migrations with
base schema, stateful service stability, safer Dockerfiles/git builds, and
platform chart hardening (Redis auth, RollingUpdate, backups, Swagger off).
Co-authored-by: Cursor <cursoragent@cursor.com>
Harbor in-cluster builds via Kaniko, ArgoCD auto-sync, and production Helm values for abrban.com domains.
Co-authored-by: Cursor <cursoragent@cursor.com>
Reject zip uploads when the selected runtime does not match archive contents, and re-validate before Kaniko builds to fail fast instead of producing the wrong Dockerfile.
Co-authored-by: Cursor <cursoragent@cursor.com>
Rework the application build/deploy pipeline for scalability, reproducibility,
and security:
- Build queue: deploys run through a bounded-concurrency Bull queue
(BUILD_CONCURRENCY, default 3) so concurrent user deploys can't flood the
cluster with Kaniko jobs. Build state (progress / cancel / session) moves from
in-memory Maps to Redis, so cancel + live logs work across backend replicas.
- Nixpacks + BYO Dockerfile: code runtimes build via Nixpacks (or the user's own
Dockerfile when present); the hand-written per-runtime Dockerfile generators
and runtime auto-detection are removed. WordPress keeps its templated path.
Build-time mirror env (NIXPACKS_BUILD_ENV) supports the Iran network.
- Source upload to MinIO: archives stream to in-cluster MinIO; build pods pull
via a presigned URL. Removes the PVC + helper pod + kubectl cp upload path.
- Report-only Trivy scan after build; per-severity summary stored on the
deployment and shown as a badge in the dashboard. Never gates a deploy.
- Registry GC: a Redis-locked daily job keeps the newest N image tags per app
(REGISTRY_KEEP_VERSIONS, default 3) and reclaims disk via garbage-collect.
- Hardening: git tokens are delivered via a per-build Secret + git credential
store instead of being embedded in the clone URL / Job manifest; build timeout
is configurable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the admin-only "cluster assignment" UI from the resources &
config step of the deploy wizard and the related backend override.
App placement is now always decided automatically by the allocator.
- frontend: remove cluster/pool selection block, review-step cluster
row, clusterMode state, public cluster/pool queries, and clusterId/
poolId from CreateApplicationDto
- backend: drop clusterId/poolId override from the create DTO and
simplify ApplicationsService.create to always auto-allocate; widen
selectClusterForApplication param to keep the fallback path working
Co-Authored-By: Claude Opus 4.8 <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>
Assign unpredictable subdomains on create when no custom domain is set, and update deploy UI CNAME hints to reference the app Platform Domain after creation.
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>
When users delete an app before plan expiry, remaining resources become credits for a new deploy. The deploy calculator shows covered vs additional charges, prices optional services correctly, and prorates extras to days left on the credit.
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>
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>
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>
- 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>
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>
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
- Add GET /applications/all endpoint for admin/technical with search by user name/email/ID
- GET /applications now always returns only the current user's apps (fix for technical seeing all apps)
- Technical role can view/edit/delete any application (same as admin)
- Add 'All Applications' page with search bar, user info columns, status badges
- Add 'All Applications' link to admin and technical sidebar navigation
- Add user relation to Application TypeScript interface
Backend:
- Added TECHNICAL and SALES roles to UserRole enum
- Added TicketDepartment, TicketStatus, TicketPriority enums
- Created Ticket and TicketMessage entities with relationships
- Created TicketsModule with full CRUD service and controller
- Ticket routing: users create tickets to technical/sales departments
- Staff reply updates status (answered), user reply sets waiting
- Role-based access: technical staff sees technical tickets, sales sees sales tickets
- Admin sees all tickets with stats (total, open, avg response time)
- Updated access control: technical role has admin-level access (except role change)
- Sales role can view users and handle sales tickets
- Clusters controller: technical role can manage clusters/pools
- Users controller: technical/sales can view users, only admin changes roles
Frontend:
- New user ticket pages: list (with create form) + detail (chat-style messages)
- Staff ticket panel: filtered by department with status filters
- Admin all-tickets page with statistics dashboard and department/status filters
- Updated sidebar: role-based nav items (admin/technical/sales sections)
- Role badges in header for technical (blue) and sales (green)
- Admin users page: new roles in dropdowns, role change restricted to admin only
- Deploy page: technical role gets cluster selection access like admin
Backend:
- ApplicationsService.create() now accepts userRole parameter
- Non-admin users have clusterId/poolId stripped automatically
- Logs warning when non-admin attempts manual cluster selection
Frontend:
- Deploy wizard hides cluster assignment mode selector for non-admin users
- Non-admin users see a simple 'Default Cluster' info box instead
- Cluster/pool API queries only execute for admin users (enabled: isAdmin)
- Review step shows 'Default Cluster' for non-admin regardless of form state
- Add ClusterPool entity for grouping clusters into named pools
- Support 3 deployment modes: manual cluster, pool load-balanced, default fallback
- Pool strategies: least-apps (fewest deployed apps) and round-robin
- Add pool CRUD API endpoints (admin) and public pool listing
- Frontend deploy page: 3-mode cluster selector (Default/Manual/Pool)
- Frontend app detail: shows assigned cluster and pool info
- Admin pools management page with cluster selection and strategy picker
- Application entity extended with poolId field