kjh2064 9ae701ff93
TaxBaik CI/CD / build-and-deploy (push) Failing after 3m5s
fix: Harden CI against Nginx misconfiguration that caused prod 502/404
Today's incident: CI reported successful deploys while the real site
returned 502 (root) then 404 (/taxbaik/) to users. Root cause was three
compounding Nginx issues, none of which the previous CI checks could see
because they only ever curled 127.0.0.1:5001 directly, bypassing Nginx:

1. Two Nginx config files existed. sites-available/default (documented,
   but NOT symlinked into sites-enabled/) was being edited repeatedly with
   zero effect. The file actually loaded was
   sites-available/taxbaik-domains.conf (-> sites-enabled/), undocumented.
2. That real file hardcoded the Green-Blue app port (5003) directly in
   both `location /` and `location /taxbaik`, instead of the persistent
   TaxBaik.Proxy on 5001. When the active port flipped to 5004, Nginx kept
   pointing at the dead 5003 -> 502.
3. Fixing the port to 5001 with a trailing slash on proxy_pass triggered
   Nginx URI rewriting, sending a double slash ("//") to the backend,
   which 404'd. Confirmed via `curl http://backend//` -> 404.

Changes:
- deploy.yml: replace the old blind `grep sites-available/default` check
  (checked the wrong, unloaded file) with a hard-failing check that (a)
  resolves the actual file via sites-enabled/ symlinks, (b) fails the
  deploy if either location block hardcodes 5003/5004 instead of 5001,
  (c) fails if /taxbaik's proxy_pass carries a stray trailing slash.
- deploy.yml: add an external, post-deploy check that curls the real
  public domain (www.taxbaik.com root, /taxbaik/, /taxbaik/admin/login)
  through Cloudflare + Nginx, with retries — this is what would have
  caught the whole incident on the very first broken deploy instead of
  requiring live user reports.
- deploy_gb.sh: drop the stale comment implying Nginx needs updating
  per-deploy; it never should, since Nginx always points at the
  persistent 5001 proxy which reads taxbaik_port itself.
- CLAUDE.md: document the real config file, the 5001-only invariant, the
  proxy_pass trailing-slash gotcha, and the Host-header/SNI trick for
  testing domain-based server blocks locally; record the incident in the
  CI troubleshooting harness section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 18:51:19 +09:00

TaxBaik - 세무사 백원숙 전문성 표현 홈페이지

온라인 세무 상담 플랫폼 | 블로그 SEO 최적화 | 전국 고객 확보

CI deploy trigger verification note.


개요

TaxBaik는 세무사 백원숙의 전문성을 온라인으로 표현하기 위해 설계된 풀스택 웹 애플리케이션입니다.

핵심 포지셔닝

"사업자 세금 + 부동산 + 가족자산 = 맞춤형 세무 파트너"

전문가 자격

  • 세무사 (세무 대리인, 기획세무사)
  • 부동산중개사
  • 보험설계사

기술 스택

계층 기술
백엔드 ASP.NET Core 10, C#
공개 사이트 Razor Pages (SSR)
관리자 Blazor Server + MudBlazor
데이터베이스 PostgreSQL 18.4
ORM Dapper
리버스 프록시 Nginx
배포 Gitea Actions CI/CD, systemd 단일 서비스
아키텍처 DDD (Domain-Driven Design), Layered Architecture

프로젝트 구조

TaxBaik/
├── TaxBaik.Domain/           # 비즈니스 규칙, 엔티티, 인터페이스
├── TaxBaik.Infrastructure/   # DB 접근, Dapper 구현체, 마이그레이션
├── TaxBaik.Application/      # 서비스, DTO, 비즈니스 워크플로우
├── TaxBaik.Web/              # Razor Pages + 관리자 통합 앱 (port 5001)
├── db/migrations/            # 데이터베이스 마이그레이션 SQL
├── deploy/                   # systemd 서비스 파일, Nginx 설정
└── .gitea/workflows/         # CI/CD 파이프라인

주요 기능

