Commit Graph

25 Commits

Author SHA1 Message Date
keyhan 22359be40e fix(platform): apply production hardening from audit plan
Close billing, tenancy, migration, build, and CI/CD gaps identified in the
audit: wallet/gateway guards, full-UUID namespaces, idempotent migrations with
base schema, stateful service stability, safer Dockerfiles/git builds, and
platform chart hardening (Redis auth, RollingUpdate, backups, Swagger off).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 19:35:07 +03:30
keyhan 5ed2ef0958 Add GitOps stack for abrban.com with Gitea Actions CI/CD.
Build and Deploy Platform / build-push-deploy (push) Has been cancelled
Harbor in-cluster builds via Kaniko, ArgoCD auto-sync, and production Helm values for abrban.com domains.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 01:27:20 +03:30
keyhan 8d1855b89c Detect and validate app runtime from uploaded archives.
Reject zip uploads when the selected runtime does not match archive contents, and re-validate before Kaniko builds to fail fast instead of producing the wrong Dockerfile.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 00:27:03 +03:30
keyhan 9c16b462f4 revert(build): remove app build pipeline revamp (Nixpacks/MinIO/Trivy/registry GC)
Reverts commits 3eff38f and c379a23 and restores the previous Kaniko-only
build pipeline (runtime detection + per-runtime Dockerfile generation,
disk-based source upload).

Removed: Nixpacks Dockerfile generation, MinIO source storage (common/storage),
Bull build queue + Redis build state (common/redis, deployment.processor),
Trivy image scan (scan.service, deployment.vulnerabilitySummary), and daily
registry garbage collection (registry-gc). Nothing outside the build/deploy
path depended on these. Backend tsc + 105/106 tests green (the pre-existing
helm.service chartPath failure is unrelated); frontend tsc green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:21:30 +03:30
keyhan 3eff38f8d2 feat(build): revamp app build pipeline (queue, Nixpacks, MinIO, Trivy, registry GC)
Rework the application build/deploy pipeline for scalability, reproducibility,
and security:

- Build queue: deploys run through a bounded-concurrency Bull queue
  (BUILD_CONCURRENCY, default 3) so concurrent user deploys can't flood the
  cluster with Kaniko jobs. Build state (progress / cancel / session) moves from
  in-memory Maps to Redis, so cancel + live logs work across backend replicas.
- Nixpacks + BYO Dockerfile: code runtimes build via Nixpacks (or the user's own
  Dockerfile when present); the hand-written per-runtime Dockerfile generators
  and runtime auto-detection are removed. WordPress keeps its templated path.
  Build-time mirror env (NIXPACKS_BUILD_ENV) supports the Iran network.
- Source upload to MinIO: archives stream to in-cluster MinIO; build pods pull
  via a presigned URL. Removes the PVC + helper pod + kubectl cp upload path.
- Report-only Trivy scan after build; per-severity summary stored on the
  deployment and shown as a badge in the dashboard. Never gates a deploy.
- Registry GC: a Redis-locked daily job keeps the newest N image tags per app
  (REGISTRY_KEEP_VERSIONS, default 3) and reclaims disk via garbage-collect.
- Hardening: git tokens are delivered via a per-build Secret + git credential
  store instead of being embedded in the clone URL / Job manifest; build timeout
  is configurable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:58:58 +03:30
keyhan dbc169206f feat(deploy): remove cluster allocation section from app creation
Drop the admin-only "cluster assignment" UI from the resources &
config step of the deploy wizard and the related backend override.
App placement is now always decided automatically by the allocator.

- frontend: remove cluster/pool selection block, review-step cluster
  row, clusterMode state, public cluster/pool queries, and clusterId/
  poolId from CreateApplicationDto
- backend: drop clusterId/poolId override from the create DTO and
  simplify ApplicationsService.create to always auto-allocate; widen
  selectClusterForApplication param to keep the fallback path working

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:58:30 +03:30
keyhan 8b77656bb7 chore(deps): upgrade all dependencies to latest stable
Bring backend and frontend to the latest stable releases (no pre-releases),
including major upgrades that required code migration. Both projects pass
typecheck and production builds.

Backend
- NestJS 10 -> 11 (common/core/platform-express/jwt/passport/bull/cli/
  schematics/testing), @nestjs/config 3->4, @nestjs/swagger 7->11,
  @nestjs/typeorm 10->11
- @kubernetes/client-node 0.21 -> 1.4: migrate ~200+ call sites across 6
  services to the v1 single-object argument API, unwrapped responses, err.code,
  setHeaderOptions for patch content-type, applyToHTTPSOptions. Add regression
  spec k8s-client-v1-migration.spec.ts.
- typeorm 0.3 -> 1.0: relations/select string arrays -> object form
- uuid 9->14 (drops @types/uuid), multer 1->2, bcrypt 5->6, helmet 7->8,
  class-validator 0.14->0.15
