Backend
- Add platform-wide global discount (platform_settings: global_discount_percent),
applied centrally in PricingCatalogService.computeTotalsFromDb so it reaches
every real charge (previews, deploys, renewals, upgrades, invoices). Admin
GET/PATCH /billing/settings/global-discount.
- Add unauthenticated PublicPricingController (catalog + calculate) for the
public landing page, returning gross/net and the discount percentage.
- Bill application replicas by the user-selected footprint: app CPU/RAM/storage
now all scale by replica count; the single-replica database stays unscaled.
Frontend
- Landing: Services bar (PaaS active, DBaaS, KaaS/LaaS "coming soon" with
expandable runtime/database menus), transparent Pricing section (per-resource
rate cards with cycle toggle + discount strikethrough), and a cost Estimator
("estimate your package").
- Optional services and the database are priced like runtimes: the estimator
lets users pick their CPU/RAM/storage (and DB type) so the cost scales by need.
- Admin billing: global-discount editor.
- i18n: fa/en strings for services, pricing, estimator and global discount.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
☁️ 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.
Architecture Overview
┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
│ Next.js 16 │ REST │ NestJS API │ K8s │ Kubernetes │
│ Frontend │◄───────►│ Backend │◄──────►│ Cluster(s) │
└─────────────┘ └────────┬────────┘ └──────────────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
PostgreSQL Redis Container
(Bull) Registry
| 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 |
📖 See ARCHITECTURE.md for detailed system design. 🔼 See UPGRADE.en.md (فارسی) for the latest dependency-upgrade notes (React 19, Next 16, NestJS 11, Tailwind 4, k8s-client v1).
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
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
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
│
├── backend/ # NestJS API
│ ├── 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
│ └── 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
│
└── uploads/ # User-uploaded code archives
Quick Start
Prerequisites
| Tool | Version |
|---|---|
| Node.js | ≥ 20 |
| Docker & Compose | ≥ 24 |
| PostgreSQL | 16 |
| Redis | 7 |
| Helm | ≥ 3.12 |
1. Clone & Install
git clone <repo-url> host && cd host
cd backend && npm install && cd ..
cd frontend && npm install && cd ..
2. Environment Variables
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
3. Run with Docker Compose
docker compose up --build
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.
# 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)
# Terminal 1 — Backend
cd backend && npm run start:dev
# Terminal 2 — Frontend
cd frontend && npm run dev
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 |
Configuration
| 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) |
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-validatoron all DTOs
License
MIT