From 78f357809830131852c1c2648c320b1df5a3879d Mon Sep 17 00:00:00 2001 From: chyoo Date: Tue, 14 Jul 2026 13:15:21 +0900 Subject: [PATCH] slim admin backend image and remove compose config --- Dockerfile | 8 +++- docker-compose.yml | 21 ---------- prisma/auth.schema.prisma | 20 ++++++---- .../migration.sql | 9 +++++ src/organizations/organizations.controller.ts | 7 +++- src/organizations/organizations.service.ts | 39 +++++++++++++++++-- 6 files changed, 68 insertions(+), 36 deletions(-) delete mode 100644 docker-compose.yml create mode 100644 prisma/migrations/20260714113000_add_organization_creator/migration.sql diff --git a/Dockerfile b/Dockerfile index 8f40395..7363237 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,11 +8,15 @@ RUN npm run build FROM node:22-bookworm-slim AS runner WORKDIR /app ENV NODE_ENV=production +ARG DOCKER_VERSION=27.5.1 RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates curl git docker.io binutils \ + && apt-get install -y --no-install-recommends ca-certificates curl git \ + && curl -fsSL "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" \ + | tar -xz -C /tmp \ + && install -m 0755 /tmp/docker/docker /usr/local/bin/docker \ && curl -fsSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl" \ && chmod 0755 /usr/local/bin/kubectl \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /tmp/docker /var/lib/apt/lists/* COPY package*.json ./ RUN npm ci --omit=dev COPY --from=builder /app/dist ./dist diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 30fc9ac..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,21 +0,0 @@ -services: - postgres: - image: postgres:17-alpine - container_name: atnmy-stdo-adm-v2-postgres - environment: - POSTGRES_DB: studio_admin - POSTGRES_USER: studio_admin - POSTGRES_PASSWORD: future1234!@ - ports: - - "5436:5432" - volumes: - - atnmy-stdo-adm-v2-postgres:/var/lib/postgresql/data - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "pg_isready -U studio_admin -d studio_admin"] - interval: 5s - timeout: 3s - retries: 20 - -volumes: - atnmy-stdo-adm-v2-postgres: diff --git a/prisma/auth.schema.prisma b/prisma/auth.schema.prisma index 8eb97cf..bf150fd 100644 --- a/prisma/auth.schema.prisma +++ b/prisma/auth.schema.prisma @@ -108,18 +108,22 @@ model UserLicense { } model Organization { - id String @id @default(uuid()) @db.Uuid - name String - type OrganizationType @default(OTHER) - domain String? + id String @id @default(uuid()) @db.Uuid + name String + type OrganizationType @default(OTHER) + domain String? defaultLicenseCode String? @map("default_license_code") - isActive Boolean @default(true) @map("is_active") - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) - affiliations UserAffiliation[] + isActive Boolean @default(true) @map("is_active") + createdById String? @map("created_by_id") @db.Uuid + createdByName String? @map("created_by_name") + createdByEmail String? @map("created_by_email") + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) + affiliations UserAffiliation[] @@unique([name, type]) @@index([isActive, type]) + @@index([createdByEmail]) @@map("organizations") } diff --git a/prisma/migrations/20260714113000_add_organization_creator/migration.sql b/prisma/migrations/20260714113000_add_organization_creator/migration.sql new file mode 100644 index 0000000..a16868f --- /dev/null +++ b/prisma/migrations/20260714113000_add_organization_creator/migration.sql @@ -0,0 +1,9 @@ +DO $$ +BEGIN + IF to_regclass('public.organizations') IS NOT NULL THEN + ALTER TABLE "organizations" + ADD COLUMN IF NOT EXISTS "created_by_id" UUID, + ADD COLUMN IF NOT EXISTS "created_by_name" TEXT, + ADD COLUMN IF NOT EXISTS "created_by_email" TEXT; + END IF; +END $$; diff --git a/src/organizations/organizations.controller.ts b/src/organizations/organizations.controller.ts index 97f53bb..179b0d8 100644 --- a/src/organizations/organizations.controller.ts +++ b/src/organizations/organizations.controller.ts @@ -13,8 +13,11 @@ export class OrganizationsController { } @Post() - create(@Body() body: CreateOrganizationDto) { - return this.organizationsService.create(body); + create( + @Body() body: CreateOrganizationDto, + @Req() request: { admin?: { id: string; name: string; email: string } }, + ) { + return this.organizationsService.create(body, request.admin); } @Patch(':id') diff --git a/src/organizations/organizations.service.ts b/src/organizations/organizations.service.ts index 54557b8..a3e6e92 100644 --- a/src/organizations/organizations.service.ts +++ b/src/organizations/organizations.service.ts @@ -1,12 +1,23 @@ import { ConflictException, Injectable, NotFoundException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; import { Prisma } from '@prisma/auth-client'; +import { getAdminAvatarUrl } from '../admins/admin-avatar'; import { AuthPrismaService } from '../auth-prisma/auth-prisma.service'; import { CreateOrganizationDto, ListOrganizationsQuery, UpdateOrganizationDto, UpdateOrganizationLicenseDto } from './dto'; +type AdminRequester = { + id: string; + name: string; + email: string; +}; + @Injectable() export class OrganizationsService { - constructor(private readonly authPrisma: AuthPrismaService) {} + constructor( + private readonly authPrisma: AuthPrismaService, + private readonly configService: ConfigService, + ) {} async list(query: ListOrganizationsQuery = {}) { const page = toPositiveInt(query.page, 1); @@ -37,6 +48,9 @@ export class OrganizationsService { type: true, domain: true, defaultLicenseCode: true, + createdById: true, + createdByName: true, + createdByEmail: true, createdAt: true, }, }), @@ -51,6 +65,7 @@ export class OrganizationsService { organizations: organizations.map((organization, index) => ({ ...organization, defaultLicenseName: organization.defaultLicenseCode ? licenseNameByCode.get(organization.defaultLicenseCode) ?? organization.defaultLicenseCode : null, + createdByAvatarUrl: getAdminAvatarUrl(organization.createdById, this.configService), no: total - ((page - 1) * limit + index), })), total, @@ -59,13 +74,20 @@ export class OrganizationsService { }; } - async create(body: CreateOrganizationDto) { + async create(body: CreateOrganizationDto, requester?: AdminRequester) { try { const organization = await this.authPrisma.organization.create({ data: { name: body.name.trim(), type: body.type, domain: body.domain?.trim() || null, + ...(requester + ? { + createdById: requester.id, + createdByName: requester.name, + createdByEmail: requester.email, + } + : {}), }, select: { id: true, @@ -73,11 +95,19 @@ export class OrganizationsService { type: true, domain: true, defaultLicenseCode: true, + createdById: true, + createdByName: true, + createdByEmail: true, createdAt: true, }, }); - return { organization }; + return { + organization: { + ...organization, + createdByAvatarUrl: getAdminAvatarUrl(organization.createdById, this.configService), + }, + }; } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && @@ -105,6 +135,9 @@ export class OrganizationsService { type: true, domain: true, defaultLicenseCode: true, + createdById: true, + createdByName: true, + createdByEmail: true, createdAt: true, }, });