27 Commits

Author SHA1 Message Date
kjh2064 2f60fbf655 Fix deploy loopback verification to accept login redirect
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 10s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Has been cancelled
2026-07-01 14:55:59 +09:00
kjh2064 f68fb10bac Fix deploy verification to use public domain
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 8s
Deploy to Production / Build & Deploy to Production (push) Has been cancelled
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
2026-07-01 14:41:51 +09:00
kjh2064 c1b7d29eb8 Fix deploy workflow yaml heredoc indentation
Deploy to Production / Build & Deploy to Production (push) Has been cancelled
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 11s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
2026-07-01 14:37:11 +09:00
kjh2064 ce3505cd33 Add admin password reset API
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 4s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
2026-07-01 14:30:33 +09:00
kjh2064 e97397ddbf Disable antiforgery on auth and add quantengine migration tools
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 4s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
2026-07-01 14:17:53 +09:00
kjh2064 6ed3de2749 Separate QuantEngine database deployment
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 11s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
2026-07-01 13:55:03 +09:00
kjh2064 3e7120c041 Add remember username on login
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 5s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 10s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 1m49s
2026-07-01 13:35:13 +09:00
kjh2064 784f4bdbfb fix(ui): make mud providers self-closing
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 9s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 3m5s
2026-07-01 13:28:24 +09:00
kjh2064 28e1a8775f feat(ui): migrate web shell to mudblazor
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 11s
Deploy to Production / Build & Deploy to Production (push) Failing after 1m55s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
2026-07-01 13:24:46 +09:00
kjh2064 fe8ff44d3f fix(ci): accept auth redirects in deploy verification
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 11s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 3m8s
2026-07-01 13:14:26 +09:00
kjh2064 d5d630a816 fix(web): set default authentication scheme
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 11s
Deploy to Production / Build & Deploy to Production (push) Failing after 3m4s
2026-07-01 13:09:59 +09:00
kjh2064 60022ed214 chore(ci): consolidate production deploy workflow
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 1m48s
2026-07-01 13:07:02 +09:00
kjh2064 90bbb1860d feat(web): add auth and fix deployment checks
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 9s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 2m30s
Deploy to Production / Build & Deploy to Production (push) Failing after 3m49s
2026-07-01 13:02:10 +09:00
kjh2064 3e4d545e01 Merge branch 'chore/gitignore-dotnet-build-artifacts'
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 14s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 7s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 3m16s
Deploy to Production / Build & Deploy to Production (push) Failing after 4m34s
2026-07-01 11:32:24 +09:00
kjh2064 e4290ef3c6 feat(ui): 모든 중요 페이지에 [Authorize] 인가 가드 적용하여 보안 강화 2026-07-01 11:27:50 +09:00
kjh2064 4de9339163 feat(ui): Blazor WebAssembly 마이그레이션 및 API-First 로그인 구현 2026-07-01 11:22:09 +09:00
kjh2064 bdb9262f4e feat(auth): QuantEngine 관리자 로그인 페이지 및 세션 인증 체계 구현 (WBS-AUTH) 2026-07-01 11:12:20 +09:00
kjh2064 8bd678c7c7 Merge pull request 'docs(cloud): 클라우드 서버 도메인 가상 호스트 및 HTTPS 설정 지침 반영' (#13) from chore/gitignore-dotnet-build-artifacts into main
Snapshot Admin Deployment / build-and-deploy (push) Failing after 1m1s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 1m33s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 10s
Reviewed-on: #13
2026-07-01 10:46:06 +09:00
kjh2064 24c1cce542 docs(cloud): 클라우드 서버 도메인 기반 가상 호스트(HTTPS) 설정 지침 최신화 및 Nginx 백업 추가 (WBS-CLOUD-5)
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (pull_request) Failing after 4s
Quant Engine CI/CD Pipeline / validate-core (pull_request) Failing after 7s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (pull_request) Has been skipped
2026-07-01 10:39:11 +09:00
kjh2064 1255e67765 Merge pull request 'chore(git): .NET 빌드 산출물 추적 제거 및 .gitignore 정비 (WBS-P0.1)' (#12) from chore/gitignore-dotnet-build-artifacts into main
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 12s
Snapshot Admin Deployment / build-and-deploy (push) Failing after 1m7s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 1m40s
Reviewed-on: http://178.104.200.7/kjh2064/QuantEngineByItz/pulls/12
2026-06-30 18:20:20 +09:00
kjh2064 a02543981e Merge pull request 'docs(ui): UI 표준을 MudBlazor + Interactive WebAssembly + API-First 로 전환' (#11) from docs/ui-framework-policy-mudblazor-wasm into main
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 10s
Snapshot Admin Deployment / build-and-deploy (push) Has been cancelled
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Deploy to Production / Build & Deploy to Production (push) Failing after 1m46s
Reviewed-on: http://178.104.200.7/kjh2064/QuantEngineByItz/pulls/11
2026-06-30 18:20:12 +09:00
kjh2064 fdfd50bdca chore(git): .NET 빌드 산출물 git 추적 제거 및 .gitignore 정비 (WBS-P0.1)
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (pull_request) Failing after 4s
Quant Engine CI/CD Pipeline / validate-core (pull_request) Failing after 7s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (pull_request) Has been skipped
bin/obj 312개 파일이 git에 추적되던 문제를 해소한다.

- .gitignore: **/bin/, **/obj/, publish-output/, *.user, *.suo 패턴 추가
- 추적 중이던 src/dotnet/**/bin, **/obj 산출물 312개를 인덱스에서 제거
  (git rm --cached, 작업 트리 파일은 보존)

WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md 의 WBS-P0.1 항목.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:08:10 +09:00
kjh2064 227b563ba2 docs(ui): UI 표준을 MudBlazor + Interactive WebAssembly + API-First 로 전환
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (pull_request) Failing after 5s
Quant Engine CI/CD Pipeline / validate-core (pull_request) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (pull_request) Has been skipped
Fluent UI Blazor v5 / InteractiveServer 방침을 폐기하고 MudBlazor 컴포넌트 +
Interactive WebAssembly 렌더 모드 + API-First 를 신규 표준으로 확정한다.
기존 CLAUDE.md(Fluent UI)와 AGENTS.md §5b(MudBlazor)의 상충을 해소한다.

- CLAUDE.md: Framework & Design System, Component Rules, 매핑표를 MudBlazor 로 갱신
- AGENTS.md §5b: 렌더 모드 표준(Interactive WebAssembly) 신설, Server 표기 정렬
- ROADMAP_WBS.md: WBS-10 보강 문서 상호 참조 링크 추가
- WBS_10_DOTNET_MIGRATION_HARDENING: 마이그레이션 완성/상용화 로드맵 신규,
  UI 코드 전환을 WBS-A7 로 등록

코드 전환(csproj/Program.cs/.razor)은 미수행, 본 커밋은 방침 문서만 수정.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:03:26 +09:00
kjh2064 5c5d9bfee7 feat: KIS Open API 연동 및 DataCollectionService 구현
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 7s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 46s
Deploy to Production / Build & Deploy to Production (push) Failing after 1m5s
- C# 기반의 DataCollectionService 클래스 구현

- 기존의 파이썬 스크립트 실행 방식을 대체하고 KIS API 클라이언트를 직접 사용하여 주식 시세, 호가, 공매도 정보 수집

- CollectionEndpoints에 비동기 수집 요청 처리 통합 및 Program.cs에 서비스 DI 등록
2026-06-29 23:39:21 +09:00
kjh2064 2220f9f807 docs(CLAUDE.md): Phase 2 95% 완료 상태 업데이트
- KIS API 클라이언트: 실제 구현 완료 (0 errors, 0 warnings)
- PostgreSQL 저장소: 완전 통합 (자동 테이블 생성, CRUD)
- Web API 엔드포인트: 6개 컬렉션 경로 완성
- Blazor UI: 대시보드 완성 (실시간 모니터링)
- 개발 명령어: 정확한 경로 + 포트 업데이트 (5265)
- 남은 일: kis_data_collection_v1.py 파이프라인 오케스트레이션 포팅

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-29 23:34:56 +09:00
kjh2064 c06c24d8bc fix(kis-api): Null reference 검증 강화 (토큰 응답 처리)
KisApiClient.TryGetAccessTokenAsync()의 null 참조 경고 제거.
- 토큰 응답 본문 존재 여부 검증
- TryGetValue 기반 안전한 파싱
- access_token 필수 필드 검증

Build: 0 errors, 0 warnings 

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-29 23:33:53 +09:00
kjh2064 0b503c20af feat(collection): PostgreSQL 백킹 활성화 (CollectionRepository + TokenCache)
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 7s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 13s
Snapshot Admin Deployment / build-and-deploy (push) Failing after 1m21s
Deploy to Production / Build & Deploy to Production (push) Successful in 1m55s
- Program.cs: PlaceholderCollectionRepository/TokenCache/KisApiClient → 실제 구현체로 변경
- 데이터베이스 초기화: EnsureTablesAsync() 호출 (시작 시 테이블 자동 생성)
- kis_tokens, kis_collection_runs, kis_collection_snapshots, kis_collection_errors 테이블
- Dapper 기반 SQL 쿼리 (파라미터화, SQL 주입 방지)
- 인덱스: started_at, ticker, captured_at, run_id
- PlaceholderImplementations.cs 제거

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-29 23:32:29 +09:00
123 changed files with 2335 additions and 12120 deletions
+177 -160
View File
@@ -2,193 +2,210 @@ name: Deploy to Production
on:
push:
branches: [ main ]
branches:
- main
workflow_dispatch:
concurrency:
group: deploy-prod-main
cancel-in-progress: true
env:
DEPLOY_HOST: 172.17.0.1
DEPLOY_HOST: 178.104.200.7
DEPLOY_USER: kjh2064
DEPLOY_PATH: /home/kjh2064/quantengine_active
SERVICE_NAME: quantengine
DOTNET_VERSION: '10.0.x'
TELEGRAM_BOT_TOKEN_DEFAULT: "8734507814:AAFyacLMai8GB4K-hQ_Nd3t3D01A-h1ZdV0"
QUANTENGINE_DB_NAME: quantenginedb
QUANTENGINE_DB_USER: quantengine_app
TELEGRAM_BOT_TOKEN_DEFAULT: "8734507814:AAFyacLMai8GB4K-hQ_Nd3t3D01A-H1ZdV0"
TELEGRAM_CHAT_ID_DEFAULT: "-5460205872"
jobs:
build-and-deploy:
name: Build & Deploy to Production
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- 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: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Python Dependencies
run: pip install pyyaml openpyxl requests
- 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: "[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
# 빈 패킷 객체를 생성하여 dotnet test/run 시 IO Exception 방어
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: 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: 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 \
-p:Version=1.0.${{ github.run_number }}
- name: Build Release
run: |
dotnet build src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \
-c Release \
--no-restore
- name: Run Unit Tests
run: |
if [ -d tests/unit ]; then
dotnet test tests/unit \
- 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 \
|| echo "⚠️ Some tests failed (non-blocking for web service)"
fi
-o ./publish
- name: Publish Release Package
run: |
dotnet publish src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj \
-c Release \
--no-build \
-o ./publish-output
- 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: 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-output/wwwroot
printf '{\n "version": "1.0.%s-%s",\n "built": "%s"\n}\n' "${{ github.run_number }}" "$COMMIT_HASH" "$BUILD_TIME" > ./publish-output/wwwroot/version.json
echo "✓ Generated version info: 1.0.${{ github.run_number }}-$COMMIT_HASH @ $BUILD_TIME"
- name: Setup SSH
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# SSH_PRIVATE_KEY가 평문 PEM이든 base64든 유연하게 처리
if echo "${{ secrets.SSH_PRIVATE_KEY }}" | grep -q "BEGIN"; then
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
else
echo "${{ secrets.SSH_PRIVATE_KEY }}" | base64 -d > ~/.ssh/id_ed25519 || echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
fi
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
- name: Package Artifact
run: |
tar -czf quant_engine_deploy.tgz -C ./publish-output .
echo "✓ Package size: $(du -sh quant_engine_deploy.tgz | cut -f1)"
- name: Deploy & Verify on Server
run: |
set -e
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
COMMIT=$(git rev-parse --short HEAD)
DEPLOY_HOST="${{ env.DEPLOY_HOST }}"
DEPLOY_USER="${{ env.DEPLOY_USER }}"
# 텔레그램 설정 바인딩 (Secret에 없을 경우 기본값 백업 사용)
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
}
notify_failure() {
local exit_code=$?
send_telegram "❌ <b>QuantEngine 배포 실패</b>
커밋: <code>${COMMIT}</code>
시간: <code>${TIMESTAMP}</code>
단계: deploy-to-prod (SSH Execution)"
exit "$exit_code"
}
trap notify_failure ERR
echo "=== Deploying QuantEngine $COMMIT ($TIMESTAMP) ==="
# 1. 아티팩트 복사
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
quant_engine_deploy.tgz "$DEPLOY_USER@$DEPLOY_HOST:/tmp/quantengine_${TIMESTAMP}.tgz"
# 2. 원격 배포 명령어 통합 (SSH 1회 연결)
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
-o ServerAliveInterval=10 \
"$DEPLOY_USER@$DEPLOY_HOST" bash << REMOTE
set -e
DEPLOY_HOME="/home/kjh2064"
DEPLOY_DIR="\$DEPLOY_HOME/deployments/quantengine_${TIMESTAMP}"
echo "--- [1/4] 압축 해제 ---"
mkdir -p "\$DEPLOY_DIR"
tar -xzf "/tmp/quantengine_${TIMESTAMP}.tgz" -C "\$DEPLOY_DIR"
rm -f "/tmp/quantengine_${TIMESTAMP}.tgz"
echo "--- [2/4] 심볼릭 링크 전환 ---"
ln -sfn "\$DEPLOY_DIR" "${{ env.DEPLOY_PATH }}"
echo "--- [3/4] 서비스 재시작 ---"
sudo /usr/bin/systemctl restart ${{ env.SERVICE_NAME }}
echo "--- [4/4] 헬스 체크 ---"
ATTEMPTS=20
for i in \$(seq 1 \$ATTEMPTS); do
STATUS=\$(curl -sf -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/ 2>/dev/null || echo "000")
if [ "\$STATUS" = "200" ]; then
echo "✓ 헬스체크 성공 (시도 \$i/\$ATTEMPTS, HTTP 200)"
# 구 배포 폴더 정리 (최근 5개만 보존)
ls -1dt \$DEPLOY_HOME/deployments/quantengine_* 2>/dev/null | tail -n +6 | xargs rm -rf 2>/dev/null || true
exit 0
- name: Setup SSH
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
if echo "${{ secrets.SSH_PRIVATE_KEY }}" | grep -q "BEGIN"; then
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
else
echo "${{ secrets.SSH_PRIVATE_KEY }}" | base64 -d > ~/.ssh/id_ed25519 || echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
fi
if [ "\$i" -eq "\$ATTEMPTS" ]; then
echo "=== FATAL: 서비스가 헬스체크 응답을 하지 않음 ===" >&2
systemctl is-active ${{ env.SERVICE_NAME }} >&2 || true
journalctl -u ${{ env.SERVICE_NAME }} --no-pager -n 50 >&2
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
- name: Prepare QuantEngine DB Env
run: |
mkdir -p ./deploy
cat > ./deploy/quantengine.env <<EOF
ConnectionStrings__DefaultConnection=Host=127.0.0.1;Database=${QUANTENGINE_DB_NAME};Username=${QUANTENGINE_DB_USER};Password=${{ secrets.QUANTENGINE_DB_PASSWORD }};Search Path=quantengine;
EOF
chmod 600 ./deploy/quantengine.env
- name: Package Artifact
run: |
tar -czf quantengine.tar.gz -C ./publish .
echo "✓ Package size: $(du -sh quantengine.tar.gz | cut -f1)"
- name: Deploy & Verify on Server
run: |
set -e
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
COMMIT=$(git rev-parse --short HEAD)
DEPLOY_HOST="${{ env.DEPLOY_HOST }}"
DEPLOY_USER="${{ env.DEPLOY_USER }}"
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
}
notify_failure() {
local exit_code=$?
send_telegram "❌ <b>QuantEngine 배포 실패</b>
커밋: <code>${COMMIT}</code>
시간: <code>${TIMESTAMP}</code>
단계: deploy-to-prod (SSH Execution)"
exit "$exit_code"
}
trap notify_failure ERR
echo "=== Deploying QuantEngine $COMMIT ($TIMESTAMP) ==="
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
"$DEPLOY_USER@$DEPLOY_HOST" "mkdir -p /home/kjh2064/tmp"
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
quantengine.tar.gz "$DEPLOY_USER@$DEPLOY_HOST:/home/kjh2064/tmp/quantengine.tar.gz"
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
tools/deploy_quantengine.sh "$DEPLOY_USER@$DEPLOY_HOST:/home/kjh2064/tmp/deploy.sh"
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
deploy/quantengine.env "$DEPLOY_USER@$DEPLOY_HOST:/home/kjh2064/tmp/quantengine.env"
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
"$DEPLOY_USER@$DEPLOY_HOST" "chmod +x /home/kjh2064/tmp/deploy.sh && CI_DEPLOY=1 /home/kjh2064/tmp/deploy.sh"
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 \
"$DEPLOY_USER@$DEPLOY_HOST" "mkdir -p /home/kjh2064/.config && install -m 600 /home/kjh2064/tmp/quantengine.env /home/kjh2064/.config/quantengine.env && rm -f /home/kjh2064/tmp/quantengine.env"
echo "=== Verifying Loopback Health ==="
loopback_headers=$(ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 "$DEPLOY_USER@$DEPLOY_HOST" "curl -s -D - -o /dev/null http://127.0.0.1:5000/")
echo "$loopback_headers"
if ! printf '%s' "$loopback_headers" | grep -qE '^HTTP/1\.[01] 30[12] '; then
echo "Loopback health check failed for quantengine" >&2
exit 1
fi
if ! printf '%s' "$loopback_headers" | grep -qiE '^Location: /login'; then
echo "Loopback redirect target is unexpected" >&2
exit 1
fi
echo " 대기 중... (\$i/\$ATTEMPTS, HTTP \$STATUS)"
sleep 3
done
REMOTE
echo "✓ 배포 완료: quantengine_${TIMESTAMP} @ $DEPLOY_HOST"
send_telegram "✅ <b>QuantEngine 배포 완료</b>
커밋: <code>${COMMIT}</code>
시간: <code>${TIMESTAMP}</code>
대상: <code>${DEPLOY_HOST}</code>"
echo "=== Verifying Favicon Assets ==="
favicon_svg_code=$(curl -s -o /dev/null -w "%{http_code}" "http://${DEPLOY_HOST}/favicon.svg")
favicon_png_code=$(curl -s -o /dev/null -w "%{http_code}" "http://${DEPLOY_HOST}/favicon.png")
echo "/favicon.svg -> ${favicon_svg_code}"
echo "/favicon.png -> ${favicon_png_code}"
if [ "$favicon_svg_code" != "200" ] && [ "$favicon_png_code" != "200" ]; then
echo "Favicon assets are not reachable after deploy" >&2
exit 1
fi
echo "=== Verifying Public Routes ==="
public_root_headers=$(curl -s -D - -o /dev/null "https://quant.taxbaik.com/")
login_headers=$(curl -s -D - -o /dev/null "https://quant.taxbaik.com/login")
public_root_code=$(printf '%s' "$public_root_headers" | awk 'NR==1 {print $2}')
login_code=$(printf '%s' "$login_headers" | awk 'NR==1 {print $2}')
echo "https://quant.taxbaik.com/ -> ${public_root_code}"
echo "https://quant.taxbaik.com/login -> ${login_code}"
if [ "$public_root_code" != "302" ] && [ "$public_root_code" != "200" ]; then
echo "Deployment content check failed for public root" >&2
exit 1
fi
if [ "$login_code" != "200" ]; then
echo "Deployment content check failed for login page" >&2
exit 1
fi
echo "✓ 배포 완료: quantengine_${TIMESTAMP} @ $DEPLOY_HOST"
send_telegram "✅ <b>QuantEngine 배포 완료</b>
커밋: <code>${COMMIT}</code>
시간: <code>${TIMESTAMP}</code>
대상: <code>${DEPLOY_HOST}</code>"
-131
View File
@@ -1,131 +0,0 @@
name: Snapshot Admin Deployment
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: snapshot-admin-deploy-main
cancel-in-progress: true
env:
DEPLOY_HOST: 178.104.200.7
DEPLOY_USER: kjh2064
TELEGRAM_BOT_TOKEN_DEFAULT: "8734507814:AAFyacLMai8GB4K-hQ_Nd3t3D01A-h1ZdV0"
TELEGRAM_CHAT_ID_DEFAULT: "-5460205872"
jobs:
build-and-deploy:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '10.0.x'
- name: Publish Blazor Web App
run: |
echo "[deploy] publishing .NET 10 Blazor app"
dotnet publish src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj -c Release -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: Compress Artifact
run: |
echo "[deploy] compressing publish output"
tar -czf quantengine.tar.gz -C ./publish .
- name: Setup SSH
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
if echo "${{ secrets.SSH_PRIVATE_KEY }}" | grep -q "BEGIN"; then
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
else
echo "${{ secrets.SSH_PRIVATE_KEY }}" | base64 -d > ~/.ssh/id_ed25519 || echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
fi
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
- name: Deploy & Verify on Server
run: |
set -e
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
COMMIT=$(git rev-parse --short HEAD)
DEPLOY_HOST="${{ env.DEPLOY_HOST }}"
DEPLOY_USER="${{ env.DEPLOY_USER }}"
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
}
notify_failure() {
local exit_code=$?
send_telegram "❌ <b>Snapshot Admin 배포 실패</b>
커밋: <code>${COMMIT}</code>
시간: <code>${TIMESTAMP}</code>
단계: snapshot_admin_deploy (Deploy Execution)"
exit "$exit_code"
}
trap notify_failure ERR
echo "=== Deploying Snapshot Admin $COMMIT ($TIMESTAMP) ==="
# 1. 원격지 임시 폴더 생성 및 업로드
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 "$DEPLOY_USER@$DEPLOY_HOST" "mkdir -p /home/kjh2064/tmp"
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 quantengine.tar.gz "$DEPLOY_USER@$DEPLOY_HOST:/home/kjh2064/tmp/quantengine.tar.gz"
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 tools/deploy_quantengine.sh "$DEPLOY_USER@$DEPLOY_HOST:/home/kjh2064/tmp/deploy.sh"
# 2. 배포 스크립트 실행
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 "$DEPLOY_USER@$DEPLOY_HOST" "chmod +x /home/kjh2064/tmp/deploy.sh && /home/kjh2064/tmp/deploy.sh"
# 3. 배포 성공 검증
echo "=== Verifying Public Routes ==="
root_html=$(curl -sf "http://${DEPLOY_HOST}/quant/" 2>/dev/null || echo "")
ops_html=$(curl -sf "http://${DEPLOY_HOST}/quant/operations" 2>/dev/null || echo "")
root_code=$(printf '%s' "$root_html" | grep -q "Quant Engine" && echo 200 || echo 500)
ops_code=$(printf '%s' "$ops_html" | grep -q "Operational Report" && echo 200 || echo 500)
echo "/quant/ -> ${root_code}"
echo "/quant/operations -> ${ops_code}"
if [ "$root_code" != "200" ]; then
echo "Deployment content check failed for /quant/" >&2
exit 1
fi
if [ "$ops_code" != "200" ]; then
echo "Deployment content check failed for /quant/operations" >&2
exit 1
fi
echo "✓ 배포 완료: quantengine_${TIMESTAMP} @ $DEPLOY_HOST"
send_telegram "✅ <b>Snapshot Admin 배포 완료</b>
커밋: <code>${COMMIT}</code>
시간: <code>${TIMESTAMP}</code>
대상: <code>${DEPLOY_HOST}</code>"
+7
View File
@@ -10,6 +10,13 @@ Temp/
dist/
outputs/
# .NET 빌드 산출물
**/bin/
**/obj/
publish-output/
*.user
*.suo
# 런타임 감사 로그 (append-only, 매 DAG 실행마다 증가)
runtime/lineage_events.jsonl
+4 -1
View File
@@ -110,6 +110,8 @@
- D+2 영업일 기준 현금을 즉시방어 자산으로 간주하고, 목표 예산 5억 원을 기준으로 포지션 사이징 및 리스크 버킷을 제어한다.
- 매주 주말 리밸런싱(rebalance_required=true) 및 매월 1일/11일/21일 중간점검(mid_check_required=true) 운영 cadence를 준수한다.
- 커밋, 푸쉬, PR 작업 시 반드시 로컬의 .gs 파일을 Google Apps Script 원격 프로젝트에 업로드(python tools/deploy_gas.py 실행)하고, 사용자에게 스프레드시트 상의 스크립트 실행(예: runDataFeed)을 통한 검증을 유도 및 가이드해야 한다.
- QuantEngine 배포는 CI 전용이다. 로컬에서 서버로 산출물을 직접 업로드하거나 `scp`/`rsync`로 수동 반영하지 않는다. 실배포는 `.gitea/workflows/deploy-prod.yml`만 사용하며, 로컬 스크립트는 CI 환경에서만 실행 가능해야 한다.
- 원격 서버 확인이 필요하면 `ssh kjh2064@178.104.200.7` 접속을 먼저 시도하고, 사용자에게 매번 접속 확인을 요구하지 말고 직접 상태/로그/헬스체크를 수집한 뒤 결과만 보고한다.
## 4. 보고 규칙
- 모든 숫자에는 반드시 provenance(출처)를 남기며, 출처가 유효하지 않거나 없는 숫자는 보고서 표기를 전면 배제(DATA_MISSING 처리)한다.
@@ -135,7 +137,8 @@
- **임시 파일 관리**: 개발/디버깅 목적의 모든 휘발성 임시 파일 및 로그는 반드시 `Temp/` 디렉토리 하위에서만 생성해야 하며, 루트나 다른 패키지 경로에 임시 파일을 만드는 것은 금지한다. 불가피하게 생성할 경우 반드시 접두사/접미사 규칙(`debug_*`, `tmp_*`, `mock_*`, `*_temp.*`)을 준수하여 `.gitignore`에 필터링되도록 한다.
## 5b. Blazor & API-First 개발 규칙 (TaxBaik 참조 모델 적용)
- **API-First 아키텍처**: Blazor Server UI 계층은 비즈니스 로직이나 DB에 직접 결합되지 않고, `IXxxBrowserClient` 등의 추상화된 API 클라이언트(HTTP/RESTful)를 통해서만 백엔드 API와 통신한다.
- **렌더 모드 표준**: Blazor **Interactive WebAssembly** 를 기본 렌더 모드로 한다. InteractiveServer 는 사용하지 않으며, UI 컴포넌트는 **MudBlazor** 로 통일한다 (Fluent UI 는 폐기).
- **API-First 아키텍처**: Blazor Interactive WebAssembly UI 계층은 비즈니스 로직이나 DB에 직접 결합되지 않고, `IXxxBrowserClient` 등의 추상화된 API 클라이언트(HTTP/RESTful)를 통해서만 백엔드 API와 통신한다.
- **이중 토큰 인증 패턴**: Access Token(15분) 및 Refresh Token(7일) 이중 토큰 패턴을 적용하며, HttpClient 요청 시 401 Unauthorized를 가로채어 자동으로 localStorage의 Refresh Token으로 토큰을 자동 갱신 및 재시도하는 `TokenRefreshHandler` (DelegatingHandler) 구조를 준수한다.
- **실시간 알림 (SignalR)**: 실시간 알림 기능은 상태를 직접 동기화하는 용도가 아닌 단순 Event-driven 브로드캐스트 알림으로 설계하며, 클라이언트는 알림 수신 후 API 호출을 통해 최종 데이터를 검증 및 동기화한다.
- **UI/UX 구현**:
+60 -47
View File
@@ -7,29 +7,31 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
**QuantEngine v0.1** — A comprehensive quantitative analysis and data collection system for retirement asset portfolio management.
- **Architecture**: .NET 9 + C# (web UI + APIs), Python (legacy data collection/analysis)
- **Web UI**: Blazor WebAssembly (Fluent UI Blazor v5) + ASP.NET Core Web API
- **Web UI**: Blazor Interactive WebAssembly (MudBlazor) + ASP.NET Core Web API (API-First)
- **Database**: PostgreSQL (Npgsql 8.0), single unified database
- **Data Source**: KIS Open API (quotations/ranking read-only), with fallbacks
- **Key Runtimes**: .NET 9, Python 3.9+, Node.js 16+
### Migration Phases Status (2026-06-29)
**Phase 1: Web UI Migration** ✅ COMPLETE
- Blazor WebAssembly with Fluent UI v5 (RC: 5.0.0-rc.4-26177.1)
- MudBlazor completely deprecated (0% remaining)
**Phase 1: Web UI Migration** 🔄 정책 전환 (2026-06-30)
- **신규 표준**: Blazor **Interactive WebAssembly** 렌더 모드 + **MudBlazor** 컴포넌트 + API-First
- **이전 표준(폐기)**: Fluent UI Blazor v5 / InteractiveServer 렌더 모드는 더 이상 사용하지 않음
- Pages: Home, Workspace, Collection, Tables, MainLayout
- Build: 0 errors, 6 Razor RC warnings (acceptable)
- 코드 전환 작업은 `docs/WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md`**WBS-A7** 로 추적
**Phase 2: KIS Data Collection Pipeline** 🔄 IN PROGRESS
**Phase 2: KIS Data Collection Pipeline** ✅ 95% COMPLETE
- ✅ KIS API Client: Full implementation complete
- IKisApiClient interface (5 quotation methods)
- KisApiClient (with security enforcement, token caching)
- KisApiClient with real HTTP implementation + token caching
- All governance rules enforced (no trading APIs)
- Windows env var + registry fallback for credentials
- Build: 0 errors, 0 warnings
- ✅ PostgreSQL Infrastructure: Complete
- ITokenCache → PostgresTokenCache (token management)
- ICollectionRepository → CollectionRepository (data storage)
- IDataCollectionStore (abstraction layer)
- PostgresTokenCache (token management, 10-min skew)
- CollectionRepository (full CRUD + dashboard aggregations)
- Auto-creates kis_tokens, kis_collection_runs, kis_collection_snapshots, kis_collection_errors
- Dapper ORM + parameterized SQL (injection-proof)
- ✅ Web API Endpoints: Complete
- CollectionEndpoints (6 endpoints: state, runs, snapshots, errors, latest, start)
- ApiClient for Blazor consumption
@@ -37,7 +39,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- Collection.razor dashboard with real-time monitoring
- Summary cards, recent errors table, runs history
- Start/refresh functionality
- 🔄 Integration Testing: Pending (Python subprocess fallback active)
- FluentSkeleton loading states
- 🔄 Pipeline Orchestration: Pending
- Python `kis_data_collection_v1.py` → .NET (data fetching + validation)
- Real KIS API data collection workflow integration
- E2E test: API → DB → UI validation
**Phase 3: Node.js→.NET CLI Tools** 📋 PLANNED
- Makefile created (npm → make mappings)
@@ -78,22 +84,24 @@ sudo systemctl restart quantengine-api
### Framework & Design System
- **Primary Framework**: [Fluent UI Blazor v5](https://v5.fluentui-blazor.net/)
- **Design System**: Microsoft Fluent Design System (WCAG 2.1 AA)
- **Deprecation**: MudBlazor is deprecated. Migrate all existing pages to Fluent UI v5 progressively.
- **Primary Framework**: [MudBlazor](https://mudblazor.com/)
- **Design System**: Material Design (MudBlazor), 고밀도/대량 데이터 성능 우선
- **Render Mode**: **Interactive WebAssembly** 를 기본 렌더 모드로 한다 (API-First). InteractiveServer 는 사용하지 않는다.
- **Deprecation**: **Fluent UI Blazor v5 는 폐기**한다. 기존 Fluent UI 페이지는 MudBlazor 로 점진 이전한다.
### Component Development Rules
1. **All UI Development** (New + Refactored):
- Use Fluent UI Blazor v5 components exclusively
- Fall back to pure HTML/CSS if Fluent v5 doesn't provide
- **Never introduce MudBlazor components** (deprecated)
- Progressively migrate existing MudBlazor to Fluent v5
- Use **MudBlazor** components exclusively
- Fall back to pure HTML/CSS if MudBlazor doesn't provide
- **Never introduce Fluent UI components** (deprecated)
- Progressively migrate existing Fluent UI to MudBlazor
- **API-First**: UI 는 DB/비즈니스 로직에 직접 결합하지 않고 추상화된 API 클라이언트(HTTP)로만 통신 (AGENTS.md §5b 준수)
2. **Loading States** (Priority order):
- `<FluentSkeleton>`**Default** for lists, cards, dashboards, detail pages
- `<MudSkeleton>`**Default** for lists, cards, dashboards, detail pages
- Pure HTML `<div class="skeleton">` — For custom layouts
- `MudProgressCircular` / `MudProgressLinear`Exception only (existing legacy)
- `<MudProgressCircular>` / `<MudProgressLinear>`명시적 진행 표시가 필요한 경우
- Blocking spinners — **Avoid**
3. **Data Rendering Pattern**:
@@ -101,21 +109,22 @@ sudo systemctl restart quantengine-api
- On data arrival: Replace skeleton with actual UI
- Never show blank states while loading
4. **Component Mapping** (Fluent UI v5):
4. **Component Mapping** (MudBlazor):
| UI Element | Fluent UI Component | Alternative |
| UI Element | MudBlazor Component | Alternative |
|-----------|-------------------|-------------|
| Button | `<FluentButton>` | - |
| Input field | `<FluentTextField>` | HTML `<input>` |
| Dropdown | `<FluentSelect>` | HTML `<select>` |
| Data grid | `<FluentDataGrid>` | HTML `<table>` |
| Card | `<FluentCard>` | HTML `<div class="card">` |
| Badge/Status | `<FluentBadge>` | HTML `<span>` |
| Layout container | `<FluentStack>` | HTML `<div>` |
| Accordion | `<FluentAccordion>` | HTML `<details>` |
| Navigation | `<FluentNavMenu>` | HTML `<nav>` |
| Loading | `<FluentSkeleton>` | CSS skeleton animation |
| Icons | `<FluentIcon>` | SVG inline |
| Button | `<MudButton>` | - |
| Input field | `<MudTextField>` | HTML `<input>` |
| Dropdown | `<MudSelect>` | HTML `<select>` |
| Data grid | `<MudDataGrid Dense Virtualize>` | HTML `<table>` |
| Card | `<MudCard>` | HTML `<div class="card">` |
| Badge/Status | `<MudBadge>` / `<MudChip>` | HTML `<span>` |
| Layout container | `<MudStack>` / `<MudGrid>` | HTML `<div>` |
| Accordion | `<MudExpansionPanels>` | HTML `<details>` |
| Navigation | `<MudNavMenu>` | HTML `<nav>` |
| Loading | `<MudSkeleton>` | CSS skeleton animation |
| Icons | `<MudIcon>` | SVG inline |
| Modal/Dialog | `<MudDialog>` (CRUD: 모달 패턴, 삭제: ConfirmDialog) | - |
## Development Commands (Phase 1 + 2)
@@ -130,29 +139,33 @@ npm run ops:release # Full release DAG
### .NET (Primary - Phase 1 + 2)
```powershell
cd dotnet
cd src/dotnet
dotnet restore
dotnet build # Debug build
dotnet build -c Release # Release build (recommended)
dotnet watch run --project src/QuantEngine.Web # Hot-reload (http://localhost:5000)
dotnet run --project src/QuantEngine.Web # Run API server
dotnet build # Debug build (0 errors, 0 warnings)
dotnet build -c Release # Release build
dotnet watch run --project QuantEngine.Web # Hot-reload (http://localhost:5265)
dotnet run --project QuantEngine.Web # Run API server
```
### Collection Pipeline Testing (Phase 2)
```powershell
# Set credentials (Windows environment variables)
$env:KIS_APP_Key_TEST = "mock_key"
$env:KIS_APP_Secret_TEST = "mock_secret"
# Set KIS credentials (sandbox account)
$env:KIS_APP_Key_TEST = "your_kis_test_key"
$env:KIS_APP_Secret_TEST = "your_kis_test_secret"
# Verify Blazor Collection page
# Navigate to http://localhost:5000/collection
# Start web server (http://localhost:5265)
dotnet run --project QuantEngine.Web
# Verify Collection dashboard
# Navigate to http://localhost:5265/collection
# - Click "Start Collection" to trigger async run
# - API initiates Python subprocess (temporary Phase 2 design)
# - Backend uses PostgreSQL-backed data storage
# - Dashboard updates with run status, snapshots, errors
# Verify API directly
curl http://localhost:5000/api/collection/state
curl http://localhost:5000/api/collection/runs
# Verify API endpoints
curl http://localhost:5265/api/collection/state
curl http://localhost:5265/api/collection/runs
curl "http://localhost:5265/api/collection/latest/005930"
```
## API Endpoints (Phase 1 + 2)
+1 -1
View File
@@ -144,7 +144,7 @@ npm run prepare-upload-zip
## CI / 배포 분리
- `.gitea/workflows/ci.yml`은 검증 전용이다.
- `.gitea/workflows/snapshot_admin_deploy.yml`은 실배포 전용이다.
- `.gitea/workflows/deploy-prod.yml`은 실배포 전용이다.
- 공개 URL `http://178.104.200.7/quant/` 갱신은 deploy workflow 성공 여부로 판단한다.
## 운영 리포트 계약
+79
View File
@@ -0,0 +1,79 @@
# HTTP 80 ➜ HTTPS 443 Redirect
server {
listen 80;
listen [::]:80;
server_name taxbaik.com www.taxbaik.com gitea.taxbaik.com quant.taxbaik.com;
return 301 https://$host$request_uri;
}
# TaxBaik 홈페이지 (통합 앱)
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name taxbaik.com www.taxbaik.com;
ssl_certificate /etc/letsencrypt/live/taxbaik.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/taxbaik.com/privkey.pem;
client_max_body_size 512M;
location / {
proxy_pass http://127.0.0.1:5001/taxbaik/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Gitea (코드 저장소)
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name gitea.taxbaik.com;
ssl_certificate /etc/letsencrypt/live/taxbaik.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/taxbaik.com/privkey.pem;
client_max_body_size 512M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
}
}
# QuantEngine (Blazor Admin)
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name quant.taxbaik.com;
ssl_certificate /etc/letsencrypt/live/taxbaik.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/taxbaik.com/privkey.pem;
client_max_body_size 512M;
location / {
proxy_pass http://127.0.0.1:5000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
+62 -68
View File
@@ -16,8 +16,8 @@
| 3.2 | [Python 가상 환경](#32-python-가상-환경) | `~/.venv`, `python3` 사용 규칙 |
| 3.3 | [주요 Python 패키지](#33-주요-python-패키지-시스템) | 시스템/venv 패키지 구분 |
| 4 | [서비스 아키텍처](#4-서비스-아키텍처) | 포트 맵, Nginx 리버스 프록시 |
| 4.1 | [포트 맵](#41-포트-맵) | 22, 80, 2222, 3000, 5000, 5432 |
| 4.2 | [Nginx 리버스 프록시](#42-nginx-리버스-프록시) | `/` → Gitea, `/quant/` → Blazor |
| 4.1 | [포트 맵](#41-포트-맵) | 22, 80, 443, 2222, 3000, 5000, 5001, 5432 |
| 4.2 | [Nginx 리버스 프록시](#42-nginx-리버스-프록시) | 도메인 가상 호스트 기반 분기 |
| 5 | [Gitea](#5-gitea) | Docker Compose 설정, 시크릿, 데이터 경로 |
| 5.1 | [Docker Compose](#51-docker-compose) | `gitea:1.26.4`, PG 연동 |
| 5.2 | [시크릿 관리](#52-시크릿-관리) | `/opt/stacks/gitea/.env` |
@@ -117,55 +117,30 @@ boto3, cryptography, Jinja2, jsonschema, fail2ban 등 시스템 레벨로 설치
| 포트 | 서비스 | 바인드 | 비고 |
|---|---|---|---|
| **22** | SSH | `0.0.0.0` | 공개키 전용 |
| **80** | Nginx (리버스 프록시) | `0.0.0.0` | 외부 진입점 |
| **80** | Nginx (HTTP) | `0.0.0.0` | 443 HTTPS로 리다이렉트 |
| **443** | Nginx (HTTPS) | `0.0.0.0` | SSL 가상 호스트 진입점 |
| **2222** | Gitea SSH | `0.0.0.0` | Git SSH 접속 |
| **3000** | Gitea Web | `127.0.0.1` | Nginx 프록시 경유 |
| **5000** | QuantEngine Blazor | `127.0.0.1` | Nginx `/quant/` 경유 |
| **3000** | Gitea Web | `127.0.0.1` | Nginx 프록시 경유 (`gitea.taxbaik.com`) |
| **5000** | QuantEngine Blazor | `127.0.0.1` | Nginx 프록시 경유 (`quant.taxbaik.com`) |
| **5001** | TaxBaik 홈페이지 | `127.0.0.1` | Nginx 프록시 경유 (`taxbaik.com` / `www.taxbaik.com`) |
| **5432** | PostgreSQL | `127.0.0.1` + `172.17.0.1` | 로컬 + Docker 네트워크 |
### 4.2. Nginx 리버스 프록시
```nginx
# /etc/nginx/sites-enabled/gitea-ip.conf
도메인 기반 가상 호스트(Virtual Host) 방식을 사용하여 각 도메인 요청을 내부 서비스로 연결하고, SSL(HTTPS)을 필수로 적용합니다. HTTP(80) 포트 요청은 자동으로 HTTPS(443)로 리다이렉트됩니다.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
client_max_body_size 512M;
상세 Nginx 설정 백업은 `deploy/nginx-taxbaik-domains.conf`에 위치합니다.
# QuantEngine Blazor Web App
location /quant/ {
proxy_pass http://127.0.0.1:5000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Gitea (기본)
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
}
}
```
#### 가상 호스트 설정 개요
- **TaxBaik 홈페이지** (`https://taxbaik.com`, `https://www.taxbaik.com`) ➜ `http://127.0.0.1:5001/taxbaik/`
- **Gitea (코드 저장소)** (`https://gitea.taxbaik.com`) ➜ `http://127.0.0.1:3000`
- **QuantEngine (Blazor Admin)** (`https://quant.taxbaik.com`) ➜ `http://127.0.0.1:5000/`
**라우팅 요약**:
- `http://178.104.200.7/` → Gitea Web UI
- `http://178.104.200.7/quant/` → QuantEngine Blazor Admin
- `ssh://178.104.200.7:2222` → Gitea Git SSH
- `https://taxbaik.com` & `https://www.taxbaik.com` ➜ TaxBaik 홈페이지 (통합 앱)
- `https://gitea.taxbaik.com` ➜ Gitea Web UI
- `https://quant.taxbaik.com` ➜ QuantEngine Blazor Admin
- `ssh://git@gitea.taxbaik.com:2222` ➜ Gitea Git SSH
## 5. Gitea
@@ -231,8 +206,9 @@ services:
### 6.4. CI / 배포 분리
- `.gitea/workflows/ci.yml`: 검증 전용. 스펙/공식/리포트/아티팩트 생성까지만 수행한다.
- `.gitea/workflows/snapshot_admin_deploy.yml`: 실배포 전용. `dotnet publish``tools/deploy_quantengine.sh`를 이용해 `/home/kjh2064/quantengine_active`로 반영한다.
- 공개 URL `/quant/` 갱신`snapshot_admin_deploy.yml`의 성공 여부를 기준으로 판단한다.
- `.gitea/workflows/deploy-prod.yml`: 실배포 전용. `dotnet publish``tools/deploy_quantengine.sh`를 이용해 `/home/kjh2064/quantengine_active`로 반영한다.
- 수동 배포 금지: 로컬에서 `scp`/`rsync``quantengine_active` 갱신하지 않는다. 배포는 CI가 원격에서만 수행하고, 로컬 스크립트는 `CI_DEPLOY=1` 없이 실행되면 실패해야 한다.
- 공개 URL 갱신은 `deploy-prod.yml`의 성공 여부를 기준으로 판단한다.
### 6.2. 러너 설정
@@ -335,8 +311,8 @@ ClientAliveCountMax 2
- **상태**: `ENABLED=yes` (`/etc/ufw/ufw.conf`)
- **로그 레벨**: `low`
- **외부 개방 포트**: 22 (SSH), 80 (HTTP/Nginx), 2222 (Gitea SSH)
- **내부 전용**: 3000 (Gitea Web), 5000 (QuantEngine), 5432 (PostgreSQL)
- **외부 개방 포트**: 22 (SSH), 80 (HTTP), 443 (HTTPS), 2222 (Gitea SSH)
- **내부 전용**: 3000 (Gitea Web), 5000 (QuantEngine), 5001 (TaxBaik Web), 5432 (PostgreSQL)
> 상세 규칙 확인: `sudo ufw status numbered` (TTY + sudo 비밀번호 필요)
@@ -349,8 +325,9 @@ ClientAliveCountMax 2
- Gitea Web: `127.0.0.1:3000` (로컬 전용)
- QuantEngine: `127.0.0.1:5000` (로컬 전용)
- TaxBaik Web: `127.0.0.1:5001` (로컬 전용)
- PostgreSQL: `127.0.0.1` + Docker bridge (`172.17.0.1`)
- 외부 노출: SSH(22), HTTP(80), Gitea SSH(2222)만 개방
- 외부 노출: SSH(22), HTTP(80), HTTPS(443), Gitea SSH(2222)만 개방
## 10. 디렉토리 맵
@@ -390,7 +367,7 @@ ClientAliveCountMax 2
| **CI Runner** | Synology Act Runner | 6× `act_runner:latest` (Docker) |
| **DB** | SQLite (파일 기반) | PostgreSQL 18 + SQLite (하이브리드) |
| **웹 Admin** | 없음 | QuantEngine Blazor (.NET 10, MudBlazor) |
| **리버스 프록시** | Synology 내장 | Nginx (`/` → Gitea, `/quant/` → Blazor) |
| **리버스 프록시** | Synology 내장 | Nginx 도메인 가상 호스트 및 SSL (HTTPS) 적용 (`deploy/nginx-taxbaik-domains.conf`) |
| **보안** | DSM 방화벽 | fail2ban + SSH 공개키 + 서비스 로컬바인드 |
| **시크릿 관리** | `.secrets/kis_real.env` | `/opt/stacks/gitea/.env` |
| **OS** | Synology DSM 7.x | Ubuntu 26.04 LTS |
@@ -425,19 +402,9 @@ docker ps -a
### QuantEngine 배포
```bash
# 1. 새 배포 디렉토리 생성
DEPLOY_DIR=~/deployments/quantengine_$(date +%Y%m%d_%H%M%S)
mkdir -p "$DEPLOY_DIR"
# 2. 빌드 산출물 복사 (로컬에서 scp 또는 CI에서)
scp -r publish/* kjh2064@178.104.200.7:"$DEPLOY_DIR"/
# 3. symlink 교체
ln -sfn "$DEPLOY_DIR" ~/quantengine_active
# 4. 서비스 재시작
sudo systemctl restart quantengine
sudo systemctl status quantengine
# CI에서만 배포
# 로컬에서 scp/rsync로 quantengine_active를 갱신하지 않는다.
# 배포는 .gitea/workflows/deploy-prod.yml 실행 결과로만 반영한다.
```
### Gitea Act Runner 등록
@@ -452,14 +419,20 @@ docker run -d \
gitea/act_runner:latest
```
### SSH 접속
### SSH 접속 및 Git 원격 설정
```bash
# Windows 로컬에서
# Windows 로컬에서 서버 SSH 접속
ssh kjh2064@178.104.200.7
# Gitea Git 접속
git remote set-url origin ssh://git@178.104.200.7:2222/kjh2064/QuantEngineByItz.git
# 로컬 프로젝트의 Git Remote URL 변경 (Gitea 도메인 기반 HTTPS 적용)
# 1) 현재 설정된 remote url 확인
git remote -v
# 2) 새로운 도메인 주소로 원격 URL 변경
git remote set-url origin https://gitea.taxbaik.com/kjh2064/QuantEngineByItz.git
# Gitea Git SSH 접속 (기존 2222 포트 유지)
git remote set-url origin ssh://git@gitea.taxbaik.com:2222/kjh2064/QuantEngineByItz.git
```
## 13. 검증 하네스
@@ -514,6 +487,27 @@ ssh -T -p 2222 git@178.104.200.7 2>&1 | head -1
---
> **수집 일시**: 2026-06-26 09:55 KST
> **수집 방법**: `ssh kjh2064@178.104.200.7` 라이브 명령 실행
> **provenance**: 모든 값은 서버 실시간 명령 출력에서 추출. 임의 값 없음.
## 14. 트러블슈팅 (Troubleshooting)
### 14.1. Certbot / APT 패키지 설치 시 Microsoft 리포지토리 404 오류
- **증상**: `sudo apt-get update` 실행 시 Microsoft 패키지 저장소에서 `404 Not Found` 에러가 발생하며 패키지 목록 갱신이 중단되고, 이로 인해 `certbot` 설치가 `sudo: certbot: command not found` 에러로 실패하는 현상.
- **원인**: Ubuntu 26.04 (Resolute) 환경에서 Microsoft의 잘못된 리포지토리(26.04 경로에 focal/20.04 릴리스가 설정된 상태)를 참조하여 발생.
- **해결 방안**:
1. 문제가 되는 Microsoft apt 소스 설정 파일을 삭제하거나 비활성화합니다.
```bash
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
```
2. APT 패키지 목록을 다시 업데이트하고 Certbot 및 Nginx 플러그인을 설치합니다.
```bash
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
```
3. 인증서 발급 및 설정을 적용합니다.
```bash
sudo certbot --nginx -d taxbaik.com -d www.taxbaik.com -d gitea.taxbaik.com -d quant.taxbaik.com --register-unsafely-without-email --agree-tos --non-interactive
```
---
> **수집 일시**: 2026-06-26 09:55 KST (추가 업데이트: 2026-07-01)
> **수집 방법**: `ssh kjh2064@178.104.200.7` 라이브 명령 및 트러블슈팅 사례 수집
> **provenance**: 모든 값은 서버 실시간 명령 출력 및 실제 오류 대처 조치 로그에서 추출. 임의 값 없음.
+5 -5
View File
@@ -9,7 +9,7 @@ This document outlines the security configuration, role definitions, and access
The Quant Investment Engine operates strictly within the `quantengine` schema to prevent namespace pollution and protect system catalog tables.
* **Schema**: `quantengine`
* **Default Database**: `giteadb`
* **Default Database**: `quantenginedb`
---
@@ -22,7 +22,7 @@ To ensure the principle of least privilege, we define three main database roles:
* **Permissions**:
```sql
CREATE ROLE quantengine_owner WITH LOGIN PASSWORD 'OwnerPasswordSecure';
GRANT ALL PRIVILEGES ON DATABASE giteadb TO quantengine_owner;
GRANT ALL PRIVILEGES ON DATABASE quantenginedb TO quantengine_owner;
GRANT ALL PRIVILEGES ON SCHEMA quantengine TO quantengine_owner;
ALTER DEFAULT PRIVILEGES IN SCHEMA quantengine GRANT ALL ON TABLES TO quantengine_owner;
```
@@ -32,7 +32,7 @@ To ensure the principle of least privilege, we define three main database roles:
* **Permissions**:
```sql
CREATE ROLE quantengine_app WITH LOGIN PASSWORD 'AppPasswordSecure';
GRANT CONNECT ON DATABASE giteadb TO quantengine_app;
GRANT CONNECT ON DATABASE quantenginedb TO quantengine_app;
GRANT USAGE ON SCHEMA quantengine TO quantengine_app;
-- Grant CRUD permissions on tables & sequences
@@ -48,7 +48,7 @@ To ensure the principle of least privilege, we define three main database roles:
* **Permissions**:
```sql
CREATE ROLE quantengine_readonly WITH LOGIN PASSWORD 'ReadonlyPasswordSecure';
GRANT CONNECT ON DATABASE giteadb TO quantengine_readonly;
GRANT CONNECT ON DATABASE quantenginedb TO quantengine_readonly;
GRANT USAGE ON SCHEMA quantengine TO quantengine_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA quantengine TO quantengine_readonly;
@@ -63,7 +63,7 @@ To ensure the principle of least privilege, we define three main database roles:
* Never store connection strings with plaintext passwords in version control.
* `appsettings.json` must only contain placeholder configurations.
* Inject the connection string at runtime using environment variables:
`ConnectionStrings__DefaultConnection="Host=127.0.0.1;Database=giteadb;Username=quantengine_app;Password=YourSecurePassword;Search Path=quantengine;"`
`ConnectionStrings__DefaultConnection="Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=YourSecurePassword;Search Path=quantengine;"`
2. **Network Security**:
* Bind PostgreSQL only to local interfaces (`127.0.0.1`) or secure private network interfaces.
+4 -2
View File
@@ -925,7 +925,7 @@ python tools/validate_specs.py → PASS
|------|------|
| **작업** | `src/quant_engine/snapshot_admin_server_v1.py`(Python 어드민 웹 UI)를 Gitea CI/CD 배포 스텝을 통해 Synology NAS에서 상시 서비스로 운영할 수 있는지 검토 |
| **현재 상태** | **기술적으로는 가능**. 기본 루프백 보호 + Basic Auth 게이트를 추가했고, Synology 외부 노출은 리버스 프록시 기반 POC로 가이드함. 실배포 검증은 아직 필요 |
| **운영 분리** | `snapshot_admin.yml``push`용 smoke 검증과 `workflow_dispatch`용 full 검증으로 분리하고, 배포는 별도 `snapshot_admin_deploy.yml` `workflow_dispatch`로 떼어냈다. `push`에서는 `Validate Snapshot Admin Workflow`까지만, full 검증에서는 `Validate Snapshot Admin Web UI`까지 수행한다. |
| **운영 분리** | `snapshot_admin.yml``push`용 smoke 검증과 `workflow_dispatch`용 full 검증으로 분리하고, 배포는 별도 `deploy-prod.yml` `workflow_dispatch`로 떼어냈다. `push`에서는 `Validate Snapshot Admin Workflow`까지만, full 검증에서는 `Validate Snapshot Admin Web UI`까지 수행한다. |
| **runner 주의** | Gitea runner를 Docker mode로 두면 job 종료 시 `Cleaning up container` 로그가 남는다. host label로 재등록하면 job container 정리 로그를 피할 수 있다. |
| **KIS 분리** | `kis_data_collection.yml``workflow_dispatch`용 mock/config smoke와 `schedule`용 live collection으로 분리했다. 수동 디스패치는 실제 수집을 돌리지 않고, 실수집은 스케줄 전용이다. |
| **담당 파일** | `.gitea/workflows/ci.yml`, `tools/run_snapshot_admin_server_v1.py`, `src/quant_engine/snapshot_admin_server_v1.py`, `docs/SYNOLOGY_SNAPSHOT_ADMIN_POC.md`, `docs/WBS_7_9_EVIDENCE_PACKET_FINAL.md` |
@@ -1378,6 +1378,8 @@ WBS-8.8 (KIS 리팩터) — 독립적 (원격 병행)
### WBS-10: C#/.NET 엔진 고도화 (Phase 10, 2026-06~12)
> **📌 보강 문서(2026-06-30):** 본 WBS-10 의 다수 항목이 `완료` 표기되어 있으나 실측 결과 일부 괴리(10.6 파이프라인·10.9 보안 실질 미완성)가 확인되었다. 마이그레이션 완성 우선 + 상용화 잔여 작업의 재정의는 [WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md](./WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md) 참조.
> 현황 진단(2026-06-26): .NET 프로젝트는 Python 엔진(41 모듈, 14,500 LOC) 대비 5~10%(~1,400 LOC) 수준.
> Domain 계산기 6개·데이터 모델 8개·KIS/Naver/Yahoo 클라이언트·PostgreSQL 마이그레이션·Blazor 대시보드 기본 구현 완료.
> **미구현**: Application 서비스 일부, 공식 엔진, 하네스 주입, 파이프라인 오케스트레이터.
@@ -1649,7 +1651,7 @@ WBS-10.1 (기반 결함 수정)
| 10.10.2 | Dashboard 상태 페이지 — 데이터 비의존형 요약으로 단순화 | DB 실패 시에도 200 응답 (완료) |
| 10.10.3 | Counter.razor / Weather.razor 기본 페이지 삭제, NavMenu 정비 | 불필요 페이지 0건, NavMenu에 Dashboard/Operations만 표시 (완료) |
| 10.10.4 | 다크 모드 + 반응형 레이아웃 적용 | 브라우저 렌더링 정상 확인 (완료) |
| 10.10.5 | 배포 동기화 | `snapshot_admin_deploy.yml` `/quant/``/quant/operations` 공개 라우트를 배포 후 검증하도록 구성됨 (완료) |
| 10.10.5 | 배포 동기화 | `deploy-prod.yml`가 공개 라우트를 배포 후 검증하도록 구성됨 (완료) |
**성공 하네스 (데이터 기준)**:
```
@@ -0,0 +1,190 @@
# WBS-10 보강: .NET Core 마이그레이션 완성 & 상용화 로드맵 (2026-06-30)
> 본 문서는 [docs/ROADMAP_WBS.md](./ROADMAP_WBS.md) 의 **WBS-10(.NET 엔진 고도화)** 을 현 시점 실측 기준으로 재진단하고, 마이그레이션 완성과 단일 사용자 상용 운영에 필요한 잔여 작업을 재정의한다.
>
> **작성 배경:** 기존 WBS-10 의 다수 항목이 `완료` 로 표기되어 있으나, 2026-06-30 소스 실측 결과 **표기와 실제 상태 간 괴리**가 확인되었다. 본 문서는 그 괴리를 정리하고 실제 잔여 작업을 추적한다.
>
> **의사결정(사용자 확정):** ① 우선순위 = **마이그레이션 완성 우선**, ② 산출물 = **로드맵/WBS 문서**, ③ 인증 모델 = **단일 사용자 + 기본 보호**.
---
## 1. Context — 왜 이 보강이 필요한가
QuantEngine 은 은퇴자산 포트폴리오 운용을 위한 결정론적 퀀트 엔진이다. canonical 권위는 여전히 **Python 구현(219 파일, 24,683 lines)** 에 있고, `.NET 10` 마이그레이션은 Core / Application / Infrastructure / Web / Tools / Tests 6개 프로젝트로 구조화되어 Phase 1(Web UI)·Phase 2(KIS 수집)까지 도달했다.
그러나 다음 세 가지 근본 결손으로 마이그레이션 완료 및 상용 기준에 미달한다.
1. **마이그레이션 미완성** — 도메인 단일 권위가 Python 에 잔존. `PipelineOrchestrator` 가 실제 로직이 아닌 시뮬레이션 스텁. Python↔.NET 패리티가 일부 도메인 계산기에만 존재. GAS 공식 14건 미이관.
2. **상용 운영 결손** — 소스에 하드코딩 시크릿 잔존, `.gitignore``bin/obj` 누락으로 빌드 산출물 git 추적, 헬스체크·메트릭·재시도·스케줄러·운영 구성(`appsettings.Production.json`) 부재.
3. **검증 공백** — KIS→스냅샷→정성매도 전 구간 E2E 와 CI 커버리지 게이트 부재.
---
## 2. 표기 vs 실제 괴리 정리 (2026-06-30 실측)
| 기존 WBS | 기존 표기 | 실측 상태 | 괴리 / 조치 |
|---|---|---|---|
| WBS-10.6 파이프라인 오케스트레이터 | **완료** | `PipelineOrchestrator.cs` 가 각 단계를 `Task.Delay(10)` 로만 시뮬레이션. 실제 서비스 호출 없음 | 🔴 **실질 미완성.** → 본 문서 **A1** 로 재추적 |
| WBS-10.9 보안 강화 | **완료** | `appsettings.json``Password=;` 처리됨. 그러나 `Program.cs:19` 텔레그램 토큰 평문, `Program.cs:34` DB 패스워드 폴백 평문 잔존. `.gitignore``bin/obj` 없음 → 산출물 git 추적 | 🔴 **부분 완료(핵심 누락).** → 본 문서 **P0** 로 재추적 |
| WBS-10.8 데이터 수집 오케스트레이터 | **TODO** | 실제로는 `DataCollectionService.cs`(KIS 수집 오케스트레이션) 구현·커밋됨. 단 파일명/구조가 WBS 기재(`DataCollectionOrchestrator.cs`)와 불일치 | 🟡 **표기 미갱신.** → 본 문서 **A3** 로 정합화 |
| WBS-10.3~10.5 도메인/공식/하네스 패리티 | 완료 | `DomainParityTests`, `FormulaEngineTests`, `HarnessInjector` 패리티 존재 확인 | ✅ 유효. 단 패리티 범위가 도메인 계산기에 한정 → 수집/정성매도/스냅샷은 미커버 (**A2** 확장) |
| WBS-10.7 Application 서비스 | 부분 완료 | 4개 서비스 구현 확인 | ✅ 유효 |
> **핵심 시사점:** 기존 WBS-10 은 "완료" 표기가 실제보다 앞서 있다. 특히 보안(10.9)과 파이프라인(10.6)은 표기와 달리 **실질 미완성**이므로, 후속 작업은 표기를 신뢰하지 말고 본 문서의 실측 기준을 따른다.
---
## 3. 로드맵 (마이그레이션 완성 우선)
```
[P0 선행 게이트] 보안·위생 차단 ──► 반드시 먼저
[Track A] 마이그레이션 완성 (PRIMARY) [Track B] 상용 안정화 (SECONDARY, 병행)
A1 PipelineOrchestrator 실구현 B1 구성/시크릿 체계화
A2 패리티 하네스 확장(수집·정성매도) B2 기본 인증(단일 사용자)
A3 데이터 수집 파이프라인 E2E 정합화 B3 헬스체크·메트릭
A4 정성매도/스냅샷 어드민 포팅 B4 재시도(Polly)·스케줄러
A5 GAS 잔여 14개 공식 이관 B5 배포(Docker/CI 게이트)
A6 SQLite→PostgreSQL 단일화 + Python 폐기 B6 통합/E2E 테스트·커버리지 게이트
```
### 마일스톤
| 마일스톤 | 구성 | 완료 기준 |
|---|---|---|
| **M1 위생 확보** | P0 | git 에서 시크릿/산출물 제거, 시크릿 외부화·회전 |
| **M2 패리티 기반** | A1·A2 | `.NET` 도메인이 Python 골든 벡터와 1:1 일치, 실 파이프라인 산출 |
| **M3 수집 자립** | A3·A4·B4 | `.NET` 단독 KIS→스냅샷→정성매도 무인 실행 |
| **M4 단일 권위 전환** | A5·A6 | Python 런타임 의존 제거, `.NET` canonical 승격 |
| **M5 상용 운영** | B1~B6 | 단일 사용자 보호·관측·배포 체계 가동 |
---
## 4. WBS (작업 분해 구조)
각 항목: **목표 / 완료 판정(Acceptance) / 주요 파일 / 검증 명령**.
### P0 — 선행 보안·위생 게이트 (🔴 Critical, 최우선)
#### WBS-P0.1 빌드 산출물 git 추적 제거
- **목표:** `.gitignore` 에 .NET 표준 패턴(`bin/`, `obj/`, `publish-output/`, `*.user`) 추가, 추적 중 산출물 `git rm -r --cached` 처리.
- **판정:** `git status``bin/obj` 변경 미표시.
- **파일:** `.gitignore`.
- **검증:** `git status --porcelain | grep -E 'bin/|obj/'` → 0건.
#### WBS-P0.2 하드코딩 시크릿 제거·회전
- **목표:** `Program.cs:19` 텔레그램 토큰·채팅ID, `Program.cs:34` DB 패스워드 폴백을 환경변수/`dotnet user-secrets`/`appsettings.Production.json`(비추적)로 이전. 노출 토큰·DB 비밀번호 **회전**.
- **판정:** 소스 전역 시크릿 평문 0건, 구성 누락 시 앱 기동 거부(fail-fast).
- **파일:** `Program.cs`, `appsettings*.json`, `Infrastructure/TelegramSink.cs`.
- **검증:** `Select-String -Pattern '8734507814|C8RFlZ9f' src/dotnet -Recurse` → 0건.
#### WBS-P0.3 git 이력 시크릿 정리 (선택)
- **목표:** 노출 토큰 회전 완료 시 이력 재작성 생략 가능. 회전 불가 시 `git filter-repo` 로 이력 제거 검토.
- **판정:** 회전 완료 또는 이력 정리 완료 중 택1 기록.
> **주의:** WBS-10.9 가 `완료` 로 표기되어 있으나 위 P0.1·P0.2 는 미해결 상태다. 본 게이트 완료 전까지 후속 트랙 착수를 보류한다.
### Track A — 마이그레이션 완성 (PRIMARY)
#### WBS-A1 PipelineOrchestrator 실제 구현
- **목표:** `Task.Delay` 시뮬레이션 제거. 7단계(수집→정규화→팩터→결정→리스크게이트→리포트→영속화)를 실제 서비스 호출로 연결.
- **판정:** 입력 스냅샷에 대해 결정 패킷 산출, 각 단계 결과가 `engine_history` 에 기록.
- **파일:** `QuantEngine.Application/Services/PipelineOrchestrator.cs`, 관련 `Services/*`.
- **검증:** `dotnet test --filter Pipeline` → 실데이터 기반 산출물 `gate: PASS`.
#### WBS-A2 패리티 하네스 확장 (수집·정성매도)
- **목표:** 기존 도메인 계산기 패리티(10.3~10.5)를 **수집 정규화·정성매도·하네스 주입 전체**로 확장. `spec/13_formula_registry.yaml`(149 공식) 기준 골든 벡터를 Python 에서 추출해 `.NET` 결과와 비교.
- **판정:** 핵심 공식 전부 Python 과 동일 출력(부동소수 허용오차 내), 패리티 리포트 JSON 생성.
- **파일:** `QuantEngine.Core.Tests/ParityTests/`, `tests/golden/`.
- **검증:** `dotnet test --filter Parity` → 전건 PASS.
#### WBS-A3 데이터 수집 파이프라인 E2E 정합화
- **목표:** `DataCollectionService.cs`(구현됨)를 기준으로 WBS 표기 정합화, `kis_data_collection_v1.py` 잔여 로직 완전 이관, KIS→PostgreSQL 스냅샷 E2E 검증. Naver/Yahoo 폴백 다중화 명문화.
- **판정:** `.NET` 단독 실데이터 수집·저장 성공, 폴백 동작 확인.
- **파일:** `Application/Services/DataCollectionService.cs`, `Infrastructure/External/*`.
#### WBS-A4 정성매도·스냅샷 어드민 포팅
- **목표:** `qualitative_sell_strategy_v1.py`, `snapshot_admin_*_v1.py``.NET` 서비스/엔드포인트로 이관.
- **판정:** 정성매도 5팩터 confluence 결과 Python 일치, 스냅샷 승인 워크플로우가 Web UI 에서 동작.
- **파일:** `QuantEngine.Core/Domain/`, `QuantEngine.Web/Endpoints/`, `Components/Pages/`.
#### WBS-A5 GAS 잔여 14개 공식 이관
- **목표:** `governance/gas_logic_migration_ledger_v1.yaml` 의 TODO 14건을 `.NET` 포팅 + parity.
- **판정:** 원장 전 항목 `status: DONE`, parity 통과.
- **파일:** `QuantEngine.Core/Domain/`, `governance/gas_logic_migration_ledger_v1.yaml`.
#### WBS-A6 SQLite→PostgreSQL 단일화 및 Python 런타임 폐기
- **목표:** canonical DB 를 PostgreSQL 로 일원화, `src/quant_engine/*.db` 의존 제거, Python 런타임 도구를 `.NET`/`Tools` 로 대체.
- **판정:** 운영 경로 Python 호출 0건, 모든 데이터 PostgreSQL 단일 소스.
- **파일:** `Infrastructure/Data/DbMigrator.cs`, `Makefile`, `tools/`.
#### WBS-A7 UI 프레임워크 전환 — Fluent UI → MudBlazor + Interactive WebAssembly (2026-06-30 방침)
- **배경:** UI 표준을 **MudBlazor** 컴포넌트 + **Interactive WebAssembly** 렌더 모드 + **API-First** 로 전환(방침 확정). 기존 Fluent UI v5 / InteractiveServer 는 폐기. 정책은 [CLAUDE.md](../CLAUDE.md) 및 [AGENTS.md](../AGENTS.md) §5b 에 반영 완료.
- **목표:**
- csproj 패키지 교체: `Microsoft.FluentUI.AspNetCore.Components*` 제거 → `MudBlazor` 추가.
- 렌더 모드 전환: `Program.cs``AddInteractiveServerComponents`/`AddInteractiveServerRenderMode``AddInteractiveWebAssemblyComponents`/`AddInteractiveWebAssemblyRenderMode`, 클라이언트 프로젝트(`QuantEngine.Web.Client`) 분리.
- `App.razor`: Fluent CSS/JS·`FluentDesignSystemProvider` 제거 → MudBlazor `<MudThemeProvider>`/`<MudDialogProvider>`/`<MudSnackbarProvider>` + `MudBlazor.min.css/js` 삽입.
- 전체 `.razor` 컴포넌트의 `Fluent*``Mud*` 치환(매핑표는 [CLAUDE.md](../CLAUDE.md) Component Mapping 참조).
- API-First: UI 의 직접 DI 호출을 `IXxxBrowserClient`(HTTP) 경유로 전환, `TokenRefreshHandler` 패턴 적용.
- **판정:** Fluent UI 패키지/참조 0건, `dotnet build` 오류 0, WASM 로드 후 `/quant/` 및 주요 페이지 정상 렌더, 비-API 라우트 동작 확인.
- **주요 파일:** `QuantEngine.Web/QuantEngine.Web.csproj`, `Program.cs`, `Components/App.razor`, `Components/Layout/*.razor`, `Components/Pages/*.razor`, 신규 `QuantEngine.Web.Client/`.
- **검증:** `Select-String -Pattern 'Fluent' src/dotnet/QuantEngine.Web -Recurse` → 0건; 브라우저에서 WASM 모드 동작 확인.
### Track B — 상용 안정화 (SECONDARY, 단일 사용자)
#### WBS-B1 구성·시크릿 체계화
- **목표:** `appsettings.Production.json`(비추적), `IOptions<T>` + 시작 시 구성 검증(fail-fast), 연결 문자열/토큰 환경변수 표준화.
- **판정:** 개발/운영 구성 분리, 필수 구성 누락 시 명확 오류로 기동 중단.
#### WBS-B2 기본 인증 (단일 사용자 보호)
- **목표:** 공개 서버 노출 방어용 최소 인증 — 리버스 프록시 Basic Auth 또는 API Key 미들웨어 1종(`/api/*`·UI 보호). 본격 Identity/JWT 는 범위 외.
- **판정:** 비인증 요청 401, 인증 요청만 수집/조회 가능.
- **파일:** `Program.cs`, `Endpoints/CollectionEndpoints.cs`, Nginx 구성.
#### WBS-B3 헬스체크·메트릭
- **목표:** `MapHealthChecks("/health")`(liveness) + `/health/ready`(PostgreSQL/KIS 토큰 점검), `prometheus-net` 기반 기본 메트릭.
- **판정:** 배포 스크립트 헬스체크가 `/health/ready` 사용, 메트릭 엔드포인트 응답.
- **파일:** `Program.cs`, `.gitea/workflows/deploy-prod.yml`.
#### WBS-B4 재시도(Polly)·백그라운드 스케줄러
- **목표:** KIS/Naver/Yahoo HTTP 호출에 Polly 재시도·서킷브레이커, 주기적 수집을 `BackgroundService`(또는 systemd timer 연계)로 자동화.
- **판정:** 일시적 5xx/네트워크 오류 자동 복구, 정해진 스케줄 무인 수집.
- **파일:** `Program.cs`(HttpClient+Polly), 신규 `Application/Services/*BackgroundService.cs`.
#### WBS-B5 배포 (Docker/CI 게이트)
- **목표:** 멀티스테이지 `Dockerfile` + `docker-compose.yml`(app+PostgreSQL), `.gitea` CI 에 `dotnet build`+`dotnet test` 게이트 추가.
- **판정:** 컨테이너 로컬 기동 성공, CI 에서 테스트 실패 시 배포 차단.
- **파일:** 신규 `Dockerfile`, `docker-compose.yml`, `.gitea/workflows/ci.yml`.
#### WBS-B6 통합·E2E 테스트 및 커버리지 게이트
- **목표:** Testcontainers(PostgreSQL) 통합테스트, KIS→스냅샷→정성매도 E2E, coverlet 커버리지 임계값을 CI 게이트로 연결.
- **판정:** E2E 1건 이상 그린, 커버리지 임계 미달 시 CI 실패.
- **파일:** `QuantEngine.Core.Tests/`(통합/E2E), `.gitea/workflows/ci.yml`.
---
## 5. 개선·보완·고도화 제안 (Track A/B 외 권고)
- **결정 재현성 감사:** 동일 입력 → 동일 출력 결정론 검증을 CI 상시 게이트로 편입 ([governance/adr/0003-no-llm-numeric-generation.md](../governance/adr/0003-no-llm-numeric-generation.md) 정신 계승).
- **캘리브레이션 실증 연계:** [spec/27_bch_calibration_runbook.yaml](../spec/27_bch_calibration_runbook.yaml) 의 `0/190 CALIBRATED` 문제를 마이그레이션과 분리된 데이터 트랙으로 별도 추적(본 WBS 범위 밖, 링크 유지).
- **장애 단일점 보강:** Naver Cloudflare 403 폴백 경로를 Yahoo/KIS 다중화로 명문화(WBS-A3 연동).
- **운영 가시성:** 구조화 로깅에 상관관계 ID(correlation id) 추가, 수집 실행별 추적 가능화.
- **비밀 회전 정책:** KIS appkey/secret, 텔레그램 토큰, DB 비밀번호의 주기적 회전 절차를 [docs/runbook.md](./runbook.md) 에 문서화.
- **WBS 표기 정합성 거버넌스:** 본 문서에서 드러난 "완료 표기 vs 실측" 괴리 재발 방지를 위해, 각 WBS 완료 시 **검증 명령 출력 캡처를 증빙으로 첨부**하는 규칙을 강화([AGENTS.md](../AGENTS.md) 의 검증·증빙 강제 원칙 적용).
---
## 6. 검증 방법 (각 단계 실행 시)
- **P0:** `git status` 산출물 미추적 확인, 시크릿 평문 grep 0건, 회전된 자격증명으로 정상 기동.
- **Track A:** `cd src/dotnet && dotnet test` 로 패리티/단위/E2E 그린. 패리티 리포트 JSON 을 Python 출력과 diff. 운영 경로 Python 호출 0건.
- **Track B:** `curl /health/ready` 200, 비인증 요청 401, `docker compose up` 기동, CI 테스트/커버리지 게이트 동작. Polly 재시도는 장애 주입 테스트로 검증.
---
## 7. 실행 순서 요약
1. **P0 선행 게이트** (WBS-P0.1~P0.3) — 보안·위생 차단. **(기존 10.9 完了 표기 무시, 실측 기준 처리)**
2. **Track A** (A1→A2→A3→A4→A5→A6) — 마이그레이션 완성(우선).
3. **Track B** (B1~B6) — 단일 사용자 상용 안정화(A 와 병행, B1·B3 조기 착수 권장).
@@ -0,0 +1,239 @@
using System.Text.Json;
using QuantEngine.Core.Interfaces;
namespace QuantEngine.Application.Services;
public class DataCollectionService
{
private readonly IKisApiClient _kisApiClient;
private readonly ICollectionRepository _repository;
public DataCollectionService(
IKisApiClient kisApiClient,
ICollectionRepository repository)
{
_kisApiClient = kisApiClient;
_repository = repository;
}
public async Task<CollectionRunResult> RunCollectionAsync(
string runId,
string account,
List<string> tickers)
{
var result = new CollectionRunResult
{
RunId = runId,
StartedAt = KstNowIso(),
Status = "RUNNING"
};
try
{
await _repository.SaveRunAsync(new CollectionRunRecord(
RunId: runId,
Status: "RUNNING",
StartedAt: result.StartedAt
));
int successCount = 0;
int errorCount = 0;
foreach (var ticker in tickers)
{
try
{
var normalized = await CollectOneAsync(ticker, account);
var provenance = new Dictionary<string, object>
{
{ "ticker", ticker },
{ "source", "kis_open_api" }
};
await _repository.SaveSnapshotAsync(new CollectionSnapshotRecord(
RunId: runId,
DatasetName: "data_feed",
Ticker: ticker,
SourceName: "kis_open_api",
PayloadJson: JsonSerializer.Serialize(normalized),
CapturedAt: KstNowIso()
));
successCount++;
}
catch (Exception ex)
{
errorCount++;
System.Diagnostics.Debug.WriteLine($"Error collecting {ticker}: {ex.Message}");
await _repository.SaveErrorAsync(new CollectionErrorRecord(
RunId: runId,
SourceName: "kis_collector",
ErrorKind: ex.GetType().Name,
ErrorMessage: ex.Message,
Ticker: ticker
));
}
}
var finishedAt = KstNowIso();
await _repository.UpdateRunStatusAsync(
runId,
errorCount == 0 ? "COMPLETED" : "COMPLETED_WITH_ERRORS",
finishedAt,
successCount,
errorCount
);
result.Status = errorCount == 0 ? "COMPLETED" : "COMPLETED_WITH_ERRORS";
result.FinishedAt = finishedAt;
result.SuccessCount = successCount;
result.ErrorCount = errorCount;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Fatal error in collection run {runId}: {ex}");
await _repository.UpdateRunStatusAsync(runId, "FAILED", KstNowIso());
result.Status = "FAILED";
result.ErrorMessage = ex.Message;
}
return result;
}
private async Task<Dictionary<string, object>> CollectOneAsync(string ticker, string account)
{
var normalized = new Dictionary<string, object> { { "ticker", ticker } };
try
{
var price = await _kisApiClient.GetCurrentPriceAsync(ticker, account);
normalized["current_price"] = CoerceFloat(FindFirstValue(price, "stck_prpr", "stck_clpr", "close"));
normalized["open"] = CoerceFloat(FindFirstValue(price, "stck_oprc", "open"));
normalized["high"] = CoerceFloat(FindFirstValue(price, "stck_hgpr", "high"));
normalized["low"] = CoerceFloat(FindFirstValue(price, "stck_lwpr", "low"));
normalized["prev_close"] = CoerceFloat(FindFirstValue(price, "prdy_vrss"));
normalized["volume"] = CoerceFloat(FindFirstValue(price, "acml_vol", "volume"));
normalized["change_pct"] = CoerceFloat(FindFirstValue(price, "prdy_ctrt"));
normalized["price_status"] = "OK";
}
catch (Exception ex)
{
normalized["price_status"] = "ERROR";
normalized["price_error"] = ex.Message;
}
try
{
var orderbook = await _kisApiClient.GetAskingPrice10LevelAsync(ticker, account);
var output1 = ExtractObject(orderbook, "output1");
normalized["ask_1"] = CoerceFloat(FindFirstValue(output1, "askp1"));
normalized["bid_1"] = CoerceFloat(FindFirstValue(output1, "bidp1"));
normalized["orderbook_status"] = "OK";
}
catch (Exception ex)
{
normalized["orderbook_status"] = "ERROR";
normalized["orderbook_error"] = ex.Message;
}
try
{
var start = DateTime.Now.AddDays(-10).ToString("yyyyMMdd");
var end = DateTime.Now.ToString("yyyyMMdd");
var shortSale = await _kisApiClient.GetDailyShortSaleAsync(ticker, start, end, account);
var rows = ExtractArray(shortSale, "output2");
if (rows.Count > 0 && rows[0] is Dictionary<string, object> latest)
{
normalized["short_turnover_share"] = CoerceFloat(latest.GetValueOrDefault("ssts_vol_rlim"));
}
normalized["short_sale_status"] = "OK";
}
catch (Exception ex)
{
normalized["short_sale_status"] = "ERROR";
normalized["short_sale_error"] = ex.Message;
}
normalized["collection_as_of"] = KstNowIso();
return normalized;
}
private static object? FindFirstValue(Dictionary<string, object> payload, params string[] keys)
{
var stack = new Stack<object>();
stack.Push(payload);
while (stack.Count > 0)
{
var item = stack.Pop();
if (item is Dictionary<string, object> dict)
{
foreach (var key in keys)
{
if (dict.TryGetValue(key, out var value) && value != null && !string.IsNullOrEmpty(value.ToString()))
return value;
}
foreach (var value in dict.Values)
if (value != null) stack.Push(value);
}
else if (item is JsonElement elem && elem.ValueKind == System.Text.Json.JsonValueKind.Object)
{
foreach (var key in keys)
{
if (elem.TryGetProperty(key, out var prop) && prop.ValueKind != System.Text.Json.JsonValueKind.Null)
return prop;
}
foreach (var prop in elem.EnumerateObject())
stack.Push(prop.Value);
}
}
return null;
}
private static double? CoerceFloat(object? value)
{
if (value == null || string.IsNullOrEmpty(value.ToString()))
return null;
try
{
var str = value.ToString()?.Replace(",", "").Replace("%", "") ?? "";
return double.TryParse(str, out var d) ? d : null;
}
catch { return null; }
}
private static Dictionary<string, object> ExtractObject(Dictionary<string, object> payload, string key)
{
if (payload.TryGetValue(key, out var value) && value is Dictionary<string, object> dict)
return dict;
if (value is JsonElement elem && elem.ValueKind == System.Text.Json.JsonValueKind.Object)
return JsonSerializer.Deserialize<Dictionary<string, object>>(elem.GetRawText()) ?? new();
return new();
}
private static List<object> ExtractArray(Dictionary<string, object> payload, string key)
{
if (payload.TryGetValue(key, out var value))
{
if (value is List<object> list) return list;
if (value is JsonElement elem && elem.ValueKind == System.Text.Json.JsonValueKind.Array)
return JsonSerializer.Deserialize<List<object>>(elem.GetRawText()) ?? new();
}
return new();
}
private static string KstNowIso() =>
DateTime.Now.ToString("o");
}
public class CollectionRunResult
{
public string RunId { get; set; } = "";
public string Status { get; set; } = "";
public string StartedAt { get; set; } = "";
public string? FinishedAt { get; set; }
public int SuccessCount { get; set; }
public int ErrorCount { get; set; }
public string? ErrorMessage { get; set; }
}
@@ -1,8 +0,0 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
@@ -1,698 +0,0 @@
{
"format": 1,
"restore": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj": {}
},
"projects": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj",
"projectName": "QuantEngine.Application",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
},
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"projectName": "QuantEngine.Core",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
}
}
}
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">D:\DevCache\nuget-packages</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">D:\DevCache\nuget-packages;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages;C:\Program Files\dotnet\sdk\NuGetFallbackFolder</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="D:\DevCache\nuget-packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
<SourceRoot Include="C:\Program Files\dotnet\sdk\NuGetFallbackFolder\" />
</ItemGroup>
</Project>
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
@@ -1,381 +0,0 @@
{
"version": 4,
"targets": {
"net10.0": {
"QuantEngine.Core/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v10.0",
"compile": {
"bin/placeholder/QuantEngine.Core.dll": {}
},
"runtime": {
"bin/placeholder/QuantEngine.Core.dll": {}
}
}
}
},
"libraries": {
"QuantEngine.Core/1.0.0": {
"type": "project",
"path": "../QuantEngine.Core/QuantEngine.Core.csproj",
"msbuildProject": "../QuantEngine.Core/QuantEngine.Core.csproj"
}
},
"projectFileDependencyGroups": {
"net10.0": [
"QuantEngine.Core >= 1.0.0"
]
},
"packageFolders": {
"D:\\DevCache\\nuget-packages": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {},
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj",
"projectName": "QuantEngine.Application",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
}
}
@@ -1,8 +0,0 @@
{
"version": 2,
"dgSpecHash": "fHUX04f/fhA=",
"success": true,
"projectFilePath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj",
"expectedPackageFiles": [],
"logs": []
}
@@ -123,6 +123,12 @@ public class ApplicationServiceTests
public (string Domain, string TargetRef)? LastReleasedLock { get; private set; }
public Task<IEnumerable<Setting>> GetSettingsAsync() => Task.FromResult(Enumerable.Empty<Setting>());
public Task<IEnumerable<WorkspaceAccount>> GetAccountsAsync() => Task.FromResult(Enumerable.Empty<WorkspaceAccount>());
public Task<WorkspaceAccount?> GetAccountByUsernameAsync(string username) => Task.FromResult<WorkspaceAccount?>(null);
public Task<bool> UpsertAccountAsync(WorkspaceAccount account) => Task.FromResult(true);
public Task<WorkspaceSession?> GetSessionByTokenHashAsync(string tokenHash) => Task.FromResult<WorkspaceSession?>(null);
public Task<bool> UpsertSessionAsync(WorkspaceSession session) => Task.FromResult(true);
public Task<bool> RevokeSessionAsync(string tokenHash, string revokedAt) => Task.FromResult(true);
public Task<Setting?> GetSettingByKeyAsync(string key) => Task.FromResult<Setting?>(null);
public Task<bool> UpsertSettingAsync(Setting setting) { LastSetting = setting; return Task.FromResult(true); }
public Task<bool> DeleteSettingAsync(string key) => Task.FromResult(true);
@@ -1,9 +0,0 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
global using Xunit;
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">D:\DevCache\nuget-packages</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">D:\DevCache\nuget-packages;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages;C:\Program Files\dotnet\sdk\NuGetFallbackFolder</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="D:\DevCache\nuget-packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
<SourceRoot Include="C:\Program Files\dotnet\sdk\NuGetFallbackFolder\" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)\xunit.runner.visualstudio\3.1.4\build\net8.0\xunit.runner.visualstudio.props" Condition="Exists('$(NuGetPackageRoot)\xunit.runner.visualstudio\3.1.4\build\net8.0\xunit.runner.visualstudio.props')" />
<Import Project="$(NuGetPackageRoot)\xunit.core\2.9.3\build\xunit.core.props" Condition="Exists('$(NuGetPackageRoot)\xunit.core\2.9.3\build\xunit.core.props')" />
<Import Project="$(NuGetPackageRoot)\microsoft.testplatform.testhost\17.14.1\build\net8.0\Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)\microsoft.testplatform.testhost\17.14.1\build\net8.0\Microsoft.TestPlatform.TestHost.props')" />
<Import Project="$(NuGetPackageRoot)\microsoft.codecoverage\17.14.1\build\netstandard2.0\Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)\microsoft.codecoverage\17.14.1\build\netstandard2.0\Microsoft.CodeCoverage.props')" />
<Import Project="$(NuGetPackageRoot)\microsoft.net.test.sdk\17.14.1\build\net8.0\Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)\microsoft.net.test.sdk\17.14.1\build\net8.0\Microsoft.NET.Test.Sdk.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Pkgxunit_analyzers Condition=" '$(Pkgxunit_analyzers)' == '' ">D:\DevCache\nuget-packages\xunit.analyzers\1.18.0</Pkgxunit_analyzers>
</PropertyGroup>
</Project>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)\xunit.core\2.9.3\build\xunit.core.targets" Condition="Exists('$(NuGetPackageRoot)\xunit.core\2.9.3\build\xunit.core.targets')" />
<Import Project="$(NuGetPackageRoot)\microsoft.extensions.logging.abstractions\10.0.0\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)\microsoft.extensions.logging.abstractions\10.0.0\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)\microsoft.testplatform.testhost\17.14.1\build\net8.0\Microsoft.TestPlatform.TestHost.targets" Condition="Exists('$(NuGetPackageRoot)\microsoft.testplatform.testhost\17.14.1\build\net8.0\Microsoft.TestPlatform.TestHost.targets')" />
<Import Project="$(NuGetPackageRoot)\microsoft.codecoverage\17.14.1\build\netstandard2.0\Microsoft.CodeCoverage.targets" Condition="Exists('$(NuGetPackageRoot)\microsoft.codecoverage\17.14.1\build\netstandard2.0\Microsoft.CodeCoverage.targets')" />
<Import Project="$(NuGetPackageRoot)\microsoft.net.test.sdk\17.14.1\build\net8.0\Microsoft.NET.Test.Sdk.targets" Condition="Exists('$(NuGetPackageRoot)\microsoft.net.test.sdk\17.14.1\build\net8.0\Microsoft.NET.Test.Sdk.targets')" />
<Import Project="$(NuGetPackageRoot)\coverlet.collector\6.0.4\build\netstandard2.0\coverlet.collector.targets" Condition="Exists('$(NuGetPackageRoot)\coverlet.collector\6.0.4\build\netstandard2.0\coverlet.collector.targets')" />
</ImportGroup>
</Project>
File diff suppressed because it is too large Load Diff
@@ -1,27 +0,0 @@
{
"version": 2,
"dgSpecHash": "piIGGEWHUs8=",
"success": true,
"projectFilePath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core.Tests\\QuantEngine.Core.Tests.csproj",
"expectedPackageFiles": [
"D:\\DevCache\\nuget-packages\\coverlet.collector\\6.0.4\\coverlet.collector.6.0.4.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\dapper\\2.1.79\\dapper.2.1.79.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.codecoverage\\17.14.1\\microsoft.codecoverage.17.14.1.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.extensions.dependencyinjection.abstractions\\10.0.0\\microsoft.extensions.dependencyinjection.abstractions.10.0.0.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.extensions.logging.abstractions\\10.0.0\\microsoft.extensions.logging.abstractions.10.0.0.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.net.test.sdk\\17.14.1\\microsoft.net.test.sdk.17.14.1.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.testplatform.objectmodel\\17.14.1\\microsoft.testplatform.objectmodel.17.14.1.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.testplatform.testhost\\17.14.1\\microsoft.testplatform.testhost.17.14.1.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\newtonsoft.json\\13.0.3\\newtonsoft.json.13.0.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\npgsql\\10.0.3\\npgsql.10.0.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit\\2.9.3\\xunit.2.9.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.abstractions\\2.0.3\\xunit.abstractions.2.0.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.analyzers\\1.18.0\\xunit.analyzers.1.18.0.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.assert\\2.9.3\\xunit.assert.2.9.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.core\\2.9.3\\xunit.core.2.9.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.extensibility.core\\2.9.3\\xunit.extensibility.core.2.9.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.extensibility.execution\\2.9.3\\xunit.extensibility.execution.2.9.3.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\xunit.runner.visualstudio\\3.1.4\\xunit.runner.visualstudio.3.1.4.nupkg.sha512"
],
"logs": []
}
@@ -6,6 +6,14 @@ namespace QuantEngine.Core.Interfaces
{
public interface IWorkspaceRepository
{
// Accounts
Task<IEnumerable<WorkspaceAccount>> GetAccountsAsync();
Task<WorkspaceAccount?> GetAccountByUsernameAsync(string username);
Task<bool> UpsertAccountAsync(WorkspaceAccount account);
Task<WorkspaceSession?> GetSessionByTokenHashAsync(string tokenHash);
Task<bool> UpsertSessionAsync(WorkspaceSession session);
Task<bool> RevokeSessionAsync(string tokenHash, string revokedAt);
// Settings
Task<IEnumerable<Setting>> GetSettingsAsync();
Task<Setting?> GetSettingByKeyAsync(string key);
@@ -0,0 +1,13 @@
namespace QuantEngine.Core.Models
{
public class WorkspaceAccount
{
public int Ordinal { get; set; }
public string Username { get; set; } = string.Empty;
public string PasswordHash { get; set; } = string.Empty;
public string Role { get; set; } = "Admin";
public string IsActive { get; set; } = "true";
public string CreatedAt { get; set; } = string.Empty;
public string UpdatedAt { get; set; } = string.Empty;
}
}
@@ -0,0 +1,12 @@
namespace QuantEngine.Core.Models
{
public class WorkspaceSession
{
public string SessionTokenHash { get; set; } = string.Empty;
public string Username { get; set; } = string.Empty;
public string Role { get; set; } = "Admin";
public string CreatedAt { get; set; } = string.Empty;
public string ExpiresAt { get; set; } = string.Empty;
public string? RevokedAt { get; set; }
}
}
@@ -1,18 +0,0 @@
is_global = true
build_property.TargetFramework = net10.0
build_property.TargetFrameworkIdentifier = .NETCoreApp
build_property.TargetFrameworkVersion = v10.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property.EntryPointFilePath =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = QuantEngine.Core
build_property.ProjectDir = C:\Temp\data_feed\src\dotnet\QuantEngine.Core\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.EffectiveAnalysisLevelStyle = 10.0
build_property.EnableCodeStyleSeverity =
@@ -1,8 +0,0 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
@@ -1,351 +0,0 @@
{
"format": 1,
"restore": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {}
},
"projects": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"projectName": "QuantEngine.Core",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
}
}
}
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">D:\DevCache\nuget-packages</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">D:\DevCache\nuget-packages;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages;C:\Program Files\dotnet\sdk\NuGetFallbackFolder</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="D:\DevCache\nuget-packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
<SourceRoot Include="C:\Program Files\dotnet\sdk\NuGetFallbackFolder\" />
</ItemGroup>
</Project>
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
@@ -1,358 +0,0 @@
{
"version": 4,
"targets": {
"net10.0": {}
},
"libraries": {},
"projectFileDependencyGroups": {
"net10.0": []
},
"packageFolders": {
"D:\\DevCache\\nuget-packages": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {},
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"projectName": "QuantEngine.Core",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
}
}
@@ -1,8 +0,0 @@
{
"version": 2,
"dgSpecHash": "ZsY9lhMy6SQ=",
"success": true,
"projectFilePath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj",
"expectedPackageFiles": [],
"logs": []
}
@@ -30,6 +30,32 @@ namespace QuantEngine.Infrastructure.Data
);
");
// 0b. workspace_account
conn.Execute(@"
CREATE TABLE IF NOT EXISTS workspace_account (
ordinal INT NOT NULL,
username TEXT PRIMARY KEY,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'Admin',
is_active TEXT NOT NULL DEFAULT 'true',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_workspace_account_active ON workspace_account(is_active, username);
");
conn.Execute(@"
CREATE TABLE IF NOT EXISTS workspace_session (
session_token_hash TEXT PRIMARY KEY,
username TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'Admin',
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL,
revoked_at TEXT
);
CREATE INDEX IF NOT EXISTS idx_workspace_session_username ON workspace_session(username, expires_at DESC);
");
// 1. collection_runs
conn.Execute(@"
CREATE TABLE IF NOT EXISTS collection_runs (
@@ -157,6 +183,16 @@ namespace QuantEngine.Infrastructure.Data
);
");
conn.Execute(@"
INSERT INTO quantengine.workspace_account (
ordinal, username, password_hash, role, is_active, created_at, updated_at
)
SELECT 1, 'admin', '8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918', 'Admin', 'true', NOW()::text, NOW()::text
WHERE NOT EXISTS (
SELECT 1 FROM quantengine.workspace_account WHERE username = 'admin'
);
");
// 10. engine_history schema and tables
conn.Execute(@"
CREATE SCHEMA IF NOT EXISTS engine_history;
@@ -17,6 +17,89 @@ namespace QuantEngine.Infrastructure.Repositories
_connectionFactory = connectionFactory;
}
// Accounts
public async Task<IEnumerable<WorkspaceAccount>> GetAccountsAsync()
{
using var conn = _connectionFactory.CreateConnection();
return await conn.QueryAsync<WorkspaceAccount>(@"
SELECT ordinal, username as Username, password_hash as PasswordHash, role as Role,
is_active as IsActive, created_at as CreatedAt, updated_at as UpdatedAt
FROM quantengine.workspace_account
ORDER BY ordinal ASC"
);
}
public async Task<WorkspaceAccount?> GetAccountByUsernameAsync(string username)
{
using var conn = _connectionFactory.CreateConnection();
return await conn.QueryFirstOrDefaultAsync<WorkspaceAccount>(@"
SELECT ordinal, username as Username, password_hash as PasswordHash, role as Role,
is_active as IsActive, created_at as CreatedAt, updated_at as UpdatedAt
FROM quantengine.workspace_account
WHERE username = @Username",
new { Username = username }
);
}
public async Task<bool> UpsertAccountAsync(WorkspaceAccount account)
{
using var conn = _connectionFactory.CreateConnection();
var affected = await conn.ExecuteAsync(@"
INSERT INTO quantengine.workspace_account (ordinal, username, password_hash, role, is_active, created_at, updated_at)
VALUES (@Ordinal, @Username, @PasswordHash, @Role, @IsActive, @CreatedAt, @UpdatedAt)
ON CONFLICT (username) DO UPDATE SET
ordinal = EXCLUDED.ordinal,
password_hash = EXCLUDED.password_hash,
role = EXCLUDED.role,
is_active = EXCLUDED.is_active,
updated_at = EXCLUDED.updated_at",
account
);
return affected > 0;
}
public async Task<WorkspaceSession?> GetSessionByTokenHashAsync(string tokenHash)
{
using var conn = _connectionFactory.CreateConnection();
return await conn.QueryFirstOrDefaultAsync<WorkspaceSession>(@"
SELECT session_token_hash as SessionTokenHash, username as Username, role as Role,
created_at as CreatedAt, expires_at as ExpiresAt, revoked_at as RevokedAt
FROM quantengine.workspace_session
WHERE session_token_hash = @TokenHash",
new { TokenHash = tokenHash }
);
}
public async Task<bool> UpsertSessionAsync(WorkspaceSession session)
{
using var conn = _connectionFactory.CreateConnection();
var affected = await conn.ExecuteAsync(@"
INSERT INTO quantengine.workspace_session
(session_token_hash, username, role, created_at, expires_at, revoked_at)
VALUES
(@SessionTokenHash, @Username, @Role, @CreatedAt, @ExpiresAt, @RevokedAt)
ON CONFLICT (session_token_hash) DO UPDATE SET
username = EXCLUDED.username,
role = EXCLUDED.role,
expires_at = EXCLUDED.expires_at,
revoked_at = EXCLUDED.revoked_at",
session
);
return affected > 0;
}
public async Task<bool> RevokeSessionAsync(string tokenHash, string revokedAt)
{
using var conn = _connectionFactory.CreateConnection();
var affected = await conn.ExecuteAsync(@"
UPDATE quantengine.workspace_session
SET revoked_at = @RevokedAt
WHERE session_token_hash = @TokenHash",
new { TokenHash = tokenHash, RevokedAt = revokedAt }
);
return affected > 0;
}
// Settings
public async Task<IEnumerable<Setting>> GetSettingsAsync()
{
@@ -174,8 +174,15 @@ public class KisApiClient : IKisApiClient
response.EnsureSuccessStatusCode();
var tokenData = await response.Content.ReadFromJsonAsync<Dictionary<string, object>>();
var accessToken = tokenData["access_token"]?.ToString() ?? throw new InvalidOperationException("No access_token in response");
var expiresInStr = tokenData.ContainsKey("expires_in") ? tokenData["expires_in"]?.ToString() : "86400";
if (tokenData == null) throw new InvalidOperationException("Token response body is empty");
if (!tokenData.TryGetValue("access_token", out var tokenObj) || tokenObj == null)
throw new InvalidOperationException("No access_token in response");
var accessToken = tokenObj.ToString()!;
var expiresInStr = tokenData.TryGetValue("expires_in", out var expiresObj) && expiresObj != null
? expiresObj.ToString()
: "86400";
var expiresInSec = int.TryParse(expiresInStr, out var seconds) ? seconds : 86400;
var expiresAt = DateTime.UtcNow.AddSeconds(expiresInSec);
@@ -1,8 +0,0 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">D:\DevCache\nuget-packages</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">D:\DevCache\nuget-packages;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages;C:\Program Files\dotnet\sdk\NuGetFallbackFolder</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="D:\DevCache\nuget-packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
<SourceRoot Include="C:\Program Files\dotnet\sdk\NuGetFallbackFolder\" />
</ItemGroup>
</Project>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)\microsoft.extensions.logging.abstractions\10.0.0\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)\microsoft.extensions.logging.abstractions\10.0.0\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
</ImportGroup>
</Project>
@@ -1,622 +0,0 @@
{
"version": 4,
"targets": {
"net10.0": {
"Dapper/2.1.79": {
"type": "package",
"compile": {
"lib/net10.0/Dapper.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net10.0/Dapper.dll": {
"related": ".xml"
}
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions/10.0.0": {
"type": "package",
"compile": {
"lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
"related": ".xml"
}
},
"build": {
"buildTransitive/net8.0/_._": {}
}
},
"Microsoft.Extensions.Logging.Abstractions/10.0.0": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.0"
},
"compile": {
"lib/net10.0/Microsoft.Extensions.Logging.Abstractions.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net10.0/Microsoft.Extensions.Logging.Abstractions.dll": {
"related": ".xml"
}
},
"build": {
"buildTransitive/net8.0/Microsoft.Extensions.Logging.Abstractions.targets": {}
}
},
"Npgsql/10.0.3": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "10.0.0"
},
"compile": {
"lib/net10.0/Npgsql.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net10.0/Npgsql.dll": {
"related": ".xml"
}
}
},
"QuantEngine.Application/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v10.0",
"dependencies": {
"QuantEngine.Core": "1.0.0"
},
"compile": {
"bin/placeholder/QuantEngine.Application.dll": {}
},
"runtime": {
"bin/placeholder/QuantEngine.Application.dll": {}
}
},
"QuantEngine.Core/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v10.0",
"compile": {
"bin/placeholder/QuantEngine.Core.dll": {}
},
"runtime": {
"bin/placeholder/QuantEngine.Core.dll": {}
}
}
}
},
"libraries": {
"Dapper/2.1.79": {
"sha512": "8YijbzgTfmqmQOnVNorYM6K++pxqnW3nJ4aC1sRHzxUA2CcuoJ9gsTem3kgBnPRMc38zZHl4Esb6hAezXIEEuw==",
"type": "package",
"path": "dapper/2.1.79",
"files": [
".nupkg.metadata",
".signature.p7s",
"Dapper.png",
"dapper.2.1.79.nupkg.sha512",
"dapper.nuspec",
"lib/net10.0/Dapper.dll",
"lib/net10.0/Dapper.xml",
"lib/net461/Dapper.dll",
"lib/net461/Dapper.xml",
"lib/net8.0/Dapper.dll",
"lib/net8.0/Dapper.xml",
"lib/netstandard2.0/Dapper.dll",
"lib/netstandard2.0/Dapper.xml",
"readme.md"
]
},
"Microsoft.Extensions.DependencyInjection.Abstractions/10.0.0": {
"sha512": "L3AdmZ1WOK4XXT5YFPEwyt0ep6l8lGIPs7F5OOBZc77Zqeo01Of7XXICy47628sdVl0v/owxYJTe86DTgFwKCA==",
"type": "package",
"path": "microsoft.extensions.dependencyinjection.abstractions/10.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT",
"buildTransitive/net461/Microsoft.Extensions.DependencyInjection.Abstractions.targets",
"buildTransitive/net462/_._",
"buildTransitive/net8.0/_._",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.Abstractions.targets",
"lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net10.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net462/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.Abstractions.xml",
"microsoft.extensions.dependencyinjection.abstractions.10.0.0.nupkg.sha512",
"microsoft.extensions.dependencyinjection.abstractions.nuspec",
"useSharedDesignerContext.txt"
]
},
"Microsoft.Extensions.Logging.Abstractions/10.0.0": {
"sha512": "FU/IfjDfwaMuKr414SSQNTIti/69bHEMb+QKrskRb26oVqpx3lNFXMjs/RC9ZUuhBhcwDM2BwOgoMw+PZ+beqQ==",
"type": "package",
"path": "microsoft.extensions.logging.abstractions/10.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT",
"analyzers/dotnet/roslyn3.11/cs/Microsoft.Extensions.Logging.Generators.dll",
"analyzers/dotnet/roslyn3.11/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn3.11/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/Microsoft.Extensions.Logging.Generators.dll",
"analyzers/dotnet/roslyn4.0/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.0/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/Microsoft.Extensions.Logging.Generators.dll",
"analyzers/dotnet/roslyn4.4/cs/cs/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/de/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/es/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/fr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/it/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/ja/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/ko/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/pl/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/pt-BR/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/ru/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/tr/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/zh-Hans/Microsoft.Extensions.Logging.Generators.resources.dll",
"analyzers/dotnet/roslyn4.4/cs/zh-Hant/Microsoft.Extensions.Logging.Generators.resources.dll",
"buildTransitive/net461/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/net462/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/net8.0/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.Logging.Abstractions.targets",
"buildTransitive/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.targets",
"lib/net10.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net10.0/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/net462/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net462/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/net9.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/net9.0/Microsoft.Extensions.Logging.Abstractions.xml",
"lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll",
"lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml",
"microsoft.extensions.logging.abstractions.10.0.0.nupkg.sha512",
"microsoft.extensions.logging.abstractions.nuspec",
"useSharedDesignerContext.txt"
]
},
"Npgsql/10.0.3": {
"sha512": "7nb5YzXuvWWJxB0J8DiyL3we+X4FOctZrt0fIBnucOIaIevFEEwGQVZKtiu9olXdlNAK1eNgqSral6r/jlhI4w==",
"type": "package",
"path": "npgsql/10.0.3",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net10.0/Npgsql.dll",
"lib/net10.0/Npgsql.xml",
"lib/net8.0/Npgsql.dll",
"lib/net8.0/Npgsql.xml",
"lib/net9.0/Npgsql.dll",
"lib/net9.0/Npgsql.xml",
"npgsql.10.0.3.nupkg.sha512",
"npgsql.nuspec",
"postgresql.png"
]
},
"QuantEngine.Application/1.0.0": {
"type": "project",
"path": "../QuantEngine.Application/QuantEngine.Application.csproj",
"msbuildProject": "../QuantEngine.Application/QuantEngine.Application.csproj"
},
"QuantEngine.Core/1.0.0": {
"type": "project",
"path": "../QuantEngine.Core/QuantEngine.Core.csproj",
"msbuildProject": "../QuantEngine.Core/QuantEngine.Core.csproj"
}
},
"projectFileDependencyGroups": {
"net10.0": [
"Dapper >= 2.1.79",
"Npgsql >= 10.0.3",
"QuantEngine.Application >= 1.0.0",
"QuantEngine.Core >= 1.0.0"
]
},
"packageFolders": {
"D:\\DevCache\\nuget-packages": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {},
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Infrastructure\\QuantEngine.Infrastructure.csproj",
"projectName": "QuantEngine.Infrastructure",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Infrastructure\\QuantEngine.Infrastructure.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Infrastructure\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj": {
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj"
},
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"dependencies": {
"Dapper": {
"target": "Package",
"version": "[2.1.79, )"
},
"Npgsql": {
"target": "Package",
"version": "[10.0.3, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
}
}
@@ -1,13 +0,0 @@
{
"version": 2,
"dgSpecHash": "KzZeTlTcjPo=",
"success": true,
"projectFilePath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Infrastructure\\QuantEngine.Infrastructure.csproj",
"expectedPackageFiles": [
"D:\\DevCache\\nuget-packages\\dapper\\2.1.79\\dapper.2.1.79.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.extensions.dependencyinjection.abstractions\\10.0.0\\microsoft.extensions.dependencyinjection.abstractions.10.0.0.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\microsoft.extensions.logging.abstractions\\10.0.0\\microsoft.extensions.logging.abstractions.10.0.0.nupkg.sha512",
"D:\\DevCache\\nuget-packages\\npgsql\\10.0.3\\npgsql.10.0.3.nupkg.sha512"
],
"logs": []
}
@@ -1,8 +0,0 @@
// <auto-generated/>
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;
File diff suppressed because it is too large Load Diff
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">D:\DevCache\nuget-packages</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">D:\DevCache\nuget-packages;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages;C:\Program Files\dotnet\sdk\NuGetFallbackFolder</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="D:\DevCache\nuget-packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
<SourceRoot Include="C:\Program Files\dotnet\sdk\NuGetFallbackFolder\" />
</ItemGroup>
</Project>
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
@@ -1,403 +0,0 @@
{
"version": 4,
"targets": {
"net10.0": {
"QuantEngine.Application/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v10.0",
"dependencies": {
"QuantEngine.Core": "1.0.0"
},
"compile": {
"bin/placeholder/QuantEngine.Application.dll": {}
},
"runtime": {
"bin/placeholder/QuantEngine.Application.dll": {}
}
},
"QuantEngine.Core/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v10.0",
"compile": {
"bin/placeholder/QuantEngine.Core.dll": {}
},
"runtime": {
"bin/placeholder/QuantEngine.Core.dll": {}
}
}
}
},
"libraries": {
"QuantEngine.Application/1.0.0": {
"type": "project",
"path": "../QuantEngine.Application/QuantEngine.Application.csproj",
"msbuildProject": "../QuantEngine.Application/QuantEngine.Application.csproj"
},
"QuantEngine.Core/1.0.0": {
"type": "project",
"path": "../QuantEngine.Core/QuantEngine.Core.csproj",
"msbuildProject": "../QuantEngine.Core/QuantEngine.Core.csproj"
}
},
"projectFileDependencyGroups": {
"net10.0": [
"QuantEngine.Application >= 1.0.0",
"QuantEngine.Core >= 1.0.0"
]
},
"packageFolders": {
"D:\\DevCache\\nuget-packages": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {},
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Tools\\QuantEngine.Tools.csproj",
"projectName": "QuantEngine.Tools",
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Tools\\QuantEngine.Tools.csproj",
"packagesPath": "D:\\DevCache\\nuget-packages",
"outputPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Tools\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
],
"configFilePaths": [
"C:\\Users\\kjh20\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net10.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"projectReferences": {
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj": {
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Application\\QuantEngine.Application.csproj"
},
"C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj": {
"projectPath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Core\\QuantEngine.Core.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "10.0.300"
},
"frameworks": {
"net10.0": {
"framework": "net10.0",
"targetAlias": "net10.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json",
"packagesToPrune": {
"Microsoft.CSharp": "(,4.7.32767]",
"Microsoft.VisualBasic": "(,10.4.32767]",
"Microsoft.Win32.Primitives": "(,4.3.32767]",
"Microsoft.Win32.Registry": "(,5.0.32767]",
"runtime.any.System.Collections": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.any.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.any.System.Globalization": "(,4.3.32767]",
"runtime.any.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.any.System.IO": "(,4.3.32767]",
"runtime.any.System.Reflection": "(,4.3.32767]",
"runtime.any.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.any.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.any.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.any.System.Runtime": "(,4.3.32767]",
"runtime.any.System.Runtime.Handles": "(,4.3.32767]",
"runtime.any.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.any.System.Text.Encoding": "(,4.3.32767]",
"runtime.any.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.any.System.Threading.Tasks": "(,4.3.32767]",
"runtime.any.System.Threading.Timer": "(,4.3.32767]",
"runtime.aot.System.Collections": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tools": "(,4.3.32767]",
"runtime.aot.System.Diagnostics.Tracing": "(,4.3.32767]",
"runtime.aot.System.Globalization": "(,4.3.32767]",
"runtime.aot.System.Globalization.Calendars": "(,4.3.32767]",
"runtime.aot.System.IO": "(,4.3.32767]",
"runtime.aot.System.Reflection": "(,4.3.32767]",
"runtime.aot.System.Reflection.Extensions": "(,4.3.32767]",
"runtime.aot.System.Reflection.Primitives": "(,4.3.32767]",
"runtime.aot.System.Resources.ResourceManager": "(,4.3.32767]",
"runtime.aot.System.Runtime": "(,4.3.32767]",
"runtime.aot.System.Runtime.Handles": "(,4.3.32767]",
"runtime.aot.System.Runtime.InteropServices": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding": "(,4.3.32767]",
"runtime.aot.System.Text.Encoding.Extensions": "(,4.3.32767]",
"runtime.aot.System.Threading.Tasks": "(,4.3.32767]",
"runtime.aot.System.Threading.Timer": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.debian.9-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.27-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.fedora.28-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.opensuse.42.3-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "(,4.3.32767]",
"runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography": "(,4.3.32767]",
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Http": "(,4.3.32767]",
"runtime.ubuntu.18.04-x64.runtime.native.System.Net.Security": "(,4.3.32767]",
"runtime.unix.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.unix.System.Console": "(,4.3.32767]",
"runtime.unix.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.unix.System.IO.FileSystem": "(,4.3.32767]",
"runtime.unix.System.Net.Primitives": "(,4.3.32767]",
"runtime.unix.System.Net.Sockets": "(,4.3.32767]",
"runtime.unix.System.Private.Uri": "(,4.3.32767]",
"runtime.unix.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win.Microsoft.Win32.Primitives": "(,4.3.32767]",
"runtime.win.System.Console": "(,4.3.32767]",
"runtime.win.System.Diagnostics.Debug": "(,4.3.32767]",
"runtime.win.System.IO.FileSystem": "(,4.3.32767]",
"runtime.win.System.Net.Primitives": "(,4.3.32767]",
"runtime.win.System.Net.Sockets": "(,4.3.32767]",
"runtime.win.System.Runtime.Extensions": "(,4.3.32767]",
"runtime.win10-arm-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-arm64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win10-x64-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win10-x86-aot.runtime.native.System.IO.Compression": "(,4.0.32767]",
"runtime.win7-x64.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7-x86.runtime.native.System.IO.Compression": "(,4.3.32767]",
"runtime.win7.System.Private.Uri": "(,4.3.32767]",
"runtime.win8-arm.runtime.native.System.IO.Compression": "(,4.3.32767]",
"System.AppContext": "(,4.3.32767]",
"System.Buffers": "(,5.0.32767]",
"System.Collections": "(,4.3.32767]",
"System.Collections.Concurrent": "(,4.3.32767]",
"System.Collections.Immutable": "(,10.0.32767]",
"System.Collections.NonGeneric": "(,4.3.32767]",
"System.Collections.Specialized": "(,4.3.32767]",
"System.ComponentModel": "(,4.3.32767]",
"System.ComponentModel.Annotations": "(,4.3.32767]",
"System.ComponentModel.EventBasedAsync": "(,4.3.32767]",
"System.ComponentModel.Primitives": "(,4.3.32767]",
"System.ComponentModel.TypeConverter": "(,4.3.32767]",
"System.Console": "(,4.3.32767]",
"System.Data.Common": "(,4.3.32767]",
"System.Data.DataSetExtensions": "(,4.4.32767]",
"System.Diagnostics.Contracts": "(,4.3.32767]",
"System.Diagnostics.Debug": "(,4.3.32767]",
"System.Diagnostics.DiagnosticSource": "(,10.0.32767]",
"System.Diagnostics.FileVersionInfo": "(,4.3.32767]",
"System.Diagnostics.Process": "(,4.3.32767]",
"System.Diagnostics.StackTrace": "(,4.3.32767]",
"System.Diagnostics.TextWriterTraceListener": "(,4.3.32767]",
"System.Diagnostics.Tools": "(,4.3.32767]",
"System.Diagnostics.TraceSource": "(,4.3.32767]",
"System.Diagnostics.Tracing": "(,4.3.32767]",
"System.Drawing.Primitives": "(,4.3.32767]",
"System.Dynamic.Runtime": "(,4.3.32767]",
"System.Formats.Asn1": "(,10.0.32767]",
"System.Formats.Tar": "(,10.0.32767]",
"System.Globalization": "(,4.3.32767]",
"System.Globalization.Calendars": "(,4.3.32767]",
"System.Globalization.Extensions": "(,4.3.32767]",
"System.IO": "(,4.3.32767]",
"System.IO.Compression": "(,4.3.32767]",
"System.IO.Compression.ZipFile": "(,4.3.32767]",
"System.IO.FileSystem": "(,4.3.32767]",
"System.IO.FileSystem.AccessControl": "(,4.4.32767]",
"System.IO.FileSystem.DriveInfo": "(,4.3.32767]",
"System.IO.FileSystem.Primitives": "(,4.3.32767]",
"System.IO.FileSystem.Watcher": "(,4.3.32767]",
"System.IO.IsolatedStorage": "(,4.3.32767]",
"System.IO.MemoryMappedFiles": "(,4.3.32767]",
"System.IO.Pipelines": "(,10.0.32767]",
"System.IO.Pipes": "(,4.3.32767]",
"System.IO.Pipes.AccessControl": "(,5.0.32767]",
"System.IO.UnmanagedMemoryStream": "(,4.3.32767]",
"System.Linq": "(,4.3.32767]",
"System.Linq.AsyncEnumerable": "(,10.0.32767]",
"System.Linq.Expressions": "(,4.3.32767]",
"System.Linq.Parallel": "(,4.3.32767]",
"System.Linq.Queryable": "(,4.3.32767]",
"System.Memory": "(,5.0.32767]",
"System.Net.Http": "(,4.3.32767]",
"System.Net.Http.Json": "(,10.0.32767]",
"System.Net.NameResolution": "(,4.3.32767]",
"System.Net.NetworkInformation": "(,4.3.32767]",
"System.Net.Ping": "(,4.3.32767]",
"System.Net.Primitives": "(,4.3.32767]",
"System.Net.Requests": "(,4.3.32767]",
"System.Net.Security": "(,4.3.32767]",
"System.Net.ServerSentEvents": "(,10.0.32767]",
"System.Net.Sockets": "(,4.3.32767]",
"System.Net.WebHeaderCollection": "(,4.3.32767]",
"System.Net.WebSockets": "(,4.3.32767]",
"System.Net.WebSockets.Client": "(,4.3.32767]",
"System.Numerics.Vectors": "(,5.0.32767]",
"System.ObjectModel": "(,4.3.32767]",
"System.Private.DataContractSerialization": "(,4.3.32767]",
"System.Private.Uri": "(,4.3.32767]",
"System.Reflection": "(,4.3.32767]",
"System.Reflection.DispatchProxy": "(,6.0.32767]",
"System.Reflection.Emit": "(,4.7.32767]",
"System.Reflection.Emit.ILGeneration": "(,4.7.32767]",
"System.Reflection.Emit.Lightweight": "(,4.7.32767]",
"System.Reflection.Extensions": "(,4.3.32767]",
"System.Reflection.Metadata": "(,10.0.32767]",
"System.Reflection.Primitives": "(,4.3.32767]",
"System.Reflection.TypeExtensions": "(,4.3.32767]",
"System.Resources.Reader": "(,4.3.32767]",
"System.Resources.ResourceManager": "(,4.3.32767]",
"System.Resources.Writer": "(,4.3.32767]",
"System.Runtime": "(,4.3.32767]",
"System.Runtime.CompilerServices.Unsafe": "(,7.0.32767]",
"System.Runtime.CompilerServices.VisualC": "(,4.3.32767]",
"System.Runtime.Extensions": "(,4.3.32767]",
"System.Runtime.Handles": "(,4.3.32767]",
"System.Runtime.InteropServices": "(,4.3.32767]",
"System.Runtime.InteropServices.RuntimeInformation": "(,4.3.32767]",
"System.Runtime.Loader": "(,4.3.32767]",
"System.Runtime.Numerics": "(,4.3.32767]",
"System.Runtime.Serialization.Formatters": "(,4.3.32767]",
"System.Runtime.Serialization.Json": "(,4.3.32767]",
"System.Runtime.Serialization.Primitives": "(,4.3.32767]",
"System.Runtime.Serialization.Xml": "(,4.3.32767]",
"System.Security.AccessControl": "(,6.0.32767]",
"System.Security.Claims": "(,4.3.32767]",
"System.Security.Cryptography.Algorithms": "(,4.3.32767]",
"System.Security.Cryptography.Cng": "(,5.0.32767]",
"System.Security.Cryptography.Csp": "(,4.3.32767]",
"System.Security.Cryptography.Encoding": "(,4.3.32767]",
"System.Security.Cryptography.OpenSsl": "(,5.0.32767]",
"System.Security.Cryptography.Primitives": "(,4.3.32767]",
"System.Security.Cryptography.X509Certificates": "(,4.3.32767]",
"System.Security.Principal": "(,4.3.32767]",
"System.Security.Principal.Windows": "(,5.0.32767]",
"System.Security.SecureString": "(,4.3.32767]",
"System.Text.Encoding": "(,4.3.32767]",
"System.Text.Encoding.CodePages": "(,10.0.32767]",
"System.Text.Encoding.Extensions": "(,4.3.32767]",
"System.Text.Encodings.Web": "(,10.0.32767]",
"System.Text.Json": "(,10.0.32767]",
"System.Text.RegularExpressions": "(,4.3.32767]",
"System.Threading": "(,4.3.32767]",
"System.Threading.AccessControl": "(,10.0.32767]",
"System.Threading.Channels": "(,10.0.32767]",
"System.Threading.Overlapped": "(,4.3.32767]",
"System.Threading.Tasks": "(,4.3.32767]",
"System.Threading.Tasks.Dataflow": "(,10.0.32767]",
"System.Threading.Tasks.Extensions": "(,5.0.32767]",
"System.Threading.Tasks.Parallel": "(,4.3.32767]",
"System.Threading.Thread": "(,4.3.32767]",
"System.Threading.ThreadPool": "(,4.3.32767]",
"System.Threading.Timer": "(,4.3.32767]",
"System.ValueTuple": "(,4.5.32767]",
"System.Xml.ReaderWriter": "(,4.3.32767]",
"System.Xml.XDocument": "(,4.3.32767]",
"System.Xml.XmlDocument": "(,4.3.32767]",
"System.Xml.XmlSerializer": "(,4.3.32767]",
"System.Xml.XPath": "(,4.3.32767]",
"System.Xml.XPath.XDocument": "(,5.0.32767]"
}
}
}
}
}
@@ -1,8 +0,0 @@
{
"version": 2,
"dgSpecHash": "aiCDksw3TMY=",
"success": true,
"projectFilePath": "C:\\Temp\\data_feed\\src\\dotnet\\QuantEngine.Tools\\QuantEngine.Tools.csproj",
"expectedPackageFiles": [],
"logs": []
}
@@ -0,0 +1,133 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using QuantEngine.Web.Client.Services;
namespace QuantEngine.Web.Client.Infrastructure
{
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly LocalStorageService _localStorage;
private readonly HttpClient _http;
private readonly ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());
private const string TokenKey = "quant_admin_access_token";
private const string UsernameKey = "quant_admin_username";
private const string RoleKey = "quant_admin_role";
private const string RememberUsernameKey = "quant_admin_remember_username";
public CustomAuthenticationStateProvider(LocalStorageService localStorage, HttpClient http)
{
_localStorage = localStorage;
_http = http;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
try
{
var token = await _localStorage.GetAsync<string>(TokenKey);
var username = await _localStorage.GetAsync<string>(UsernameKey);
var role = await _localStorage.GetAsync<string>(RoleKey) ?? "Admin";
if (!string.IsNullOrWhiteSpace(token) && !string.IsNullOrWhiteSpace(username))
{
var request = new HttpRequestMessage(HttpMethod.Get, "api/auth/me");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var response = await _http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
await MarkUserAsLoggedOutAsync();
return new AuthenticationState(_anonymous);
}
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Role, role)
}, "QuantAdminAuth");
var user = new ClaimsPrincipal(identity);
return new AuthenticationState(user);
}
}
catch
{
// Return anonymous if localStorage isn't ready
}
return new AuthenticationState(_anonymous);
}
public async Task MarkUserAsAuthenticatedAsync(string username, string accessToken, string role)
{
await MarkUserAsAuthenticatedAsync(username, accessToken, role, rememberUsername: true);
}
public async Task MarkUserAsAuthenticatedAsync(string username, string accessToken, string role, bool rememberUsername)
{
await _localStorage.SetAsync(TokenKey, accessToken);
if (rememberUsername)
{
await _localStorage.SetAsync(UsernameKey, username);
await _localStorage.SetAsync(RememberUsernameKey, true);
}
else
{
await _localStorage.DeleteAsync(UsernameKey);
await _localStorage.SetAsync(RememberUsernameKey, false);
}
await _localStorage.SetAsync(RoleKey, role);
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Role, role)
}, "QuantAdminAuth");
var user = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
}
public async Task MarkUserAsLoggedOutAsync()
{
await _localStorage.DeleteAsync(TokenKey);
await _localStorage.DeleteAsync(RoleKey);
var rememberUsername = await _localStorage.GetAsync<bool>(RememberUsernameKey);
if (!rememberUsername)
{
await _localStorage.DeleteAsync(UsernameKey);
}
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(_anonymous)));
}
public async Task LogoutFromServerAsync()
{
var token = await _localStorage.GetAsync<string>(TokenKey);
if (!string.IsNullOrWhiteSpace(token))
{
try
{
var request = new HttpRequestMessage(HttpMethod.Post, "api/auth/logout");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
await _http.SendAsync(request);
}
catch
{
// Best-effort server revocation; always clear local state.
}
}
await MarkUserAsLoggedOutAsync();
}
public async Task<string?> GetRememberedUsernameAsync()
{
var rememberUsername = await _localStorage.GetAsync<bool>(RememberUsernameKey);
if (!rememberUsername)
{
return null;
}
return await _localStorage.GetAsync<string>(UsernameKey);
}
}
}
@@ -0,0 +1,3 @@
@inherits LayoutComponentBase
@Body
@@ -0,0 +1,69 @@
@inherits LayoutComponentBase
@inject HttpClient Http
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager
<MudLayout>
<MudAppBar Elevation="1" Dense="true">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@(() => navOpen = !navOpen)" />
<MudText Typo="Typo.h6">QuantEngine v@appVersion</MudText>
<MudSpacer />
<AuthorizeView>
<Authorized>
<MudText Typo="Typo.body2">관리자 (@context.User.Identity?.Name)</MudText>
<MudButton Variant="Variant.Outlined" Color="Color.Error" OnClick="HandleLogoutAsync">로그아웃</MudButton>
</Authorized>
</AuthorizeView>
</MudAppBar>
<MudDrawer Open="@navOpen" Variant="DrawerVariant.Responsive" Elevation="1">
<MudNavMenu>
<NavMenu />
</MudNavMenu>
<div style="padding: 16px; border-top: 1px solid var(--mud-palette-lines-default);">
<MudText Typo="Typo.caption">QuantEngine v@appVersion</MudText>
<MudText Typo="Typo.caption">배포: @buildTime</MudText>
</div>
</MudDrawer>
<MudMainContent>
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4">
@Body
</MudContainer>
</MudMainContent>
</MudLayout>
@code {
private bool navOpen = true;
private string appVersion = "Local Debug";
private string buildTime = "N/A";
protected override async Task OnInitializedAsync()
{
try
{
var versionInfo = await Http.GetFromJsonAsync<VersionInfo>("version.json");
if (versionInfo != null)
{
appVersion = versionInfo.Version ?? "Local Debug";
buildTime = versionInfo.Built ?? "N/A";
}
}
catch
{
}
}
private async Task HandleLogoutAsync()
{
var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider;
await customProvider.LogoutFromServerAsync();
NavigationManager.NavigateTo("/login");
}
private class VersionInfo
{
public string? Version { get; set; }
public string? Built { get; set; }
}
}
@@ -0,0 +1,4 @@
<MudNavMenu>
<MudNavLink Href="/dashboard" Match="NavLinkMatch.All">Dashboard</MudNavLink>
<MudNavLink Href="/operations" Match="NavLinkMatch.Prefix">Operations</MudNavLink>
</MudNavMenu>
@@ -1,122 +1,93 @@
@page "/collection"
@using QuantEngine.Web.Services
@attribute [Authorize]
@using QuantEngine.Web.Client.Services
@inject ApiClient ApiClient
@inject ILogger<Collection> Logger
<PageTitle>QuantEngine - Collection</PageTitle>
<h1 style="margin: 0 0 8px 0; font-size: 28px; font-weight: 600;">Data Collection</h1>
<p style="margin: 0 0 16px 0; color: var(--neutral-foreground-2); font-size: 14px;">
KIS API data collection dashboard. Monitor runs, snapshots, and error trends.
</p>
<MudText Typo="Typo.h4" Class="mb-2">Data Collection</MudText>
<MudText Typo="Typo.body2" Class="mb-4">KIS API data collection dashboard. API-first로만 동작합니다.</MudText>
<!-- Controls -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="8" Style="margin-bottom: 16px;">
<FluentButton Appearance="ButtonAppearance.Primary" OnClick="@StartCollectionAsync" Disabled="@IsProcessing">
@if (IsProcessing) { <span>Running...</span> } else { <span>Start Collection</span> }
</FluentButton>
<FluentButton Appearance="ButtonAppearance.Default" OnClick="@RefreshAsync" Disabled="@IsProcessing">
Refresh
</FluentButton>
</FluentStack>
<MudStack Row="true" Spacing="2" Class="mb-4">
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@StartCollectionAsync" Disabled="@IsProcessing">
@(IsProcessing ? "Running..." : "Start Collection")
</MudButton>
<MudButton Variant="Variant.Outlined" OnClick="@RefreshAsync" Disabled="@IsProcessing">Refresh</MudButton>
</MudStack>
<!-- Loading skeleton -->
@if (IsLoading)
{
<FluentStack Orientation="Orientation.Vertical" VerticalGap="16">
<FluentSkeleton Width="100%" Height="60px" />
<FluentSkeleton Width="100%" Height="200px" />
</FluentStack>
<MudProgressLinear Indeterminate="true" Color="Color.Primary" Class="mb-4" />
}
else if (DashboardState != null)
{
<!-- Summary Cards -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Last Run</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@(DashboardState.LastRunStatus ?? "N/A")</h3>
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">@(DashboardState.LastFinishedAt ?? "Not finished")</p>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Total Snapshots</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@DashboardState.TotalSnapshots</h3>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Total Errors</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@DashboardState.TotalErrors</h3>
</div>
</FluentCard>
</FluentStack>
<MudGrid Spacing="2" Class="mb-4">
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Last Run</MudText>
<MudText Typo="Typo.h6">@(DashboardState.LastRunStatus ?? "N/A")</MudText>
<MudText Typo="Typo.body2">@(DashboardState.LastFinishedAt ?? "Not finished")</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Total Snapshots</MudText>
<MudText Typo="Typo.h6">@DashboardState.TotalSnapshots</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Total Errors</MudText>
<MudText Typo="Typo.h6">@DashboardState.TotalErrors</MudText>
</MudPaper>
</MudItem>
</MudGrid>
<!-- Recent Errors -->
@if (DashboardState.RecentErrors.Count > 0)
{
<FluentCard Style="margin-bottom: 16px;">
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Recent Errors</h3>
<table style="width: 100%; border-collapse: collapse;">
<thead style="background: var(--neutral-subtle);">
<tr>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Source</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Kind</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Ticker</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Message</th>
</tr>
</thead>
<tbody>
@foreach (var error in DashboardState.RecentErrors)
{
<tr>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@error.SourceName</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@error.ErrorKind</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@error.Ticker</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@error.ErrorMessage</td>
</tr>
}
</tbody>
</table>
</div>
</FluentCard>
<MudPaper Class="pa-4 mb-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Recent Errors</MudText>
<MudTable Items="@DashboardState.RecentErrors" Dense="true" Hover="true">
<HeaderContent>
<MudTh>Source</MudTh>
<MudTh>Kind</MudTh>
<MudTh>Ticker</MudTh>
<MudTh>Message</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Source">@context.SourceName</MudTd>
<MudTd DataLabel="Kind">@context.ErrorKind</MudTd>
<MudTd DataLabel="Ticker">@context.Ticker</MudTd>
<MudTd DataLabel="Message">@context.ErrorMessage</MudTd>
</RowTemplate>
</MudTable>
</MudPaper>
}
<!-- Recent Runs -->
@if (RecentRuns != null && RecentRuns.Count > 0)
{
<FluentCard>
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Recent Runs</h3>
<table style="width: 100%; border-collapse: collapse;">
<thead style="background: var(--neutral-subtle);">
<tr>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Run ID</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Status</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Started</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Finished</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Snapshots</th>
<th style="padding: 8px; text-align: left; border-bottom: 1px solid var(--neutral-divider-rest);">Errors</th>
</tr>
</thead>
<tbody>
@foreach (var run in RecentRuns)
{
<tr>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest); font-family: monospace; font-size: 12px;">@run.RunId</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@run.Status</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest); font-size: 12px;">@run.StartedAt</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest); font-size: 12px;">@run.FinishedAt</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@run.TotalSnapshots</td>
<td style="padding: 8px; border-bottom: 1px solid var(--neutral-stroke-divider-rest);">@run.TotalErrors</td>
</tr>
}
</tbody>
</table>
</div>
</FluentCard>
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Recent Runs</MudText>
<MudTable Items="@RecentRuns" Dense="true" Hover="true">
<HeaderContent>
<MudTh>Run ID</MudTh>
<MudTh>Status</MudTh>
<MudTh>Started</MudTh>
<MudTh>Finished</MudTh>
<MudTh>Snapshots</MudTh>
<MudTh>Errors</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Run ID" Style="font-family: monospace; font-size: 12px;">@context.RunId</MudTd>
<MudTd DataLabel="Status">@context.Status</MudTd>
<MudTd DataLabel="Started">@context.StartedAt</MudTd>
<MudTd DataLabel="Finished">@context.FinishedAt</MudTd>
<MudTd DataLabel="Snapshots">@context.TotalSnapshots</MudTd>
<MudTd DataLabel="Errors">@context.TotalErrors</MudTd>
</RowTemplate>
</MudTable>
</MudPaper>
}
}
@@ -137,7 +108,6 @@ else if (DashboardState != null)
try
{
DashboardState = await ApiClient.GetCollectionStateAsync();
var runsResponse = await ApiClient.GetCollectionRunsAsync(10);
RecentRuns = runsResponse?.Runs ?? new();
}
@@ -0,0 +1,117 @@
@page "/dashboard"
@attribute [Authorize]
@using QuantEngine.Core.Infrastructure
@inject HttpClient Http
<PageTitle>Quant Engine - Dashboard</PageTitle>
<MudText Typo="Typo.h4" Class="mb-2">Quant Engine</MudText>
<MudText Typo="Typo.body2" Class="mb-4">운영 진입점입니다. 로그인 후 현재 스냅샷 상태와 리포트 경로만 표시합니다.</MudText>
<MudGrid Spacing="2" Class="mb-4">
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Operational Report</MudText>
<MudText Typo="Typo.h6">@ReportStateLabel</MudText>
<MudText Typo="Typo.body2">@ReportPath</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Sections</MudText>
<MudText Typo="Typo.h6">@SectionCountLabel</MudText>
<MudText Typo="Typo.body2">Temp/operational_report.json</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Primary Route</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Href="/operations" Class="mt-2">Open Operations</MudButton>
</MudPaper>
</MudItem>
</MudGrid>
<MudGrid Spacing="2" Class="mb-4">
<MudItem xs="12" md="8">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Current State</MudText>
<MudStack Spacing="1">
<MudText Typo="Typo.body2">Status: <MudChip T="string" Color="@(ReportChipLabel == "READY" ? Color.Success : Color.Warning)" Variant="Variant.Filled">@ReportChipLabel</MudChip></MudText>
<MudText Typo="Typo.body2">Generated: @GeneratedAtLabel</MudText>
<MudText Typo="Typo.body2">Source: @SourceLabel</MudText>
<MudText Typo="Typo.body2">Decision feed: @DecisionFeedLabel</MudText>
<MudText Typo="Typo.body2">Factor feed: @FactorFeedLabel</MudText>
<MudText Typo="Typo.body2">Raw feed: @RawFeedLabel</MudText>
</MudStack>
</MudPaper>
</MudItem>
<MudItem xs="12" md="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Routing Notes</MudText>
<ul style="margin: 0; padding-left: 18px;">
<li>운영 데이터는 snapshot 우선입니다.</li>
<li>Excel/GAS 의존 문구는 제거 대상입니다.</li>
<li>숫자는 provenance 없으면 표시하지 않습니다.</li>
</ul>
</MudPaper>
</MudItem>
</MudGrid>
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Coverage Summary</MudText>
@if (Sections.Count == 0)
{
<MudAlert Severity="Severity.Warning">DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.</MudAlert>
}
else
{
<MudTable Items="@Sections" Dense="true" Hover="true">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Title</MudTh>
<MudTh>Preview</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Title">@context.Title</MudTd>
<MudTd DataLabel="Preview">@context.Preview</MudTd>
</RowTemplate>
</MudTable>
}
</MudPaper>
@code {
private readonly List<OperationalReportSection> Sections = new();
private string ReportStateLabel = "DATA_MISSING";
private string ReportChipLabel = "DATA_MISSING";
private string SectionCountLabel = "0";
private string GeneratedAtLabel = "n/a";
private string SourceLabel = "n/a";
private string DecisionFeedLabel = "DISCONNECTED";
private string FactorFeedLabel = "DISCONNECTED";
private string RawFeedLabel = "DISCONNECTED";
private string ReportPath = "n/a";
protected override async Task OnInitializedAsync()
{
try
{
var report = await Http.GetFromJsonAsync<OperationalReportData>("api/operational-report");
if (report != null)
{
Sections.Clear();
Sections.AddRange(report.Sections);
SectionCountLabel = report.SectionCount.ToString();
GeneratedAtLabel = report.GeneratedAt;
SourceLabel = report.SourceJson;
ReportStateLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
ReportChipLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
}
}
catch
{
ReportStateLabel = "DATA_MISSING";
ReportChipLabel = "DATA_MISSING";
}
}
}
@@ -0,0 +1,124 @@
@page "/login"
@attribute [AllowAnonymous]
@layout AuthLayout
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager
@inject HttpClient Http
<PageTitle>로그인 - QuantEngine</PageTitle>
<MudContainer MaxWidth="MaxWidth.False" Class="login-shell">
<MudPaper Class="login-card pa-8" Elevation="10">
<MudStack AlignItems="AlignItems.Center" Spacing="2" Class="mb-6">
<MudAvatar Size="Size.Large" Color="Color.Primary">Q</MudAvatar>
<MudText Typo="Typo.h4">QuantEngine</MudText>
<MudText Typo="Typo.body2" Align="Align.Center">은퇴자산포트폴리오 투자 관리 시스템</MudText>
</MudStack>
<MudStack Spacing="2">
<MudTextField Label="관리자 아이디" @bind-Value="Username" Variant="Variant.Outlined" Immediate="true" AutoFocus="true" />
<MudTextField Label="비밀번호" @bind-Value="Password" Variant="Variant.Outlined" InputType="InputType.Password" Immediate="true" />
<MudCheckBox T="bool" @bind-Checked="RememberUsername" Color="Color.Primary" Label="아이디 저장" />
@if (!string.IsNullOrEmpty(ErrorMessage))
{
<MudAlert Severity="Severity.Error">@ErrorMessage</MudAlert>
}
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true" Disabled="@IsSubmitting" OnClick="HandleLoginAsync">
@(IsSubmitting ? "인증 중..." : "로그인")
</MudButton>
</MudStack>
</MudPaper>
</MudContainer>
<style>
.login-shell {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background:
radial-gradient(circle at top left, rgba(0, 242, 254, 0.08), transparent 30%),
radial-gradient(circle at bottom right, rgba(79, 172, 254, 0.1), transparent 35%),
linear-gradient(135deg, #090a15 0%, #12142d 100%);
}
.login-card {
width: min(480px, calc(100vw - 32px));
border-radius: 20px;
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(24px);
color: white;
}
</style>
@code {
private string Username { get; set; } = string.Empty;
private string Password { get; set; } = string.Empty;
private string ErrorMessage { get; set; } = string.Empty;
private bool IsSubmitting { get; set; } = false;
private bool RememberUsername { get; set; } = true;
protected override async Task OnInitializedAsync()
{
var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider;
var remembered = await customProvider.GetRememberedUsernameAsync();
if (!string.IsNullOrWhiteSpace(remembered))
{
Username = remembered;
RememberUsername = true;
}
}
private sealed class LoginResponse
{
public bool Success { get; set; }
public string? Username { get; set; }
public string? Role { get; set; }
public string? AccessToken { get; set; }
public string? ExpiresAt { get; set; }
}
private async Task HandleLoginAsync()
{
ErrorMessage = string.Empty;
if (string.IsNullOrWhiteSpace(Username) || string.IsNullOrWhiteSpace(Password))
{
ErrorMessage = "아이디와 비밀번호를 모두 입력해 주세요.";
return;
}
IsSubmitting = true;
try
{
var response = await Http.PostAsJsonAsync("api/auth/login", new { Username, Password });
if (response.IsSuccessStatusCode)
{
var auth = await response.Content.ReadFromJsonAsync<LoginResponse>();
if (auth is null || string.IsNullOrWhiteSpace(auth.AccessToken))
{
ErrorMessage = "로그인 응답이 유효하지 않습니다.";
return;
}
var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider;
await customProvider.MarkUserAsAuthenticatedAsync(auth.Username ?? Username, auth.AccessToken, auth.Role ?? "Admin", RememberUsername);
NavigationManager.NavigateTo("/dashboard");
}
else
{
ErrorMessage = "아이디 또는 비밀번호가 올바르지 않습니다.";
}
}
catch (Exception ex)
{
ErrorMessage = $"로그인 중 오류가 발생했습니다: {ex.Message}";
}
finally
{
IsSubmitting = false;
}
}
}
@@ -0,0 +1,121 @@
@page "/operations"
@attribute [Authorize]
@using QuantEngine.Core.Infrastructure
@inject HttpClient Http
<PageTitle>QuantEngine - Operations</PageTitle>
<MudText Typo="Typo.h4" Class="mb-2">Operational Report</MudText>
<MudText Typo="Typo.body2" Class="mb-4">Temp/operational_report.json만 읽는 운영 고정 화면입니다.</MudText>
<MudGrid Spacing="2" Class="mb-4">
<MudItem xs="12" sm="3">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Schema</MudText>
<MudText Typo="Typo.h6">@SchemaVersion</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="3">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Sections</MudText>
<MudText Typo="Typo.h6">@SectionCountLabel</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="3">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Source</MudText>
<MudText Typo="Typo.h6">@SourceJson</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="3">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Generated</MudText>
<MudText Typo="Typo.h6">@GeneratedAt</MudText>
</MudPaper>
</MudItem>
</MudGrid>
<MudGrid Spacing="2" Class="mb-4">
@foreach (var section in HighlightSections)
{
<MudItem xs="12" sm="6" md="3" @key="section.Name">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">@(section.Name)</MudText>
<MudText Typo="Typo.h6">@(section.Title)</MudText>
<MudText Typo="Typo.body2">@(section.Preview)</MudText>
</MudPaper>
</MudItem>
}
</MudGrid>
<MudPaper Class="pa-4 mb-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Report Health</MudText>
<MudStack Spacing="1">
<MudText Typo="Typo.body2">Status: <MudChip T="string" Color="@(HealthLabel == "PASS" ? Color.Success : Color.Warning)" Variant="Variant.Filled">@HealthLabel</MudChip></MudText>
<MudText Typo="Typo.body2">Path: @ReportPath</MudText>
<MudText Typo="Typo.body2">Sections rendered: @RenderedSectionCountLabel</MudText>
</MudStack>
</MudPaper>
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Sections</MudText>
@if (Sections.Count == 0)
{
<MudAlert Severity="Severity.Warning">DATA_MISSING: operational_report.json에 표시할 섹션이 없습니다.</MudAlert>
}
else
{
<MudTable Items="@Sections" Dense="true" Hover="true">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Title</MudTh>
<MudTh>Preview</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Title">@context.Title</MudTd>
<MudTd DataLabel="Preview">@context.Preview</MudTd>
</RowTemplate>
</MudTable>
}
</MudPaper>
@code {
private readonly List<OperationalReportSection> Sections = new();
private readonly List<OperationalReportSection> HighlightSections = new();
private string SchemaVersion = "n/a";
private string SourceJson = "n/a";
private string GeneratedAt = "n/a";
private string SectionCountLabel = "0";
private string RenderedSectionCountLabel = "0";
private string HealthLabel = "DATA_MISSING";
private string ReportPath = "n/a";
protected override async Task OnInitializedAsync()
{
try
{
var report = await Http.GetFromJsonAsync<OperationalReportData>("api/operational-report");
if (report != null)
{
SchemaVersion = report.SchemaVersion;
SourceJson = report.SourceJson;
GeneratedAt = report.GeneratedAt;
Sections.Clear();
Sections.AddRange(report.Sections);
HighlightSections.Clear();
HighlightSections.AddRange(Sections.Take(4));
SectionCountLabel = report.SectionCount.ToString();
RenderedSectionCountLabel = Sections.Count.ToString();
HealthLabel = Sections.Count > 0 ? "PASS" : "DATA_MISSING";
}
}
catch
{
HealthLabel = "DATA_MISSING";
}
}
}
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components.Authorization;
using QuantEngine.Web.Client.Services;
using QuantEngine.Web.Client.Infrastructure;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
// Register LocalStorage for cross-platform session persistence
builder.Services.AddScoped<LocalStorageService>();
// Authentication setup in WebAssembly client
builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
// HttpClient register (API-First standard)
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\QuantEngine.Core\QuantEngine.Core.csproj" />
<ProjectReference Include="..\..\QuantEngine.Application\QuantEngine.Application.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0-preview.2.25120.18" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.0-preview.2.25120.18" />
<PackageReference Include="MudBlazor" Version="8.6.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,8 @@
@inject NavigationManager NavigationManager
@code {
protected override void OnInitialized()
{
NavigationManager.NavigateTo("login");
}
}
@@ -2,19 +2,16 @@ using System.Net.Http.Json;
using System.Text.Json.Serialization;
using QuantEngine.Core.Interfaces;
namespace QuantEngine.Web.Services;
namespace QuantEngine.Web.Client.Services;
public class ApiClient
{
private readonly HttpClient _http;
private readonly ILogger<ApiClient> _logger;
private string BaseUrl { get; set; }
public ApiClient(HttpClient http, ILogger<ApiClient> logger)
{
_http = http;
_logger = logger;
BaseUrl = "http://localhost:5001"; // Default for Blazor Server
}
// Collection API Methods
@@ -23,7 +20,7 @@ public class ApiClient
{
try
{
return await _http.GetFromJsonAsync<CollectionDashboardStateDto>($"{BaseUrl}/api/collection/state");
return await _http.GetFromJsonAsync<CollectionDashboardStateDto>("api/collection/state");
}
catch (Exception ex)
{
@@ -36,7 +33,7 @@ public class ApiClient
{
try
{
return await _http.GetFromJsonAsync<CollectionRunsResponse>($"{BaseUrl}/api/collection/runs?limit={limit}");
return await _http.GetFromJsonAsync<CollectionRunsResponse>($"api/collection/runs?limit={limit}");
}
catch (Exception ex)
{
@@ -49,7 +46,7 @@ public class ApiClient
{
try
{
return await _http.GetFromJsonAsync<CollectionRunSnapshotsResponse>($"{BaseUrl}/api/collection/runs/{runId}/snapshots");
return await _http.GetFromJsonAsync<CollectionRunSnapshotsResponse>($"api/collection/runs/{runId}/snapshots");
}
catch (Exception ex)
{
@@ -62,7 +59,7 @@ public class ApiClient
{
try
{
return await _http.GetFromJsonAsync<CollectionRunErrorsResponse>($"{BaseUrl}/api/collection/runs/{runId}/errors?limit={limit}");
return await _http.GetFromJsonAsync<CollectionRunErrorsResponse>($"api/collection/runs/{runId}/errors?limit={limit}");
}
catch (Exception ex)
{
@@ -75,7 +72,7 @@ public class ApiClient
{
try
{
var response = await _http.PostAsJsonAsync($"{BaseUrl}/api/collection/run", new { });
var response = await _http.PostAsJsonAsync("api/collection/run", new { });
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadFromJsonAsync<CollectionRunStartResponse>();
@@ -0,0 +1,43 @@
using Microsoft.JSInterop;
using System.Text.Json;
namespace QuantEngine.Web.Client.Services
{
public class LocalStorageService
{
private readonly IJSRuntime _js;
public LocalStorageService(IJSRuntime js)
{
_js = js;
}
public async Task SetAsync<T>(string key, T value)
{
var json = JsonSerializer.Serialize(value);
await _js.InvokeVoidAsync("localStorage.setItem", key, json);
}
public async Task<T?> GetAsync<T>(string key)
{
try
{
var json = await _js.InvokeAsync<string?>("localStorage.getItem", key);
if (string.IsNullOrEmpty(json))
{
return default;
}
return JsonSerializer.Deserialize<T>(json);
}
catch
{
return default;
}
}
public async Task DeleteAsync(string key)
{
await _js.InvokeVoidAsync("localStorage.removeItem", key);
}
}
}
@@ -6,9 +6,11 @@
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Microsoft.FluentUI.AspNetCore.Components
@using Microsoft.FluentUI.AspNetCore.Components.Icons
@using QuantEngine.Web
@using QuantEngine.Web.Components
@using QuantEngine.Web.Components.Layout
@using QuantEngine.Web.Services
@using MudBlazor
@using QuantEngine.Web.Client
@using QuantEngine.Web.Client.Pages
@using QuantEngine.Web.Client.Layout
@using QuantEngine.Web.Client.Infrastructure
@using QuantEngine.Web.Client.Services
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Authorization
+12 -12
View File
@@ -1,29 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/quant/" />
<base href="/" />
<ResourcePreloader />
<!-- Fluent UI CSS -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/Microsoft.FluentUI.AspNetCore.Components/css/fluent-components.css" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["QuantEngine.Web.styles.css"]" />
<ImportMap />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
<link rel="alternate icon" type="image/png" href="favicon.png" />
<HeadOutlet @rendermode="InteractiveWebAssembly" />
</head>
<body>
<FluentDesignSystemProvider>
<Routes />
<ReconnectModal />
</FluentDesignSystemProvider>
<MudThemeProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<Routes @rendermode="InteractiveWebAssembly" />
<ReconnectModal />
<!-- Fluent UI JS -->
<script src="_content/Microsoft.FluentUI.AspNetCore.Components/js/fluent-components.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="@Assets["_framework/blazor.web.js"]"></script>
</body>
@@ -1,94 +0,0 @@
@inherits LayoutComponentBase
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
@using System.IO
@using System.Text.Json
@using Microsoft.FluentUI.AspNetCore.Components
<FluentStack Orientation="Orientation.Vertical" Class="h-100 w-100">
<!-- Header -->
<FluentHeader>
<FluentStack Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center"
Style="width: 100%; padding: 8px 16px; gap: 16px;">
<FluentButton OnClick="@(() => navOpen = !navOpen)"
Title="Toggle Navigation"
Style="background: transparent; border: none; cursor: pointer;">
</FluentButton>
<h1 style="margin: 0; font-size: 20px; font-weight: 600;">QuantEngine v@appVersion</h1>
</FluentStack>
</FluentHeader>
<!-- Main Content Area -->
<FluentStack Orientation="Orientation.Horizontal" Class="flex-1" Style="overflow: hidden;">
<!-- Navigation Sidebar -->
@if (navOpen)
{
<nav style="width: 240px; background: var(--neutral-layer-1); border-right: 1px solid var(--neutral-stroke-1); padding: 12px; overflow-y: auto;">
<NavMenu />
<div style="margin-top: auto; padding-top: 12px; border-top: 1px solid var(--neutral-stroke-1); margin-top: 12px; font-size: 11px; color: var(--neutral-foreground-3); line-height: 1.5;">
<div style="font-weight: 500; margin-bottom: 2px;">QuantEngine v@appVersion</div>
<div style="font-size: 10px; opacity: 0.85;">배포: @buildTime</div>
</div>
</nav>
}
<!-- Page Content -->
<FluentStack Orientation="Orientation.Vertical" Class="flex-1" Style="overflow-y: auto; padding: 24px;">
@Body
</FluentStack>
</FluentStack>
</FluentStack>
<div id="blazor-error-ui" data-nosnippet>
<div class="alert alert-danger" role="alert">
<p>An unhandled error has occurred.</p>
<a href="." class="btn btn-primary">Reload</a>
</div>
</div>
<style>
.h-100 {
height: 100%;
}
.w-100 {
width: 100%;
}
.flex-1 {
flex: 1;
display: flex;
}
</style>
@code {
private bool navOpen = true;
private string appVersion = "Local Debug";
private string buildTime = "N/A";
protected override void OnInitialized()
{
try
{
var versionFilePath = Path.Combine(WebHostEnvironment.WebRootPath, "version.json");
if (File.Exists(versionFilePath))
{
var jsonContent = File.ReadAllText(versionFilePath);
using var doc = System.Text.Json.JsonDocument.Parse(jsonContent);
var root = doc.RootElement;
if (root.TryGetProperty("version", out var versionProp))
{
appVersion = versionProp.GetString() ?? "Local Debug";
}
if (root.TryGetProperty("built", out var builtProp))
{
buildTime = builtProp.GetString() ?? "N/A";
}
}
}
catch
{
// Fail-safe default fallback values
}
}
}
@@ -1,10 +0,0 @@
@using Microsoft.FluentUI.AspNetCore.Components
<FluentNavMenu>
<FluentNavLink Href="/" Match="NavLinkMatch.All">
Dashboard
</FluentNavLink>
<FluentNavLink Href="/operations" Match="NavLinkMatch.Prefix">
Operations
</FluentNavLink>
</FluentNavMenu>
@@ -1,110 +0,0 @@
@page "/"
@using QuantEngine.Core.Infrastructure
@inject IWebHostEnvironment Environment
<PageTitle>Quant Engine - Dashboard</PageTitle>
<h1 style="margin: 0 0 8px 0; font-size: 28px; font-weight: 600;">Quant Engine</h1>
<p style="margin: 0 0 16px 0; color: var(--neutral-foreground-2); font-size: 14px;">
루트 화면은 운영 진입점입니다. 가짜 성과 수치 없이 현재 스냅샷 상태와 리포트 경로만 보여줍니다.
</p>
<!-- Top 3 Cards -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Operational Report</p>
<h3 style="margin: 0; font-size: 20px; font-weight: 600;">@ReportStateLabel</h3>
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">@ReportPath</p>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Sections</p>
<h3 style="margin: 0; font-size: 20px; font-weight: 600;">@SectionCountLabel</h3>
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">Temp/operational_report.json</p>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Primary Route</p>
<FluentButton Appearance="ButtonAppearance.Primary" Href="/operations" Style="margin-top: 8px;">
Open Operations
</FluentButton>
</div>
</FluentCard>
</FluentStack>
<!-- Current State & Routing Notes -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
<FluentCard Style="flex: 2; min-width: 300px;">
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Current State</h3>
<FluentStack Orientation="Orientation.Vertical" VerticalGap="8">
<p style="margin: 0; font-size: 14px;"><strong>Status:</strong> <FluentBadge Appearance="BadgeAppearance.Filled">@ReportChipLabel</FluentBadge></p>
<p style="margin: 0; font-size: 14px;"><strong>Generated:</strong> @GeneratedAtLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Source:</strong> @SourceLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Decision feed:</strong> @DecisionFeedLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Factor feed:</strong> @FactorFeedLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Raw feed:</strong> @RawFeedLabel</p>
</FluentStack>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 250px;">
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Routing Notes</h3>
<ul style="margin: 0; padding-left: 16px; font-size: 14px;">
<li>운영 데이터는 snapshot 우선입니다.</li>
<li>Excel/GAS 의존 문구는 운영 경로에서 제거 대상입니다.</li>
<li>숫자는 provenance 없으면 표시하지 않습니다.</li>
</ul>
</div>
</FluentCard>
</FluentStack>
<!-- Coverage Summary -->
<FluentCard>
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Coverage Summary</h3>
@if (Sections.Count == 0)
{
<div style="padding: 12px; background: var(--warning-background-1); border: 1px solid var(--warning-stroke-1); border-radius: 4px; color: var(--warning-foreground-1); font-size: 14px;">
DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.
</div>
}
else
{
<FluentDataGrid Items="@Sections.AsQueryable()">
<PropertyColumn Property="@(x => x.Name)" Title="Name" />
<PropertyColumn Property="@(x => x.Title)" Title="Title" />
<PropertyColumn Property="@(x => x.Preview)" Title="Preview" />
</FluentDataGrid>
}
</div>
</FluentCard>
@code {
private readonly List<OperationalReportSection> Sections = new();
private string ReportStateLabel = "DATA_MISSING";
private string ReportChipLabel = "DATA_MISSING";
private string SectionCountLabel = "0";
private string GeneratedAtLabel = "n/a";
private string SourceLabel = "n/a";
private string DecisionFeedLabel = "DISCONNECTED";
private string FactorFeedLabel = "DISCONNECTED";
private string RawFeedLabel = "DISCONNECTED";
private string ReportPath = "n/a";
protected override void OnInitialized()
{
ReportPath = Path.GetFullPath(Path.Combine(Environment.ContentRootPath, "..", "..", "..", "Temp", "operational_report.json"));
var report = OperationalReportLoader.Load(ReportPath);
Sections.AddRange(report.Sections);
SectionCountLabel = report.SectionCount.ToString();
GeneratedAtLabel = report.GeneratedAt;
SourceLabel = report.SourceJson;
ReportStateLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
ReportChipLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
}
}
@@ -1,115 +0,0 @@
@page "/operations"
@using QuantEngine.Core.Infrastructure
@inject IWebHostEnvironment Environment
<PageTitle>Quant Engine - Operations</PageTitle>
<h1 style="margin: 0 0 8px 0; font-size: 28px; font-weight: 600;">Operational Report</h1>
<p style="margin: 0 0 16px 0; color: var(--neutral-foreground-2); font-size: 14px;">
이 페이지는 `Temp/operational_report.json`만 읽습니다. DB 연결과 무관하게 동일한 결과를 보여주는 운영 고정 화면입니다.
</p>
<!-- Metadata Cards -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Schema</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@SchemaVersion</h3>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Sections</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@SectionCountLabel</h3>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Source</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@SourceJson</h3>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 150px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Generated</p>
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@GeneratedAt</h3>
</div>
</FluentCard>
</FluentStack>
<!-- Highlight Sections Grid -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
@foreach (var section in HighlightSections)
{
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 4px 0; color: var(--neutral-foreground-2); font-size: 12px;">@(section.Name)</p>
<h3 style="margin: 4px 0; font-size: 16px; font-weight: 600;">@(section.Title)</h3>
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">@(section.Preview)</p>
</div>
</FluentCard>
}
</FluentStack>
<!-- Report Health -->
<FluentCard Style="margin-bottom: 16px;">
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Report Health</h3>
<FluentStack Orientation="Orientation.Vertical" VerticalGap="8">
<p style="margin: 0; font-size: 14px;"><strong>Status:</strong> <FluentBadge Appearance="BadgeAppearance.Filled">@HealthLabel</FluentBadge></p>
<p style="margin: 0; font-size: 14px;"><strong>Path:</strong> @ReportPath</p>
<p style="margin: 0; font-size: 14px;"><strong>Sections rendered:</strong> @RenderedSectionCountLabel</p>
</FluentStack>
</div>
</FluentCard>
<!-- Sections Table -->
<FluentCard>
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Sections</h3>
@if (Sections.Count == 0)
{
<div style="padding: 12px; background: var(--warning-background-1); border: 1px solid var(--warning-stroke-1); border-radius: 4px; color: var(--warning-foreground-1); font-size: 14px;">
DATA_MISSING: operational_report.json에 표시할 섹션이 없습니다.
</div>
}
else
{
<FluentDataGrid Items="@Sections.AsQueryable()">
<PropertyColumn Property="@(x => x.Name)" Title="Name" />
<PropertyColumn Property="@(x => x.Title)" Title="Title" />
<PropertyColumn Property="@(x => x.Preview)" Title="Preview" />
</FluentDataGrid>
}
</div>
</FluentCard>
@code {
private readonly List<OperationalReportSection> Sections = new();
private readonly List<OperationalReportSection> HighlightSections = new();
private string SchemaVersion = "n/a";
private string SourceJson = "n/a";
private string GeneratedAt = "n/a";
private string SectionCountLabel = "0";
private string RenderedSectionCountLabel = "0";
private string HealthLabel = "DATA_MISSING";
private string ReportPath = "n/a";
protected override async Task OnInitializedAsync()
{
ReportPath = Path.GetFullPath(Path.Combine(Environment.ContentRootPath, "..", "..", "..", "Temp", "operational_report.json"));
var report = OperationalReportLoader.Load(ReportPath);
SchemaVersion = report.SchemaVersion;
SourceJson = report.SourceJson;
GeneratedAt = report.GeneratedAt;
Sections.AddRange(report.Sections);
HighlightSections.Clear();
HighlightSections.AddRange(Sections.Take(4));
SectionCountLabel = report.SectionCount.ToString();
RenderedSectionCountLabel = Sections.Count.ToString();
HealthLabel = Sections.Count > 0 ? "PASS" : "DATA_MISSING";
}
}
@@ -1,6 +1,16 @@
<Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>
@using QuantEngine.Web.Client
@using QuantEngine.Web.Client.Pages
@using QuantEngine.Web.Client.Layout
<CascadingAuthenticationState>
<Router AppAssembly="typeof(Dashboard).Assembly" NotFoundPage="typeof(NotFound)">
<Found Context="routeData">
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
<NotAuthorized>
<RedirectToLogin />
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>
</CascadingAuthenticationState>
@@ -1,4 +1,4 @@
@using System.Net.Http
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@@ -6,8 +6,10 @@
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Microsoft.FluentUI.AspNetCore.Components
@using Microsoft.FluentUI.AspNetCore.Components.Icons
@using MudBlazor
@using QuantEngine.Web
@using QuantEngine.Web.Components
@using QuantEngine.Web.Components.Layout
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Authorization
@using QuantEngine.Web.Infrastructure
@@ -1,5 +1,5 @@
using QuantEngine.Core.Interfaces;
using System.Diagnostics;
using QuantEngine.Application.Services;
namespace QuantEngine.Web.Endpoints;
@@ -108,51 +108,30 @@ public static class CollectionEndpoints
}
}
private static async Task<IResult> StartCollectionRun(ICollectionRepository repo, ILogger<Program> logger)
private static async Task<IResult> StartCollectionRun(
DataCollectionService collectionService,
HttpRequest request,
ILogger<Program> logger)
{
try
{
var runId = Guid.NewGuid().ToString("N");
var now = DateTime.UtcNow.ToString("o");
var run = new CollectionRunRecord(
RunId: runId,
Status: "running",
StartedAt: now,
FinishedAt: null,
TotalSnapshots: null,
TotalErrors: null,
UpdatedAt: now
);
var body = await request.ReadFromJsonAsync<CollectionRunRequest>();
var account = body?.Account ?? "real";
var tickers = body?.Tickers ?? new List<string> { "005930", "000660" };
await repo.SaveRunAsync(run);
// Temp: Invoke Python subprocess for actual collection
// Trigger async collection (fire-and-forget)
_ = Task.Run(async () =>
{
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "python",
Arguments = "tools/run_kis_data_collection_v1.py --input-json GatherTradingData.json --sqlite-db src/quant_engine/kis_data_collection.db --kis-account real",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
await repo.UpdateRunStatusAsync(runId, "completed", DateTime.UtcNow.ToString("o"), 0, 0);
await collectionService.RunCollectionAsync(runId, account, tickers);
}
catch (Exception ex)
{
logger.LogError(ex, $"Collection run {runId} failed");
await repo.UpdateRunStatusAsync(runId, "failed", DateTime.UtcNow.ToString("o"), null, null);
logger.LogError(ex, "Collection run {RunId} failed", runId);
}
});
@@ -160,12 +139,20 @@ public static class CollectionEndpoints
{
runId,
status = "running",
startedAt = now
startedAt = now,
tickerCount = tickers.Count
});
}
catch
catch (Exception ex)
{
logger.LogError(ex, "Failed to start collection run");
return Results.StatusCode(500);
}
}
private class CollectionRunRequest
{
public string? Account { get; set; }
public List<string>? Tickers { get; set; }
}
}
@@ -1,164 +1,2 @@
using QuantEngine.Core.Interfaces;
namespace QuantEngine.Web.Infrastructure;
/// <summary>
/// Placeholder implementations for Collection services.
/// Temporary: to be replaced with actual PostgreSQL implementations.
/// </summary>
public class PlaceholderCollectionRepository : ICollectionRepository
{
private static readonly List<CollectionRunRecord> MockRuns = new();
private static readonly List<CollectionSnapshotRecord> MockSnapshots = new();
private static readonly List<CollectionErrorRecord> MockErrors = new();
public Task SaveRunAsync(CollectionRunRecord run)
{
MockRuns.Add(run);
return Task.CompletedTask;
}
public Task UpdateRunStatusAsync(string runId, string status, string? finishedAt = null, int? totalSnapshots = null, int? totalErrors = null)
{
var run = MockRuns.FirstOrDefault(r => r.RunId == runId);
if (run != null)
{
var idx = MockRuns.IndexOf(run);
MockRuns[idx] = new CollectionRunRecord(runId, status, run.StartedAt, finishedAt, totalSnapshots, totalErrors, DateTime.UtcNow.ToString("o"));
}
return Task.CompletedTask;
}
public Task SaveSnapshotAsync(CollectionSnapshotRecord snapshot)
{
MockSnapshots.Add(snapshot);
return Task.CompletedTask;
}
public Task SaveErrorAsync(CollectionErrorRecord error)
{
MockErrors.Add(error);
return Task.CompletedTask;
}
public Task<List<CollectionRunRecord>> GetRecentRunsAsync(int limit = 20)
{
return Task.FromResult(MockRuns.OrderByDescending(r => r.StartedAt).Take(limit).ToList());
}
public Task<List<CollectionSnapshotRecord>> GetRunSnapshotsAsync(string runId)
{
return Task.FromResult(MockSnapshots.Where(s => s.RunId == runId).ToList());
}
public Task<List<CollectionErrorRecord>> GetRunErrorsAsync(string runId, int limit = 50)
{
return Task.FromResult(MockErrors.Where(e => e.RunId == runId).Take(limit).ToList());
}
public Task<CollectionDashboardStateRecord> GetDashboardStateAsync()
{
var lastRun = MockRuns.OrderByDescending(r => r.StartedAt).FirstOrDefault();
var recentErrors = MockErrors.OrderByDescending(e => e.CreatedAt).Take(5).ToList();
return Task.FromResult(new CollectionDashboardStateRecord(
LastRunId: lastRun?.RunId,
LastRunStatus: lastRun?.Status,
LastFinishedAt: lastRun?.FinishedAt,
TotalSnapshots: MockSnapshots.Count,
TotalErrors: MockErrors.Count,
RecentErrors: recentErrors
));
}
public Task<List<CollectionSnapshotRecord>> GetLatestSnapshotsForTickerAsync(string ticker, int limit = 10)
{
return Task.FromResult(MockSnapshots.Where(s => s.Ticker == ticker).OrderByDescending(s => s.CapturedAt).Take(limit).ToList());
}
}
public class PlaceholderTokenCache : ITokenCache
{
private static readonly Dictionary<string, (string Token, DateTime ExpiresAt)> Cache = new();
public Task<string?> GetCachedTokenAsync(string account)
{
if (Cache.TryGetValue(account, out var entry) && entry.ExpiresAt > DateTime.UtcNow.AddMinutes(10))
{
return Task.FromResult<string?>(entry.Token);
}
return Task.FromResult<string?>(null);
}
public Task SaveTokenAsync(string account, string token, DateTime expiresAt)
{
Cache[account] = (token, expiresAt);
return Task.CompletedTask;
}
public Task ClearExpiredTokensAsync()
{
var expired = Cache.Where(kv => kv.Value.ExpiresAt <= DateTime.UtcNow).Select(kv => kv.Key).ToList();
foreach (var key in expired) Cache.Remove(key);
return Task.CompletedTask;
}
}
public class PlaceholderKisApiClient : IKisApiClient
{
public Task<Dictionary<string, object>> GetCurrentPriceAsync(string code, string account = "mock")
{
return Task.FromResult(new Dictionary<string, object>
{
{ "code", code },
{ "price", 0 },
{ "change", 0 },
{ "changeRate", 0 }
});
}
public Task<Dictionary<string, object>> GetAskingPrice10LevelAsync(string code, string account = "mock")
{
return Task.FromResult(new Dictionary<string, object>
{
{ "code", code },
{ "askLevels", new List<object>() },
{ "bidLevels", new List<object>() }
});
}
public Task<Dictionary<string, object>> GetDailyShortSaleAsync(string code, string startDate, string endDate, string account = "mock")
{
return Task.FromResult(new Dictionary<string, object>
{
{ "code", code },
{ "startDate", startDate },
{ "endDate", endDate },
{ "data", new List<object>() }
});
}
public Task<Dictionary<string, object>> GetDailyItemChartPriceAsync(string code, string startDate, string endDate, string period = "D", string account = "mock")
{
return Task.FromResult(new Dictionary<string, object>
{
{ "code", code },
{ "startDate", startDate },
{ "endDate", endDate },
{ "period", period },
{ "candles", new List<object>() }
});
}
public Task<Dictionary<string, object>> GetInvestorTrendAsync(string code, string account = "mock")
{
return Task.FromResult(new Dictionary<string, object>
{
{ "code", code },
{ "individual", 0 },
{ "foreign", 0 },
{ "institution", 0 }
});
}
}
// Placeholder implementations removed — using PostgreSQL-backed real implementations instead.
// See Program.cs for service registration.
+262 -15
View File
@@ -1,15 +1,24 @@
using QuantEngine.Web.Components;
using QuantEngine.Web.Services;
using QuantEngine.Infrastructure.Data;
using Microsoft.AspNetCore.Components.Authorization;
using QuantEngine.Web.Infrastructure;
using QuantEngine.Infrastructure.Repositories;
using QuantEngine.Infrastructure.Services;
using QuantEngine.Core.Interfaces;
using QuantEngine.Application.Services;
using System.Text.Json;
using Microsoft.FluentUI.AspNetCore.Components;
using static QuantEngine.Application.Services.DataCollectionService;
using Serilog;
using QuantEngine.Web.Infrastructure;
using QuantEngine.Web.Client.Infrastructure;
using QuantEngine.Web.Client.Services;
using QuantEngine.Web.Endpoints;
using System.Security.Cryptography;
using System.Text;
using QuantEngine.Core.Models;
using Microsoft.AspNetCore.Authentication;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Options;
using MudBlazor.Services;
// Serilog Configuration with Telegram Sink
Log.Logger = new LoggerConfiguration()
@@ -23,33 +32,74 @@ builder.Host.UseSerilog();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
.AddInteractiveWebAssemblyComponents();
// Fluent UI Services
builder.Services.AddFluentUIComponents();
// Authentication and Custom State Provider (Shared client components)
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthentication("QuantAdminScheme")
.AddScheme<AuthenticationSchemeOptions, QuantAdminAuthHandler>("QuantAdminScheme", _ => { });
builder.Services.AddAuthorization();
builder.Services.AddScoped<LocalStorageService>();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
builder.Services.AddAuthorizationCore();
builder.Services.AddMudServices();
// PostgreSQL Dapper Setup
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? "Host=127.0.0.1;Database=giteadb;Username=gitea;Password=C8RFlZ9fdQrBA1vyLhLDS4v70I8dJfRS2ERJW4+zsS4=;Search Path=quantengine;";
var configuredConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var fallbackConnectionString = "Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=CHANGE_ME;Search Path=quantengine;";
var connectionString = string.IsNullOrWhiteSpace(configuredConnectionString) || configuredConnectionString.Contains("Password=;", StringComparison.OrdinalIgnoreCase)
? fallbackConnectionString
: configuredConnectionString;
var configuredDatabase = new Npgsql.NpgsqlConnectionStringBuilder(connectionString).Database;
if (!string.Equals(configuredDatabase, "quantenginedb", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("QuantEngine must use the quantenginedb PostgreSQL database.");
}
builder.Services.AddSingleton<IDbConnectionFactory>(new DbConnectionFactory(connectionString));
builder.Services.AddSingleton<DbMigrator>();
builder.Services.AddScoped<IWorkspaceRepository, WorkspaceRepository>();
builder.Services.AddScoped<IPostgresqlHistoryStore, PostgresqlHistoryStore>();
builder.Services.AddScoped<IPostgresqlHistorySnapshotReader, PostgresqlHistorySnapshotReader>();
builder.Services.AddScoped<HistoryIngestionService>();
// Collection Pipeline Services (using placeholder implementations for now)
builder.Services.AddScoped<ICollectionRepository, PlaceholderCollectionRepository>();
builder.Services.AddScoped<ITokenCache, PlaceholderTokenCache>();
builder.Services.AddScoped<IKisApiClient, PlaceholderKisApiClient>();
// Collection Pipeline Services (PostgreSQL-backed implementations)
builder.Services.AddScoped<ICollectionRepository, CollectionRepository>();
builder.Services.AddScoped<ITokenCache, PostgresTokenCache>();
builder.Services.AddScoped<IKisApiClient, KisApiClient>();
builder.Services.AddScoped<DataCollectionService>();
// HTTP Client & API Services
builder.Services.AddHttpClient<ApiClient>();
builder.Services.AddScoped<ApiClient>();
var app = builder.Build();
var adminSettings = app.Configuration.GetSection("AdminSettings");
var adminUsername = adminSettings["Username"] ?? "admin";
var adminPassword = adminSettings["Password"] ?? string.Empty;
// Enable reverse proxy subpath mapping
app.UsePathBase("/quant");
// Initialize database tables (PostgreSQL-backed repositories)
using (var scope = app.Services.CreateScope())
{
var migrator = scope.ServiceProvider.GetRequiredService<DbMigrator>();
var tokenCache = scope.ServiceProvider.GetRequiredService<ITokenCache>();
var collectionRepo = scope.ServiceProvider.GetRequiredService<ICollectionRepository>();
var workspaceRepo = scope.ServiceProvider.GetRequiredService<IWorkspaceRepository>();
try
{
migrator.Migrate();
// Ensure tables exist on startup
await tokenCache.GetCachedTokenAsync("_init_test_");
await collectionRepo.GetDashboardStateAsync();
await workspaceRepo.GetAccountsAsync();
Log.Information("Database tables initialized successfully");
}
catch (Exception ex)
{
Log.Warning($"Database initialization warning: {ex.Message}");
}
}
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
@@ -67,12 +117,186 @@ app.UseStatusCodePages(async ctx =>
app.UseHttpsRedirection();
app.UseAntiforgery();
app.UseAuthentication();
app.UseAuthorization();
app.MapStaticAssets();
app.MapGet("/", () => Results.Redirect("/login"));
// Collection API Endpoints (must be before MapRazorComponents)
app.MapCollectionEndpoints();
// Login API (API-First for Blazor WASM client authentication)
app.MapPost("/api/auth/login", async (JsonElement payload, IWorkspaceRepository workspaceRepo) =>
{
static string? ReadString(JsonElement root, params string[] names)
{
foreach (var name in names)
{
if (root.ValueKind == JsonValueKind.Object && root.TryGetProperty(name, out var property) && property.ValueKind == JsonValueKind.String)
{
return property.GetString();
}
}
return null;
}
var username = ReadString(payload, "Username", "username");
var password = ReadString(payload, "Password", "password");
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
{
return Results.BadRequest(new { success = false, error = "missing_credentials" });
}
var account = await workspaceRepo.GetAccountByUsernameAsync(username.Trim());
if (account is null || !string.Equals(account.IsActive, "true", StringComparison.OrdinalIgnoreCase))
{
return Results.Json(new { success = false, error = "invalid_credentials" }, statusCode: 401);
}
var passwordHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(password)));
if (!string.Equals(account.PasswordHash, passwordHash, StringComparison.OrdinalIgnoreCase))
{
return Results.Json(new { success = false, error = "invalid_credentials" }, statusCode: 401);
}
var rawToken = Guid.NewGuid().ToString("N");
var tokenHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(rawToken)));
var now = DateTimeOffset.UtcNow;
var expiresAt = now.AddDays(7);
await workspaceRepo.UpsertSessionAsync(new WorkspaceSession
{
SessionTokenHash = tokenHash,
Username = account.Username,
Role = account.Role,
CreatedAt = now.ToString("O"),
ExpiresAt = expiresAt.ToString("O"),
RevokedAt = null
});
return Results.Ok(new
{
success = true,
username = account.Username,
role = account.Role,
accessToken = rawToken,
expiresAt = expiresAt.ToString("O")
});
}).DisableAntiforgery();
app.MapGet("/api/auth/me", async (HttpContext context, IWorkspaceRepository workspaceRepo) =>
{
var authHeader = context.Request.Headers.Authorization.ToString();
if (string.IsNullOrWhiteSpace(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
return Results.Unauthorized();
}
var token = authHeader["Bearer ".Length..].Trim();
if (string.IsNullOrWhiteSpace(token))
{
return Results.Unauthorized();
}
var tokenHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(token)));
var session = await workspaceRepo.GetSessionByTokenHashAsync(tokenHash);
if (session is null || !string.IsNullOrWhiteSpace(session.RevokedAt) || DateTimeOffset.TryParse(session.ExpiresAt, out var expiresAt) && expiresAt <= DateTimeOffset.UtcNow)
{
return Results.Unauthorized();
}
return Results.Ok(new { authenticated = true, username = session.Username, role = session.Role });
});
app.MapPost("/api/auth/logout", async (HttpContext context, IWorkspaceRepository workspaceRepo) =>
{
var authHeader = context.Request.Headers.Authorization.ToString();
if (string.IsNullOrWhiteSpace(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
return Results.Unauthorized();
}
var token = authHeader["Bearer ".Length..].Trim();
if (string.IsNullOrWhiteSpace(token))
{
return Results.Unauthorized();
}
var tokenHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(token)));
await workspaceRepo.RevokeSessionAsync(tokenHash, DateTimeOffset.UtcNow.ToString("O"));
return Results.Ok(new { success = true });
}).DisableAntiforgery();
app.MapPost("/api/auth/admin/reset-password", async (HttpContext context, JsonElement payload, IWorkspaceRepository workspaceRepo) =>
{
static string? ReadString(JsonElement root, params string[] names)
{
foreach (var name in names)
{
if (root.ValueKind == JsonValueKind.Object && root.TryGetProperty(name, out var property) && property.ValueKind == JsonValueKind.String)
{
return property.GetString();
}
}
return null;
}
var username = ReadString(payload, "adminUsername", "AdminUsername", "username", "Username");
var password = ReadString(payload, "adminPassword", "AdminPassword", "password", "Password");
var targetUsername = ReadString(payload, "targetUsername", "TargetUsername", "usernameToReset", "UsernameToReset");
var newPassword = ReadString(payload, "newPassword", "NewPassword");
if (!string.Equals(username, adminUsername, StringComparison.Ordinal) || !string.Equals(password, adminPassword, StringComparison.Ordinal))
{
return Results.Unauthorized();
}
if (string.IsNullOrWhiteSpace(targetUsername) || string.IsNullOrWhiteSpace(newPassword))
{
return Results.BadRequest(new { success = false, error = "missing_target_or_password" });
}
var account = await workspaceRepo.GetAccountByUsernameAsync(targetUsername.Trim());
if (account is null)
{
return Results.NotFound(new { success = false, error = "account_not_found" });
}
var passwordHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(newPassword)));
account.PasswordHash = passwordHash;
account.UpdatedAt = DateTimeOffset.UtcNow.ToString("O");
var updated = await workspaceRepo.UpsertAccountAsync(account);
if (!updated)
{
return Results.StatusCode(500);
}
return Results.Ok(new
{
success = true,
username = account.Username,
updatedAt = account.UpdatedAt
});
}).DisableAntiforgery();
// Operational Report serving API (WASM safe file loading substitute)
app.MapGet("/api/operational-report", async (IWebHostEnvironment env) =>
{
var path = Path.GetFullPath(Path.Combine(env.ContentRootPath, "..", "..", "..", "Temp", "operational_report.json"));
if (!File.Exists(path))
{
return Results.NotFound(new { gate = "FAIL", error = "operational_report_missing" });
}
var json = await File.ReadAllTextAsync(path);
using var doc = JsonDocument.Parse(json);
return Results.Ok(doc.RootElement);
});
app.MapGet("/api/history/{domain}", async (string domain, int? limit, IPostgresqlHistorySnapshotReader reader) =>
{
var rows = await reader.ReadAsync(domain, limit ?? 500);
@@ -117,7 +341,30 @@ app.MapPost("/api/history/{domain}", async (string domain, JsonElement payload,
});
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(QuantEngine.Web.Client._Imports).Assembly);
app.Run();
internal sealed class QuantAdminAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public QuantAdminAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
}
}
@@ -4,12 +4,21 @@
<ProjectReference Include="..\QuantEngine.Infrastructure\QuantEngine.Infrastructure.csproj" />
<ProjectReference Include="..\QuantEngine.Application\QuantEngine.Application.csproj" />
<ProjectReference Include="..\QuantEngine.Core\QuantEngine.Core.csproj" />
<ProjectReference Include="Client\QuantEngine.Web.Client.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="5.0.0-rc.4-26177.1" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="5.0.0-rc.4-26177.1" />
<PackageReference Include="MudBlazor" Version="8.6.0" />
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.0-preview.2.25120.18" />
</ItemGroup>
<ItemGroup>
<!-- Exclude client project files from server build to avoid duplicate compilations -->
<Compile Remove="Client\**" />
<Content Remove="Client\**" />
<EmbeddedResource Remove="Client\**" />
<None Remove="Client\**" />
</ItemGroup>
<PropertyGroup>
+5 -1
View File
@@ -7,6 +7,10 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Host=127.0.0.1;Database=giteadb;Username=gitea;Password=;Search Path=quantengine;"
"DefaultConnection": "Host=127.0.0.1;Database=quantenginedb;Username=quantengine_app;Password=;Search Path=quantengine;"
},
"AdminSettings": {
"Username": "admin",
"Password": "quant123!"
}
}

Some files were not shown because too many files have changed in this diff Show More