Update both docs to match the code after reverting the build-pipeline revamp: Kaniko with per-runtime generated Dockerfiles, disk/PVC + git source, no Nixpacks/MinIO/Trivy/registry-GC/build-queue. Also refreshes the stack (Next.js 16, NestJS 11), mobile-OTP auth, the three Helm charts, project structure, and local + cluster deploy steps. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
15 KiB
🏗️ CloudHost PaaS — System Architecture
Overview
CloudHost is a self-service PaaS that lets users deploy applications onto Kubernetes clusters managed by a super admin. Source code (uploaded archive or git repo) is turned into a container image inside the cluster with Kaniko, then rolled out via Helm. It includes a full billing/wallet system, automated lifecycle management, managed databases/services, Elasticsearch-backed logging, and a bilingual (Persian/English) panel.
Supported runtimes — each built from a platform-maintained Dockerfile template:
Node.js, Laravel, Go, PHP, Python, Django, .NET, and WordPress (official image).
🧱 High-Level Architecture
┌─────────────────────────────────────────────────────────────────┐
│ USERS / ADMINS (Browser) │
└──────────────────────────┬──────────────────────────────────────┘
│ HTTPS
▼
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND — Next.js 16 (App Router, bilingual) │
│ Landing │ Auth (OTP) │ Deploy Wizard │ Dashboard │ Admin Panel │
└──────────────────────────┬──────────────────────────────────────┘
│ REST /api/v1 (JSON)
▼
┌─────────────────────────────────────────────────────────────────┐
│ BACKEND — NestJS 11 │
│ Auth · Users · Admin · Applications · Deployments · Clusters │
│ Build · Billing · Lifecycle · Snapshots · Tickets · Access · │
│ Notifications · Kubernetes/Helm/Registry │
└───┬───────────┬───────────────────┬───────────────┬─────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌────────┐ ┌────────┐ ┌──────────┐ ┌──────────────────┐
│Postgres│ │ Redis │ │ Registry │ │ Kubernetes │
│ 16 │ │(cache/ │ │ (:2) │ │ Cluster(s) │
│ │ │ Bull) │ └──────────┘ │ ┌────────────┐ │
└────────┘ └────────┘ │ │ Build Jobs │ │
│ │ (Kaniko) │ │
│ └────────────┘ │
│ Helm releases │
│ (user apps) │
└──────────────────┘
🧩 Module Overview
| Module | Purpose |
|---|---|
| Auth | Mobile-number + OTP (SMS) and password login; JWT access/refresh; Passport strategies; role guards |
| Users | User CRUD, profile, phone verification |
| Admin | Super-admin user-detail dashboard and operations |
| Applications | App CRUD, code upload (→ disk), git config, runtime/version metadata |
| Application-migrations | Import / migrate existing applications (Bull queue) |
| Build | build.service — runtime detection + per-runtime Dockerfile generation, Kaniko image builds inside K8s |
| Deployments | Deploy orchestration (build → Helm), history, stop/restart |
| Kubernetes | K8s API wrapper, Helm CLI wrapper, registry service |
| Clusters | Multi-cluster management, kubeconfig storage, default cluster |
| Billing | Wallet (deposit/deduct), transaction ledger, invoices, pricing catalog, coupons/discounts |
| Lifecycle | Interval scanner: auto-suspend expired apps, auto-delete after grace period |
| Snapshots | Application snapshot/backup & restore |
| Tickets | Support ticket system (technical/sales departments) |
| Access | Time-limited external access to app services via temporary NodePort grants (Bull queue) |
| Notifications | User-facing notifications |
| Common / Config | Shared enums, guards, decorators; env & TypeORM config |
🔧 Tech Stack
Frontend: Next.js 16 (App Router) + Tailwind CSS v4
| Reason | Detail |
|---|---|
| SSR & SEO | Server-side rendering for fast initial loads and a public landing/blog |
| App Router | React Server Components, layouts, locale routing under app/[lang]/ |
| Bilingual | fa-IR (default) + en-US; middleware.ts also splits landing vs authenticated panel |
| React Query | Server state, caching, polling for live build/deploy status |
| Zustand | Lightweight client auth store |
| TypeScript | End-to-end type safety |
Backend: NestJS 11 (Node.js 20)
| Reason | Detail |
|---|---|
| Modular | Each domain is a self-contained module |
| @kubernetes/client-node | Direct K8s API interaction (Jobs, Deployments, logs, scale) |
| Helm CLI | Shell-out to helm for chart-based app deployments |
| Bull (Redis) | Async queues for service-access grants and application migrations |
| TypeORM | PostgreSQL ORM. synchronize is development-only; production schema changes ship as idempotent SQL migrations / ALTER ... IF NOT EXISTS |
Build System: Kaniko (in-cluster)
| Reason | Detail |
|---|---|
| No Docker daemon | Builds run as unprivileged K8s Jobs in cloudhost-builds |
| Runtime detection | detectRuntime() infers Node.js / Laravel / WordPress from source files; the app may also pin a runtime explicitly |
| Per-runtime Dockerfiles | generateDockerfile() emits a tailored Dockerfile for Node.js, Laravel, WordPress, Go, PHP, Python, Django, or .NET |
| WordPress | Templated Dockerfile + custom entrypoint that merges wp-content |
| Source ingestion | Uploaded archives saved to disk and streamed into a per-build PVC (helper pod + kubectl cp); git repos cloned in-pod |
| Registry push | Native push to the in-cluster (insecure) registry |
Deployment: Helm v3 Charts
| Reason | Detail |
|---|---|
| Templated manifests | One cloudhost-app chart handles all runtimes + attached services |
| Rollback | Built-in revision history |
| Persistence | DB/app PVCs and secrets use keep policies so they survive helm uninstall |
| Ingress | Traefik by default (k3s); INGRESS_CLASS=nginx for ingress-nginx |
🔄 Build & Deploy Flow
User triggers deploy (panel)
│
▼
Backend runs the build-and-deploy pipeline, creating a Kubernetes Job in `cloudhost-builds`:
┌─ init: prepare source (uploaded zip → disk → helper pod + `kubectl cp` → build PVC) ─┐
│ …or… │ → /workspace/source
└─ init: git-clone (clone repo; token injected into the URL for private repos) ───┘
│
▼
The platform detects the runtime and generates a Dockerfile for it
(Node.js / Laravel / WordPress / Go / PHP / Python / Django / .NET)
│
▼
container: kaniko → build image (cache per user) → push to in-cluster registry
│
▼
HelmService install/upgrade `cloudhost-app`
│
▼
Helm creates: Namespace, Deployment, Service, Ingress (+TLS), per-app
DB/Redis/RabbitMQ, PVCs, Secrets, registry pull secret, log shipper
│
▼
App live at https://<subdomain>.<PLATFORM_DOMAIN>
Notes:
- The build runs inline within the deploy request (it is not queued); build progress/logs are tracked in memory and polled by the frontend. This assumes a single active backend replica for an in-flight build.
- Bull/Redis queues are used by other subsystems (service-access grants, application migrations), not by the image build.
🔐 Security Architecture
- Mobile-OTP + password authentication; JWT access + refresh
- Live role/active-status enforcement —
JwtStrategyreads the user from the DB each request - Role-Based Access Control (
user/admin/technical/sales) - K8s namespace isolation per user; scoped ServiceAccounts
- Resource quotas & limit ranges; expandable per-app storage
- Secrets stored as K8s Secrets (env vars, DB creds)
- Input validation (class-validator), Helmet headers, Bcrypt password hashing
💰 Billing & Lifecycle Flow
ACTIVE ──(expires)──► SUSPENDED ──(grace)──► PENDING_DELETION ──► DELETED
▲ │ │
└────── payment ────────┘ │
└────── payment (within grace) ──────────────────┘
DOCKED ── user removed the service; data retained until the plan expires
- Billing cycles: HOURLY | MONTHLY | YEARLY
- Wallet: deposits, deductions, refunds, gateway payments; invoices with coupons/discounts
- Grace periods: admin-configurable via the PlatformSettings entity (per cycle)
- Lifecycle scanner: runs on an interval (default 60s); suspends expired apps (scale to 0, data retained) and deletes them after the grace period
⚠️ The lifecycle scanner and other interval jobs assume a single backend replica — guard them (e.g. a Redis lock) before scaling the control plane horizontally.
📦 Helm Charts
cloudhost-platform — control plane
Deploys the API, UI, PostgreSQL, and Redis into a namespace (default cloudhost).
| Template | Purpose |
|---|---|
backend-deployment.yaml / backend-service.yaml / backend-pvc.yaml |
NestJS API + uploads PVC |
frontend-deployment.yaml / frontend-service.yaml |
Next.js UI |
postgres-*.yaml / redis-*.yaml |
Control-plane database & queue |
ingress.yaml |
Frontend / API / panel host rules (+ TLS) |
secret.yaml |
JWT, DB, registry, SMS and other platform secrets |
migrations-configmap.yaml / migrations-job.yaml |
Optional SQL migration Job (migrations.enabled) |
namespace.yaml / _helpers.tpl / NOTES.txt |
Namespace + chart helpers |
Key values: ingress.enabled, ingress.tls.*, ingress.frontend.host / ingress.api.host,
postgres.password, secrets.jwtSecret, migrations.enabled.
cloudhost-app — a single user application
| Template | Purpose |
|---|---|
deployment.yaml |
App pod (imagePullSecret, probes, WordPress volumes, env) |
service.yaml / ingress.yaml |
ClusterIP + ingress with TLS |
secret.yaml |
User env vars as a K8s Secret |
db-deployment.yaml / db-service.yaml / db-pvc.yaml / db-secret.yaml |
Optional managed PostgreSQL/MySQL/MariaDB/MongoDB |
redis-deployment.yaml / rabbitmq-deployment.yaml |
Optional attached services |
app-storage-pvc.yaml |
App persistent storage |
storageclass.yaml |
Expandable StorageClass (created on demand) |
registry-pull-secret.yaml |
imagePullSecret for the in-cluster registry |
fluent-bit-configmap.yaml / log-shipper-configmap.yaml / _log-shipper.tpl / elasticsearch-credentials-secret.yaml |
Per-app log shipping to Elasticsearch |
cloudhost-logging — observability
Elasticsearch / Kibana / Fluent-bit stack for centralized build and runtime logs
(also see backend/k8s/logging/).
📁 Project Structure
cloud-host/
├── ARCHITECTURE.md README.md RUNBOOK.fa.md CHANGELOG.md CONTRIBUTING.md
├── UPGRADE.md UPGRADE.en.md docker-compose.yml
├── backend/ # NestJS 11 API
│ ├── Dockerfile
│ ├── helm/{cloudhost-platform, cloudhost-app, cloudhost-logging}/
│ ├── k8s/{logging, mail}/ # standalone manifests
│ ├── migrations/ # SQL migrations (one-off Jobs in prod)
│ └── src/
│ ├── main.ts / app.module.ts
│ ├── auth/ users/ admin/ # OTP auth, users, super-admin dashboard
│ ├── applications/ application-migrations/
│ ├── deployments/ # orchestration (build → Helm)
│ ├── build/ # build.service: runtime detection + per-runtime Dockerfiles + Kaniko
│ ├── kubernetes/ # K8s client, Helm, registry
│ ├── clusters/ # multi-cluster management
│ ├── billing/ lifecycle/ snapshots/ tickets/ access/ notifications/
│ ├── common/ # enums, guards, decorators
│ └── config/ # env + TypeORM config
└── frontend/ # Next.js 16 (App Router, fa-IR / en-US)
├── Dockerfile # ARG NEXT_PUBLIC_API_URL
└── src/
├── middleware.ts # locale routing + landing/panel split
├── app/[lang]/{page, login, register, blog, dashboard/*}
├── components/ hooks/ lib/ types/
└── i18n/ # dictionaries, provider, switcher
🔮 Future Considerations
- Per-app horizontal autoscaling (HPA) based on CPU/memory
- WebSocket/SSE for real-time build log streaming (currently polled)
- A Redis-backed build queue (so builds survive a replica restart and the control plane can scale out)
- In-cluster image vulnerability scanning (report-only)
- GitOps integration (e.g. ArgoCD) and git-push-to-deploy
- Automated control-plane database backups (scheduled
pg_dump+ retention) - App marketplace with pre-built templates