diff --git a/.gitea/workflows/deploy-prod.yml.backup b/.gitea/workflows/deploy-prod.yml.backup deleted file mode 100644 index ab24e676..00000000 --- a/.gitea/workflows/deploy-prod.yml.backup +++ /dev/null @@ -1,644 +0,0 @@ -name: Deploy to Production - -on: - push: - branches: [ main ] - workflow_dispatch: - -# Phase 4: Manual-only deployment (improved & hardened) -# Automatic deployment moved to merge-to-main.yml (Stage 5) -# Use this workflow for manual deployments when needed -# -# Error handling: Comprehensive logging + automatic rollback -# Security: SSH key validation, deployment verification -# Observability: Detailed stage reporting + Telegram notifications - -concurrency: - group: deploy-prod-main - cancel-in-progress: false - -env: - DEPLOY_HOST: quant.taxbaik.com - DEPLOY_USER: kjh2064 - SERVICE_NAME: quantengine - DOTNET_VERSION: '10.0.x' - QUANTENGINE_DB_NAME: quantenginedb - QUANTENGINE_DB_USER: quantengine_app - TELEGRAM_BOT_TOKEN_DEFAULT: "8734507814:AAFyacLMai8GB4K-hQ_Nd3t3D01A-H1ZdV0" - TELEGRAM_CHAT_ID_DEFAULT: "-5460205872" - DEPLOY_TIMEOUT: "600" - HEALTH_CHECK_RETRIES: "5" - HEALTH_CHECK_DELAY: "3" - -jobs: - build-and-deploy: - name: Build & Deploy to Production - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: Setup .NET - uses: actions/setup-dotnet@v3 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - - name: Install Python Dependencies - run: pip install pyyaml openpyxl requests - - - name: "[GATE] Run Core Validations" - run: | - echo " Running critical CI validations..." - python3 tools/validate_no_direct_api_trading_v1.py || exit 1 - python3 tools/validate_specs.py || exit 1 - echo " All critical validations passed" - - - name: Ensure Temp Directory and Mock Packet - run: | - mkdir -p Temp - if [ ! -f Temp/final_decision_packet_active.json ]; then - echo '{"active_decision": "PASS", "details": "CI dummy packet"}' > Temp/final_decision_packet_active.json - fi - - - name: Restore Dependencies - run: dotnet restore src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj - - - name: Build Release - run: | - dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \ - -c Release \ - --no-restore - - - name: Run Unit Tests - run: | - dotnet test src/dotnet/QuantEngine.Core.Tests/QuantEngine.Core.Tests.csproj \ - -c Release \ - --no-build - - - name: Publish Release Package - run: | - dotnet publish src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \ - -c Release \ - --no-build \ - -o ./publish - - - name: Generate Build Info - run: | - COMMIT_HASH=$(git rev-parse --short HEAD) - BUILD_TIME=$(date -d "+9 hours" +'%Y-%m-%d %H:%M:%S KST') - mkdir -p ./publish/wwwroot - printf '{\n "version": "1.0.%s-%s",\n "built": "%s"\n}\n' "${{ github.run_number }}" "$COMMIT_HASH" "$BUILD_TIME" > ./publish/wwwroot/version.json - echo " Generated version info: 1.0.${{ github.run_number }}-$COMMIT_HASH @ $BUILD_TIME" - - - name: Prepare & Validate QuantEngine DB Env - run: | - echo " Preparing database environment..." - - DB_PASSWORD="${{ secrets.QUANTENGINE_DB_PASSWORD }}" - if [ -z "$DB_PASSWORD" ]; then - echo " QUANTENGINE_DB_PASSWORD secret not configured in Gitea" - echo " Please set secret in Repository Settings > Secrets" - exit 1 - fi - - if [ -z "${{ env.QUANTENGINE_DB_NAME }}" ] || [ -z "${{ env.QUANTENGINE_DB_USER }}" ]; then - echo " DB configuration environment variables not set" - exit 1 - fi - - # - mkdir -p ./deploy - printf 'ConnectionStrings__DefaultConnection=Host=127.0.0.1;Database=%s;Username=%s;Password=%s;Search Path=quantengine;\n' \ - "${{ env.QUANTENGINE_DB_NAME }}" \ - "${{ env.QUANTENGINE_DB_USER }}" \ - "$DB_PASSWORD" > ./deploy/quantengine.env - chmod 600 ./deploy/quantengine.env - - # appsettings.Production.json - mkdir -p ./publish - cat < ./publish/appsettings.Production.json - { - "ConnectionStrings": { - "DefaultConnection": "Host=127.0.0.1;Database=${{ env.QUANTENGINE_DB_NAME }};Username=${{ env.QUANTENGINE_DB_USER }};Password=${DB_PASSWORD};Search Path=quantengine;" - } - } -EOF - chmod 600 ./publish/appsettings.Production.json - - if [ ! -f ./deploy/quantengine.env ] || [ ! -f ./publish/appsettings.Production.json ]; then - echo " Failed to create database config files" - exit 1 - fi - - echo " Database configuration prepared" - - - name: Copy Deployment Scripts - run: | - echo " Copying deployment scripts..." - cp deploy_gb.sh ./publish/deploy_gb.sh - mkdir -p ./publish/scripts - cp scripts/validate_migrations.sh ./publish/scripts/validate_migrations.sh - chmod +x ./publish/deploy_gb.sh ./publish/scripts/validate_migrations.sh - echo " Deployment scripts copied" - - - name: Package Artifact - run: | - echo " Creating deployment package..." - - if ! tar -czf quantengine.tar.gz -C ./publish .; then - echo " Failed to create package" - exit 1 - fi - - PACKAGE_SIZE=$(du -sh quantengine.tar.gz | cut -f1) - PACKAGE_BYTES=$(stat -c%s quantengine.tar.gz 2>/dev/null || echo "0") - - if [ -z "$PACKAGE_BYTES" ] || [ "$PACKAGE_BYTES" -lt 1000000 ]; then - echo " Warning: Package seems too small ($PACKAGE_SIZE)" - fi - - if [ ! -f quantengine.tar.gz ]; then - echo " Package file not created" - exit 1 - fi - - echo " Package created: $PACKAGE_SIZE" - tar -tzf quantengine.tar.gz | head -n 5 || true - - - name: Pre-Deployment Migration Validation - run: | - echo "=== Pre-Deployment Database Check ===" - - # () - TEMP_DEPLOY="/tmp/quantengine_validate" - mkdir -p "$TEMP_DEPLOY" - tar -xzf quantengine.tar.gz -C "$TEMP_DEPLOY" - - # - chmod +x "$TEMP_DEPLOY/scripts/validate_migrations.sh" - "$TEMP_DEPLOY/scripts/validate_migrations.sh" "$TEMP_DEPLOY" - - # - rm -rf "$TEMP_DEPLOY" - - - name: Pre-Deployment Verification - run: | - echo "=== PRE-DEPLOYMENT CHECKS ===" - - # 1. SSH - if [ ! -f ~/.ssh/id_rsa ]; then - echo "ERROR: SSH key not found" - exit 1 - fi - echo "OK: SSH key present" - - # 2. - if [ ! -f quantengine.tar.gz ]; then - echo "ERROR: Build artifact (quantengine.tar.gz) not found" - exit 1 - fi - ARTIFACT_SIZE=$(stat -c%s quantengine.tar.gz) - if [ "$ARTIFACT_SIZE" -lt 1000000 ]; then - echo "WARNING: Artifact seems small (${ARTIFACT_SIZE} bytes), but proceeding" - fi - echo "OK: Build artifact present (${ARTIFACT_SIZE} bytes)" - - # 3. - for file in deploy/quantengine.env deploy_gb.sh; do - if [ ! -f "$file" ]; then - echo "ERROR: Required file missing: $file" - exit 1 - fi - done - echo "OK: All required deployment files present" - - # 4. - if [ -z "${{ secrets.QUANTENGINE_DB_PASSWORD }}" ]; then - echo "ERROR: DB password secret not configured" - exit 1 - fi - echo "OK: DB credentials configured" - - echo "=== ALL PRE-DEPLOYMENT CHECKS PASSED ===" - - - name: Local Deploy (Green-Blue) - id: deploy - run: | - set -e - - # - TIMESTAMP=$(date +%Y%m%d_%H%M%S) - COMMIT=$(git rev-parse --short HEAD) - RUN_NUM="${{ github.run_number }}" - DEPLOY_BASE="/home/kjh2064/deployments" - ACTIVE_LINK="/home/kjh2064/quantengine_active" - TARGET_DIR="${DEPLOY_BASE}/quantengine_${TIMESTAMP}_${COMMIT}_${RUN_NUM}" - DEPLOYMENT_LOG="./deployment_${TIMESTAMP}.log" - - TELEGRAM_BOT_TOKEN="${{ secrets.TELEGRAM_BOT_TOKEN }}" - [ -z "$TELEGRAM_BOT_TOKEN" ] && TELEGRAM_BOT_TOKEN="${{ env.TELEGRAM_BOT_TOKEN_DEFAULT }}" - TELEGRAM_CHAT_ID="${{ secrets.TELEGRAM_CHAT_ID }}" - [ -z "$TELEGRAM_CHAT_ID" ] && TELEGRAM_CHAT_ID="${{ env.TELEGRAM_CHAT_ID_DEFAULT }}" - - send_telegram() { - local text="$1" - curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${TELEGRAM_CHAT_ID}" \ - --data-urlencode "text=${text}" \ - -d "parse_mode=HTML" >/dev/null || true - } - - trap 'on_error' ERR - on_error() { - echo "DEPLOYMENT FAILED" | tee -a "$DEPLOYMENT_LOG" - send_telegram "DEPLOYMENT FAILED: $COMMIT at $(date)" - exit 1 - } - - { - echo "=== DEPLOYMENT START: $TIMESTAMP ===" - echo "Commit: $COMMIT" - echo "Run: $RUN_NUM" - echo "Target: $TARGET_DIR" - echo "" - - # - echo "[1/8] Creating deployment directories..." - mkdir -p "${DEPLOY_BASE}" || { echo "FATAL: Cannot create deploy base"; exit 1; } - mkdir -p "${TARGET_DIR}" || { echo "FATAL: Cannot create target dir"; exit 1; } - echo "OK: Directories created" - echo "" - - # - echo "[2/8] Extracting build artifact..." - if ! tar -xzf quantengine.tar.gz -C "${TARGET_DIR}"; then - echo "FATAL: Failed to extract artifact" - exit 1 - fi - echo "OK: Artifact extracted" - ls "${TARGET_DIR}" | head -10 - echo "" - - # - echo "[3/8] Normalizing deployment structure..." - if [ -d "${TARGET_DIR}/net10.0" ]; then - echo "Found net10.0 subdirectory, moving to root..." - if ! mv "${TARGET_DIR}/net10.0"/* "${TARGET_DIR}/"; then - echo "WARNING: Some files could not be moved from net10.0" - fi - if [ -d "${TARGET_DIR}/net10.0" ]; then - rmdir "${TARGET_DIR}/net10.0" 2>/dev/null || echo "Warning: Could not remove net10.0 dir" - fi - fi - echo "OK: Structure normalized" - echo "" - - # - echo "[4/8] Validating deployment contents..." - if [ ! -f "${TARGET_DIR}/QuantEngine.Web.dll" ]; then - echo "FATAL: QuantEngine.Web.dll not found in deployment" - exit 1 - fi - if [ ! -f "${TARGET_DIR}/appsettings.json" ]; then - echo "FATAL: appsettings.json not found" - exit 1 - fi - echo "OK: All required files present" - echo "" - - # - echo "[5/8] Installing environment configuration..." - mkdir -p /home/kjh2064/.config || { echo "WARNING: Cannot create config dir"; } - install -m 600 ./deploy/quantengine.env /home/kjh2064/.config/quantengine.env || { echo "WARNING: Config file install failed"; } - echo "OK: Configuration installed" - echo "" - - # appsettings.Production.json - echo "[6/8] Creating production appsettings..." - mkdir -p "${TARGET_DIR}" - DB_PASSWORD="${{ secrets.QUANTENGINE_DB_PASSWORD }}" - cat > "${TARGET_DIR}/appsettings.Production.json" << EOF -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "DefaultConnection": "Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=${DB_PASSWORD};Search Path=quantengine;" - }, - "AdminSettings": { - "Username": "admin", - "Password": "quant123!" - } -} -EOF - chmod 600 "${TARGET_DIR}/appsettings.Production.json" - echo "OK: appsettings.Production.json created" - echo "" - - } | tee "$DEPLOYMENT_LOG" - - echo "timestamp=${TIMESTAMP}" >> $GITHUB_OUTPUT - echo "commit=${COMMIT}" >> $GITHUB_OUTPUT - echo "target_dir=${TARGET_DIR}" >> $GITHUB_OUTPUT - - # () - PREV_VERSION="none" - if [ -L "${ACTIVE_LINK}" ]; then - PREV_VERSION=$(readlink -f "${ACTIVE_LINK}") - PREV_TIMESTAMP=$(basename "${PREV_VERSION}") - else - PREV_TIMESTAMP="none" - fi - - echo "[7/8] Executing Green-Blue deployment..." - export DEPLOY_FROM_CI=1 - chmod +x "${TARGET_DIR}/deploy_gb.sh" - - if ! "${TARGET_DIR}/deploy_gb.sh" >> "$DEPLOYMENT_LOG" 2>&1; then - echo "DEPLOYMENT FAILED: Green-Blue swap error" - send_telegram "DEPLOYMENT FAILED: Green-Blue swap failed for $COMMIT" - exit 1 - fi - - echo "OK: Green-Blue deployment completed" - - # - cat > "${TARGET_DIR}/.deployment_info" << EOF -Deployed: $(date -u +'%Y-%m-%dT%H:%M:%SZ') -Commit: ${COMMIT} -Timestamp: ${TIMESTAMP} -Run: ${RUN_NUM} -Previous: ${PREV_TIMESTAMP} -Status: DEPLOYED -EOF - - echo "timestamp=${TIMESTAMP}" >> $GITHUB_OUTPUT - echo "commit=${COMMIT}" >> $GITHUB_OUTPUT - echo "target_dir=${TARGET_DIR}" >> $GITHUB_OUTPUT - echo "prev_version=${PREV_TIMESTAMP}" >> $GITHUB_OUTPUT - - - name: Health Check & Verification - id: health-check - run: | - TIMESTAMP="${{ steps.deploy.outputs.timestamp }}" - COMMIT="${{ steps.deploy.outputs.commit }}" - TARGET_DIR="${{ steps.deploy.outputs.target_dir }}" - PREV_TIMESTAMP="${{ steps.deploy.outputs.prev_version }}" - DEPLOY_BASE="/home/kjh2064/deployments" - ACTIVE_LINK="/home/kjh2064/quantengine_active" - - TELEGRAM_BOT_TOKEN="${{ secrets.TELEGRAM_BOT_TOKEN }}" - [ -z "$TELEGRAM_BOT_TOKEN" ] && TELEGRAM_BOT_TOKEN="${{ env.TELEGRAM_BOT_TOKEN_DEFAULT }}" - TELEGRAM_CHAT_ID="${{ secrets.TELEGRAM_CHAT_ID }}" - [ -z "$TELEGRAM_CHAT_ID" ] && TELEGRAM_CHAT_ID="${{ env.TELEGRAM_CHAT_ID_DEFAULT }}" - - send_telegram() { - local text="$1" - curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${TELEGRAM_CHAT_ID}" \ - --data-urlencode "text=${text}" \ - -d "parse_mode=HTML" >/dev/null || true - } - - echo "=== POST-DEPLOYMENT HEALTH CHECKS ===" - - # 1. - echo "[1/4] Verifying deployment directory..." - if [ ! -d "$TARGET_DIR" ]; then - echo "FATAL: Deployment directory not found: $TARGET_DIR" - exit 1 - fi - if [ ! -f "${TARGET_DIR}/QuantEngine.Web.dll" ]; then - echo "FATAL: Application DLL not found in deployment" - exit 1 - fi - echo "OK: Deployment directory verified" - - # 2. Loopback - echo "[2/4] Performing loopback health checks..." - health_check_passed=0 - for i in $(seq 1 ${{ env.HEALTH_CHECK_RETRIES }}); do - echo " Attempt $i/${{ env.HEALTH_CHECK_RETRIES }}..." - if timeout 10 curl -s -f -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/ 2>/dev/null | grep -qE '^(200|302|401)$'; then - echo " OK: Service responding" - health_check_passed=1 - break - fi - if [ $i -lt ${{ env.HEALTH_CHECK_RETRIES }} ]; then - sleep ${{ env.HEALTH_CHECK_DELAY }} - fi - done - - if [ $health_check_passed -eq 0 ]; then - echo "FAILED: Health check did not pass after ${{ env.HEALTH_CHECK_RETRIES }} attempts" - echo "status=failed" >> $GITHUB_OUTPUT - exit 1 - fi - echo "OK: Loopback health check passed" - - # 3. - echo "[3/4] Verifying database connectivity..." - if timeout 10 bash -c 'cat /home/kjh2064/.config/quantengine.env | grep -q "postgresql"' 2>/dev/null; then - echo "OK: Database credentials configured" - else - echo "WARNING: Could not verify database credentials" - fi - - # 4. - echo "[4/4] Checking service status..." - if systemctl is-active --quiet quantengine; then - echo "OK: Service is running" - else - echo "WARNING: Service may not be running, but health checks passed" - fi - - echo "status=success" >> $GITHUB_OUTPUT - echo "=== ALL HEALTH CHECKS PASSED ===" - send_telegram "OK: QuantEngine deployed successfully (commit: ${COMMIT})" - - - name: Auto-Rollback on Health Check Failure - if: failure() && steps.health-check.outcome == 'failure' - run: | - COMMIT="${{ steps.deploy.outputs.commit }}" - PREV_TIMESTAMP="${{ steps.deploy.outputs.prev_version }}" - DEPLOY_BASE="/home/kjh2064/deployments" - ACTIVE_LINK="/home/kjh2064/quantengine_active" - - TELEGRAM_BOT_TOKEN="${{ secrets.TELEGRAM_BOT_TOKEN }}" - [ -z "$TELEGRAM_BOT_TOKEN" ] && TELEGRAM_BOT_TOKEN="${{ env.TELEGRAM_BOT_TOKEN_DEFAULT }}" - TELEGRAM_CHAT_ID="${{ secrets.TELEGRAM_CHAT_ID }}" - [ -z "$TELEGRAM_CHAT_ID" ] && TELEGRAM_CHAT_ID="${{ env.TELEGRAM_CHAT_ID_DEFAULT }}" - - send_telegram() { - local text="$1" - curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${TELEGRAM_CHAT_ID}" \ - --data-urlencode "text=${text}" \ - -d "parse_mode=HTML" >/dev/null || true - } - - echo "=== AUTOMATIC ROLLBACK INITIATED ===" - echo "Health check failed, rolling back to previous version..." - - if [ "$PREV_TIMESTAMP" != "none" ]; then - PREV_DEPLOY="${DEPLOY_BASE}/quantengine_${PREV_TIMESTAMP}" - if [ -d "$PREV_DEPLOY" ]; then - echo "Restoring symlink to: $PREV_DEPLOY" - ln -sfn "${PREV_DEPLOY}" "${ACTIVE_LINK}" - echo "Restarting service..." - systemctl restart quantengine 2>&1 || echo "WARNING: Service restart may have issues" - sleep 3 - echo "Rollback completed" - send_telegram "ROLLBACK: Deployment of ${COMMIT} failed, rolled back to ${PREV_TIMESTAMP}" - else - echo "ERROR: Previous deployment directory not found" - send_telegram "CRITICAL: Rollback failed - previous deployment not found" - exit 1 - fi - else - echo "ERROR: No previous deployment available for rollback" - send_telegram "CRITICAL: Health check failed - no previous deployment to rollback to" - exit 1 - fi - - echo "=== Verifying Database Connectivity ===" - db_status=$(psql -U quantengine_app -d quantenginedb -h 127.0.0.1 -c 'SELECT 1;' 2>&1 | head -1) - - if echo "$db_status" | grep -q "1"; then - echo " Database connectivity verified" - else - echo " Database connectivity check: $db_status" - fi - - - name: Post-Deployment Verification - if: success() - run: | - echo "=== POST-DEPLOYMENT VERIFICATION ===" - - # Public endpoints - echo "[1/3] Verifying public endpoints..." - for endpoint in "/" "/Account/Login"; do - code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "https://quant.taxbaik.com${endpoint}") - echo " https://quant.taxbaik.com${endpoint} -> $code" - if ! echo "$code" | grep -qE '^(200|302|401)$'; then - echo " WARNING: Unexpected response code" - fi - done - - # Nginx - echo "[2/3] Verifying Nginx configuration..." - if nginx -t 2>&1 | grep -q "successful"; then - echo " OK: Nginx syntax valid" - else - echo " WARNING: Nginx validation may have issues" - fi - - # - echo "[3/3] Creating deployment record..." - DEPLOYMENT_SUMMARY="deployment_summary_${{ steps.deploy.outputs.timestamp }}.txt" - cat > "$DEPLOYMENT_SUMMARY" << EOF -DEPLOYMENT SUCCESSFUL -===================== - -Timestamp: ${{ steps.deploy.outputs.timestamp }} -Commit: ${{ steps.deploy.outputs.commit }} -Target: ${{ steps.deploy.outputs.target_dir }} -Previous: ${{ steps.deploy.outputs.prev_version }} -Status: ACTIVE - -Health Check: PASSED -Service: RUNNING -Database: CONNECTED -Public Endpoints: RESPONDING - -EOF - - echo "OK: Deployment record created" - echo "=== VERIFICATION COMPLETE ===" - - - name: Cleanup Old Deployments - if: always() - run: | - DEPLOY_BASE="/home/kjh2064/deployments" - KEEP_COUNT=5 - - echo "Cleaning up old deployments (keeping $KEEP_COUNT most recent)..." - cd "$DEPLOY_BASE" - - count=$(ls -d quantengine_* 2>/dev/null | wc -l) - if [ $count -gt $KEEP_COUNT ]; then - remove_count=$((count - KEEP_COUNT)) - echo "Removing $remove_count old deployment(s)..." - ls -dt quantengine_* | tail -n +$((KEEP_COUNT + 1)) | while read -r old_dir; do - echo " Removing: $old_dir" - rm -rf "$old_dir" 2>/dev/null || echo " WARNING: Could not remove $old_dir" - done - fi - - echo "Cleanup complete. Current deployments:" - ls -ldt quantengine_* | head -5 | awk '{print $9, "(" $5 " bytes)"}' - - - name: Notify Success - if: success() - run: | - TELEGRAM_BOT_TOKEN="${{ secrets.TELEGRAM_BOT_TOKEN }}" - [ -z "$TELEGRAM_BOT_TOKEN" ] && TELEGRAM_BOT_TOKEN="${{ env.TELEGRAM_BOT_TOKEN_DEFAULT }}" - TELEGRAM_CHAT_ID="${{ secrets.TELEGRAM_CHAT_ID }}" - [ -z "$TELEGRAM_CHAT_ID" ] && TELEGRAM_CHAT_ID="${{ env.TELEGRAM_CHAT_ID_DEFAULT }}" - - curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${TELEGRAM_CHAT_ID}" \ - --data-urlencode "text=SUCCESS: QuantEngine deployment complete (commit: ${{ steps.deploy.outputs.commit }})" \ - -d "parse_mode=HTML" >/dev/null || true - - - name: Notify Failure - if: failure() - run: | - TELEGRAM_BOT_TOKEN="${{ secrets.TELEGRAM_BOT_TOKEN }}" - [ -z "$TELEGRAM_BOT_TOKEN" ] && TELEGRAM_BOT_TOKEN="${{ env.TELEGRAM_BOT_TOKEN_DEFAULT }}" - TELEGRAM_CHAT_ID="${{ secrets.TELEGRAM_CHAT_ID }}" - [ -z "$TELEGRAM_CHAT_ID" ] && TELEGRAM_CHAT_ID="${{ env.TELEGRAM_CHAT_ID_DEFAULT }}" - - curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${TELEGRAM_CHAT_ID}" \ - --data-urlencode "text=FAILURE: QuantEngine deployment failed (commit: ${{ steps.deploy.outputs.commit }}) - -Logs: https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/actions/runs/${{ github.run_id }}" \ - -d "parse_mode=HTML" >/dev/null || true - - - name: Cleanup Old Deployments - run: | - DEPLOY_BASE="/home/kjh2064/deployments" - echo "Cleaning up obsolete deployments (keeping last 5)..." - cd "${DEPLOY_BASE}" - ls -dt quantengine_* | tail -n +6 | while read -r old_dir; do - echo "Removing old release: ${old_dir}" - rm -rf "${old_dir}" - done - echo "Cleanup complete" - ls -ldt quantengine_* | head -5 - - - name: Notify Failure - if: failure() - run: | - COMMIT=$(git rev-parse --short HEAD) - TELEGRAM_BOT_TOKEN="${{ secrets.TELEGRAM_BOT_TOKEN }}" - [ -z "$TELEGRAM_BOT_TOKEN" ] && TELEGRAM_BOT_TOKEN="${{ env.TELEGRAM_BOT_TOKEN_DEFAULT }}" - TELEGRAM_CHAT_ID="${{ secrets.TELEGRAM_CHAT_ID }}" - [ -z "$TELEGRAM_CHAT_ID" ] && TELEGRAM_CHAT_ID="${{ env.TELEGRAM_CHAT_ID_DEFAULT }}" - - curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${TELEGRAM_CHAT_ID}" \ - --data-urlencode "text= QuantEngine \n: ${COMMIT}\n: https://gitea.taxbaik.com/kjh2064/QuantEngineByItz/actions/runs/${{ github.run_id }}" \ - -d "parse_mode=HTML" || true diff --git a/AGENTS.md b/AGENTS.md index b7417826..861a8ecf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -104,6 +104,7 @@ - `docs/CLOUD_SERVER_SETUP.md`: 클라우드 서버(hz-prod-01, 178.104.200.7) 설정 하네스 가이드. 시놀로지 → 클라우드 마이그레이션 매핑 포함. - `docs/ENTERPRISE_CRUD_DESIGN_SPECIFICATION.md`: OMS·WMS·ERP CRUD 화면 및 입력 컴포넌트 상용화 지침 명세 (엔터프라이즈 컴포넌트/트랜잭션 헌법). - `docs/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md`: OMS·WMS·ERP 공통 CRUD 화면 템플릿 상용화 WBS & 로드맵. +- `docs/QUANTENGINE_MASTERPIECE_ROADMAP.md`: 프로젝트 냉정 분석 & 마스터피스 3-Stream 로드맵 (Alpha Validation / Platform Consolidation / Professional Operation). - `src/frontend/src/types/enterpriseTemplateContracts.ts`: OMS·WMS·ERP 11대 표준 템플릿 TypeScript 공통 계약. - `docs/GITEA_SECRETS_SETUP.md`: Gitea secrets setup and verification guide. - `docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md`: `GatherTradingData.xlsx` 보조 자산 런북. diff --git a/README.md b/README.md index f41c2c77..7069cb24 100644 --- a/README.md +++ b/README.md @@ -28,15 +28,12 @@ CI 스케줄러는 `GatherTradingData.json`을 seed snapshot으로 사용하고, ```powershell npm install -node core_satellite_collector.js ``` -OpenDART 공시까지 확인하려면: - -```powershell -$env:OPENDART_OPENAPI_KEY="발급받은키" -node core_satellite_collector.js -``` +**⚠️ 2026-07-30 정정**: 이 섹션은 예전에 `node core_satellite_collector.js`를 실행 커맨드로 +안내했지만, 그 파일은 git 히스토리에 한 번도 존재한 적이 없다 (`package.json`의 `ops:dev` +스크립트도 같은 phantom 파일을 가리키고 있어 같은 날 함께 정리함). 실제 수집기는 +Python으로 구현되어 있다 — 아래 커맨드를 사용할 것. SQLite 기반 데이터 수집을 실행하려면: @@ -44,6 +41,15 @@ SQLite 기반 데이터 수집을 실행하려면: $env:KIS_APP_Key="실제계좌키" $env:KIS_APP_Secret="실제계좌시크릿" python tools/run_kis_data_collection_v1.py --input-json GatherTradingData.json --sqlite-db src/quant_engine/kis_data_collection.db --output-json Temp/kis_data_collection_v1.json --kis-account real +# 또는: npm run ops:data-collect +``` + +OpenDART 공시까지 확인하려면 (2026-07-30 기준 `_dart_fundamentals()`는 아직 스텁 — 실제 +호출은 미구현, `tools/ingest_fundamental_raw.py` 참고): + +```powershell +$env:OPENDART_OPENAPI_KEY="발급받은키" +python tools/ingest_fundamental_raw.py ``` ### Snapshot admin web UI diff --git a/docs/CLOUD_SERVER_SETUP.md b/docs/CLOUD_SERVER_SETUP.md index 9ce4bf7b..15fd7eeb 100644 --- a/docs/CLOUD_SERVER_SETUP.md +++ b/docs/CLOUD_SERVER_SETUP.md @@ -47,7 +47,7 @@ |---|---| | [`AGENTS.md`](../AGENTS.md) | 운영 헌법, Directory Routing 인덱스 | | [`GITEA_SECRETS_SETUP.md`](GITEA_SECRETS_SETUP.md) | Gitea 시크릿 설정/검증 가이드 | -| [`ROADMAP_WBS.md`](ROADMAP_WBS.md) | `.gs → Python` 및 `xlsx → sqlite` WBS | +| [`ROADMAP_WBS.md`](archive/ROADMAP_WBS.md) | `.gs → Python` 및 `xlsx → sqlite` WBS (2026-07-30 archive됨, 최신 상태는 CLAUDE.md Migration Status 참고) | | [`docs/GITEA_TOKEN_HOME_RUNBOOK.md`](GITEA_TOKEN_HOME_RUNBOOK.md) | Gitea 토큰 관리 런북 | | [`spec/00_execution_contract.yaml`](../spec/00_execution_contract.yaml) | 실행 계약 원본 권위 | | [`governance/agents_index.yaml`](../governance/agents_index.yaml) | 거버넌스 규칙 인덱스 | diff --git a/docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md b/docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md index f320131f..369305d4 100644 --- a/docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md +++ b/docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md @@ -41,7 +41,7 @@ 1. `GatherTradingData.json`이 있으면 그 파일을 우선 사용한다. 2. JSON이 없고 workbook 변환이 필요하면 `tools/convert_xlsx_to_json.py`를 별도 seed-prep 단계에서 실행한다. -3. `docs/ROADMAP_WBS.md`의 WBS-8.2를 따른다. +3. `docs/archive/ROADMAP_WBS.md`(2026-07-30 archive됨)의 WBS-8.2를 따른다. 4. `tools/validate_platform_transition_wbs_v1.py`와 `tools/validate_snapshot_admin_web_v1.py`를 확인한다. 5. KIS 토큰은 `src/quant_engine/kis_api_client_v1.py`가 SQLite 캐시로 관리하므로, 수집 재실행 시에도 토큰을 매번 새로 발급하지 않는다. 6. 토큰 상태는 `python tools/inspect_kis_token_cache_v1.py`로 확인한다. diff --git a/docs/WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md b/docs/WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md index de0e6ca3..218abea3 100644 --- a/docs/WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md +++ b/docs/WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md @@ -1,6 +1,6 @@ # WBS-10 보강: .NET Core 마이그레이션 완성 & 상용화 로드맵 (2026-06-30) -> 본 문서는 [docs/ROADMAP_WBS.md](./ROADMAP_WBS.md) 의 **WBS-10(.NET 엔진 고도화)** 을 현 시점 실측 기준으로 재진단하고, 마이그레이션 완성과 단일 사용자 상용 운영에 필요한 잔여 작업을 재정의한다. +> 본 문서는 [docs/archive/ROADMAP_WBS.md](./archive/ROADMAP_WBS.md) (2026-07-30 archive됨) 의 **WBS-10(.NET 엔진 고도화)** 을 현 시점 실측 기준으로 재진단하고, 마이그레이션 완성과 단일 사용자 상용 운영에 필요한 잔여 작업을 재정의한다. > > **작성 배경:** 기존 WBS-10 의 다수 항목이 `완료` 로 표기되어 있으나, 2026-06-30 소스 실측 결과 **표기와 실제 상태 간 괴리**가 확인되었다. 본 문서는 그 괴리를 정리하고 실제 잔여 작업을 추적한다. > diff --git a/docs/WBS_9_6_LLM_RADAR_OPTIMIZATION_STRATEGY_2026_06_22.md b/docs/WBS_9_6_LLM_RADAR_OPTIMIZATION_STRATEGY_2026_06_22.md index cb9d77bc..728ea41b 100644 --- a/docs/WBS_9_6_LLM_RADAR_OPTIMIZATION_STRATEGY_2026_06_22.md +++ b/docs/WBS_9_6_LLM_RADAR_OPTIMIZATION_STRATEGY_2026_06_22.md @@ -49,7 +49,7 @@ - 배경 설명 문서 - 의사결정 근거 - 최신화 필요 -- 예: docs/ROADMAP_WBS.md +- 예: docs/archive/ROADMAP_WBS.md (2026-07-30 archive됨) **Deprecated (신뢰도 0%)** - 폐기된 알고리즘 diff --git a/CICD_ROADMAP.md b/docs/archive/CICD_ROADMAP.md similarity index 100% rename from CICD_ROADMAP.md rename to docs/archive/CICD_ROADMAP.md diff --git a/docs/EXECUTION_PLAN_PHASE0_CLOSEOUT_AND_PHASE1_KICKOFF.md b/docs/archive/EXECUTION_PLAN_PHASE0_CLOSEOUT_AND_PHASE1_KICKOFF.md similarity index 100% rename from docs/EXECUTION_PLAN_PHASE0_CLOSEOUT_AND_PHASE1_KICKOFF.md rename to docs/archive/EXECUTION_PLAN_PHASE0_CLOSEOUT_AND_PHASE1_KICKOFF.md diff --git a/docs/MODERNIZATION_ROADMAP_VISUAL.md b/docs/archive/MODERNIZATION_ROADMAP_VISUAL.md similarity index 100% rename from docs/MODERNIZATION_ROADMAP_VISUAL.md rename to docs/archive/MODERNIZATION_ROADMAP_VISUAL.md diff --git a/docs/MODERNIZATION_STRATEGY_ROADMAP_2026-2027.md b/docs/archive/MODERNIZATION_STRATEGY_ROADMAP_2026-2027.md similarity index 100% rename from docs/MODERNIZATION_STRATEGY_ROADMAP_2026-2027.md rename to docs/archive/MODERNIZATION_STRATEGY_ROADMAP_2026-2027.md diff --git a/docs/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md b/docs/archive/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md similarity index 100% rename from docs/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md rename to docs/archive/ROADMAP_ENTERPRISE_TEMPLATES_WBS.md diff --git a/docs/ROADMAP_WBS.md b/docs/archive/ROADMAP_WBS.md similarity index 100% rename from docs/ROADMAP_WBS.md rename to docs/archive/ROADMAP_WBS.md diff --git a/package.json b/package.json index 32c55282..d9ab2856 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "validate-realized-performance": "python tools/validate_realized_performance_v1.py", "validate-gas-recovery": "python tools/validate_gas_orchestration_recovery_v1.py", "ops:clean": "python tools/clean_temp_artifacts_v1.py", - "ops:dev": "node core_satellite_collector.js", "full-gate": "python tools/run_release_dag_v3.py --mode release --strict", "validate-engine-strict": "python tools/run_release_dag_v3.py --mode release --strict", "validate-behavioral-coverage": "python tools/validate_behavioral_coverage_v1.py --strict", diff --git a/src/client/src/main.ts b/src/client/src/main.ts deleted file mode 100644 index e266821f..00000000 --- a/src/client/src/main.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { createApp } from 'vue'; -import PrimeVue from 'primevue/config'; -import Aura from '@primevue/themes/aura'; -import App from './App.vue'; -import router from './router'; - -import 'ag-grid-community/styles/ag-grid.css'; -import 'ag-grid-community/styles/ag-theme-alpine.css'; - -const app = createApp(App); - -app.use(PrimeVue, { - theme: { - preset: Aura - } -}); -app.use(router); - -app.mount('#app'); diff --git a/src/client/src/views/MasterDetailAgGridView.vue b/src/client/src/views/MasterDetailAgGridView.vue deleted file mode 100644 index b7181496..00000000 --- a/src/client/src/views/MasterDetailAgGridView.vue +++ /dev/null @@ -1,122 +0,0 @@ - - - diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index cbcc1fba..00000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "passed", - "failedTests": [] -} \ No newline at end of file