feat: complete Oracle and MariaDB WebView data layer

This commit is contained in:
2026-07-10 05:33:19 +09:00
parent 5aa90e4aaa
commit 39c4504b87
44 changed files with 3956 additions and 46 deletions

77
docs/DATABASE.md Normal file
View File

@@ -0,0 +1,77 @@
# Oracle/MariaDB 연결 운영 가이드
## 적용된 공급자
`.NET 8`용 실제 ADO.NET 계층은 다음 버전을 고정합니다.
- Oracle: `Oracle.ManagedDataAccess.Core` `23.26.200`
- MariaDB: `MySqlConnector` `2.6.1`
Oracle ODP.NET Core 23 계열은 TAP 기반 `OpenAsync`/명령 비동기를 지원하며, 이 구현은 Oracle pipelining을 켜지 않습니다. MariaDB Connector/NET 공식 가이드가 권장하는 MySqlConnector는 `OpenAsync`, reader 비동기와 취소를 사용합니다. Oracle 23.26.200은 Oracle Database 19c 이상을 전제로 하며, 현재 운영 스모크에서 서버 주 버전 21을 확인했습니다.
공식 참고:
- https://www.nuget.org/packages/Oracle.ManagedDataAccess.Core/23.26.200
- https://docs.oracle.com/en/database/oracle/oracle-database/26/odpnt/featAsyncPipelining.html
- https://mariadb.com/docs/connectors/mariadb-connector-net/mariadb-connector-net-guide
- https://www.nuget.org/packages/MySqlConnector/2.6.1
## 런타임 설정
MSIX 설치 폴더는 읽기 전용이므로 설정 파일을 패키지 디렉터리에 두지 않습니다. 기본 경로는 다음과 같습니다.
```text
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\database.local.json
```
저장소의 [appsettings.example.json](../Config/appsettings.example.json)은 비밀값이 없는 구조 예시입니다. 실제 파일은 [Initialize-DatabaseConfig.ps1](../scripts/Initialize-DatabaseConfig.ps1)로 만들 수 있습니다. 이 스크립트는 비밀번호를 프롬프트로 받고 현재 Windows 사용자만 파일을 읽도록 ACL을 설정합니다.
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\Initialize-DatabaseConfig.ps1 `
-OracleHost '<host>' -OraclePort 1521 -OracleSid '<sid>' -OracleUserName '<user>' `
-MariaDbHost '<host>' -MariaDbPort 3306 -MariaDbDatabase '<database>' -MariaDbUserName '<user>'
```
Oracle은 `sid` 또는 `serviceName` 중 정확히 하나를 설정합니다. 원본 MBN_STOCK_N은 SID descriptor를 사용했으므로 legacy 연결은 `sid`로 옮깁니다. 설정 파일은 평문 비밀번호를 포함할 수 있으므로 저장소·로그·첨부파일로 복사하지 않습니다. 운영 환경에서는 실행 계정의 파일 ACL을 유지하고, 환경 변수 오버라이드 또는 조직의 승인된 비밀 저장소를 사용할 수 있습니다.
JSON보다 환경 변수가 우선합니다.
```text
MBN_STOCK_ORACLE_HOST / PORT / SID / SERVICE_NAME / USERNAME / PASSWORD
MBN_STOCK_MARIADB_HOST / PORT / DATABASE / USERNAME / PASSWORD / TLS_MODE
MBN_STOCK_DB_OPERATION_TIMEOUT_SECONDS
MBN_STOCK_DB_MAX_RETRY_COUNT
MBN_STOCK_DB_INITIAL_RETRY_DELAY_MS
```
MariaDB `tlsMode``Disabled`, `Preferred`, `Required`, `VerifyCertificate`, `VerifyIdentity`를 지원합니다. 인증서와 호스트 이름을 운영 환경에서 검증할 수 있으면 `VerifyIdentity`를 사용합니다. legacy LAN과의 호환을 위해 예시 기본값은 `Preferred`입니다.
## 실행 정책
각 조회는 연결을 새로 만들고 공급자 풀링을 사용합니다. `OpenAsync`, `ExecuteReaderAsync`, `ReadAsync`에 같은 취소 토큰을 전달하며, 공급자 command timeout과 전체 작업 timeout을 모두 적용합니다. 호출자가 취소한 작업은 재시도하지 않습니다. 재시도는 `SELECT`/`WITH` 읽기와 검토된 일시적 네트워크 오류에만 제한하고, 매 시도마다 기존 연결을 폐기한 뒤 새 연결을 엽니다. INSERT/UPDATE/DDL과 인증·스키마·SQL 오류는 재실행하지 않습니다.
DB 오류는 `DatabaseOperationException`의 안전한 한국어 메시지로 변환됩니다. provider 예외, raw connection string, 사용자명, 비밀번호, SQL은 WebView 메시지나 예외 `ToString()`에 포함하지 않습니다. health 상태는 Oracle과 MariaDB를 별도로 표시하므로 한쪽 장애가 앱 종료나 다른 쪽 결과 표시를 막지 않습니다.
## WebView 메시지
Web UI가 `request-database-status`를 보내면 native bridge가 양쪽 health 상태를 반환합니다. `kospi`, `kosdaq`, `index`, `overseas` 메뉴는 `request-market-data`를 보내고, native는 bounded DTO로 열 이름·행·전체 행 수를 반환합니다. `DataTable` 자체를 JSON으로 직렬화하지 않으며, 이전 `requestId` 응답은 Web UI가 버립니다. 오류는 `market-data-error`로 표시되고 기존 플레이리스트·PREPARE/TAKE IN/TAKE OUT UI는 계속 동작합니다.
## 검증 명령
단위 테스트:
```powershell
dotnet test MBN_STOCK_WEBVIEW.sln -c Release -p:Platform=x64
```
실제 DB 스모크(설정 파일을 읽어 비밀값은 출력하지 않음):
```powershell
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.DbSmoke\MBN_STOCK_WEBVIEW.DbSmoke.csproj -c Release
```
스모크는 양쪽 `SELECT 1`, Oracle 서버 버전, 코스피·코스닥·NXT·5개 국내 지수·해외 종목 카탈로그의 실제 행을 확인합니다. 출력에는 상태, 테이블 이름, 행 수만 포함합니다.
## MSIX
패키지 앱은 `internetClient``privateNetworkClientServer` capability를 사용합니다. Debug/Release x64와 MSIX 생성은 저장소 루트 README의 명령을 사용합니다. `ThirdPartyNotices`의 Oracle 및 MySqlConnector 고지는 MSIX 콘텐츠에 포함됩니다. 실제 운영 배포는 조직 인증서로 서명해야 하며 `.pfx`/비밀키는 저장소에 넣지 않습니다.