- TypeScript 5->6, ESLint 8->9, @typescript-eslint 6->8, jest 29->30,
  @types/node 20->24; tsconfig: strictPropertyInitialization:false,
  ignoreDeprecations, rootDir, explicit types[]
- @nestjs/config 4: jwt.strategy uses getOrThrow; @types/express kept at 4
  (Nest 11 runs Express 4)

Frontend
- React 18->19, Next 14->16 (async params via official codemod),
  Tailwind 3->4 (@tailwindcss/postcss, @import + @config, inline custom @apply),
  framer-motion 11->12, zustand 4->5, three 0.169->0.184, @react-three/* majors
- TypeScript 5->6 (tsconfig target es5->ES2017), ESLint 8->9,
  eslint-config-next 14->16

Infra/docs
- Dockerfiles node:20-alpine -> node:24-alpine (require-esm for k8s client)
- Add UPGRADE.md / UPGRADE.en.md; refresh README tech-stack versions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 18:05:33 +03:30
keyhan 4301277b48 Serve preview URLs over Traefik+TLS, stabilize them, and speed up builds.
Ingress / preview URLs:
- Default the app Ingress class and ACME HTTP-01 solver to Traefik
  (k3s default) via a new INGRESS_CLASS env, instead of hardcoding nginx —
  fixes 404s on clusters without ingress-nginx.
- Only put public, real-TLD hosts (custom domain + preview) in the TLS
  block; the internal *.apps.cloudhost.local host no longer poisons the
  Let's Encrypt order, so certs actually issue.
- Make the per-app preview number stable across redeploys so URLs stop
  breaking, and let PREVIEW_BASE_DOMAIN configure the base domain.

Registry pulls:
- Point the k3s registries.yaml mirror endpoint at the registry NodePort on
  loopback so node containerd never depends on cluster DNS (image pulls
  survive node restarts).

Builds:
- Pin the Kaniko image, use IfNotPresent pull policy, drop the dead build
  queue/processor, and retry transient Kubernetes API errors while polling
  build jobs.

Logs & apps list:
- fluent-bit reads log files from head so startup output reaches
  Elasticsearch.
- Order joined deployments newest-first so the apps list shows the latest
  deployment status.

Allocation:
- Reserve in-flight (pending/building) capacity and stop globally degrading
  the cluster on a single allocation failure, so concurrent deploys don't
  starve or wrongly report "no healthy cluster".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 15:44:08 +03:30
keyhan 20c4184cde Generate random platform subdomains for apps without custom domains.
Assign unpredictable subdomains on create when no custom domain is set, and update deploy UI CNAME hints to reference the app Platform Domain after creation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 19:55:44 +03:30
keyhan 695e05f948 Add managed databases and services with billing-aligned upgrades.
Introduce product types for managed PostgreSQL, Redis, and RabbitMQ with a dedicated dashboard, Helm-only deploy pipeline, external access, snapshots with progress, and prorated resource or storage upgrades matching application billing rules. PVCs use an expandable StorageClass with automatic migration when legacy disks cannot resize in place.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 19:00:09 +03:30
keyhan fda8384a5c Improve cluster allocation strategy.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 23:18:50 +03:30
keyhan 72a1519ea0 Add automatic cluster pool allocation.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 23:08:06 +03:30
keyhan 5239e8aa94 Add prepaid resource credits with prorated deploy billing.
When users delete an app before plan expiry, remaining resources become credits for a new deploy. The deploy calculator shows covered vs additional charges, prices optional services correctly, and prorates extras to days left on the credit.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 17:37:44 +03:30
keyhan 35dd771f63 Add unified logs platform with Helm-managed central Elasticsearch.
Deploy cloudhost-logging on cluster registration, ship app and optional service logs to ES with owner isolation, and fix Kibana 8.12 auth via kibana_system.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 15:56:33 +03:30
keyhan 7c7e8ae254 fix(deploy): persist replica snapshot before stop for restore on start
Read live deployment replica counts from K8s before scaling to zero,
store them on the application as suspendedReplicas, and use that snapshot
when resuming so Start restores the pre-stop replica layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 01:03:52 +03:30
keyhan abd8848180 feat(laravel): auto-set APP_URL from platform or custom domain
Inject APP_URL for Laravel/PHP apps when missing: on create from the
platform subdomain, on custom-domain verification from the verified host,
and at deploy time as a safety net. Never overwrites user-provided values.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 00:51:09 +03:30
keyhan 0c0a6cd5be fix: reliable source upload, build cancel, WordPress port 80 default
- Replace port-forward/netcat PVC upload with kubectl cp for integrity
- Add build cancellation API and session cleanup; deploy catches cancel
- Default port 80 for WordPress, PHP, and Laravel on create
- Build progress modal with cancel; Helm/K8s adjustments for deployments
- Update build and kubernetes specs

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 16:03:45 +03:30
keyhan 435cf92817 feat: add custom domain support with SSL, DNS verification, and billing
Users can assign a custom domain to their app with automatic SSL via
cert-manager. Includes DNS verification flow (CNAME check), Persian
instructions, admin-configurable pricing via PlatformSetting, and
integration into the deploy wizard cost calculation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 00:36:29 +03:30
keyhan 5f6eccc483 fix(apps): always attempt K8s cleanup on delete, cluster service fixes
- Delete endpoint no longer requires clusterId && latestImageTag
- Clusters: getDefault fallback logic, reassign apps on delete
- Unit tests for cluster default/delete logic
2026-04-22 16:44:43 +03:30
keyhan 9e3347cb71 feat: database management — custom credentials, dump upload/restore
Backend:
- Add dbUsername/dbPassword columns to Application entity
- Add optional DB credential fields to CreateApplicationDto
- Auto-generate dbPassword (crypto.randomBytes) and default dbUsername='appuser'
  when databaseType != 'none' on app creation
- Store both username and password in K8s DB secret (was password-only)
- Read DB_USER/POSTGRES_USER/MYSQL_USER from secretKeyRef instead of hardcoded
- New restoreDatabaseDump() in KubernetesService: creates K8s Job with
  psql/mysql client to restore uploaded SQL dump, waits for completion,
  returns logs
- New POST /applications/:id/db-upload endpoint with 500MB file limit

Frontend:
- Add dbUsername/dbPassword to Application and CreateApplicationDto types
- Deploy page: show username/password fields when database is selected,
  with generate-random-password button and show/hide toggle
- App detail page: new Database section with connection info (host, port,
  db name, username, password with copy-to-clipboard), SQL dump upload
  area with drag-and-drop, and restore output logs display

Security:
- Database remains ClusterIP only (no external exposure)
- Credentials stored in K8s Secrets (base64-encoded)
- Dump file uploaded as temporary K8s Secret, auto-cleaned after restore
2026-04-06 22:47:41 +03:30
keyhan 8243ac7df2 feat: technical role can view all applications with search, separate /all route
- Add GET /applications/all endpoint for admin/technical with search by user name/email/ID
- GET /applications now always returns only the current user's apps (fix for technical seeing all apps)
- Technical role can view/edit/delete any application (same as admin)
- Add 'All Applications' page with search bar, user info columns, status badges
- Add 'All Applications' link to admin and technical sidebar navigation
- Add user relation to Application TypeScript interface
2026-04-06 14:43:46 +03:30
keyhan 3ab647be2e feat: ticketing system with technical/sales roles and department routing
Backend:
- Added TECHNICAL and SALES roles to UserRole enum
- Added TicketDepartment, TicketStatus, TicketPriority enums
- Created Ticket and TicketMessage entities with relationships
- Created TicketsModule with full CRUD service and controller
- Ticket routing: users create tickets to technical/sales departments
- Staff reply updates status (answered), user reply sets waiting
- Role-based access: technical staff sees technical tickets, sales sees sales tickets
- Admin sees all tickets with stats (total, open, avg response time)
- Updated access control: technical role has admin-level access (except role change)
- Sales role can view users and handle sales tickets
- Clusters controller: technical role can manage clusters/pools
- Users controller: technical/sales can view users, only admin changes roles

Frontend:
- New user ticket pages: list (with create form) + detail (chat-style messages)
- Staff ticket panel: filtered by department with status filters
- Admin all-tickets page with statistics dashboard and department/status filters
- Updated sidebar: role-based nav items (admin/technical/sales sections)
- Role badges in header for technical (blue) and sales (green)
- Admin users page: new roles in dropdowns, role change restricted to admin only
- Deploy page: technical role gets cluster selection access like admin
2026-04-06 12:36:41 +03:30
keyhan 4fd102468e security: restrict cluster/pool selection to admin users only
Backend:
- ApplicationsService.create() now accepts userRole parameter
- Non-admin users have clusterId/poolId stripped automatically
- Logs warning when non-admin attempts manual cluster selection

Frontend:
- Deploy wizard hides cluster assignment mode selector for non-admin users
- Non-admin users see a simple 'Default Cluster' info box instead
- Cluster/pool API queries only execute for admin users (enabled: isAdmin)
- Review step shows 'Default Cluster' for non-admin regardless of form state
2026-04-06 11:36:58 +03:30
keyhan 2621dc0cc6 feat: multi-cluster management with pool-based load balancing
- Add ClusterPool entity for grouping clusters into named pools
- Support 3 deployment modes: manual cluster, pool load-balanced, default fallback
- Pool strategies: least-apps (fewest deployed apps) and round-robin
- Add pool CRUD API endpoints (admin) and public pool listing
- Frontend deploy page: 3-mode cluster selector (Default/Manual/Pool)
- Frontend app detail: shows assigned cluster and pool info
- Admin pools management page with cluster selection and strategy picker
- Application entity extended with poolId field
2026-04-05 17:37:05 +03:30
keyhan 33be1649c4 init 2026-04-05 15:22:01 +03:30