diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment-datastore.service.spec.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment-datastore.service.spec.ts new file mode 100644 index 0000000000..87f28194c2 --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment-datastore.service.spec.ts @@ -0,0 +1,128 @@ +import type { TestingModule } from '@nestjs/testing' +import type { DeepMockProxy } from 'vitest-mock-extended' +import { Test } from '@nestjs/testing' +import { beforeEach, describe, expect, it } from 'vitest' +import { mockDeep } from 'vitest-mock-extended' +import { PrismaService } from '../infrastructure/database/prisma.service.js' +import { DeploymentDatastoreService } from './deployment-datastore.service.js' + +describe('deploymentDatastoreService', () => { + let module: TestingModule + let service: DeploymentDatastoreService + let prisma: DeepMockProxy + + beforeEach(async () => { + prisma = mockDeep() + + module = await Test.createTestingModule({ + providers: [ + DeploymentDatastoreService, + { provide: PrismaService, useValue: prisma }, + ], + }).compile() + + service = module.get(DeploymentDatastoreService) + }) + + describe('getDeploymentById', () => { + it('should return a deployment with sources and repository', async () => { + const deployment = { id: 'dep1' } + + prisma.deployment.findUnique.mockResolvedValue(deployment as any) + + const result = await service.getDeploymentById('dep1') + + expect(prisma.deployment.findUnique).toHaveBeenCalledWith({ + where: { id: 'dep1' }, + include: { + deploymentSources: { + include: { repository: true }, + }, + }, + }) + expect(result).toEqual(deployment) + }) + }) + + describe('getDeploymentsByProjectId', () => { + it('should return deployments for a project', async () => { + const deployments = [{ id: 'dep1' }] + + prisma.deployment.findMany.mockResolvedValue(deployments as any) + + const result = await service.getDeploymentsByProjectId('project1') + + expect(prisma.deployment.findMany).toHaveBeenCalledWith({ + where: { projectId: 'project1' }, + include: { + deploymentSources: { + include: { repository: true }, + }, + }, + }) + expect(result).toEqual(deployments) + }) + }) + + describe('createDeployment', () => { + it('should create a deployment', async () => { + const data = { name: 'test' } + const created = { id: 'dep1', ...data } + + prisma.deployment.create.mockResolvedValue(created as any) + + const result = await service.createDeployment(data as any) + + expect(prisma.deployment.create).toHaveBeenCalledWith({ data }) + expect(result).toEqual(created) + }) + }) + + describe('updateDeployment', () => { + it('should update a deployment', async () => { + const updated = { id: 'dep1', name: 'updated' } + + prisma.deployment.update.mockResolvedValue(updated as any) + + const result = await service.updateDeployment('dep1', { + name: 'updated', + } as any) + + expect(prisma.deployment.update).toHaveBeenCalledWith({ + where: { id: 'dep1' }, + data: { name: 'updated' }, + }) + expect(result).toEqual(updated) + }) + }) + + describe('deleteDeployment', () => { + it('should delete a deployment', async () => { + const deleted = { id: 'dep1' } + + prisma.deployment.delete.mockResolvedValue(deleted as any) + + const result = await service.deleteDeployment('dep1') + + expect(prisma.deployment.delete).toHaveBeenCalledWith({ + where: { id: 'dep1' }, + }) + expect(result).toEqual(deleted) + }) + }) + + describe('deleteAllDeploymentsByProjectId', () => { + it('should delete all deployments for a project', async () => { + const response = { count: 3 } + + prisma.deployment.deleteMany.mockResolvedValue(response) + + const result = await service.deleteAllDeploymentsByProjectId('project1') + + expect(prisma.deployment.deleteMany).toHaveBeenCalledWith({ + where: { projectId: 'project1' }, + }) + expect(result).toEqual(response) + }) + }) +}) diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment-datastore.service.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment-datastore.service.ts new file mode 100644 index 0000000000..575e748c09 --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment-datastore.service.ts @@ -0,0 +1,53 @@ +import type { Prisma } from '@prisma/client' +import { Inject, Injectable } from '@nestjs/common' +import { PrismaService } from '../infrastructure/database/prisma.service.js' + +@Injectable() +export class DeploymentDatastoreService { + constructor(@Inject(PrismaService) private readonly prisma: PrismaService) {} + + getDeploymentById(deploymentId: string) { + return this.prisma.deployment.findUnique({ + where: { id: deploymentId }, + include: { + deploymentSources: { + include: { repository: true }, + }, + }, + }) + } + + getDeploymentsByProjectId(projectId: string) { + return this.prisma.deployment.findMany({ + where: { projectId }, + include: { + deploymentSources: { + include: { repository: true }, + }, + }, + }) + } + + createDeployment(data: Prisma.DeploymentCreateInput) { + return this.prisma.deployment.create({ data }) + } + + updateDeployment(deploymentId: string, data: Prisma.DeploymentUpdateInput) { + return this.prisma.deployment.update({ + where: { id: deploymentId }, + data, + }) + } + + deleteDeployment(deploymentId: string) { + return this.prisma.deployment.delete({ + where: { id: deploymentId }, + }) + } + + deleteAllDeploymentsByProjectId(projectId: string) { + return this.prisma.deployment.deleteMany({ + where: { projectId }, + }) + } +} diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment.controller.spec.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment.controller.spec.ts new file mode 100644 index 0000000000..519d01798f --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment.controller.spec.ts @@ -0,0 +1,20 @@ +import type { TestingModule } from '@nestjs/testing' +import { Test } from '@nestjs/testing' +import { beforeEach, describe, expect, it } from 'vitest' +import { DeploymentController } from './deployment.controller.js' + +describe('deploymentController', () => { + let module: TestingModule + + beforeEach(async () => { + module = await Test.createTestingModule({ + controllers: [ + DeploymentController, + ], + }).compile() + }) + + it('should be defined', () => { + expect(module).toBeDefined() + }) +}) diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment.controller.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment.controller.ts new file mode 100644 index 0000000000..18f2070b12 --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment.controller.ts @@ -0,0 +1,5 @@ +import { Controller } from '@nestjs/common' + +@Controller('api/v1/deployments') +export class DeploymentController { +} diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment.module.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment.module.ts new file mode 100644 index 0000000000..d52e2b8e9a --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common' +import { DeploymentDatastoreService } from './deployment-datastore.service.js' +import { DeploymentController } from './deployment.controller.js' +import { DeploymentService } from './deployment.service.js' + +@Module({ + imports: [], + controllers: [DeploymentController], + providers: [ + DeploymentDatastoreService, + DeploymentService, + ], +}) +export class DeploymentModule {} diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment.service.spec.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment.service.spec.ts new file mode 100644 index 0000000000..d2daac446c --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment.service.spec.ts @@ -0,0 +1,20 @@ +import type { TestingModule } from '@nestjs/testing' +import { Test } from '@nestjs/testing' +import { beforeEach, describe, expect, it } from 'vitest' +import { DeploymentService } from './deployment.service.js' + +describe('deploymentService', () => { + let module: TestingModule + + beforeEach(async () => { + module = await Test.createTestingModule({ + providers: [ + DeploymentService, + ], + }).compile() + }) + + it('should be defined', () => { + expect(module).toBeDefined() + }) +}) diff --git a/apps/server-nestjs/src/cpin-module/deployment/deployment.service.ts b/apps/server-nestjs/src/cpin-module/deployment/deployment.service.ts new file mode 100644 index 0000000000..381cefaa04 --- /dev/null +++ b/apps/server-nestjs/src/cpin-module/deployment/deployment.service.ts @@ -0,0 +1,5 @@ +import { Injectable } from '@nestjs/common' + +@Injectable() +export class DeploymentService { +} diff --git a/apps/server-nestjs/src/prisma/migrations/20260416165651_add_deployment/migration.sql b/apps/server-nestjs/src/prisma/migrations/20260416165651_add_deployment/migration.sql new file mode 100644 index 0000000000..24a972b729 --- /dev/null +++ b/apps/server-nestjs/src/prisma/migrations/20260416165651_add_deployment/migration.sql @@ -0,0 +1,44 @@ +-- CreateEnum +CREATE TYPE "DeploymentSourceType" AS ENUM ('git', 'oci'); + +-- CreateTable +CREATE TABLE "Deployment" ( + "id" UUID NOT NULL, + "projectId" UUID NOT NULL, + "name" VARCHAR(11) NOT NULL, + "memory" REAL NOT NULL, + "cpu" REAL NOT NULL, + "gpu" REAL NOT NULL, + "autosync" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "environmentId" UUID NOT NULL, + + CONSTRAINT "Deployment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DeploymentSource" ( + "id" UUID NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deploymentId" UUID NOT NULL, + "repositoryId" UUID NOT NULL, + "type" "DeploymentSourceType" NOT NULL, + "targetRevision" TEXT NOT NULL DEFAULT '', + "path" TEXT NOT NULL DEFAULT '', + + CONSTRAINT "DeploymentSource_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Deployment" ADD CONSTRAINT "Deployment_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Deployment" ADD CONSTRAINT "Deployment_environmentId_fkey" FOREIGN KEY ("environmentId") REFERENCES "Environment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DeploymentSource" ADD CONSTRAINT "DeploymentSource_repositoryId_fkey" FOREIGN KEY ("repositoryId") REFERENCES "Repository"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DeploymentSource" ADD CONSTRAINT "DeploymentSource_deploymentId_fkey" FOREIGN KEY ("deploymentId") REFERENCES "Deployment"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/server-nestjs/src/prisma/schema/project.prisma b/apps/server-nestjs/src/prisma/schema/project.prisma index 833845eee1..8f619fbbf7 100644 --- a/apps/server-nestjs/src/prisma/schema/project.prisma +++ b/apps/server-nestjs/src/prisma/schema/project.prisma @@ -1,35 +1,67 @@ +model Deployment { + id String @id @default(uuid()) @db.Uuid + projectId String @db.Uuid + name String @db.VarChar(11) + memory Float @db.Real + cpu Float @db.Real + gpu Float @db.Real + autosync Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + environmentId String @db.Uuid + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + environment Environment @relation(fields: [environmentId], references: [id]) + deploymentSources DeploymentSource[] +} + +model DeploymentSource { + id String @id @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deploymentId String @db.Uuid + repositoryId String @db.Uuid + type DeploymentSourceType + targetRevision String @default("") + path String @default("") + repository Repository @relation(fields: [repositoryId], references: [id]) + deployment Deployment @relation(fields: [deploymentId], references: [id], onDelete: Cascade) +} + model Environment { - id String @id @default(uuid()) @db.Uuid - name String @db.VarChar(11) - projectId String @db.Uuid - memory Float @db.Real - cpu Float @db.Real - gpu Float @db.Real - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - clusterId String @db.Uuid - stageId String @db.Uuid - cluster Cluster @relation(fields: [clusterId], references: [id]) - project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) - stage Stage @relation(fields: [stageId], references: [id]) + id String @id @default(uuid()) @db.Uuid + name String @db.VarChar(11) + projectId String @db.Uuid + memory Float @db.Real + cpu Float @db.Real + gpu Float @db.Real + autosync Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + clusterId String @db.Uuid + stageId String @db.Uuid + cluster Cluster @relation(fields: [clusterId], references: [id]) + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + stage Stage @relation(fields: [stageId], references: [id]) + deployments Deployment[] @@unique([projectId, name]) } model Repository { - id String @id @default(uuid()) @db.Uuid - projectId String @db.Uuid - internalRepoName String - externalRepoUrl String @default("") - externalUserName String @default("") - isInfra Boolean @default(false) - isPrivate Boolean @default(false) - deployRevision String @default("") - deployPath String @default("") - helmValuesFiles String @default("") - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + id String @id @default(uuid()) @db.Uuid + projectId String @db.Uuid + internalRepoName String + externalRepoUrl String @default("") + externalUserName String @default("") + isInfra Boolean @default(false) + isPrivate Boolean @default(false) + deployRevision String @default("") + deployPath String @default("") + helmValuesFiles String @default("") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + deploymentSources DeploymentSource[] } model ProjectClusterHistory { @@ -71,32 +103,33 @@ model ProjectRole { } model Project { - id String @id @unique @default(uuid()) @db.Uuid - name String - description String @default("") - status ProjectStatus @default(initializing) - locked Boolean @default(false) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - everyonePerms BigInt @default(896) - ownerId String @db.Uuid - environments Environment[] - logs Log[] - owner User @relation(fields: [ownerId], references: [id]) - members ProjectMembers[] - plugins ProjectPlugin[] - roles ProjectRole[] - repositories Repository[] - clusters Cluster[] @relation("ClusterToProject") - slug String @unique - limitless Boolean @default(true) - hprodCpu Float @db.Real - hprodGpu Float @db.Real - hprodMemory Float @db.Real - prodCpu Float @db.Real - prodGpu Float @db.Real - prodMemory Float @db.Real + id String @id @unique @default(uuid()) @db.Uuid + name String + description String @default("") + status ProjectStatus @default(initializing) + locked Boolean @default(false) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + everyonePerms BigInt @default(896) + ownerId String @db.Uuid + environments Environment[] + logs Log[] + owner User @relation(fields: [ownerId], references: [id]) + members ProjectMembers[] + plugins ProjectPlugin[] + roles ProjectRole[] + repositories Repository[] + clusters Cluster[] @relation("ClusterToProject") + slug String @unique + limitless Boolean @default(true) + hprodCpu Float @db.Real + hprodGpu Float @db.Real + hprodMemory Float @db.Real + prodCpu Float @db.Real + prodGpu Float @db.Real + prodMemory Float @db.Real lastSuccessProvisionningVersion String? + deployments Deployment[] } enum ProjectStatus { @@ -106,3 +139,8 @@ enum ProjectStatus { archived warning } + +enum DeploymentSourceType { + git + oci +} diff --git a/apps/server/src/prisma/migrations/20260416165651_add_deployment/migration.sql b/apps/server/src/prisma/migrations/20260416165651_add_deployment/migration.sql new file mode 100644 index 0000000000..24a972b729 --- /dev/null +++ b/apps/server/src/prisma/migrations/20260416165651_add_deployment/migration.sql @@ -0,0 +1,44 @@ +-- CreateEnum +CREATE TYPE "DeploymentSourceType" AS ENUM ('git', 'oci'); + +-- CreateTable +CREATE TABLE "Deployment" ( + "id" UUID NOT NULL, + "projectId" UUID NOT NULL, + "name" VARCHAR(11) NOT NULL, + "memory" REAL NOT NULL, + "cpu" REAL NOT NULL, + "gpu" REAL NOT NULL, + "autosync" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "environmentId" UUID NOT NULL, + + CONSTRAINT "Deployment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DeploymentSource" ( + "id" UUID NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deploymentId" UUID NOT NULL, + "repositoryId" UUID NOT NULL, + "type" "DeploymentSourceType" NOT NULL, + "targetRevision" TEXT NOT NULL DEFAULT '', + "path" TEXT NOT NULL DEFAULT '', + + CONSTRAINT "DeploymentSource_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Deployment" ADD CONSTRAINT "Deployment_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Deployment" ADD CONSTRAINT "Deployment_environmentId_fkey" FOREIGN KEY ("environmentId") REFERENCES "Environment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DeploymentSource" ADD CONSTRAINT "DeploymentSource_repositoryId_fkey" FOREIGN KEY ("repositoryId") REFERENCES "Repository"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DeploymentSource" ADD CONSTRAINT "DeploymentSource_deploymentId_fkey" FOREIGN KEY ("deploymentId") REFERENCES "Deployment"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/server/src/prisma/schema/project.prisma b/apps/server/src/prisma/schema/project.prisma index d45ccf451e..8f619fbbf7 100644 --- a/apps/server/src/prisma/schema/project.prisma +++ b/apps/server/src/prisma/schema/project.prisma @@ -1,36 +1,67 @@ +model Deployment { + id String @id @default(uuid()) @db.Uuid + projectId String @db.Uuid + name String @db.VarChar(11) + memory Float @db.Real + cpu Float @db.Real + gpu Float @db.Real + autosync Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + environmentId String @db.Uuid + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + environment Environment @relation(fields: [environmentId], references: [id]) + deploymentSources DeploymentSource[] +} + +model DeploymentSource { + id String @id @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deploymentId String @db.Uuid + repositoryId String @db.Uuid + type DeploymentSourceType + targetRevision String @default("") + path String @default("") + repository Repository @relation(fields: [repositoryId], references: [id]) + deployment Deployment @relation(fields: [deploymentId], references: [id], onDelete: Cascade) +} + model Environment { - id String @id @default(uuid()) @db.Uuid - name String @db.VarChar(11) - projectId String @db.Uuid - memory Float @db.Real - cpu Float @db.Real - gpu Float @db.Real - autosync Boolean @default(true) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - clusterId String @db.Uuid - stageId String @db.Uuid - cluster Cluster @relation(fields: [clusterId], references: [id]) - project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) - stage Stage @relation(fields: [stageId], references: [id]) + id String @id @default(uuid()) @db.Uuid + name String @db.VarChar(11) + projectId String @db.Uuid + memory Float @db.Real + cpu Float @db.Real + gpu Float @db.Real + autosync Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + clusterId String @db.Uuid + stageId String @db.Uuid + cluster Cluster @relation(fields: [clusterId], references: [id]) + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + stage Stage @relation(fields: [stageId], references: [id]) + deployments Deployment[] @@unique([projectId, name]) } model Repository { - id String @id @default(uuid()) @db.Uuid - projectId String @db.Uuid - internalRepoName String - externalRepoUrl String @default("") - externalUserName String @default("") - isInfra Boolean @default(false) - isPrivate Boolean @default(false) - deployRevision String @default("") - deployPath String @default("") - helmValuesFiles String @default("") - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + id String @id @default(uuid()) @db.Uuid + projectId String @db.Uuid + internalRepoName String + externalRepoUrl String @default("") + externalUserName String @default("") + isInfra Boolean @default(false) + isPrivate Boolean @default(false) + deployRevision String @default("") + deployPath String @default("") + helmValuesFiles String @default("") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) + deploymentSources DeploymentSource[] } model ProjectClusterHistory { @@ -72,32 +103,33 @@ model ProjectRole { } model Project { - id String @id @unique @default(uuid()) @db.Uuid - name String - description String @default("") - status ProjectStatus @default(initializing) - locked Boolean @default(false) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - everyonePerms BigInt @default(896) - ownerId String @db.Uuid - environments Environment[] - logs Log[] - owner User @relation(fields: [ownerId], references: [id]) - members ProjectMembers[] - plugins ProjectPlugin[] - roles ProjectRole[] - repositories Repository[] - clusters Cluster[] @relation("ClusterToProject") - slug String @unique - limitless Boolean @default(true) - hprodCpu Float @db.Real - hprodGpu Float @db.Real - hprodMemory Float @db.Real - prodCpu Float @db.Real - prodGpu Float @db.Real - prodMemory Float @db.Real + id String @id @unique @default(uuid()) @db.Uuid + name String + description String @default("") + status ProjectStatus @default(initializing) + locked Boolean @default(false) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + everyonePerms BigInt @default(896) + ownerId String @db.Uuid + environments Environment[] + logs Log[] + owner User @relation(fields: [ownerId], references: [id]) + members ProjectMembers[] + plugins ProjectPlugin[] + roles ProjectRole[] + repositories Repository[] + clusters Cluster[] @relation("ClusterToProject") + slug String @unique + limitless Boolean @default(true) + hprodCpu Float @db.Real + hprodGpu Float @db.Real + hprodMemory Float @db.Real + prodCpu Float @db.Real + prodGpu Float @db.Real + prodMemory Float @db.Real lastSuccessProvisionningVersion String? + deployments Deployment[] } enum ProjectStatus { @@ -107,3 +139,8 @@ enum ProjectStatus { archived warning } + +enum DeploymentSourceType { + git + oci +}