feat: version selection for runtimes and databases

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
This commit is contained in:
keyhan
2026-04-06 23:38:23 +03:30
parent c411c5873e
commit 762657f9ed
8 changed files with 172 additions and 19 deletions
@@ -32,6 +32,21 @@ export class CreateApplicationDto {
@IsEnum(DatabaseType)
databaseType: DatabaseType;
@ApiPropertyOptional({ example: '20', description: 'Runtime version — Node: 20/18/16, WordPress: 6.7/6.6/6.5, Laravel: ignored (uses phpVersion)' })
@IsOptional()
@IsString()
runtimeVersion?: string;
@ApiPropertyOptional({ example: '8.3', description: 'PHP version for Laravel/WordPress (8.3/8.2/8.1)' })
@IsOptional()
@IsString()
phpVersion?: string;
@ApiPropertyOptional({ example: '16', description: 'Database version — PostgreSQL: 17/16/15/14, MySQL: 9.0/8.4/8.0' })
@IsOptional()
@IsString()
dbVersion?: string;
@ApiPropertyOptional({ example: 'appuser', description: 'Database username (default: appuser)' })
@IsOptional()
@IsString()
@@ -29,6 +29,15 @@ export class Application {
@Column({ type: 'enum', enum: DatabaseType, default: DatabaseType.NONE })
databaseType: DatabaseType;
@Column({ nullable: true })
runtimeVersion: string; // e.g. node: '20', '18', '16' | laravel php: '8.3', '8.2' | wordpress: '6.7', '6.6'
@Column({ nullable: true })
phpVersion: string; // PHP version for Laravel/WordPress (e.g. '8.3', '8.2', '8.1')
@Column({ nullable: true })
dbVersion: string; // e.g. postgres: '17', '16', '15' | mysql: '9.0', '8.4', '8.0'
@Column({ nullable: true })
dbUsername: string;
+8 -4
View File
@@ -297,8 +297,9 @@ export class BuildService {
private nodeDockerfile(app: Application): string {
const port = app.port || 3000;
const nodeVersion = app.runtimeVersion || '20';
return `# --- Build stage ---
FROM node:20-alpine AS builder
FROM node:${nodeVersion}-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install --legacy-peer-deps && npm cache clean --force
@@ -330,7 +331,7 @@ RUN if ([ -f next.config.js ] || [ -f next.config.mjs ] || [ -f next.config.ts ]
RUN npm run build 2>/dev/null || true
# --- Production stage ---
FROM node:20-alpine AS runner
FROM node:${nodeVersion}-alpine AS runner
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001
@@ -360,6 +361,7 @@ CMD ["sh", "-c", "if [ \\"$(cat /app/.mode)\\" = \\"standalone\\" ] && [ -f serv
}
private laravelDockerfile(app: Application): string {
const phpVersion = app.phpVersion || '8.3';
return `# --- Build stage ---
FROM composer:2 AS composer
WORKDIR /app
@@ -369,7 +371,7 @@ COPY . .
RUN composer dump-autoload --optimize --no-dev
# --- Production stage ---
FROM php:8.3-fpm-alpine
FROM php:${phpVersion}-fpm-alpine
RUN apk add --no-cache nginx supervisor \\
&& docker-php-ext-install pdo pdo_mysql pdo_pgsql opcache
@@ -387,7 +389,9 @@ CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
}
private wordpressDockerfile(app: Application): string {
return `FROM wordpress:6-php8.3-apache
const wpVersion = app.runtimeVersion || '6.7';
const phpVersion = app.phpVersion || '8.3';
return `FROM wordpress:${wpVersion}-php${phpVersion}-apache
# Install additional PHP extensions commonly needed by WordPress
RUN docker-php-ext-install opcache
+8 -2
View File
@@ -25,6 +25,7 @@ interface ManifestContext {
subdomain: string;
dbUsername: string;
dbPassword: string;
dbVersion: string;
}
@Injectable()
@@ -97,6 +98,7 @@ export class KubernetesService implements OnModuleInit {
subdomain: app.subdomain || app.name,
dbUsername: app.dbUsername || 'appuser',
dbPassword: app.dbPassword || this.generatePassword(),
dbVersion: app.dbVersion || '',
};
const manifests: Record<string, any> = {};
@@ -398,7 +400,9 @@ export class KubernetesService implements OnModuleInit {
// Deploy database
const isPostgres = ctx.databaseType === DatabaseType.POSTGRESQL;
const image = isPostgres ? 'postgres:16-alpine' : 'mysql:8.0';
const defaultDbVersion = isPostgres ? '16' : '8.0';
const dbVer = ctx.dbVersion || defaultDbVersion;
const image = isPostgres ? `postgres:${dbVer}-alpine` : `mysql:${dbVer}`;
const port = isPostgres ? 5432 : 3306;
const envVars = isPostgres
? [
@@ -902,7 +906,9 @@ export class KubernetesService implements OnModuleInit {
`mysql -h ${dbName} -u "$DB_USER" -p"$DB_PASSWORD" ${dbDatabase} < /dump/dump.sql 2>&1`,
];
const image = isPostgres ? 'postgres:16-alpine' : 'mysql:8.0';
const defaultRestoreDbVer = isPostgres ? '16' : '8.0';
const restoreDbVer = app.dbVersion || defaultRestoreDbVer;
const image = isPostgres ? `postgres:${restoreDbVer}-alpine` : `mysql:${restoreDbVer}`;
// 3. Create the restore Job
const job: k8s.V1Job = {