docs: sync README + ARCHITECTURE to the Kaniko build pipeline
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>
This commit is contained in:
+187
-175
@@ -2,7 +2,14 @@
|
|||||||
|
|
||||||
## Overview
|
## 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 │
|
│ USERS / ADMINS (Browser) │
|
||||||
│ (Browser / CLI) │
|
|
||||||
└──────────────────────────┬──────────────────────────────────────┘
|
└──────────────────────────┬──────────────────────────────────────┘
|
||||||
│ HTTPS
|
│ HTTPS
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
│ FRONTEND (Next.js 14) │
|
│ FRONTEND — Next.js 16 (App Router, bilingual) │
|
||||||
│ ┌──────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────┐ │
|
│ Landing │ Auth (OTP) │ Deploy Wizard │ Dashboard │ Admin Panel │
|
||||||
│ │ Auth UI │ │ Deploy Wizard │ │ Dashboard│ │Admin Panel│ │
|
|
||||||
│ └──────────┘ └───────────────┘ └──────────┘ └───────────┘ │
|
|
||||||
└──────────────────────────┬──────────────────────────────────────┘
|
└──────────────────────────┬──────────────────────────────────────┘
|
||||||
│ REST API (JSON)
|
│ REST /api/v1 (JSON)
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
│ BACKEND (NestJS 10) │
|
│ BACKEND — NestJS 11 │
|
||||||
│ │
|
│ Auth · Users · Admin · Applications · Deployments · Clusters │
|
||||||
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐ │
|
│ Build · Billing · Lifecycle · Snapshots · Tickets · Access · │
|
||||||
│ │Auth │ │Applications │ │Deployments │ │Clusters │ │
|
│ Notifications · Kubernetes/Helm/Registry │
|
||||||
│ │Module │ │Module │ │Module │ │Module │ │
|
└───┬───────────┬───────────────────┬───────────────┬─────────────┘
|
||||||
│ └──────────┘ └──────────────┘ └────────────┘ └──────────┘ │
|
│ │ │ │
|
||||||
│ │
|
▼ ▼ ▼ ▼
|
||||||
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐ │
|
┌────────┐ ┌────────┐ ┌──────────┐ ┌──────────────────┐
|
||||||
│ │Billing │ │Lifecycle │ │Snapshots │ │Tickets │ │
|
│Postgres│ │ Redis │ │ Registry │ │ Kubernetes │
|
||||||
│ │Module │ │Module │ │Module │ │Module │ │
|
│ 16 │ │(cache/ │ │ (:2) │ │ Cluster(s) │
|
||||||
│ └──────────┘ └──────────────┘ └────────────┘ └──────────┘ │
|
│ │ │ Bull) │ └──────────┘ │ ┌────────────┐ │
|
||||||
│ │
|
└────────┘ └────────┘ │ │ Build Jobs │ │
|
||||||
│ ┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
│ │ (Kaniko) │ │
|
||||||
│ │ Kubernetes │ │ Helm │ │ Build │ │
|
│ └────────────┘ │
|
||||||
│ │ Service │ │ Service │ │ Service │ │
|
│ Helm releases │
|
||||||
│ └────────┬─────────┘ └──────┬───────┘ └──────┬───────────┘ │
|
│ (user apps) │
|
||||||
└───────────┼───────────────────┼──────────────────┼───────────────┘
|
└──────────────────┘
|
||||||
│ │ │
|
|
||||||
┌───────▼────────┐ ┌──────▼────────┐ ┌──────▼────────┐
|
|
||||||
│ Kubernetes │ │ Helm CLI │ │ Kaniko │
|
|
||||||
│ Cluster(s) │ │ (v3) │ │ (in-cluster) │
|
|
||||||
└───────────────┘ └───────────────┘ └───────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -54,110 +53,118 @@ CloudHost is a self-service PaaS platform that enables users to deploy **Node.js
|
|||||||
|
|
||||||
| Module | Purpose |
|
| Module | Purpose |
|
||||||
|--------|---------|
|
|--------|---------|
|
||||||
| **Auth** | JWT access/refresh tokens, Passport strategies, role guards |
|
| **Auth** | Mobile-number + OTP (SMS) and password login; JWT access/refresh; Passport strategies; role guards |
|
||||||
| **Users** | User CRUD, admin activate/deactivate, profile management |
|
| **Users** | User CRUD, profile, phone verification |
|
||||||
| **Applications** | App CRUD, code upload (zip), metadata, runtime detection |
|
| **Admin** | Super-admin user-detail dashboard and operations |
|
||||||
| **Build** | Kaniko-based image builds via BullMQ queue; auto-detects Node.js/Laravel/WordPress |
|
| **Applications** | App CRUD, code upload (→ disk), git config, runtime/version metadata |
|
||||||
| **Kubernetes** | K8s API interactions — namespace, scale, delete, pod logs, build pods |
|
| **Application-migrations** | Import / migrate existing applications (Bull queue) |
|
||||||
| **Helm** | Helm CLI wrapper — install/upgrade, rollback, uninstall, history |
|
| **Build** | `build.service` — runtime detection + per-runtime Dockerfile generation, Kaniko image builds inside K8s |
|
||||||
| **Deployments** | Deployment lifecycle orchestration, history, stop/restart |
|
| **Deployments** | Deploy orchestration (build → Helm), history, stop/restart |
|
||||||
| **Clusters** | Multi-cluster management, kubeconfig storage, default cluster selection |
|
| **Kubernetes** | K8s API wrapper, Helm CLI wrapper, registry service |
|
||||||
| **Billing** | Wallet system (deposit/deduct), transaction ledger, plan cost calculation |
|
| **Clusters** | Multi-cluster management, kubeconfig storage, default cluster |
|
||||||
| **Lifecycle** | Cron-based scanner: auto-suspend expired apps, auto-delete after grace period |
|
| **Billing** | Wallet (deposit/deduct), transaction ledger, invoices, pricing catalog, coupons/discounts |
|
||||||
| **Snapshots** | Application snapshot/backup management |
|
| **Lifecycle** | Interval scanner: auto-suspend expired apps, auto-delete after grace period |
|
||||||
| **Tickets** | Support ticket system for users |
|
| **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
|
## 🔧 Tech Stack
|
||||||
|
|
||||||
### Frontend: Next.js 14 (App Router) + Tailwind CSS
|
### Frontend: Next.js 16 (App Router) + Tailwind CSS v4
|
||||||
|
|
||||||
| Reason | Detail |
|
| Reason | Detail |
|
||||||
|--------|--------|
|
|--------|--------|
|
||||||
| **SSR & SEO** | Server-side rendering for fast initial loads |
|
| **SSR & SEO** | Server-side rendering for fast initial loads and a public landing/blog |
|
||||||
| **App Router** | React Server Components, layouts, loading states |
|
| **App Router** | React Server Components, layouts, locale routing under `app/[lang]/` |
|
||||||
| **Tailwind CSS** | Rapid UI development, consistent design system |
|
| **Bilingual** | `fa-IR` (default) + `en-US`; `middleware.ts` also splits landing vs authenticated panel |
|
||||||
| **TypeScript** | End-to-end type safety with shared types |
|
| **React Query** | Server state, caching, polling for live build/deploy status |
|
||||||
| **React Query** | Server state management, caching, polling for live status |
|
| **Zustand** | Lightweight client auth store |
|
||||||
| **Zustand** | Lightweight client state management (auth store) |
|
| **TypeScript** | End-to-end type safety |
|
||||||
|
|
||||||
### Backend: NestJS 10 (Node.js)
|
### Backend: NestJS 11 (Node.js 20)
|
||||||
|
|
||||||
| Reason | Detail |
|
| Reason | Detail |
|
||||||
|--------|--------|
|
|--------|--------|
|
||||||
| **Modular architecture** | Each domain is a self-contained module |
|
| **Modular** | Each domain is a self-contained module |
|
||||||
| **TypeScript native** | Full type safety, shared interfaces with frontend |
|
| **@kubernetes/client-node** | Direct K8s API interaction (Jobs, Deployments, logs, scale) |
|
||||||
| **@kubernetes/client-node** | Official K8s client for direct API interaction |
|
| **Helm CLI** | Shell-out to helm for chart-based app deployments |
|
||||||
| **Helm CLI** | Shell-out to helm for chart-based deployments |
|
| **Bull (Redis)** | Async queues for service-access grants and application migrations |
|
||||||
| **Bull/BullMQ** | Redis-backed job queues for async build pipelines |
|
| **TypeORM** | PostgreSQL ORM. `synchronize` is **development-only**; production schema changes ship as idempotent SQL migrations / `ALTER ... IF NOT EXISTS` |
|
||||||
| **TypeORM** | PostgreSQL ORM with entity-based schema |
|
|
||||||
|
|
||||||
### Build System: Kaniko (in-cluster)
|
### Build System: Kaniko (in-cluster)
|
||||||
|
|
||||||
| Reason | Detail |
|
| Reason | Detail |
|
||||||
|--------|--------|
|
|--------|--------|
|
||||||
| **No Docker daemon** | Builds inside K8s pods — no Docker-in-Docker |
|
| **No Docker daemon** | Builds run as unprivileged K8s Jobs in `cloudhost-builds` |
|
||||||
| **Runtime detection** | Auto-detects Node.js, Laravel, WordPress from source files |
|
| **Runtime detection** | `detectRuntime()` infers Node.js / Laravel / WordPress from source files; the app may also pin a runtime explicitly |
|
||||||
| **WordPress support** | Custom entrypoint script for wp-content merging |
|
| **Per-runtime Dockerfiles** | `generateDockerfile()` emits a tailored Dockerfile for Node.js, Laravel, WordPress, Go, PHP, Python, Django, or .NET |
|
||||||
| **Registry push** | Native push to insecure or authenticated registries |
|
| **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
|
### Deployment: Helm v3 Charts
|
||||||
|
|
||||||
| Reason | Detail |
|
| Reason | Detail |
|
||||||
|--------|--------|
|
|--------|--------|
|
||||||
| **Templated manifests** | Single chart handles Node.js, Laravel, WordPress |
|
| **Templated manifests** | One `cloudhost-app` chart handles all runtimes + attached services |
|
||||||
| **Rollback support** | Built-in revision history and rollback |
|
| **Rollback** | Built-in revision history |
|
||||||
| **Resource policies** | PVCs and secrets persist across helm uninstall |
|
| **Persistence** | DB/app PVCs and secrets use keep policies so they survive helm uninstall |
|
||||||
| **Registry pull secrets** | Auto-created per namespace for insecure registries |
|
| **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
|
## 🔐 Security Architecture
|
||||||
|
|
||||||
- JWT Authentication (access + refresh tokens)
|
- Mobile-OTP + password authentication; JWT access + refresh
|
||||||
- Role-Based Access Control (User / Admin)
|
- **Live** role/active-status enforcement — `JwtStrategy` reads the user from the DB each request
|
||||||
- K8s Namespace Isolation per user
|
- Role-Based Access Control (`user` / `admin` / `technical` / `sales`)
|
||||||
- K8s RBAC — scoped ServiceAccounts
|
- K8s namespace isolation per user; scoped ServiceAccounts
|
||||||
- Network Policies between namespaces
|
- Resource quotas & limit ranges; expandable per-app storage
|
||||||
- Resource Quotas & Limit Ranges
|
- Secrets stored as K8s Secrets (env vars, DB creds)
|
||||||
- Secrets encryption (K8s Secrets)
|
- Input validation (class-validator), Helmet headers, Bcrypt password hashing
|
||||||
- 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://<subdomain>.apps.cloudhost.ir
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -168,95 +175,100 @@ ACTIVE ──(expires)──► SUSPENDED ──(grace)──► PENDING_DELETIO
|
|||||||
▲ │ │
|
▲ │ │
|
||||||
└────── payment ────────┘ │
|
└────── payment ────────┘ │
|
||||||
└────── payment (within grace) ──────────────────┘
|
└────── payment (within grace) ──────────────────┘
|
||||||
|
|
||||||
|
DOCKED ── user removed the service; data retained until the plan expires
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Billing Cycles**: HOURLY | MONTHLY | YEARLY
|
- **Billing cycles**: HOURLY | MONTHLY | YEARLY
|
||||||
- **Hourly plans**: auto-renew from wallet each hour
|
- **Wallet**: deposits, deductions, refunds, gateway payments; invoices with coupons/discounts
|
||||||
- **Grace periods**: admin-configurable via PlatformSettings table
|
- **Grace periods**: admin-configurable via the PlatformSettings entity (per cycle)
|
||||||
- **Lifecycle Scanner**: runs every 60s (configurable)
|
- **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 |
|
Deploys the API, UI, PostgreSQL, and Redis into a namespace (default `cloudhost`).
|
||||||
|-------|---------|
|
|
||||||
| `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:
|
|
||||||
|
|
||||||
| Template | Purpose |
|
| Template | Purpose |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| `deployment.yaml` | App pod with imagePullSecrets, probes, WordPress volumes |
|
| `backend-deployment.yaml` / `backend-service.yaml` / `backend-pvc.yaml` | NestJS API + uploads PVC |
|
||||||
| `service.yaml` | ClusterIP (port 80 → app port) |
|
| `frontend-deployment.yaml` / `frontend-service.yaml` | Next.js UI |
|
||||||
| `ingress.yaml` | Nginx ingress with cert-manager TLS |
|
| `postgres-*.yaml` / `redis-*.yaml` | Control-plane database & queue |
|
||||||
| `secret.yaml` | User env vars as K8s Secret |
|
| `ingress.yaml` | Frontend / API / panel host rules (+ TLS) |
|
||||||
| `db-deployment.yaml` | PostgreSQL or MySQL with health probes |
|
| `secret.yaml` | JWT, DB, registry, SMS and other platform secrets |
|
||||||
| `db-service.yaml` | Database ClusterIP service |
|
| `migrations-configmap.yaml` / `migrations-job.yaml` | Optional SQL migration Job (`migrations.enabled`) |
|
||||||
| `db-pvc.yaml` | Database storage (resource-policy: keep) |
|
| `namespace.yaml` / `_helpers.tpl` / `NOTES.txt` | Namespace + chart helpers |
|
||||||
| `db-secret.yaml` | Database credentials (resource-policy: keep) |
|
|
||||||
| `wp-pvc.yaml` | WordPress wp-content PVC (resource-policy: keep) |
|
Key values: `ingress.enabled`, `ingress.tls.*`, `ingress.frontend.host` / `ingress.api.host`,
|
||||||
| `registry-pull-secret.yaml` | imagePullSecret for insecure registry |
|
`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
|
## 📁 Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
host/
|
cloud-host/
|
||||||
├── ARCHITECTURE.md
|
├── ARCHITECTURE.md README.md RUNBOOK.fa.md CHANGELOG.md CONTRIBUTING.md
|
||||||
├── README.md
|
├── UPGRADE.md UPGRADE.en.md docker-compose.yml
|
||||||
├── CHANGELOG.md
|
├── backend/ # NestJS 11 API
|
||||||
├── CONTRIBUTING.md
|
|
||||||
├── docker-compose.yml
|
|
||||||
├── backend/
|
|
||||||
│ ├── Dockerfile
|
│ ├── Dockerfile
|
||||||
│ ├── package.json
|
│ ├── helm/{cloudhost-platform, cloudhost-app, cloudhost-logging}/
|
||||||
│ ├── helm/cloudhost-platform/ # Helm chart for control plane
|
│ ├── k8s/{logging, mail}/ # standalone manifests
|
||||||
│ ├── helm/cloudhost-app/ # Helm chart for user apps
|
│ ├── migrations/ # SQL migrations (one-off Jobs in prod)
|
||||||
│ ├── 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
|
|
||||||
│ └── src/
|
│ └── src/
|
||||||
│ ├── app/dashboard/ # Apps, deploy, admin pages
|
│ ├── main.ts / app.module.ts
|
||||||
│ ├── components/
|
│ ├── auth/ users/ admin/ # OTP auth, users, super-admin dashboard
|
||||||
│ ├── lib/ # API client, auth store
|
│ ├── applications/ application-migrations/
|
||||||
│ └── types/ # Shared TS interfaces
|
│ ├── deployments/ # orchestration (build → Helm)
|
||||||
└── uploads/ # User-uploaded code archives
|
│ ├── 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
|
## 🔮 Future Considerations
|
||||||
|
|
||||||
1. Custom domains with auto TLS via cert-manager
|
1. Per-app horizontal autoscaling (HPA) based on CPU/memory
|
||||||
2. Horizontal Pod Autoscaler based on CPU/memory
|
2. WebSocket/SSE for real-time build log streaming (currently polled)
|
||||||
3. WebSocket/SSE for real-time build log streaming
|
3. A Redis-backed build queue (so builds survive a replica restart and the control plane can scale out)
|
||||||
4. GitOps integration (ArgoCD)
|
4. In-cluster image vulnerability scanning (report-only)
|
||||||
5. Additional runtimes (Python, Go, Rust)
|
5. GitOps integration (e.g. ArgoCD) and git-push-to-deploy
|
||||||
6. App marketplace with pre-built templates
|
6. Automated control-plane database backups (scheduled `pg_dump` + retention)
|
||||||
7. Per-app resource consumption dashboards
|
7. App marketplace with pre-built templates
|
||||||
|
|||||||
@@ -1,303 +1,317 @@
|
|||||||
# ☁️ CloudHost — Self-Service PaaS Platform
|
# ☁️ 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
|
## Architecture Overview
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
|
┌──────────────┐ REST ┌──────────────────┐ K8s API ┌──────────────┐
|
||||||
│ Next.js 16 │ REST │ NestJS API │ K8s │ Kubernetes │
|
│ Next.js 16 │ /api/v1 │ NestJS 11 API │ + Helm │ Kubernetes │
|
||||||
│ Frontend │◄───────►│ Backend │◄──────►│ Cluster(s) │
|
│ Frontend │◄─────────►│ Backend │◄───────────►│ Cluster(s) │
|
||||||
└─────────────┘ └────────┬────────┘ └──────────────┘
|
└──────────────┘ └────────┬─────────┘ └──────┬───────┘
|
||||||
│
|
│ │ build Jobs
|
||||||
┌──────────┼──────────┐
|
┌─────────────────┼─────────────────┐ ▼
|
||||||
▼ ▼ ▼
|
▼ ▼ ▼ ┌──────────┐
|
||||||
PostgreSQL Redis Container
|
PostgreSQL Redis Registry │ Kaniko │
|
||||||
(Bull) Registry
|
16 (cache + Bull) (:2) └──────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
| Layer | Technology |
|
| Layer | Technology |
|
||||||
| ------------ | ------------------------------------------------------- |
|
| ---------------- | ----------------------------------------------------------------- |
|
||||||
| Frontend | Next.js 16, Tailwind CSS v4, React Query, Zustand |
|
| Frontend | Next.js 16 (App Router, SSR), React 19, Tailwind CSS v4, React Query, Zustand |
|
||||||
| Backend API | NestJS 11, TypeORM, Passport JWT, Bull (Redis) |
|
| Backend API | NestJS 11, TypeORM, Passport JWT, Bull (Redis) |
|
||||||
| Build Engine | Kaniko (in-cluster, daemon-less Docker builds) |
|
| Build engine | **Kaniko** (daemon-less in-cluster builds) with platform-generated per-runtime Dockerfiles |
|
||||||
| Deployment | Helm v3 charts, @kubernetes/client-node |
|
| Source ingestion | Uploaded archive (zip/tar.gz) streamed into a build PVC, **or** git clone |
|
||||||
| Database | PostgreSQL 16 |
|
| Deployment | Helm v3 charts, `@kubernetes/client-node` |
|
||||||
| Queue | Redis 7 + BullMQ |
|
| 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 **[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 [UPGRADE.en.md](UPGRADE.en.md) ([فارسی](UPGRADE.md)) for dependency-upgrade notes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### For Developers
|
### For Developers
|
||||||
- 🚀 **One-click deploys** from uploaded code archive (zip)
|
- 🚀 **Deploy from a code archive (zip/tar.gz) _or_ a git URL** (public or private via token)
|
||||||
- 🟢 **Node.js** — auto-detected via `package.json` (npm build & start)
|
- 🟢 **Multi-runtime** — Node.js, Laravel, Go, PHP, Python, Django, .NET, each built from a maintained Dockerfile template
|
||||||
- 🟣 **Laravel** — PHP 8.x + Nginx + Supervisor (auto-detected via `artisan`)
|
- 🔵 **WordPress** — official image + custom entrypoint that merges your `wp-content`
|
||||||
- 🔵 **WordPress** — official image + custom entrypoint for wp-content merging
|
- 🗄️ **Managed databases & services** — PostgreSQL, MySQL, MariaDB, MongoDB, Redis, RabbitMQ provisioned via Helm
|
||||||
- 🗄️ **Managed databases** — PostgreSQL or MySQL provisioned via Helm
|
- 💰 **Wallet system** — deposit funds, pay per plan (hourly / monthly / yearly), coupons & discounts
|
||||||
- 💰 **Wallet system** — deposit funds, pay for plans (hourly/monthly/yearly)
|
- 📊 **Live build & runtime logs** (Elasticsearch-backed) + deployment history with rollback
|
||||||
- 📊 **Live logs** & deployment history with rollback
|
- 🔒 **Environment variables** stored as Kubernetes Secrets
|
||||||
- 🔒 **Environment variables** managed as Kubernetes Secrets
|
- ⚙️ **Resource controls** — CPU, memory, replicas, expandable disk
|
||||||
- ⚙️ **Resource controls** — CPU, memory, replica count
|
- 🌐 **Custom domains** with automatic TLS
|
||||||
- 📸 **Snapshots** — backup and restore application state
|
- 📸 **Snapshots** — backup & restore application state
|
||||||
- 🎫 **Support tickets** — in-app support system
|
- 🎫 **Support tickets** with technical/sales departments
|
||||||
|
|
||||||
### For Super Admins
|
### For Super Admins
|
||||||
- 🖥️ **Multi-cluster management** — register/remove Kubernetes clusters
|
- 🖥️ **Multi-cluster management** — register/remove Kubernetes clusters (kubeconfig stored encrypted)
|
||||||
- 👥 **User management** — activate, deactivate, change roles
|
- 👥 **User management** — activate, deactivate, change roles, per-user detail dashboard
|
||||||
- 📈 **Quotas** — per-cluster limits (CPU, memory, max apps)
|
- 📈 **Quotas & pricing** — per-cluster limits and a configurable pricing catalog
|
||||||
- 💳 **Billing oversight** — view all transactions, manage wallet deposits
|
- 💳 **Billing oversight** — transactions, invoices, wallet deposits, global discount
|
||||||
- ⏱️ **Lifecycle settings** — configure grace periods per billing cycle
|
- ⏱️ **Lifecycle settings** — grace periods per billing cycle
|
||||||
- 🔐 **RBAC** — role-based guards on every endpoint
|
- 🔐 **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
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
host/
|
cloud-host/
|
||||||
├── ARCHITECTURE.md # Detailed architecture document
|
├── README.md # This file
|
||||||
├── README.md # This file
|
├── ARCHITECTURE.md # Detailed system design
|
||||||
├── CHANGELOG.md # Version history
|
├── RUNBOOK.fa.md # Persian runbook: local dev + abrban/k3s production deploy
|
||||||
├── CONTRIBUTING.md # Development workflow & conventions
|
├── CHANGELOG.md / CONTRIBUTING.md / UPGRADE.md / UPGRADE.en.md
|
||||||
├── docker-compose.yml # Local dev / production compose
|
├── docker-compose.yml # Local dev stack (Postgres + Redis + API + UI)
|
||||||
│
|
│
|
||||||
├── backend/ # NestJS API
|
├── backend/ # NestJS 11 API (REST under /api/v1)
|
||||||
│ ├── Dockerfile
|
│ ├── Dockerfile
|
||||||
│ ├── package.json
|
|
||||||
│ ├── helm/
|
│ ├── helm/
|
||||||
│ │ ├── cloudhost-platform/ # Helm chart (control plane)
|
│ │ ├── cloudhost-platform/ # Helm chart — control plane (API, UI, Postgres, Redis)
|
||||||
│ │ └── cloudhost-app/ # Helm chart (user apps)
|
│ │ ├── cloudhost-app/ # Helm chart — a single user application + its services
|
||||||
│ │ ├── Chart.yaml
|
│ │ └── cloudhost-logging/ # Helm chart — Elasticsearch / Kibana / Fluent-bit
|
||||||
│ │ ├── values.yaml
|
│ ├── k8s/ # Standalone manifests (logging, mail)
|
||||||
│ │ └── templates/ # K8s manifest templates
|
│ ├── migrations/ # SQL migrations (applied via one-off Jobs in prod)
|
||||||
│ ├── 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
|
|
||||||
│ └── src/
|
│ └── src/
|
||||||
│ ├── app/
|
│ ├── main.ts / app.module.ts
|
||||||
│ │ ├── login/ & register/
|
│ ├── auth/ # Mobile-OTP + password login, JWT strategies, role guards
|
||||||
│ │ └── dashboard/
|
│ ├── users/ # User CRUD, profile, phone verification
|
||||||
│ │ ├── apps/ # App list + detail (lifecycle status)
|
│ ├── admin/ # Super-admin user-detail dashboard & ops
|
||||||
│ │ ├── deploy/ # Multi-step deploy wizard
|
│ ├── applications/ # App CRUD, code upload (→ disk), git config
|
||||||
│ │ └── admin/ # Admin: users, clusters, billing, apps
|
│ ├── application-migrations/ # Import/migrate existing apps (Bull queue)
|
||||||
│ ├── components/
|
│ ├── deployments/ # Deploy orchestration, history, stop/restart
|
||||||
│ ├── lib/ # API client, auth store
|
│ ├── build/ # Kaniko build (build.service): per-runtime Dockerfile generation
|
||||||
│ ├── hooks/
|
│ ├── kubernetes/ # K8s client, Helm wrapper, registry service
|
||||||
│ └── types/ # TypeScript interfaces
|
│ ├── 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 |
|
> ℹ️ 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
|
||||||
| Node.js | ≥ 20 |
|
> (with the in-cluster registry). For pure UI/API development you don't need one.
|
||||||
| Docker & Compose| ≥ 24 |
|
|
||||||
| PostgreSQL | 16 |
|
|
||||||
| Redis | 7 |
|
|
||||||
| Helm | ≥ 3.12 |
|
|
||||||
|
|
||||||
### 1. Clone & Install
|
### 1. Clone & install
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <repo-url> host && cd host
|
git clone <repo-url> cloud-host && cd cloud-host
|
||||||
cd backend && npm install && cd ..
|
cd backend && npm install && cd ..
|
||||||
cd frontend && npm install && cd ..
|
cd frontend && npm install && cd ..
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Environment Variables
|
### 2. Environment variables
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp backend/.env.example backend/.env
|
cp backend/.env.example backend/.env
|
||||||
cp frontend/.env.local.example frontend/.env.local
|
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
|
```bash
|
||||||
docker compose up --build
|
docker compose up -d postgres redis
|
||||||
```
|
```
|
||||||
|
|
||||||
Backend at port 4000, Frontend at port 3000.
|
### 4. Run the apps
|
||||||
|
|
||||||
### 4. Deploy Platform on Kubernetes (Helm)
|
|
||||||
|
|
||||||
Prerequisites: NGINX Ingress, cert-manager (if TLS enabled), StorageClass for PVCs.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build images (set API URL to match ingress.api.host when TLS is on)
|
# Terminal 1 — Backend (http://localhost:4000, prefix /api/v1, Swagger at /docs)
|
||||||
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
|
|
||||||
cd backend && npm run start:dev
|
cd backend && npm run start:dev
|
||||||
|
|
||||||
# Terminal 2 — Frontend
|
# Terminal 2 — Frontend (http://localhost:3000)
|
||||||
cd frontend && npm run dev
|
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
|
> To run the **whole** stack (API + UI + Postgres + Redis) in containers instead:
|
||||||
|
> `docker compose up --build` (backend on `:4000`, frontend on `:3000`).
|
||||||
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 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 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://<frontend.host>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration (key env vars)
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
|----------|-------------|---------|
|
|----------|-------------|---------|
|
||||||
| `PORT` | Backend port | `4000` |
|
| `PORT` | Backend port | `4000` |
|
||||||
| `DB_HOST` | PostgreSQL host | `localhost` |
|
| `DB_HOST` / `DB_PORT` / `DB_USERNAME` / `DB_PASSWORD` / `DB_DATABASE` | PostgreSQL connection | `localhost` / `5432` / `cloudhost` / — / `cloudhost` |
|
||||||
| `DB_PORT` | PostgreSQL port | `5432` |
|
| `JWT_SECRET` / `JWT_EXPIRES_IN` | Access token secret + TTL | — / `1h` |
|
||||||
| `DB_USERNAME` | Database user | `cloudhost` |
|
| `JWT_REFRESH_SECRET` / `JWT_REFRESH_EXPIRES_IN` | Refresh token secret + TTL | — / `7d` |
|
||||||
| `DB_PASSWORD` | Database password | — |
|
| `REDIS_HOST` / `REDIS_PORT` | Redis (cache + Bull queues) | `localhost` / `6379` |
|
||||||
| `DB_NAME` | Database name | `cloudhost` |
|
| `SMS_PROVIDER` | OTP provider (`mizbansms` \| `kavenegar`) | `mizbansms` |
|
||||||
| `JWT_SECRET` | JWT signing secret | — |
|
| `MIZBANSMS_USERNAME` / `MIZBANSMS_PASSWORD` / `MIZBANSMS_FROM` | OTP SMS credentials (required or OTP send 503s) | — |
|
||||||
| `JWT_EXPIRES_IN` | Access token TTL | `15m` |
|
| `REGISTRY_URL` / `REGISTRY_PULL_URL` | In-cluster registry (push / pull) | `registry.cloudhost-builds.svc.cluster.local:5000` |
|
||||||
| `REDIS_HOST` | Redis host | `localhost` |
|
| `BUILD_NAMESPACE` / `BUILD_SERVICE_ACCOUNT` | Build Jobs namespace + SA | `cloudhost-builds` / `kaniko-builder` |
|
||||||
| `REDIS_PORT` | Redis port | `6379` |
|
| `KANIKO_IMAGE` | Kaniko executor image | `gcr.io/kaniko-project/executor:v1.23.2` |
|
||||||
| `REGISTRY_URL` | Container registry URL | `localhost:30500` |
|
| `UPLOAD_DIR` | Disk path for uploaded source archives | `./uploads` |
|
||||||
| `PLATFORM_DOMAIN` | Base domain for app subdomains | `apps.cloudhost.ir` |
|
| `INGRESS_CLASS` | Ingress controller for app Ingress objects | `traefik` |
|
||||||
| `LIFECYCLE_SCAN_INTERVAL_MS` | Lifecycle scanner interval | `60000` |
|
| `PLATFORM_DOMAIN` / `PREVIEW_BASE_DOMAIN` | Base domain for app subdomains / previews | `apps.cloudhost.local` / — |
|
||||||
| `LIFECYCLE_HOURLY_DELETE_AFTER_MS` | Hourly plan grace period | `3600000` (1h) |
|
| `PLATFORM_STORAGE_CLASS` | StorageClass for new PVCs (needs volume expansion) | `cloudhost-expandable` |
|
||||||
| `LIFECYCLE_MONTHLY_DELETE_AFTER_MS` | Monthly plan grace period | `259200000` (3d) |
|
| `ELASTICSEARCH_HOST` / `ELASTICSEARCH_PORT` | Log search backend | cluster DNS / `9200` |
|
||||||
| `LIFECYCLE_YEARLY_DELETE_AFTER_MS` | Yearly plan grace period | `604800000` (7d) |
|
| `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
|
## Security
|
||||||
|
|
||||||
- **JWT** access + refresh tokens with configurable expiry
|
- **JWT** access + refresh tokens; live role/active-status enforcement from DB
|
||||||
- **Bcrypt** password hashing (12 rounds)
|
- **Bcrypt** password hashing
|
||||||
- **Helmet** HTTP security headers
|
- **Helmet** HTTP security headers, **class-validator** on all DTOs
|
||||||
- **RBAC** role-based route guards (`@Roles(UserRole.ADMIN)`)
|
- **RBAC** role-based route guards (`@Roles(...)`)
|
||||||
- **Namespace isolation** — each user deploys to their own K8s namespace
|
- **Namespace isolation** — each user deploys to their own Kubernetes namespace
|
||||||
- **Secrets** — env vars stored as K8s Secrets, never in plain manifests
|
- **Secrets** — env vars stored as K8s Secrets
|
||||||
- **Input validation** — `class-validator` on all DTOs
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user