- Add AppSnapshot entity with type (pre_deploy/manual), status tracking, and file paths
- Add SnapshotsService with create, capture, rollback, prune (max 10), and download logic
- Add SnapshotsController with REST endpoints for CRUD, rollback, and file downloads
- Add K8s methods: exportDatabaseDump, archiveWpContent, restoreWpContent
- Auto-create pre-deploy snapshots before each deployment for rollback safety
- Support downloading current live state (source, wp-content, database) without snapshots
- Add snapshot management UI in app detail page with create, rollback, download, delete
- Wire circular dependencies with forwardRef between Deployments and Snapshots modules
- Add two deployment modes for WordPress: Fresh Install vs Migrate Existing Site
- Fresh Install: vanilla WordPress from official image (existing behavior)
- Migrate: upload ZIP with wp-content/ (themes, plugins, uploads), wp-config.php, .htaccess
- Custom entrypoint merges staged wp-content into PVC on first container run
- Add init container for fresh WordPress builds (empty source context for Kaniko)
- Increase upload limit to 200MB for WordPress sites
- Add PHP upload limits (64MB) and memory config in WordPress Dockerfile
- Update deploy page review step to show WordPress mode info
- All UI in English
- Backend: billing module with ServicePlan, PricingRule, Wallet, WalletTransaction entities
- Admin can CRUD service plans with hourly/monthly/yearly billing cycles
- Each plan has flexible pricing rules (base_fee, cpu, memory, storage, db addon)
- Wallet system: auto-created per user, charge, deduct, refund, transaction history
- Cost calculation endpoint: cross-cycle conversion (hourly*720=monthly, monthly*12=yearly)
- Frontend: admin billing management page (/dashboard/admin/billing)
- Frontend: user wallet page with balance, quick-charge, transaction history
- Deploy page: cost breakdown shown in Review step (hourly/monthly/yearly)
- Navigation: Wallet link for users, Billing Plans link for admins
- Add dbStorageSize column to Application entity (default: 1Gi)
- Add dbStorageSize to CreateApplicationDto, frontend types
- Use dynamic storage size in K8s deployDatabase instead of hardcoded 5Gi
- Deploy page: storage size selector with +/- buttons (min 1GB, max 100GB)
- Auto-suggest storage based on DB dump file size (3x dump size, min 1GB)
- Show DB storage in Review step
- App detail: Database Storage section with expand button
- GET /applications/:id/db-storage — read current PVC size from K8s
- PATCH /applications/:id/db-storage — expand PVC (only increase, no shrink)
- PVC resize uses JSON patch on K8s API
Backend:
- Add runtimeVersion, phpVersion, dbVersion columns to Application entity
- Add version fields to CreateApplicationDto with validation
- Node.js Dockerfile: use selected version (22/20/18/16) instead of hardcoded 20
- Laravel Dockerfile: use selected PHP version (8.4/8.3/8.2/8.1) instead of 8.3
- WordPress Dockerfile: use selected WP version (6.7/6.6/6.5/6.4) + PHP version
- K8s deployDatabase(): use selected DB version instead of hardcoded postgres:16/mysql:8.0
- K8s restoreDatabaseDump(): match DB image version for restore jobs
- Add dbVersion to ManifestContext interface
Frontend:
- Add runtimeVersion, phpVersion, dbVersion to Application and CreateApplicationDto
- Deploy page: Node.js version dropdown (22/20/18/16)
- Deploy page: Laravel PHP version dropdown (8.4/8.3/8.2/8.1)
- Deploy page: WordPress version + PHP version dropdowns
- Deploy page: PostgreSQL version dropdown (17/16/15/14)
- Deploy page: MySQL version dropdown (9.0/8.4/8.0/5.7)
- Deploy page: auto-set default versions on runtime/DB selection
- Review step: show selected versions
- App detail page: display runtime + DB versions in config and header
Backend:
- Add WORDPRESS to AppRuntime enum
- Add wordpressDockerfile() using wordpress:6-php8.3-apache base image
with custom theme/plugin/wp-content merge support
- Add WordPress-specific K8s env vars (WORDPRESS_DB_HOST, WORDPRESS_DB_USER,
WORDPRESS_DB_PASSWORD, WORDPRESS_DB_NAME, WORDPRESS_TABLE_PREFIX)
- Create wp-content PersistentVolumeClaim (2Gi) for WordPress deployments
- Mount wp-content PVC in deployment container at /var/www/html/wp-content
Frontend:
- Add 'wordpress' to runtime type unions (Application, CreateApplicationDto)
- Add WordPress runtime card in deploy page (port 80, blue icon)
- Auto-select MySQL database when WordPress is chosen, disable other DB options
- Show Persian hint 'وردپرس به MySQL نیاز دارد' when WordPress selected
- Update all runtime icon colors across dashboard, apps, admin/apps pages
to show blue-600 for WordPress
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
- 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
- Add /tickets/unanswered-counts API endpoint for staff/admin
- Show red badge with unanswered count on sidebar nav (staff tickets, admin tickets)
- Add summary cards (unanswered/answered/total) to staff tickets page
- Highlight unanswered count in admin tickets stats cards
- Staff can create tickets to OTHER departments only (not their own)
- Frontend hides own department from ticket creation dropdown
- Sidebar badges auto-refresh every 30 seconds
- Replace ticketsRepo.save(ticket) with ticketsRepo.update() to avoid
cascade orphaning existing messages (SET ticketId=null violates NOT NULL)
- Fix reply(), close() in tickets.service.ts
- Fix updateStatus() in tickets.controller.ts using new updateTicketFields() method
- Add updateTicketFields() helper to TicketsService for safe partial updates
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
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
Most user apps (e.g. Next.js) don't have a /health endpoint, causing
liveness/readiness probes to fail with 404 and crash-loop the pods.
TCP socket probes just check if the port is open, which works universally.
npm ci fails when package-lock.json is out of sync with package.json,
which is common with GitHub-downloaded ZIPs. Switched to npm install
with --legacy-peer-deps flag for maximum compatibility.
GitHub-downloaded ZIPs contain files inside a subfolder (e.g., repo-main/).
The build init container now detects this pattern and flattens the contents
to the workspace root so Kaniko can find package.json and other files.
- Add POST /users endpoint for admin to create users with hashed passwords
- Add GET /users?search= with ILike search on email/firstName/lastName
- Add PATCH /users/:id/role for role assignment (user/admin)
- Return appCount per user in the users list
- Add GET /clusters/:id/resources for node, CPU, memory, pod monitoring
- Parse K8s node capacity/allocatable with CPU millicores and memory MiB helpers
- Frontend: admin users page with search bar, create form, role dropdown, app count
- Frontend: cluster resource panel with nodes table, CPU/memory bars, summary cards
- 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
- Backend: getPreviewInfo() in KubernetesService auto-patches ClusterIP
service to NodePort for direct external access
- Backend: GET /applications/:id/preview endpoint returns access URL
with nodePort, host IP (extracted from kubeconfig), and ingress URL
- Frontend: '🌐 Preview' button on app detail page (visible when running)
opens the deployed app in a new browser tab via NodePort URL
- Tested: service patched to NodePort 30107 successfully
- Backend: getResourceUsage() method in KubernetesService fetches real-time
CPU/Memory metrics from K8s metrics-server API per pod
- Backend: updateResources() method patches live K8s deployments with new
CPU/Memory requests+limits and replica count
- Backend: GET /applications/:id/resources endpoint for monitoring
- Backend: PATCH /applications/:id/resources endpoint for scaling
- Backend: ScaleResourcesDto with validation for resource fields
- Frontend: Resource monitoring card with per-pod CPU/Memory progress bars
(color-coded: green < 50%, yellow < 80%, red > 80%)
- Frontend: Pod status table showing phase, readiness, restarts
- Frontend: Scaling controls for CPU request/limit, memory request/limit,
and replicas with +/- buttons
- Frontend: Auto-refresh metrics every 5 seconds when monitoring is open
- Frontend: parseCpuToMillicores/parseMemoryToMi helpers for metric parsing
- Backend: added redeployApplication() to DeploymentsService that creates
a new deployment record and re-runs the full build+deploy pipeline
- Backend: added POST /deployments/applications/:appId/redeploy endpoint
- Frontend: added Redeploy button on app detail page, visible after first
deploy when no build is in progress
- For git-based apps: pulls latest code from repo on each redeploy
- For zip-based apps: rebuilds from last uploaded source code