diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 732917c..91b81fc 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,7 +2,14 @@ ## Overview -CloudHost is a self-service PaaS platform that enables users to deploy **Node.js**, **Laravel**, and **WordPress** applications onto Kubernetes clusters managed by a super admin. It includes a full billing/wallet system, automated lifecycle management, and Helm-based deployments. +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). --- @@ -10,42 +17,34 @@ CloudHost is a self-service PaaS platform that enables users to deploy **Node.js ``` ┌─────────────────────────────────────────────────────────────────┐ -│ USERS / ADMINS │ -│ (Browser / CLI) │ +│ USERS / ADMINS (Browser) │ └──────────────────────────┬──────────────────────────────────────┘ │ HTTPS ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ FRONTEND (Next.js 14) │ -│ ┌──────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────┐ │ -│ │ Auth UI │ │ Deploy Wizard │ │ Dashboard│ │Admin Panel│ │ -│ └──────────┘ └───────────────┘ └──────────┘ └───────────┘ │ +│ FRONTEND — Next.js 16 (App Router, bilingual) │ +│ Landing │ Auth (OTP) │ Deploy Wizard │ Dashboard │ Admin Panel │ └──────────────────────────┬──────────────────────────────────────┘ - │ REST API (JSON) + │ REST /api/v1 (JSON) ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ BACKEND (NestJS 10) │ -│ │ -│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐ │ -│ │Auth │ │Applications │ │Deployments │ │Clusters │ │ -│ │Module │ │Module │ │Module │ │Module │ │ -│ └──────────┘ └──────────────┘ └────────────┘ └──────────┘ │ -│ │ -│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐ │ -│ │Billing │ │Lifecycle │ │Snapshots │ │Tickets │ │ -│ │Module │ │Module │ │Module │ │Module │ │ -│ └──────────┘ └──────────────┘ └────────────┘ └──────────┘ │ -│ │ -│ ┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐ │ -│ │ Kubernetes │ │ Helm │ │ Build │ │ -│ │ Service │ │ Service │ │ Service │ │ -│ └────────┬─────────┘ └──────┬───────┘ └──────┬───────────┘ │ -└───────────┼───────────────────┼──────────────────┼───────────────┘ - │ │ │ - ┌───────▼────────┐ ┌──────▼────────┐ ┌──────▼────────┐ - │ Kubernetes │ │ Helm CLI │ │ Kaniko │ - │ Cluster(s) │ │ (v3) │ │ (in-cluster) │ - └───────────────┘ └───────────────┘ └───────────────┘ +│ 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) │ + └──────────────────┘ ``` --- @@ -54,110 +53,118 @@ CloudHost is a self-service PaaS platform that enables users to deploy **Node.js | Module | Purpose | |--------|---------| -| **Auth** | JWT access/refresh tokens, Passport strategies, role guards | -| **Users** | User CRUD, admin activate/deactivate, profile management | -| **Applications** | App CRUD, code upload (zip), metadata, runtime detection | -| **Build** | Kaniko-based image builds via BullMQ queue; auto-detects Node.js/Laravel/WordPress | -| **Kubernetes** | K8s API interactions — namespace, scale, delete, pod logs, build pods | -| **Helm** | Helm CLI wrapper — install/upgrade, rollback, uninstall, history | -| **Deployments** | Deployment lifecycle orchestration, history, stop/restart | -| **Clusters** | Multi-cluster management, kubeconfig storage, default cluster selection | -| **Billing** | Wallet system (deposit/deduct), transaction ledger, plan cost calculation | -| **Lifecycle** | Cron-based scanner: auto-suspend expired apps, auto-delete after grace period | -| **Snapshots** | Application snapshot/backup management | -| **Tickets** | Support ticket system for users | +| **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 14 (App Router) + Tailwind CSS +### Frontend: Next.js 16 (App Router) + Tailwind CSS v4 | Reason | Detail | |--------|--------| -| **SSR & SEO** | Server-side rendering for fast initial loads | -| **App Router** | React Server Components, layouts, loading states | -| **Tailwind CSS** | Rapid UI development, consistent design system | -| **TypeScript** | End-to-end type safety with shared types | -| **React Query** | Server state management, caching, polling for live status | -| **Zustand** | Lightweight client state management (auth store) | +| **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 10 (Node.js) +### Backend: NestJS 11 (Node.js 20) | Reason | Detail | |--------|--------| -| **Modular architecture** | Each domain is a self-contained module | -| **TypeScript native** | Full type safety, shared interfaces with frontend | -| **@kubernetes/client-node** | Official K8s client for direct API interaction | -| **Helm CLI** | Shell-out to helm for chart-based deployments | -| **Bull/BullMQ** | Redis-backed job queues for async build pipelines | -| **TypeORM** | PostgreSQL ORM with entity-based schema | +| **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 inside K8s pods — no Docker-in-Docker | -| **Runtime detection** | Auto-detects Node.js, Laravel, WordPress from source files | -| **WordPress support** | Custom entrypoint script for wp-content merging | -| **Registry push** | Native push to insecure or authenticated registries | +| **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** | Single chart handles Node.js, Laravel, WordPress | -| **Rollback support** | Built-in revision history and rollback | -| **Resource policies** | PVCs and secrets persist across helm uninstall | -| **Registry pull secrets** | Auto-created per namespace for insecure registries | +| **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://. +``` + +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 -- JWT Authentication (access + refresh tokens) -- Role-Based Access Control (User / Admin) -- K8s Namespace Isolation per user -- K8s RBAC — scoped ServiceAccounts -- Network Policies between namespaces -- Resource Quotas & Limit Ranges -- Secrets encryption (K8s Secrets) -- Input validation (class-validator on all DTOs) -- Helmet HTTP security headers -- Bcrypt password hashing (12 rounds) - ---- - -## 🔄 Deployment Flow - -``` -User uploads code (zip) - │ - ▼ -API stores file + metadata in PostgreSQL - │ - ▼ -BullMQ build job queued - │ - ▼ -detectRuntime() → nodejs | laravel | wordpress - │ - ▼ -Generate Dockerfile per runtime - │ - ▼ -Kaniko Pod builds image → pushes to registry - │ - ▼ -HelmService.installOrUpgrade() with cloudhost-app chart - │ - ▼ -Helm creates: Namespace, Deployment, Service, Ingress, - DB, PVC, Secrets, Registry Pull Secret, TLS cert - │ - ▼ -App live at https://.apps.cloudhost.ir -``` +- Mobile-OTP + password authentication; JWT access + refresh +- **Live** role/active-status enforcement — `JwtStrategy` reads 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 --- @@ -168,95 +175,100 @@ ACTIVE ──(expires)──► SUSPENDED ──(grace)──► PENDING_DELETIO ▲ │ │ └────── payment ────────┘ │ └────── payment (within grace) ──────────────────┘ + +DOCKED ── user removed the service; data retained until the plan expires ``` -- **Billing Cycles**: HOURLY | MONTHLY | YEARLY -- **Hourly plans**: auto-renew from wallet each hour -- **Grace periods**: admin-configurable via PlatformSettings table -- **Lifecycle Scanner**: runs every 60s (configurable) +- **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 Chart: cloudhost-platform +## 📦 Helm Charts -Chart at `backend/helm/cloudhost-platform/` deploys the **control plane** (NestJS API, Next.js UI, PostgreSQL, Redis) into a dedicated namespace (default `cloudhost`). +### cloudhost-platform — control plane -| Value | Purpose | -|-------|---------| -| `ingress.enabled` | Create Ingress (default `true`) | -| `ingress.tls.enabled` | cert-manager TLS via `clusterIssuer` | -| `ingress.frontend.host` / `ingress.api.host` | Public hostnames | -| `postgres.password` / `secrets.jwtSecret` | Credentials (auto-generated if empty on first install) | -| `migrations.enabled` | Post-install SQL migration Job | - ---- - -## 🚀 Helm Chart: cloudhost-app - -Single chart at `backend/helm/cloudhost-app/` handles all runtimes: +Deploys the API, UI, PostgreSQL, and Redis into a namespace (default `cloudhost`). | Template | Purpose | |----------|---------| -| `deployment.yaml` | App pod with imagePullSecrets, probes, WordPress volumes | -| `service.yaml` | ClusterIP (port 80 → app port) | -| `ingress.yaml` | Nginx ingress with cert-manager TLS | -| `secret.yaml` | User env vars as K8s Secret | -| `db-deployment.yaml` | PostgreSQL or MySQL with health probes | -| `db-service.yaml` | Database ClusterIP service | -| `db-pvc.yaml` | Database storage (resource-policy: keep) | -| `db-secret.yaml` | Database credentials (resource-policy: keep) | -| `wp-pvc.yaml` | WordPress wp-content PVC (resource-policy: keep) | -| `registry-pull-secret.yaml` | imagePullSecret for insecure registry | +| `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 ``` -host/ -├── ARCHITECTURE.md -├── README.md -├── CHANGELOG.md -├── CONTRIBUTING.md -├── docker-compose.yml -├── backend/ +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 -│ ├── package.json -│ ├── helm/cloudhost-platform/ # Helm chart for control plane -│ ├── helm/cloudhost-app/ # Helm chart for user apps -│ ├── src/ -│ │ ├── main.ts / app.module.ts -│ │ ├── auth/ # JWT + Passport -│ │ ├── users/ # User management -│ │ ├── applications/ # App CRUD + upload -│ │ ├── deployments/ # Deploy orchestration -│ │ ├── clusters/ # Multi-cluster (admin) -│ │ ├── kubernetes/ # K8s client + Helm service -│ │ ├── build/ # Kaniko builds (BullMQ) -│ │ ├── billing/ # Wallet + transactions -│ │ ├── lifecycle/ # Auto-suspend/delete -│ │ ├── snapshots/ # App snapshots -│ │ └── tickets/ # Support tickets -│ └── templates/ # Legacy Handlebars (deprecated) -├── frontend/ -│ ├── Dockerfile -│ ├── package.json +│ ├── helm/{cloudhost-platform, cloudhost-app, cloudhost-logging}/ +│ ├── k8s/{logging, mail}/ # standalone manifests +│ ├── migrations/ # SQL migrations (one-off Jobs in prod) │ └── src/ -│ ├── app/dashboard/ # Apps, deploy, admin pages -│ ├── components/ -│ ├── lib/ # API client, auth store -│ └── types/ # Shared TS interfaces -└── uploads/ # User-uploaded code archives +│ ├── 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 -1. Custom domains with auto TLS via cert-manager -2. Horizontal Pod Autoscaler based on CPU/memory -3. WebSocket/SSE for real-time build log streaming -4. GitOps integration (ArgoCD) -5. Additional runtimes (Python, Go, Rust) -6. App marketplace with pre-built templates -7. Per-app resource consumption dashboards +1. Per-app horizontal autoscaling (HPA) based on CPU/memory +2. WebSocket/SSE for real-time build log streaming (currently polled) +3. A Redis-backed build queue (so builds survive a replica restart and the control plane can scale out) +4. In-cluster image vulnerability scanning (report-only) +5. GitOps integration (e.g. ArgoCD) and git-push-to-deploy +6. Automated control-plane database backups (scheduled `pg_dump` + retention) +7. App marketplace with pre-built templates diff --git a/README.md b/README.md index 7a0e270..ca0a87e 100644 --- a/README.md +++ b/README.md @@ -1,303 +1,317 @@ # ☁️ CloudHost — Self-Service PaaS Platform -A self-service Platform-as-a-Service (PaaS) that lets developers deploy **Node.js**, **Laravel**, and **WordPress** applications onto Kubernetes with zero DevOps overhead. Includes wallet-based billing, automated lifecycle management, and Helm-based deployments. +A self-service Platform-as-a-Service (PaaS) that lets developers deploy applications +onto Kubernetes with zero DevOps overhead. Source code is turned into a container +image **inside the cluster** with Kaniko (no Docker daemon), then rolled out with Helm — +complete with managed databases, wallet-based billing, automated lifecycle management, +live logs, 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 + +custom `wp-content` entrypoint). + +> 🇮🇷 Production deployment on the `abrban.com` k3s cluster — including all the +> Iran-network workarounds — is documented step-by-step in **[RUNBOOK.fa.md](RUNBOOK.fa.md)** (Persian). --- ## Architecture Overview ``` -┌─────────────┐ ┌─────────────────┐ ┌──────────────┐ -│ Next.js 16 │ REST │ NestJS API │ K8s │ Kubernetes │ -│ Frontend │◄───────►│ Backend │◄──────►│ Cluster(s) │ -└─────────────┘ └────────┬────────┘ └──────────────┘ - │ - ┌──────────┼──────────┐ - ▼ ▼ ▼ - PostgreSQL Redis Container - (Bull) Registry +┌──────────────┐ REST ┌──────────────────┐ K8s API ┌──────────────┐ +│ Next.js 16 │ /api/v1 │ NestJS 11 API │ + Helm │ Kubernetes │ +│ Frontend │◄─────────►│ Backend │◄───────────►│ Cluster(s) │ +└──────────────┘ └────────┬─────────┘ └──────┬───────┘ + │ │ build Jobs + ┌─────────────────┼─────────────────┐ ▼ + ▼ ▼ ▼ ┌──────────┐ + PostgreSQL Redis Registry │ Kaniko │ + 16 (cache + Bull) (:2) └──────────┘ ``` -| Layer | Technology | -| ------------ | ------------------------------------------------------- | -| Frontend | Next.js 16, Tailwind CSS v4, React Query, Zustand | -| Backend API | NestJS 11, TypeORM, Passport JWT, Bull (Redis) | -| Build Engine | Kaniko (in-cluster, daemon-less Docker builds) | -| Deployment | Helm v3 charts, @kubernetes/client-node | -| Database | PostgreSQL 16 | -| Queue | Redis 7 + BullMQ | +| Layer | Technology | +| ---------------- | ----------------------------------------------------------------- | +| Frontend | Next.js 16 (App Router, SSR), React 19, Tailwind CSS v4, React Query, Zustand | +| Backend API | NestJS 11, TypeORM, Passport JWT, Bull (Redis) | +| Build engine | **Kaniko** (daemon-less in-cluster builds) with platform-generated per-runtime Dockerfiles | +| Source ingestion | Uploaded archive (zip/tar.gz) streamed into a build PVC, **or** git clone | +| Deployment | Helm v3 charts, `@kubernetes/client-node` | +| Database | PostgreSQL 16 (control plane); per-app MySQL/MariaDB/PostgreSQL/MongoDB | +| Queue / cache | Redis 7 + Bull (service-access grants, app migrations) | +| Registry | In-cluster `registry:2` | +| Auth | Mobile number + **OTP** (SMS) and password, JWT access/refresh | -> 📖 See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed system design. -> 🔼 See [UPGRADE.en.md](UPGRADE.en.md) ([فارسی](UPGRADE.md)) for the latest dependency-upgrade notes (React 19, Next 16, NestJS 11, Tailwind 4, k8s-client v1). +> 📖 See **[ARCHITECTURE.md](ARCHITECTURE.md)** for detailed system design. +> 🔼 See [UPGRADE.en.md](UPGRADE.en.md) ([فارسی](UPGRADE.md)) for dependency-upgrade notes. --- ## Features ### For Developers -- 🚀 **One-click deploys** from uploaded code archive (zip) -- 🟢 **Node.js** — auto-detected via `package.json` (npm build & start) -- 🟣 **Laravel** — PHP 8.x + Nginx + Supervisor (auto-detected via `artisan`) -- 🔵 **WordPress** — official image + custom entrypoint for wp-content merging -- 🗄️ **Managed databases** — PostgreSQL or MySQL provisioned via Helm -- 💰 **Wallet system** — deposit funds, pay for plans (hourly/monthly/yearly) -- 📊 **Live logs** & deployment history with rollback -- 🔒 **Environment variables** managed as Kubernetes Secrets -- ⚙️ **Resource controls** — CPU, memory, replica count -- 📸 **Snapshots** — backup and restore application state -- 🎫 **Support tickets** — in-app support system +- 🚀 **Deploy from a code archive (zip/tar.gz) _or_ a git URL** (public or private via token) +- 🟢 **Multi-runtime** — Node.js, Laravel, Go, PHP, Python, Django, .NET, each built from a maintained Dockerfile template +- 🔵 **WordPress** — official image + custom entrypoint that merges your `wp-content` +- 🗄️ **Managed databases & services** — PostgreSQL, MySQL, MariaDB, MongoDB, Redis, RabbitMQ provisioned via Helm +- 💰 **Wallet system** — deposit funds, pay per plan (hourly / monthly / yearly), coupons & discounts +- 📊 **Live build & runtime logs** (Elasticsearch-backed) + deployment history with rollback +- 🔒 **Environment variables** stored as Kubernetes Secrets +- ⚙️ **Resource controls** — CPU, memory, replicas, expandable disk +- 🌐 **Custom domains** with automatic TLS +- 📸 **Snapshots** — backup & restore application state +- 🎫 **Support tickets** with technical/sales departments ### For Super Admins -- 🖥️ **Multi-cluster management** — register/remove Kubernetes clusters -- 👥 **User management** — activate, deactivate, change roles -- 📈 **Quotas** — per-cluster limits (CPU, memory, max apps) -- 💳 **Billing oversight** — view all transactions, manage wallet deposits -- ⏱️ **Lifecycle settings** — configure grace periods per billing cycle -- 🔐 **RBAC** — role-based guards on every endpoint +- 🖥️ **Multi-cluster management** — register/remove Kubernetes clusters (kubeconfig stored encrypted) +- 👥 **User management** — activate, deactivate, change roles, per-user detail dashboard +- 📈 **Quotas & pricing** — per-cluster limits and a configurable pricing catalog +- 💳 **Billing oversight** — transactions, invoices, wallet deposits, global discount +- ⏱️ **Lifecycle settings** — grace periods per billing cycle +- 🔐 **RBAC** — role-based guards on every endpoint (`user` / `admin` / `technical` / `sales`) + +--- + +## How the Build & Deploy Pipeline Works + +When a user triggers a deploy, the backend runs the build-and-deploy pipeline and creates +the build as a **Kubernetes Job** in the `cloudhost-builds` namespace: + +``` +1. SOURCE + ├─ uploaded archive → saved to disk (UPLOAD_DIR) → streamed into a per-build PVC + │ via a short-lived helper pod + `kubectl cp`, then unpacked (init: prepare source) + └─ git URL → cloned in-pod; private repos inject the token into the clone URL (init: git-clone) + +2. DOCKERFILE + The platform detects the runtime (or uses the app's selected runtime) and generates a + Dockerfile for it — Node.js, Laravel, WordPress, Go, PHP, Python, Django, or .NET. + +3. BUILD (container: kaniko) + Kaniko builds the image (layer cache per user) and pushes it to the in-cluster + registry — no Docker daemon, no privileged pod. + +4. DEPLOY + Helm installs/upgrades the `cloudhost-app` chart → Deployment, Service, Ingress, + per-app DB/Redis/RabbitMQ, PVCs, Secrets, log shipper. App goes live at its subdomain. +``` + +The build runs inline within the deploy request and its progress/logs are tracked in +memory, then polled by the frontend. (Bull/Redis queues are used elsewhere — service-access +grants and application migrations — but not for image builds.) --- ## Project Structure ``` -host/ -├── ARCHITECTURE.md # Detailed architecture document -├── README.md # This file -├── CHANGELOG.md # Version history -├── CONTRIBUTING.md # Development workflow & conventions -├── docker-compose.yml # Local dev / production compose +cloud-host/ +├── README.md # This file +├── ARCHITECTURE.md # Detailed system design +├── RUNBOOK.fa.md # Persian runbook: local dev + abrban/k3s production deploy +├── CHANGELOG.md / CONTRIBUTING.md / UPGRADE.md / UPGRADE.en.md +├── docker-compose.yml # Local dev stack (Postgres + Redis + API + UI) │ -├── backend/ # NestJS API +├── backend/ # NestJS 11 API (REST under /api/v1) │ ├── Dockerfile -│ ├── package.json │ ├── helm/ -│ │ ├── cloudhost-platform/ # Helm chart (control plane) -│ │ └── cloudhost-app/ # Helm chart (user apps) -│ │ ├── Chart.yaml -│ │ ├── values.yaml -│ │ └── templates/ # K8s manifest templates -│ ├── src/ -│ │ ├── main.ts / app.module.ts -│ │ ├── auth/ # JWT auth (register, login, refresh) -│ │ ├── users/ # User CRUD + admin ops -│ │ ├── applications/ # Application CRUD + code upload -│ │ ├── deployments/ # Deployment pipeline orchestration -│ │ ├── clusters/ # Cluster management (admin) -│ │ ├── kubernetes/ # K8s client + Helm service -│ │ ├── build/ # Kaniko build jobs (Bull queue) -│ │ ├── billing/ # Wallet, transactions, plan costs -│ │ ├── lifecycle/ # Auto-suspend/delete scanner -│ │ ├── snapshots/ # App snapshot management -│ │ ├── tickets/ # Support ticket system -│ │ ├── common/ # Enums, decorators, guards -│ │ └── config/ # Env configuration loader -│ └── templates/ # Legacy Handlebars templates (deprecated) -│ -├── frontend/ # Next.js 14 App Router -│ ├── Dockerfile -│ ├── package.json +│ │ ├── cloudhost-platform/ # Helm chart — control plane (API, UI, Postgres, Redis) +│ │ ├── cloudhost-app/ # Helm chart — a single user application + its services +│ │ └── cloudhost-logging/ # Helm chart — Elasticsearch / Kibana / Fluent-bit +│ ├── k8s/ # Standalone manifests (logging, mail) +│ ├── migrations/ # SQL migrations (applied via one-off Jobs in prod) │ └── src/ -│ ├── app/ -│ │ ├── login/ & register/ -│ │ └── dashboard/ -│ │ ├── apps/ # App list + detail (lifecycle status) -│ │ ├── deploy/ # Multi-step deploy wizard -│ │ └── admin/ # Admin: users, clusters, billing, apps -│ ├── components/ -│ ├── lib/ # API client, auth store -│ ├── hooks/ -│ └── types/ # TypeScript interfaces +│ ├── main.ts / app.module.ts +│ ├── auth/ # Mobile-OTP + password login, JWT strategies, role guards +│ ├── users/ # User CRUD, profile, phone verification +│ ├── admin/ # Super-admin user-detail dashboard & ops +│ ├── applications/ # App CRUD, code upload (→ disk), git config +│ ├── application-migrations/ # Import/migrate existing apps (Bull queue) +│ ├── deployments/ # Deploy orchestration, history, stop/restart +│ ├── build/ # Kaniko build (build.service): per-runtime Dockerfile generation +│ ├── kubernetes/ # K8s client, Helm wrapper, registry service +│ ├── clusters/ # Multi-cluster management, kubeconfig storage +│ ├── billing/ # Wallet, transactions, invoices, pricing catalog, coupons +│ ├── lifecycle/ # Scanner: auto-suspend/delete expired apps +│ ├── snapshots/ # App snapshot/restore +│ ├── tickets/ # Support tickets +│ ├── notifications/ # User notifications +│ ├── access/ # Time-limited external service access (NodePort grants, Bull queue) +│ ├── common/ # Enums, guards, decorators +│ └── config/ # Env configuration loader + TypeORM config │ -└── uploads/ # User-uploaded code archives +├── frontend/ # Next.js 16 App Router (bilingual fa-IR / en-US) +│ ├── Dockerfile # ARG NEXT_PUBLIC_API_URL baked at build time +│ └── src/ +│ ├── middleware.ts # Locale routing + landing (abrban.com) vs panel split +│ ├── app/[lang]/ +│ │ ├── page.tsx # Landing +│ │ ├── login/ register/ +│ │ ├── blog/ +│ │ └── dashboard/ # apps, deploy, logs, invoices, wallet, services, +│ │ │ # tickets, account, staff, admin +│ │ └── ... +│ ├── components/ hooks/ lib/ (API client, auth store) types/ +│ └── i18n/ # Dictionaries, provider, language switcher ``` --- -## Quick Start +## Quick Start (Local Development) -### Prerequisites +**Prerequisites:** Node.js ≥ 20, Docker & Docker Compose, and (for actually building/deploying +user apps) a Kubernetes cluster reachable via kubeconfig. -| Tool | Version | -| --------------- | ------- | -| Node.js | ≥ 20 | -| Docker & Compose| ≥ 24 | -| PostgreSQL | 16 | -| Redis | 7 | -| Helm | ≥ 3.12 | +> ℹ️ The API and UI run fine locally against Postgres + Redis. The **build/deploy pipeline +> itself runs as Kubernetes Jobs**, so triggering a real user-app build requires a cluster +> (with the in-cluster registry). For pure UI/API development you don't need one. -### 1. Clone & Install +### 1. Clone & install ```bash -git clone host && cd host +git clone cloud-host && cd cloud-host cd backend && npm install && cd .. cd frontend && npm install && cd .. ``` -### 2. Environment Variables +### 2. Environment variables ```bash cp backend/.env.example backend/.env cp frontend/.env.local.example frontend/.env.local -# Edit both files with your DB, JWT, Redis, and registry settings +# Edit both — at minimum DB, JWT, Redis. See the Configuration table below. ``` -### 3. Run with Docker Compose +### 3. Start Postgres + Redis ```bash -docker compose up --build +docker compose up -d postgres redis ``` -Backend at port 4000, Frontend at port 3000. - -### 4. Deploy Platform on Kubernetes (Helm) - -Prerequisites: NGINX Ingress, cert-manager (if TLS enabled), StorageClass for PVCs. +### 4. Run the apps ```bash -# Build images (set API URL to match ingress.api.host when TLS is on) -export REG=your-registry.example.com -docker build -t $REG/cloudhost-backend:latest ./backend -docker build -t $REG/cloudhost-frontend:latest \ - --build-arg NEXT_PUBLIC_API_URL=https://api.platform.example.com ./frontend -docker push $REG/cloudhost-backend:latest $REG/cloudhost-frontend:latest - -# Install (copy and edit values-production.example.yaml first) -helm upgrade --install cloudhost ./backend/helm/cloudhost-platform \ - -n cloudhost --create-namespace \ - -f backend/helm/cloudhost-platform/values-production.example.yaml -``` - -Key values: `ingress.enabled`, `ingress.tls.enabled`, `ingress.frontend.host`, `ingress.api.host`, `postgres.password`, `secrets.jwtSecret`. - -See chart defaults in `backend/helm/cloudhost-platform/values.yaml` and post-install notes via `helm get notes cloudhost -n cloudhost`. - -### 5. Run Locally (development) - -```bash -# Terminal 1 — Backend +# Terminal 1 — Backend (http://localhost:4000, prefix /api/v1, Swagger at /docs) cd backend && npm run start:dev -# Terminal 2 — Frontend +# Terminal 2 — Frontend (http://localhost:3000) cd frontend && npm run dev ``` ---- +In development `NODE_ENV=development`, so TypeORM `synchronize` builds the schema +automatically and the pricing catalog self-seeds. Set `frontend` `NEXT_PUBLIC_API_URL` +to the backend URL. -## API Endpoints - -All endpoints prefixed with `/api/v1`. Full Swagger docs at `http://localhost:4000/docs`. - -### Auth -| Method | Path | Description | -|--------|------|-------------| -| POST | /auth/register | Create account | -| POST | /auth/login | Get JWT tokens | -| POST | /auth/refresh | Refresh access token | - -### Applications -| Method | Path | Description | -|--------|------|-------------| -| POST | /applications | Create app | -| GET | /applications | List user's apps | -| GET | /applications/:id | App details | -| PATCH | /applications/:id | Update app | -| DELETE | /applications/:id | Delete app + K8s resources | - -### Deployments -| Method | Path | Description | -|--------|------|-------------| -| POST | /applications/:appId/deployments | Trigger deploy | -| GET | /applications/:appId/deployments | List deployments | -| GET | /deployments/:id | Deployment detail | -| GET | /deployments/:id/logs | Pod logs | -| POST | /deployments/:id/stop | Stop deployment | -| POST | /deployments/:id/restart | Restart deployment | - -### Billing -| Method | Path | Description | -|--------|------|-------------| -| GET | /billing/balance | Get wallet balance | -| POST | /billing/deposit | Add funds to wallet | -| GET | /billing/transactions | Transaction history | -| POST | /billing/pay/:appId | Pay for app plan | - -### Lifecycle (Admin) -| Method | Path | Description | -|--------|------|-------------| -| GET | /lifecycle/settings | Get retention periods | -| PATCH | /lifecycle/settings | Update retention periods | - -### Snapshots -| Method | Path | Description | -|--------|------|-------------| -| POST | /snapshots | Create snapshot | -| GET | /snapshots | List snapshots | -| POST | /snapshots/:id/restore | Restore snapshot | - -### Tickets -| Method | Path | Description | -|--------|------|-------------| -| POST | /tickets | Create ticket | -| GET | /tickets | List tickets | -| PATCH | /tickets/:id | Update ticket | - -### Users -| Method | Path | Description | -|--------|------|-------------| -| GET | /users/me | Current user | -| PATCH | /users/me | Update profile | - -### Admin — Users -| Method | Path | Description | -|--------|------|-------------| -| GET | /users | List all users | -| PATCH | /users/:id/activate | Activate user | -| PATCH | /users/:id/deactivate | Deactivate user | -| PATCH | /users/:id/role | Change role | - -### Admin — Clusters -| Method | Path | Description | -|--------|------|-------------| -| POST | /clusters | Add cluster | -| GET | /clusters | List clusters | -| GET | /clusters/:id | Cluster details | -| PATCH | /clusters/:id | Update cluster | -| DELETE | /clusters/:id | Remove cluster | +> To run the **whole** stack (API + UI + Postgres + Redis) in containers instead: +> `docker compose up --build` (backend on `:4000`, frontend on `:3000`). --- -## Configuration +## Deploy on Kubernetes (Helm) + +> This is the **generic** path. For the production `abrban.com` k3s cluster — base-image +> mirroring, the Iran-network proxy/npmmirror, the wildcard TLS cert, registry bootstrap, +> and the exact image-build flow — follow **[RUNBOOK.fa.md](RUNBOOK.fa.md)**. + +**Prerequisites:** a Kubernetes cluster, an Ingress controller (Traefik on k3s by default, +or set `INGRESS_CLASS=nginx`), a default StorageClass for PVCs, and a container registry +reachable by the cluster. + +### 1. Build & push the platform images + +```bash +export REG=your-registry.example.com +docker build -t $REG/cloudhost-backend:1.0.0 ./backend +docker build -t $REG/cloudhost-frontend:1.0.0 \ + --build-arg NEXT_PUBLIC_API_URL=https://api.platform.example.com ./frontend +docker push $REG/cloudhost-backend:1.0.0 +docker push $REG/cloudhost-frontend:1.0.0 +``` + +### 2. Install the control plane + +```bash +cp backend/helm/cloudhost-platform/values-production.example.yaml my-values.yaml +# Edit my-values.yaml: image tags, ingress hosts, postgres password, jwtSecret, registry, SMS/OTP + +helm upgrade --install cloudhost ./backend/helm/cloudhost-platform \ + -n cloudhost --create-namespace \ + -f my-values.yaml \ + --set images.backend.tag=1.0.0 \ + --set images.frontend.tag=1.0.0 +``` + +Key values: `ingress.enabled`, `ingress.tls.*`, `ingress.frontend.host`, `ingress.api.host`, +`postgres.password`, `secrets.jwtSecret`, `migrations.enabled`. Chart defaults live in +`backend/helm/cloudhost-platform/values.yaml`; post-install notes via +`helm get notes cloudhost -n cloudhost`. + +### 3. Cluster-side prerequisites for the build pipeline + +Ensure the `cloudhost-builds` namespace has: + +- the in-cluster **registry** (`registry:2`) reachable at `REGISTRY_URL`, +- a `kaniko-builder` ServiceAccount with an `imagePullSecret` for the registry, +- enough ephemeral storage for the per-build source PVC + helper pod. + +### 4. Verify + +```bash +kubectl get deploy -n cloudhost # backend & frontend 1/1 +helm status cloudhost -n cloudhost # STATUS: deployed +curl -s -o /dev/null -w '%{http_code}\n' https:// +``` + +--- + +## Configuration (key env vars) | Variable | Description | Default | |----------|-------------|---------| | `PORT` | Backend port | `4000` | -| `DB_HOST` | PostgreSQL host | `localhost` | -| `DB_PORT` | PostgreSQL port | `5432` | -| `DB_USERNAME` | Database user | `cloudhost` | -| `DB_PASSWORD` | Database password | — | -| `DB_NAME` | Database name | `cloudhost` | -| `JWT_SECRET` | JWT signing secret | — | -| `JWT_EXPIRES_IN` | Access token TTL | `15m` | -| `REDIS_HOST` | Redis host | `localhost` | -| `REDIS_PORT` | Redis port | `6379` | -| `REGISTRY_URL` | Container registry URL | `localhost:30500` | -| `PLATFORM_DOMAIN` | Base domain for app subdomains | `apps.cloudhost.ir` | -| `LIFECYCLE_SCAN_INTERVAL_MS` | Lifecycle scanner interval | `60000` | -| `LIFECYCLE_HOURLY_DELETE_AFTER_MS` | Hourly plan grace period | `3600000` (1h) | -| `LIFECYCLE_MONTHLY_DELETE_AFTER_MS` | Monthly plan grace period | `259200000` (3d) | -| `LIFECYCLE_YEARLY_DELETE_AFTER_MS` | Yearly plan grace period | `604800000` (7d) | +| `DB_HOST` / `DB_PORT` / `DB_USERNAME` / `DB_PASSWORD` / `DB_DATABASE` | PostgreSQL connection | `localhost` / `5432` / `cloudhost` / — / `cloudhost` | +| `JWT_SECRET` / `JWT_EXPIRES_IN` | Access token secret + TTL | — / `1h` | +| `JWT_REFRESH_SECRET` / `JWT_REFRESH_EXPIRES_IN` | Refresh token secret + TTL | — / `7d` | +| `REDIS_HOST` / `REDIS_PORT` | Redis (cache + Bull queues) | `localhost` / `6379` | +| `SMS_PROVIDER` | OTP provider (`mizbansms` \| `kavenegar`) | `mizbansms` | +| `MIZBANSMS_USERNAME` / `MIZBANSMS_PASSWORD` / `MIZBANSMS_FROM` | OTP SMS credentials (required or OTP send 503s) | — | +| `REGISTRY_URL` / `REGISTRY_PULL_URL` | In-cluster registry (push / pull) | `registry.cloudhost-builds.svc.cluster.local:5000` | +| `BUILD_NAMESPACE` / `BUILD_SERVICE_ACCOUNT` | Build Jobs namespace + SA | `cloudhost-builds` / `kaniko-builder` | +| `KANIKO_IMAGE` | Kaniko executor image | `gcr.io/kaniko-project/executor:v1.23.2` | +| `UPLOAD_DIR` | Disk path for uploaded source archives | `./uploads` | +| `INGRESS_CLASS` | Ingress controller for app Ingress objects | `traefik` | +| `PLATFORM_DOMAIN` / `PREVIEW_BASE_DOMAIN` | Base domain for app subdomains / previews | `apps.cloudhost.local` / — | +| `PLATFORM_STORAGE_CLASS` | StorageClass for new PVCs (needs volume expansion) | `cloudhost-expandable` | +| `ELASTICSEARCH_HOST` / `ELASTICSEARCH_PORT` | Log search backend | cluster DNS / `9200` | +| `LIFECYCLE_SCAN_INTERVAL_MS` | Lifecycle scanner tick | `60000` | + +--- + +## Authentication + +Login is **mobile-number based**: the user receives a one-time SMS code (OTP) and can also +set a password. On every request `JwtStrategy` re-reads the user's **role and active status +from the database** (not from the token), so promotions/deactivations take effect immediately. +Tokens: JWT access (`JWT_EXPIRES_IN`, default 1h) + refresh (7d). + +--- + +## API + +All endpoints are prefixed with `/api/v1`. Interactive Swagger docs at +`http://localhost:4000/docs`. Major route groups: `auth` (OTP request/verify, login, +refresh), `applications`, `deployments`, `clusters`, `billing` (wallet, invoices, +transactions, pricing), `snapshots`, `tickets`, `users`, `admin`, `notifications`. --- ## Security -- **JWT** access + refresh tokens with configurable expiry -- **Bcrypt** password hashing (12 rounds) -- **Helmet** HTTP security headers -- **RBAC** role-based route guards (`@Roles(UserRole.ADMIN)`) -- **Namespace isolation** — each user deploys to their own K8s namespace -- **Secrets** — env vars stored as K8s Secrets, never in plain manifests -- **Input validation** — `class-validator` on all DTOs +- **JWT** access + refresh tokens; live role/active-status enforcement from DB +- **Bcrypt** password hashing +- **Helmet** HTTP security headers, **class-validator** on all DTOs +- **RBAC** role-based route guards (`@Roles(...)`) +- **Namespace isolation** — each user deploys to their own Kubernetes namespace +- **Secrets** — env vars stored as K8s Secrets ---