공개 사이트 (TaxBaik.Web)

  • SEO 최적화 블로그 (5개 카테고리)

    • 사업자 세무
    • 부동산 세금
    • 종합소득세
    • 부가가치세
    • 가족자산·증여
  • 온라인 상담 폼

    • 이름, 연락처, 이메일
    • 상담 분야 선택
    • 문의 내용
  • 반응형 디자인

    • 모바일 우선 (375px+)
    • 데스크톱 최적화
    • 접근성 고려
  • 성능 최적화

    • gzip 압축
    • 이미지 lazy load
    • CSS/JS 최적화

관리자 백오피스 (TaxBaik.Web 내 Blazor Server)

  • 대시보드

    • 이번달 문의 수
    • 신규 문의 수
    • 포스트 통계
  • 블로그 관리

    • CRUD 기능
    • 카테고리 관리
    • SEO 메타데이터
    • 발행/임시저장
  • 문의 관리

    • 문의 목록
    • 상태 변경 (신규 → 연락함 → 완료)
    • 상세 보기
  • 사이트 설정

    • 연락처 정보
    • 소셜 미디어 링크

빠른 시작

개발 환경 설정

필수 요구사항:

  • .NET 10.0 SDK
  • PostgreSQL 18.4
  • Git

설정 단계:

# 1. 저장소 클론
git clone http://178.104.200.7/kjh2064/taxbaik.git
cd taxbaik

# 2. 데이터베이스 생성
createdb taxbaikdb
psql -d taxbaikdb -f db/migrations/V001__InitialSchema.sql
psql -d taxbaikdb -f db/migrations/V002__SeedData.sql
psql -d taxbaikdb -f db/migrations/V003__SeedAdminAndBlogPosts.sql
psql -d taxbaikdb -f db/migrations/V004__CreateSiteSettings.sql

# 3. 환경 변수 설정
export ConnectionStrings__Default="Host=localhost;Database=taxbaikdb;Username=postgres;Password=password"

# 4. 빌드 및 실행
dotnet build TaxBaik.sln
dotnet run --project TaxBaik.Web

# 5. 브라우저 열기
# 공개 사이트: http://localhost:5001/taxbaik
# 관리자: http://localhost:5001/taxbaik/admin/login

초기 로그인 정보

  • username: admin
  • password: <TAXBAIK_ADMIN_TEST_PASSWORD> or current rotated admin password

⚠️ 중요: 프로덕션 배포 시 비밀번호 변경 필수이며, 검증용 비밀번호는 Gitea Secrets로 관리


배포

배포 방식

배포는 Gitea Actions CI/CD만 사용합니다.

master 브랜치에 푸시하면 파이프라인이 다음 단계를 수행합니다.

  1. .NET 빌드 (Release)
  2. 단위 테스트 실행
  3. Playwright 브라우저 검증 실행
  4. TaxBaik.Web 게시
  5. 원격 서버 배포 디렉토리 업로드 및 taxbaik_active 심링크 교체
  6. systemd taxbaik 단일 서비스 재시작
  7. /taxbaik/, /taxbaik/admin/login, /taxbaik/blog/{slug}, /taxbaik/api/auth/login 검증

배포 완료 판정은 위 단계가 모두 성공하고, 배포본 기준 Playwright E2E가 통과했을 때만 한다.

필수 Gitea Secrets 설정:

  • DEPLOY_USER: kjh2064
  • DEPLOY_HOST: 178.104.200.7
  • DEPLOY_SSH_KEY_B64: base64로 인코딩한 SSH 개인키
  • TAXBAIK_ADMIN_TEST_PASSWORD: 배포 검증용 관리자 비밀번호
  • Admin__PasswordResetToken: 관리자 비밀번호 재설정 API용 서버 비밀값

배포는 Gitea Actions CI/CD로만 수행합니다. 수동 배포 경로는 CI 하네스로 차단되어 있으며, 실패 시 DEPLOYMENT_GUIDE.md의 CI 점검 절차를 따릅니다.


개발 지침

코드 컨벤션

모든 UI 문자열은 한국어로 작성합니다.

// ✅ Good
public async Task<bool> SaveAsync() { ... }
var message = "저장되었습니다.";

