diff --git a/.github/workflows/Deploy-Server.yaml b/.github/workflows/Deploy-Server.yaml index 043625e..48c2f28 100644 --- a/.github/workflows/Deploy-Server.yaml +++ b/.github/workflows/Deploy-Server.yaml @@ -17,8 +17,8 @@ jobs: run: | docker build \ -t seanyee1227/pushandpull-server:latest \ - -f PushAndPull/PushAndPull/Dockerfile \ - PushAndPull/PushAndPull + -f PushAndPull/deploy/prod.dockerfile \ + PushAndPull - name: Push Docker image run: docker push seanyee1227/pushandpull-server:latest diff --git a/PushAndPull/.claude/settings.local.json b/PushAndPull/.claude/settings.local.json index 09b37a3..f72cddc 100644 --- a/PushAndPull/.claude/settings.local.json +++ b/PushAndPull/.claude/settings.local.json @@ -27,7 +27,12 @@ "Skill(db-migrate)", "WebFetch(domain:github.com)", "WebFetch(domain:raw.githubusercontent.com)", - "Skill(pr)" + "Skill(pr)", + "Bash(dotnet tool update:*)", + "Bash(dotnet tool:*)", + "Bash(cmd.exe:*)", + "Bash(dotnet --list-sdks)", + "Bash(dotnet list:*)" ] } } diff --git a/PushAndPull/.gemini/commands/commit.toml b/PushAndPull/.gemini/commands/commit.toml new file mode 100644 index 0000000..7dcac02 --- /dev/null +++ b/PushAndPull/.gemini/commands/commit.toml @@ -0,0 +1,71 @@ +description = "Git 변경사항을 논리적 단위로 분리하여 커밋합니다." + +prompt = """ +Create Git commits following the project's commit conventions. + +## Current Changes + +### git status +!{git status} + +### git diff (unstaged) +!{git diff} + +### git diff (staged) +!{git diff --cached} + +--- + +## Commit Message Format + +{type}: {Korean description} + +**Types:** +| Type | When to use | +|--------|-------------| +| feat | New file(s) added (new service / controller / entity / test class / migration) | +| fix | Broken behavior fixed, or missing DI registration / config corrected | +| update | Existing file(s) modified — rename, restructure, method added to existing class | +| docs | Documentation changes only | +| chore | Tooling, CI/CD, dependency updates, config changes with no behavior change | + +**Boundary rules:** +- New .cs service/repository/controller file added → `feat` +- New method added to an existing .cs file → `update` +- DI registration line added alone (no new service file) → `fix` +- New service file + its DI registration together → `feat` (one logical unit) +- New migration file → `feat` +- Existing migration corrected → `fix` +- New test class → `feat` +- Test method added to existing test class → `update` +- Refactoring without behavior change → `update` + +**Description rules:** +- Written in **Korean** +- Short and imperative (단문) +- No trailing punctuation (`.`, `!`, etc.) +- Prefer verb style over noun style + +**Examples:** +- feat: 방 생성 API 추가 +- fix: 세션 DI 누락 수정 +- update: Room 엔터티 수정 +- chore: 의존성 버전 업데이트 + +**Do NOT:** +- Add Claude/Gemini as co-author +- Write descriptions in English +- Add a commit body — subject line only + +--- + +## Steps + +1. Analyze all changes from the git status and diff above. +2. Categorize changes into **logical units** — group files that belong to the same feature or fix. +3. For each logical unit: + a. Stage only the relevant files with `git add ` + b. Write a concise commit message following the format above + c. Execute `git commit -m "message"` +4. After all commits, verify with `git log --oneline -n {number of commits made}`. +""" diff --git a/PushAndPull/.gemini/commands/pr.toml b/PushAndPull/.gemini/commands/pr.toml new file mode 100644 index 0000000..ada4fd3 --- /dev/null +++ b/PushAndPull/.gemini/commands/pr.toml @@ -0,0 +1,157 @@ +description = "현재 브랜치 기반으로 GitHub PR을 생성합니다. 사용법: /pr 또는 /pr {base-branch}" + +prompt = """ +Generate and create a GitHub Pull Request based on the current branch. + +## Runtime Context + +### Current branch +!{git branch --show-current} + +### Recent tags +!{git tag --sort=-v:refname | head -10} + +### Existing release branches +!{git branch -a | grep release} + +### User-provided argument (base branch override) +{{args}} + +--- + +## Step 0. Determine behavior + +- If `{{args}}` is **not empty**: set Base Branch = `{{args}}`, skip to **Case 3** immediately. +- If `{{args}}` is **empty**: check the current branch name and follow the rules below. + +--- + +## Case 1: Current branch is `develop` + +**Step 1.** Determine the latest version from tags and release branches. + +**Step 2.** Analyze changes from `main`: +- `git log main..HEAD --oneline` +- `git diff main...HEAD --stat` + +**Step 3.** Recommend a version bump (Major / Minor / Patch) and explain why briefly. + +**Step 4.** Ask the user: "현재 버전: {current_version} / 추천: {recommended_version} ({reason}) — 사용할 버전 번호를 입력해주세요. (예: 1.0.1)" + +**Step 5.** After the user replies with a version number: +- Run: `git checkout -b release/{version}` +- Analyze changes from `main` for the PR body + +**Step 6.** Write the PR body following the **PR Body Template** below. Save to `PR_BODY.md`. + +**Step 7.** Run: +``` +gh pr create --title "release/{version}" --body-file PR_BODY.md --base main +``` + +**Step 8.** Run: `rm PR_BODY.md` + +--- + +## Case 2: Current branch matches `release/x.x.x` + +**Step 1.** Extract version from branch name (e.g., `release/1.2.0` → `1.2.0`). + +**Step 2.** Analyze changes from `main`: +- `git log main..HEAD --oneline` +- `git diff main...HEAD --stat` + +**Step 3.** Write PR body following the **PR Body Template** below. Save to `PR_BODY.md`. + +**Step 4.** Run: +``` +gh pr create --title "release/{version}" --body-file PR_BODY.md --base main +``` + +**Step 5.** Run: `rm PR_BODY.md` + +--- + +## Case 3: Any other branch (or base branch was specified via argument) + +**Step 1.** Set Base Branch: +- If `{{args}}` is not empty → Base Branch = `{{args}}` +- Otherwise → Base Branch = `develop` + +**Step 2.** Analyze changes from Base Branch: +- `git log {Base Branch}..HEAD --oneline` +- `git diff {Base Branch}...HEAD --stat` +- `git diff {Base Branch}...HEAD` + +**Step 3.** Suggest **three PR title options** following the **PR Title Convention** below. + +**Step 4.** Write the PR body following the **PR Body Template** below. Save to `PR_BODY.md`. + +**Step 5.** Show the PR body preview and the three title options to the user. Ask: +"PR 제목을 선택해주세요. (1 / 2 / 3 / 직접 입력)" + +**Step 6.** After the user selects or types a title: +``` +gh pr create --title "{chosen title}" --body-file PR_BODY.md --base {Base Branch} +``` + +**Step 7.** Run: `rm PR_BODY.md` + +--- + +## PR Title Convention + +Format: `{type}: {Korean description}` + +**Types:** +- `feature` — new feature added +- `fix` — bug fix or missing configuration/DI registration +- `update` — modification to existing code +- `refactor` — refactoring without behavior change +- `docs` — documentation changes +- `chore` — tooling, CI/CD, dependency updates + +**Rules:** +- Description in Korean +- Short and imperative (단문) +- No trailing punctuation + +**Examples:** +- `feature: 방 생성 API 추가` +- `fix: 세션 DI 누락 수정` +- `refactor: Room 서비스 리팩토링` + +--- + +## PR Body Template + +Use this exact structure (keep the emoji headers): + +``` +## 📚작업 내용 + +- {change item 1} +- {change item 2} + +## ◀️참고 사항 + +{additional notes, context, before/after comparisons if relevant. Write "." if nothing to add.} + +## ✅체크리스트 + +> `[ ]`안에 x를 작성하면 체크박스를 체크할 수 있습니다. + +- [x] 현재 의도하고자 하는 기능이 정상적으로 작동하나요? +- [x] 변경한 기능이 다른 기능을 깨뜨리지 않나요? + + +> *추후 필요한 체크리스트는 업데이트 될 예정입니다.* +``` + +**Writing rules:** +- Fill `작업 내용` bullets by grouping commits meaningfully — not one bullet per commit +- `참고 사항`: configuration notes, before/after comparisons, etc. Write `"."` if nothing to add +- Keep total body under 2500 characters +- All text content in Korean (keep section header emojis as-is) +- No emojis in body text — section headers only +""" diff --git a/PushAndPull/PushAndPull/Dockerfile b/PushAndPull/PushAndPull/Dockerfile deleted file mode 100644 index 7b97a9c..0000000 --- a/PushAndPull/PushAndPull/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base -WORKDIR /app -EXPOSE 8080 - -FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build -ARG BUILD_CONFIGURATION=Release -WORKDIR /src - -COPY ["PushAndPull.csproj", "./"] -RUN dotnet restore "PushAndPull.csproj" - -COPY . . -RUN dotnet publish "PushAndPull.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false - -FROM base AS final -WORKDIR /app -COPY --from=build /app/publish . -ENV ASPNETCORE_URLS=http://+:8080 -ENTRYPOINT ["dotnet", "PushAndPull.dll"] diff --git a/PushAndPull/PushAndPull/Domain/Auth/Entity/Config/UserConfig.cs b/PushAndPull/PushAndPull/Domain/Auth/Entity/Config/UserConfig.cs index c6f7adf..24b9250 100644 --- a/PushAndPull/PushAndPull/Domain/Auth/Entity/Config/UserConfig.cs +++ b/PushAndPull/PushAndPull/Domain/Auth/Entity/Config/UserConfig.cs @@ -7,7 +7,7 @@ public class UserConfig : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { - builder.ToTable("user", "game_user"); + builder.ToTable("user", "auth"); builder.HasKey(x => x.SteamId); diff --git a/PushAndPull/PushAndPull/Global/Config/DatabaseConfig.cs b/PushAndPull/PushAndPull/Global/Config/DatabaseConfig.cs index 381e885..2c4cd10 100644 --- a/PushAndPull/PushAndPull/Global/Config/DatabaseConfig.cs +++ b/PushAndPull/PushAndPull/Global/Config/DatabaseConfig.cs @@ -16,7 +16,7 @@ public static IServiceCollection AddDatabase( services.AddDbContext(options => { options.UseNpgsql(connectionString, npgsql => - npgsql.MigrationsHistoryTable("__EFMigrationsHistory", "room")); + npgsql.MigrationsHistoryTable("__EFMigrationsHistory", "public")); }); return services; diff --git a/PushAndPull/PushAndPull/Migrations/20260312060119_AddRoomStatusCreatedAtIndex.cs b/PushAndPull/PushAndPull/Migrations/20260312060119_AddRoomStatusCreatedAtIndex.cs deleted file mode 100644 index 4f29912..0000000 --- a/PushAndPull/PushAndPull/Migrations/20260312060119_AddRoomStatusCreatedAtIndex.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace PushAndPull.Migrations -{ - /// - public partial class AddRoomStatusCreatedAtIndex : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "idx_room_status_created_at", - schema: "room", - table: "room", - columns: new[] { "status", "created_at" }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "idx_room_status_created_at", - schema: "room", - table: "room"); - } - } -} diff --git a/PushAndPull/PushAndPull/Migrations/20260312060119_AddRoomStatusCreatedAtIndex.Designer.cs b/PushAndPull/PushAndPull/Migrations/20260402065544_InitialCreateTables.Designer.cs similarity index 92% rename from PushAndPull/PushAndPull/Migrations/20260312060119_AddRoomStatusCreatedAtIndex.Designer.cs rename to PushAndPull/PushAndPull/Migrations/20260402065544_InitialCreateTables.Designer.cs index ecc8385..518affe 100644 --- a/PushAndPull/PushAndPull/Migrations/20260312060119_AddRoomStatusCreatedAtIndex.Designer.cs +++ b/PushAndPull/PushAndPull/Migrations/20260402065544_InitialCreateTables.Designer.cs @@ -12,8 +12,8 @@ namespace PushAndPull.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20260312060119_AddRoomStatusCreatedAtIndex")] - partial class AddRoomStatusCreatedAtIndex + [Migration("20260402065544_InitialCreateTables")] + partial class InitialCreateTables { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -25,7 +25,33 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("Server.Domain.Entity.Room", b => + modelBuilder.Entity("PushAndPull.Domain.Auth.Entity.User", b => + { + b.Property("SteamId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("steam_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamptz") + .HasColumnName("created_at"); + + b.Property("LastLoginAt") + .HasColumnType("timestamptz") + .HasColumnName("last_login_at"); + + b.Property("Nickname") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("nickname"); + + b.HasKey("SteamId"); + + b.ToTable("user", "auth"); + }); + + modelBuilder.Entity("PushAndPull.Domain.Room.Entity.Room", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -109,35 +135,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("room", "room"); }); - modelBuilder.Entity("Server.Domain.Entity.User", b => - { - b.Property("SteamId") - .ValueGeneratedOnAdd() - .HasColumnType("numeric(20,0)") - .HasColumnName("steam_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamptz") - .HasColumnName("created_at"); - - b.Property("LastLoginAt") - .HasColumnType("timestamptz") - .HasColumnName("last_login_at"); - - b.Property("Nickname") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)") - .HasColumnName("nickname"); - - b.HasKey("SteamId"); - - b.ToTable("user", "user"); - }); - - modelBuilder.Entity("Server.Domain.Entity.Room", b => + modelBuilder.Entity("PushAndPull.Domain.Room.Entity.Room", b => { - b.HasOne("Server.Domain.Entity.User", "Host") + b.HasOne("PushAndPull.Domain.Auth.Entity.User", "Host") .WithMany() .HasForeignKey("HostSteamId") .OnDelete(DeleteBehavior.Restrict) diff --git a/PushAndPull/PushAndPull/Migrations/20260402065544_InitialCreateTables.cs b/PushAndPull/PushAndPull/Migrations/20260402065544_InitialCreateTables.cs new file mode 100644 index 0000000..25b2546 --- /dev/null +++ b/PushAndPull/PushAndPull/Migrations/20260402065544_InitialCreateTables.cs @@ -0,0 +1,117 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace PushAndPull.Migrations +{ + /// + public partial class InitialCreateTables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "room"); + + migrationBuilder.EnsureSchema( + name: "auth"); + + migrationBuilder.CreateTable( + name: "user", + schema: "auth", + columns: table => new + { + steam_id = table.Column(type: "numeric(20,0)", nullable: false), + nickname = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + created_at = table.Column(type: "timestamptz", nullable: false), + last_login_at = table.Column(type: "timestamptz", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_user", x => x.steam_id); + }); + + migrationBuilder.CreateTable( + name: "room", + schema: "room", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + room_name = table.Column(type: "text", nullable: false), + room_code = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + steam_lobby_id = table.Column(type: "numeric(20,0)", nullable: false), + host_steam_id = table.Column(type: "numeric(20,0)", nullable: false), + current_players = table.Column(type: "integer", nullable: false), + max_players = table.Column(type: "integer", nullable: false), + is_private = table.Column(type: "boolean", nullable: false, defaultValue: false), + password_hash = table.Column(type: "text", nullable: true), + status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + created_at = table.Column(type: "timestamptz", nullable: false), + expires_at = table.Column(type: "timestamptz", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_room", x => x.id); + table.ForeignKey( + name: "FK_room_user_host_steam_id", + column: x => x.host_steam_id, + principalSchema: "auth", + principalTable: "user", + principalColumn: "steam_id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "idx_room_expires_at", + schema: "room", + table: "room", + column: "expires_at"); + + migrationBuilder.CreateIndex( + name: "idx_room_host_steam_id", + schema: "room", + table: "room", + column: "host_steam_id"); + + migrationBuilder.CreateIndex( + name: "idx_room_room_code", + schema: "room", + table: "room", + column: "room_code", + unique: true); + + migrationBuilder.CreateIndex( + name: "idx_room_status", + schema: "room", + table: "room", + column: "status"); + + migrationBuilder.CreateIndex( + name: "idx_room_status_created_at", + schema: "room", + table: "room", + columns: new[] { "status", "created_at" }); + + migrationBuilder.CreateIndex( + name: "idx_room_status_private", + schema: "room", + table: "room", + columns: new[] { "status", "is_private" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "room", + schema: "room"); + + migrationBuilder.DropTable( + name: "user", + schema: "auth"); + } + } +} diff --git a/PushAndPull/PushAndPull/Migrations/AppDbContextModelSnapshot.cs b/PushAndPull/PushAndPull/Migrations/AppDbContextModelSnapshot.cs index d0da5e0..8511547 100644 --- a/PushAndPull/PushAndPull/Migrations/AppDbContextModelSnapshot.cs +++ b/PushAndPull/PushAndPull/Migrations/AppDbContextModelSnapshot.cs @@ -22,7 +22,33 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("Server.Domain.Entity.Room", b => + modelBuilder.Entity("PushAndPull.Domain.Auth.Entity.User", b => + { + b.Property("SteamId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("steam_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamptz") + .HasColumnName("created_at"); + + b.Property("LastLoginAt") + .HasColumnType("timestamptz") + .HasColumnName("last_login_at"); + + b.Property("Nickname") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("nickname"); + + b.HasKey("SteamId"); + + b.ToTable("user", "auth"); + }); + + modelBuilder.Entity("PushAndPull.Domain.Room.Entity.Room", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -106,35 +132,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("room", "room"); }); - modelBuilder.Entity("Server.Domain.Entity.User", b => - { - b.Property("SteamId") - .ValueGeneratedOnAdd() - .HasColumnType("numeric(20,0)") - .HasColumnName("steam_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamptz") - .HasColumnName("created_at"); - - b.Property("LastLoginAt") - .HasColumnType("timestamptz") - .HasColumnName("last_login_at"); - - b.Property("Nickname") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)") - .HasColumnName("nickname"); - - b.HasKey("SteamId"); - - b.ToTable("user", "user"); - }); - - modelBuilder.Entity("Server.Domain.Entity.Room", b => + modelBuilder.Entity("PushAndPull.Domain.Room.Entity.Room", b => { - b.HasOne("Server.Domain.Entity.User", "Host") + b.HasOne("PushAndPull.Domain.Auth.Entity.User", "Host") .WithMany() .HasForeignKey("HostSteamId") .OnDelete(DeleteBehavior.Restrict) diff --git a/PushAndPull/PushAndPull/PushAndPull.csproj b/PushAndPull/PushAndPull/PushAndPull.csproj index b574c0d..d68a219 100644 --- a/PushAndPull/PushAndPull/PushAndPull.csproj +++ b/PushAndPull/PushAndPull/PushAndPull.csproj @@ -32,4 +32,8 @@ + + + + diff --git a/PushAndPull/PushAndPull/appsettings.Development.json b/PushAndPull/PushAndPull/appsettings.Development.json index 87d5b2c..b2d1017 100644 --- a/PushAndPull/PushAndPull/appsettings.Development.json +++ b/PushAndPull/PushAndPull/appsettings.Development.json @@ -10,9 +10,9 @@ "AppId": 480 }, "Redis": { - "ConnectionString": "127.0.0.1:6379,abortConnect=false" + "ConnectionString": "127.0.0.1:6381,abortConnect=false" }, "ConnectionStrings": { - "Default": "" + "Default": "Host=localhost;Port=5434;Database=pushandpull_dev;Username=pushandpull;Password=pushandpull" } } \ No newline at end of file diff --git a/PushAndPull/deploy/compose.dev.yaml b/PushAndPull/deploy/compose.dev.yaml new file mode 100644 index 0000000..301d857 --- /dev/null +++ b/PushAndPull/deploy/compose.dev.yaml @@ -0,0 +1,40 @@ +name: pushandpull-dev + +services: + pushandpull-db: + image: postgres:17 + environment: + POSTGRES_DB: pushandpull_dev + POSTGRES_USER: pushandpull + POSTGRES_PASSWORD: pushandpull + ports: + - "5434:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + + pushandpull-redis: + image: redis:7-alpine + ports: + - "6381:6379" + + pushandpull-server: + image: pushpull.server + build: + context: .. + dockerfile: deploy/dev.dockerfile + ports: + - "8081:8080" + environment: + - ASPNETCORE_ENVIRONMENT=Development + - DOTNET_USE_POLLING_FILE_WATCHER=1 + - ConnectionStrings__Default=Host=pushandpull-db;Port=5432;Database=pushandpull_dev;Username=pushandpull;Password=pushandpull + - Redis__ConnectionString=pushandpull-redis:6379,abortConnect=false + - Steam__WebApiKey=Steam-ApiKey + volumes: + - ..:/src + depends_on: + - pushandpull-db + - pushandpull-redis + +volumes: + postgres_data: diff --git a/PushAndPull/deploy/compose.prod.yaml b/PushAndPull/deploy/compose.prod.yaml new file mode 100644 index 0000000..a8de0fd --- /dev/null +++ b/PushAndPull/deploy/compose.prod.yaml @@ -0,0 +1,40 @@ +name: pushandpull-prod + +services: + pushpull-db: + image: postgres:17 + container_name: pushpull-db + environment: + POSTGRES_DB: pushpull + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - postgres_data:/var/lib/postgresql/data + restart: unless-stopped + + pushpull-redis: + image: redis:7-alpine + container_name: pushpull-redis + volumes: + - redis_data:/data + restart: unless-stopped + + pushpull-server: + image: seanyee1227/pushandpull-server:latest + container_name: pushpull-server + ports: + - "21754:80" + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://+:80 + - ConnectionStrings__Default=${DB_CONNECTION_STRING} + - Redis__ConnectionString=${REDIS_CONNECTION_STRING} + - Steam__WebApiKey=${STEAM_WEB_API_KEY} + depends_on: + - pushpull-db + - pushpull-redis + restart: unless-stopped + +volumes: + postgres_data: + redis_data: diff --git a/PushAndPull/deploy/dev.dockerfile b/PushAndPull/deploy/dev.dockerfile new file mode 100644 index 0000000..cd12e10 --- /dev/null +++ b/PushAndPull/deploy/dev.dockerfile @@ -0,0 +1,6 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 +WORKDIR /src +COPY . . +WORKDIR /src/PushAndPull +RUN dotnet restore +ENTRYPOINT ["dotnet", "watch", "run", "--urls", "http://+:8080"] diff --git a/PushAndPull/deploy/prod.dockerfile b/PushAndPull/deploy/prod.dockerfile new file mode 100644 index 0000000..914961e --- /dev/null +++ b/PushAndPull/deploy/prod.dockerfile @@ -0,0 +1,12 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src +COPY . . +RUN dotnet publish PushAndPull/PushAndPull.csproj \ + --configuration Release \ + --output /app/publish \ + /p:UseAppHost=false + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 +WORKDIR /app +COPY --from=build /app/publish . +ENTRYPOINT ["dotnet", "PushAndPull.dll"] diff --git a/global.json b/global.json new file mode 100644 index 0000000..f99d233 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "9.0.201", + "rollForward": "latestPatch" + } +}