Skip to content

인프라 운영 (Railway + 백엔드 설정)

환경변수 파일 (APP_ENV 기반)

config.go init 이 APP_ENV 값으로 .env.<APP_ENV> 자동 로드.

  • APP_ENV 미설정 시 → .env. (빈) 로드 시도 → 실패 → 환경변수 없이 기동 → 카카오/JWT 빠져 로그인 깨짐. 반드시 APP_ENV=local 명시
  • 로컬 dev: backend/.env.local (gitignore)
  • prod: Railway 가 OS 환경변수 직접 주입 — 파일 불필요
  • .env.example 삭제됨 (2026-04-25). .env.prod 는 Railway 참고용 로컬 파일

필수 키: DATABASE_URL, DART_API_KEY, KAKAO_CLIENT_ID/SECRET, JWT_SECRET, ADMIN_KEY.

필수 prod 환경변수

변수이유
TRUSTED_CLIENT_IP_HEADERCF-Connecting-IP레이트 리밋. 미설정 시 모든 사용자가 Railway 엣지 IP 묶여 정상 트래픽도 429. CF DNS 프록시(🟠) 켜져 있어야 헤더 채워짐
STOCK_SYNC_SCHEDULER_ENABLEDtrue (prod) / false (dev)종목 마스터 일일 동기화
DISCLOSURE_MONITOR_AUTO_STARTtrue (prod) / false (dev)공시 모니터
ANALYSIS_SCHEDULER_AUTO_STARTtrue (prod) / false (dev)AI 분석 스케줄러

미들웨어 체인 (cmd/server/main.go)

바깥 → 안쪽: RateLimit/auth 전용 RateLimitCORSJWT 파싱인증 체크HTTPCachemux

  • 전역: 2 RPS / 10 burst (분당 120)
  • /auth/*: 0.5 RPS / 5 burst (분당 30, 브루트포스 방어)
  • HTTP 캐시 대상: /disclosures/{rcept} 5 분, /disclosures/recent 30 초, /disclosures?corpCode= 1 분, /stocks/search 1 분, /companies/{corp} 10 분
  • Singleflight 내장 (100 동시 → upstream 1 회), non-2xx 는 5 초 negative cache

자세한 보안: backend/docs/security.md

DB 마이그레이션 (goose v3)

  • 라이브러리: pressly/goose v3 (2026-04-22 golang-migrate 에서 전환)
  • 위치: backend/cmd/server/migrations/ (embed.FS 로 바이너리 내장)
  • 포맷: 단일 파일에 -- +goose Up 마커. down 섹션 없음 (pre-launch)
  • 서버 시작 시 goose.UpContext 자동 실행
  • schema-qualified 필수: goose.SetTableName("dartbrief.goose_db_version") 명시

Admin API

AI 분석 스케줄러

bash
curl -X POST -H "X-Admin-Key: $ADMIN_KEY" https://api.dartbrief.com/api/v1/admin/scheduler/{resume|pause}
curl -H "X-Admin-Key: $ADMIN_KEY" https://api.dartbrief.com/api/v1/admin/scheduler/status

공시 백필 (DART list.json)

bash
curl -X POST -H "X-Admin-Key: $ADMIN_KEY" \
  "https://api.dartbrief.com/api/v1/admin/backfill?fromDate=20260301&toDate=20260331&delayMs=200"
curl -H "X-Admin-Key: $ADMIN_KEY" https://api.dartbrief.com/api/v1/admin/backfill/status

종목 마스터 동기화 (corpCode.xml + company.json, KOSPI/KOSDAQ)

bash
# bootstrap: 전수 (~4분, 초기 1회), incremental: 신규만 (~수초)
curl -X POST -H "X-Admin-Key: $ADMIN_KEY" \
  "https://api.dartbrief.com/api/v1/admin/stocks/sync?mode=bootstrap"
curl -H "X-Admin-Key: $ADMIN_KEY" https://api.dartbrief.com/api/v1/admin/stocks/sync/status

매일 05:00 KST 에 incremental 자동 실행 (prod 만).


Railway GraphQL API

엔드포인트: https://backboard.railway.com/graphql/v2 헤더: Project-Access-Token: <token> (⚠️ Bearer 아님!) 토큰 위치: ~/.config/cloud-tokens/railway.env

Project-Access-Token 으로 가능

  • 변수 조회 (variables query)
  • 변수 upsert (variableUpsert mutation) — 쓰기 권한 (2026-04-23 확인)
  • 배포 목록 (deployments query)
  • 배포 로그 (deploymentLogs query)

변수 upsert 예시

bash
source ~/.config/cloud-tokens/railway.env
cat > /tmp/mut.json <<EOF
{
  "query": "mutation(\$input: VariableUpsertInput!) { variableUpsert(input: \$input) }",
  "variables": {
    "input": {
      "projectId": "$RAILWAY_PROJECT_ID",
      "environmentId": "$RAILWAY_DARTBRIEF_ENVIRONMENT_ID",
      "serviceId": "$RAILWAY_DARTBRIEF_SERVICE_ID",
      "name": "AI_CONCURRENCY",
      "value": "10"
    }
  }
}
EOF
curl -sS -X POST "https://backboard.railway.com/graphql/v2" \
  -H "Project-Access-Token: $RAILWAY_PROJECT_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @/tmp/mut.json

변수 변경 후 Railway 가 자동 재배포 트리거.

배포 상태 조회

bash
curl -sS -X POST "https://backboard.railway.com/graphql/v2" \
  -H "Project-Access-Token: $RAILWAY_PROJECT_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"query\":\"query { deployments(first: 3, input: { projectId: \\\"$RAILWAY_PROJECT_ID\\\", environmentId: \\\"$RAILWAY_DARTBRIEF_ENVIRONMENT_ID\\\", serviceId: \\\"$RAILWAY_DARTBRIEF_SERVICE_ID\\\" }) { edges { node { id status createdAt } } } }\"}"

상태: SUCCESS / BUILDING / DEPLOYING / CRASHED / REMOVED.

로그 조회

graphql
query { deploymentLogs(deploymentId: "...", limit: 2000) {
  timestamp severity message attributes { key value }
}}

Go slog 구조화 필드 (error, rceptNo 등) 는 attributes 배열로. message 는 평문만.

함정: Python urllib + os.environ

환경변수 sourcing 순서 잘못하면 빈 헤더로 호출 → HTTP 403. curl + HEREDOC 가 더 신뢰.


Bash 도구에서 Go 명령 실행

PATH 초기화되지 않아 go not found 에러. Full path 사용:

bash
/opt/homebrew/bin/go build ./...
/opt/homebrew/bin/gofmt -l .
/opt/homebrew/bin/go vet ./...

작업 디렉토리도 반드시 backend/ (go.mod 위치).