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:
keyhan
2026-06-23 19:27:32 +03:30
parent 9c16b462f4
commit a87bc49393
2 changed files with 428 additions and 402 deletions
+241 -227
View File
@@ -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 <repo-url> host && cd host
git clone <repo-url> 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://<frontend.host>
```
---
## 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
---