// ❌ Bad
public bool Save() { ... }
var message = "Saved";

SQL 쿼리 (Dapper)

// ✅ 파라미터화된 쿼리 (안전)
await conn.QueryAsync<BlogPost>(
    "SELECT * FROM blog_posts WHERE id = @Id",
    new { Id = id });

// ❌ 문자열 연결 금지 (SQL injection)
var sql = "SELECT * FROM blog_posts WHERE id = " + id;

Repository 패턴

public interface IBlogPostRepository
{
    Task<BlogPost?> GetByIdAsync(int id);
    Task<IEnumerable<BlogPost>> GetPublishedAsync();
    // ...
}

public class BlogPostRepository : IBlogPostRepository
{
    private readonly IDbConnectionFactory _connectionFactory;
    
    public async Task<BlogPost?> GetByIdAsync(int id)
    {
        using var conn = _connectionFactory.CreateConnection();
        return await conn.QueryFirstOrDefaultAsync<BlogPost>(...);
    }
}

마이그레이션

-- db/migrations/V004__AddNewColumn.sql
ALTER TABLE blog_posts ADD COLUMN status VARCHAR(50) DEFAULT 'draft';

마이그레이션은 자동으로 시작시 실행됩니다.


문제 해결

마이그레이션 오류

# 마이그레이션 테이블 확인
SELECT * FROM schema_migrations;

# 실패한 마이그레이션 롤백 (수동 실행 필요)
psql -U taxbaik -d taxbaikdb -c "DELETE FROM schema_migrations WHERE version='004';"

포트 충돌

# 포트 확인
lsof -i :5001
lsof -i :5001

# 프로세스 종료
kill -9 <PID>

데이터베이스 연결

# 연결 테스트
psql -U taxbaik -d taxbaikdb -c "SELECT 1;"

# 환경 변수 확인
echo $ConnectionStrings__Default

문서


연락처


라이선스

내부 사용 전용


개발 로그

W0 - 프로젝트 기반 구축

  • Visual Studio 솔루션 + 5개 프로젝트 생성
  • Git 초기화 및 Gitea 저장소 연결
  • PostgreSQL 스키마 + 마이그레이션 파일
  • Nginx 리버스 프록시 설정

W1 - LLM 개발 지침

  • CLAUDE.md 작성 (9개 섹션, 500+ 라인)

W2 - Domain/Infrastructure/Application

  • 엔티티: BlogPost, Category, Inquiry, AdminUser
  • Dapper Repository 패턴 구현
  • 서비스 레이어 (BlogService, InquiryService)
  • DTO 및 예외 처리

W3 - 공개 홈페이지 (Razor Pages SSR)

  • 레이아웃 및 네비게이션
  • 메인 랜딩 페이지
  • 블로그 (목록 + 상세)
  • 문의 폼 (유효성 검증)
  • SEO 최적화 (메타 태그, sitemap.xml)
  • robots.txt

W4 - 관리자 백오피스 (Blazor Server + MudBlazor)

  • 인증 (Cookie 기반, 8시간 세션)
  • 대시보드 (KPI 카드)
  • 블로그 CRUD
  • 문의 관리
  • 사이트 설정

W5 - 스타일링 & 모바일 UX

  • CSS 디자인 시스템 (색상, 스페이싱, 전환)
  • 모바일 반응형 (375px 초소형 화면까지)
  • 성능 최적화 (gzip, lazy load, 폰트 preconnect)

W6 - 출시 준비

  • 자동 DB 마이그레이션 (MigrationRunner)
  • 초기 데이터 (관리자 + 블로그 5개 포스트)
  • E2E 테스트 절차
  • 배포 가이드
  • 서버 자동 설치 스크립트
  • Gitea Actions CI/CD

최종 상태: 진행 중

완료 판정은 실제 빌드, 테스트, 배포 검증, 브라우저 E2E 통과로만 한다.

S
Description
백원숙 세무사 홈페이지
Readme 40 MiB
Languages
HTML 89.5%
JavaScript 6.7%
C# 2.7%
CSS 0.7%
TypeScript 0.4%