Implement backend API and database services in Docker setup

- Added a new `api` service for the NestJS backend, including health checks and dependencies on PostgreSQL, Redis, and MinIO.
- Introduced PostgreSQL and Redis services with health checks and configurations for data persistence.
- Added MinIO for S3-compatible object storage and a one-shot service to initialize required buckets.
- Updated the Nginx configuration to proxy requests to the new backend API and MinIO storage.
- Enhanced the Dockerfile to support the new API environment variables and configurations.
- Updated the `package.json` and `package-lock.json` to include new dependencies for QR code generation and other utilities.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dorian
2026-02-12 20:14:39 +00:00
parent f19fd6feef
commit cdd24a5def
478 changed files with 55355 additions and 529 deletions

View File

@@ -0,0 +1,6 @@
import { IsString } from 'class-validator';
export class CreateSeasonRentDto {
@IsString()
id: string; // Season id
}

View File

@@ -0,0 +1,25 @@
import { IsString, IsNumber, IsOptional, IsBoolean } from 'class-validator';
export class CreateSeasonDto {
@IsString()
projectId: string;
@IsNumber()
seasonNumber: number;
@IsOptional()
@IsNumber()
rentalPrice?: number;
@IsOptional()
@IsString()
title?: string;
@IsOptional()
@IsString()
description?: string;
@IsOptional()
@IsBoolean()
isActive?: boolean;
}

View File

@@ -0,0 +1,8 @@
import { IsOptional, IsUUID } from 'class-validator';
import { CreateSeasonDto } from './create-season.dto.entity';
export class UpdateSeasonDto extends CreateSeasonDto {
@IsUUID()
@IsOptional()
id?: string;
}

View File

@@ -0,0 +1,40 @@
import { ProjectDTO } from 'src/projects/dto/response/project.dto';
import { SeasonRent } from 'src/season/entities/season-rents.entity';
import { SeasonDTO } from './season.dto';
import { ContentDTO } from 'src/contents/dto/response/content.dto';
export class SeasonRentDTO {
id: string;
status: 'active' | 'expired';
usdAmount: number;
createdAt: Date;
expiresAt: Date;
title: string;
project: ProjectDTO;
season: SeasonDTO;
contents: ContentDTO[];
constructor(seasonRent: SeasonRent) {
this.id = seasonRent.id;
const expiresAt = new Date(seasonRent.createdAt);
expiresAt.setDate(expiresAt.getDate() + 2);
this.status =
seasonRent.status == 'paid' && new Date() < expiresAt
? 'active'
: 'expired';
this.usdAmount = seasonRent.usdAmount;
this.project = seasonRent?.season?.project
? new ProjectDTO(seasonRent.season.project)
: undefined;
this.title =
seasonRent.season?.title || seasonRent.season?.project?.title || '';
this.createdAt = seasonRent.createdAt;
this.expiresAt = expiresAt;
this.contents =
seasonRent.season?.contents?.map((content) => new ContentDTO(content)) ||
[];
this.season = seasonRent?.season
? new SeasonDTO(seasonRent.season)
: undefined;
}
}

View File

@@ -0,0 +1,29 @@
import { ContentDTO } from 'src/contents/dto/response/content.dto';
import { Season } from 'src/season/entities/season.entity';
export class SeasonDTO {
id: string;
projectId: string;
seasonNumber: number;
rentalPrice: number;
title?: string;
description?: string;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
contents?: ContentDTO[];
constructor(season: Season) {
this.id = season.id;
this.projectId = season.projectId;
this.seasonNumber = season.seasonNumber;
this.rentalPrice = season.rentalPrice;
this.title = season.title;
this.description = season.description;
this.isActive = season.isActive;
this.createdAt = season.createdAt;
this.updatedAt = season.updatedAt;
this.contents =
season?.contents?.map((content) => new ContentDTO(content)) || [];
}
}