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,103 @@
import { Content } from 'src/contents/entities/content.entity';
import { DiscountRedemption } from 'src/discount-redemption/entities/discount-redemption.entity';
import {
Entity,
Column,
ManyToOne,
OneToMany,
CreateDateColumn,
UpdateDateColumn,
JoinColumn,
DeleteDateColumn,
PrimaryColumn,
} from 'typeorm';
import {
DiscountType,
DiscountTypes,
} from '../constants/discount-type.constant';
import { User } from 'src/users/entities/user.entity';
import { Season } from 'src/season/entities/season.entity';
@Entity('discounts')
export class Discount {
@PrimaryColumn()
id: string;
@ManyToOne(() => Content, (content) => content.discounts, {
nullable: true,
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'content_id' })
content: Content | null;
@Column({ type: 'varchar', nullable: true })
contentId: string | null;
@ManyToOne(() => Season, (season) => season.discounts, {
nullable: true,
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'season_id' })
season: Season | null;
@Column({ type: 'varchar', nullable: true })
seasonId: string | null;
@Column({ type: 'varchar', length: 50, nullable: false })
couponCode: string;
@Column({
type: 'decimal',
precision: 5,
scale: 2,
nullable: false,
transformer: {
to: (value) => value,
from: (value) => Number.parseFloat(value),
},
})
value: number;
@Column({
type: 'varchar',
length: 20,
default: DiscountTypes.PERCENTAGE,
})
type: DiscountType;
// Start date (null = no start date)
@Column({ type: 'timestamp', nullable: true })
startDate: Date | null;
// End date (null = no expiration date)
@Column({ type: 'timestamp', nullable: true })
expirationDate: Date | null;
// Total usage limit (null = unlimited)
@Column({ type: 'int', nullable: true })
maxUses: number | null;
@Column({ type: 'varchar', length: 255, nullable: true })
email: string | null;
@OneToMany(() => DiscountRedemption, (redemption) => redemption.discount)
redemptions: DiscountRedemption[];
@ManyToOne(() => User, { nullable: false })
@JoinColumn({ name: 'created_by_id' })
createdBy: User;
@Column({ type: 'varchar' })
createdById: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
// Soft delete
@DeleteDateColumn()
deletedAt: Date | null;
}