diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e5cd401..cd72911 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -91,3 +91,9 @@ - Added Protein Atlas extension planning document. - Positioned Protein Atlas as education/research extension material. - Separated research/education concept material from core implementation screenshots. + +## v0.17-implementation-progress + +- Added implementation progress tracker. +- Linked roadmap documents from README. +- Prepared GitHub issue roadmap for BioDockLab MVP and pilot planning. diff --git "a/docs/review/output/BioDockLab_\355\231\224\353\251\264\354\236\220\353\243\214_\354\240\204\354\262\26413\354\236\245_ProteinAtlas\355\231\225\354\236\245\352\270\260\355\232\215\355\217\254\355\225\250.pdf" "b/docs/review/output/BioDockLab_\355\231\224\353\251\264\354\236\220\353\243\214_\354\240\204\354\262\26413\354\236\245_ProteinAtlas\355\231\225\354\236\245\352\270\260\355\232\215\355\217\254\355\225\250.pdf" new file mode 100644 index 0000000..35190f5 Binary files /dev/null and "b/docs/review/output/BioDockLab_\355\231\224\353\251\264\354\236\220\353\243\214_\354\240\204\354\262\26413\354\236\245_ProteinAtlas\355\231\225\354\236\245\352\270\260\355\232\215\355\217\254\355\225\250.pdf" differ diff --git a/docs/review/screenshots/01_login_role_based_access.png b/docs/review/screenshots/01_login_role_based_access.png index 06af444..0838072 100644 Binary files a/docs/review/screenshots/01_login_role_based_access.png and b/docs/review/screenshots/01_login_role_based_access.png differ diff --git a/docs/review/screenshots/02_patient_explanation_report.png b/docs/review/screenshots/02_patient_explanation_report.png index 49a29db..e142ac2 100644 Binary files a/docs/review/screenshots/02_patient_explanation_report.png and b/docs/review/screenshots/02_patient_explanation_report.png differ diff --git a/docs/review/screenshots/03_nurse_handoff_workspace.png b/docs/review/screenshots/03_nurse_handoff_workspace.png index b5a20ff..57ac98c 100644 Binary files a/docs/review/screenshots/03_nurse_handoff_workspace.png and b/docs/review/screenshots/03_nurse_handoff_workspace.png differ diff --git a/docs/review/screenshots/04_doctor_result_summary.png b/docs/review/screenshots/04_doctor_result_summary.png index a6b20ba..8d39c47 100644 Binary files a/docs/review/screenshots/04_doctor_result_summary.png and b/docs/review/screenshots/04_doctor_result_summary.png differ diff --git a/docs/review/screenshots/05_pharmacist_prescription_review.png b/docs/review/screenshots/05_pharmacist_prescription_review.png index af017f6..d343862 100644 Binary files a/docs/review/screenshots/05_pharmacist_prescription_review.png and b/docs/review/screenshots/05_pharmacist_prescription_review.png differ diff --git a/docs/review/screenshots/06_admin_consent_document_view.png b/docs/review/screenshots/06_admin_consent_document_view.png index 9d576e7..a0c8467 100644 Binary files a/docs/review/screenshots/06_admin_consent_document_view.png and b/docs/review/screenshots/06_admin_consent_document_view.png differ diff --git a/docs/review/screenshots/07_research_virtual_docking_lab.png b/docs/review/screenshots/07_research_virtual_docking_lab.png index ca05c4d..2c92c2e 100644 Binary files a/docs/review/screenshots/07_research_virtual_docking_lab.png and b/docs/review/screenshots/07_research_virtual_docking_lab.png differ diff --git a/docs/review/screenshots/08_security_audit_center.png b/docs/review/screenshots/08_security_audit_center.png index 2e2d2fd..2e65ac5 100644 Binary files a/docs/review/screenshots/08_security_audit_center.png and b/docs/review/screenshots/08_security_audit_center.png differ diff --git a/docs/review/screenshots/09_platform_admin_policy_matrix.png b/docs/review/screenshots/09_platform_admin_policy_matrix.png index c9fdca2..a9df2ae 100644 Binary files a/docs/review/screenshots/09_platform_admin_policy_matrix.png and b/docs/review/screenshots/09_platform_admin_policy_matrix.png differ diff --git a/docs/review/screenshots/10_access_denied_audit_log.png b/docs/review/screenshots/10_access_denied_audit_log.png index dcea8b6..315cf37 100644 Binary files a/docs/review/screenshots/10_access_denied_audit_log.png and b/docs/review/screenshots/10_access_denied_audit_log.png differ diff --git a/docs/review/screenshots/11_nurse_role_workspace.png b/docs/review/screenshots/11_nurse_role_workspace.png index 55b3dfe..8d034b7 100644 Binary files a/docs/review/screenshots/11_nurse_role_workspace.png and b/docs/review/screenshots/11_nurse_role_workspace.png differ diff --git a/docs/review/screenshots/12_bio_security_architect_workspace.png b/docs/review/screenshots/12_bio_security_architect_workspace.png index a92dbab..4ce5db6 100644 Binary files a/docs/review/screenshots/12_bio_security_architect_workspace.png and b/docs/review/screenshots/12_bio_security_architect_workspace.png differ diff --git a/docs/review/screenshots/00_integrated_bio_platform_dashboard.png b/docs/review/screenshots/13_integrated_bio_platform_dashboard.png similarity index 100% rename from docs/review/screenshots/00_integrated_bio_platform_dashboard.png rename to docs/review/screenshots/13_integrated_bio_platform_dashboard.png diff --git a/docs/roadmap/IMPLEMENTATION_PROGRESS.md b/docs/roadmap/IMPLEMENTATION_PROGRESS.md index 2292c73..32408e4 100644 --- a/docs/roadmap/IMPLEMENTATION_PROGRESS.md +++ b/docs/roadmap/IMPLEMENTATION_PROGRESS.md @@ -21,20 +21,25 @@ | Compliance / Privacy Docs | 35% | Drafting | | Pilot Proposal Package | 30% | Drafting | +--- + ## Current Development Stage BioDockLab is currently in the **Review Prototype** stage. This means: -- It is suitable for professor, doctor, nurse, and advisor review. +- It is suitable for professor, doctor, nurse, pharmacist, and advisor review. - It is not yet suitable for real patient data. - It is not yet connected to actual EMR/HIS/OCS systems. - It should be evaluated as a sample-data-based prototype. +- It must not be presented as a diagnosis, prescription, or treatment recommendation system. + +--- ## Next Milestone -### v1.0 Review MVP +## v1.0 Review MVP Target: @@ -43,6 +48,9 @@ Target: - Remove risky medical wording. - Improve backend role enforcement. - Finalize review documents. +- Prepare team-based MVP development. + +--- ## Progress Legend @@ -54,3 +62,31 @@ Target: | 60% | Implemented with sample data | | 80% | Review-ready | | 100% | Validated / completed | + +--- + +## Development Focus + +## 1. Short-Term Focus + +- Collect expert feedback. +- Fix risky medical wording. +- Clarify role-based data access. +- Separate current implementation screens from concept screens. +- Improve README and documentation. + +## 2. Mid-Term Focus + +- Backend RBAC enforcement. +- Audit log database structure. +- Role-specific API connection. +- Protein Atlas MVP. +- Security and privacy documentation. + +## 3. Long-Term Focus + +- Case Match concept validation. +- Care Connect concept validation. +- Pilot proposal package. +- Legal, privacy, and clinical review. +- Possible education/research pilot. diff --git a/docs/roadmap/TEAM_STRUCTURE.md b/docs/roadmap/TEAM_STRUCTURE.md index f8188de..3c5ddf6 100644 --- a/docs/roadmap/TEAM_STRUCTURE.md +++ b/docs/roadmap/TEAM_STRUCTURE.md @@ -36,7 +36,7 @@ BioDockLab은 단순 웹앱이 아니라 의료·바이오 데이터, 역할 기 ## 2.2 Clinical Workflow Advisor -추천 인원: +모집 인원: - 간호학과 학생 - 간호사 @@ -55,6 +55,9 @@ BioDockLab은 단순 웹앱이 아니라 의료·바이오 데이터, 역할 기 ## 2.3 Frontend Developer +모집 인원: +- 디자인학과 학생 + 역할: - 역할별 UI 구현 @@ -103,7 +106,7 @@ BioDockLab은 단순 웹앱이 아니라 의료·바이오 데이터, 역할 기 ## 2.5 Bio / Research Advisor -추천 인원: +모집 인원: - 생명공학 - 화학공학 diff --git a/docs/team/INITIAL_TEAM_CANDIDATE_MAPPING.md b/docs/team/INITIAL_TEAM_CANDIDATE_MAPPING.md index 81b923c..0d4c861 100644 --- a/docs/team/INITIAL_TEAM_CANDIDATE_MAPPING.md +++ b/docs/team/INITIAL_TEAM_CANDIDATE_MAPPING.md @@ -19,8 +19,7 @@ |---|---|---| | 이영준 | Founder / Product Architect | 전체 제품 구조, GitHub, 프로토타입, 발표, 문서화 | | 류종걸 | AI / Medical Data Lead | 인공지능 개발, 의료 데이터 구조 설계, 공개 데이터 탐색, AI 기능 기획 | -| 주수빈 | UI/UX Designer Candidate | 화면 디자인, 서비스 시각화, 발표자료 디자인 | -| 이민준 | UI/UX Designer Candidate | 화면 디자인, 사용자 흐름, 프로토타입 시각 개선 | +| ??? | UI/UX Designer Candidate | 화면 디자인, 사용자 흐름, 프로토타입 시각 개선 | | 이상목 | Business / Data Strategy | LLM 관심, 빅데이터 분석, 시장성 분석, 지표 설계 | | 이찬규 | Business / Finance / Healthcare Strategy | 경영, 회계, 사업화 전략, 의료 비즈니스 관점 검토 | diff --git a/docs/team/OPEN_POSITIONS_AND_SKILLS.md b/docs/team/OPEN_POSITIONS_AND_SKILLS.md index 2d36e8b..e90971c 100644 --- a/docs/team/OPEN_POSITIONS_AND_SKILLS.md +++ b/docs/team/OPEN_POSITIONS_AND_SKILLS.md @@ -27,7 +27,7 @@ |---|---| | Product / System Architecture | 이영준 | | AI / Medical Data Interest | 류종걸 | -| UI / Design | 주수빈, 이민준 | +| UI / Design | ??? | | Business / Data Strategy | 이상목 | | Business / Finance / Healthcare Strategy | 이찬규 | diff --git a/docs/team/TEAM_OVERVIEW.md b/docs/team/TEAM_OVERVIEW.md index f80ce7b..27bb35c 100644 --- a/docs/team/TEAM_OVERVIEW.md +++ b/docs/team/TEAM_OVERVIEW.md @@ -27,10 +27,9 @@ BioDockLab은 의료·바이오 데이터를 역할별로 안전하게 보여주 |---|---|---|---| | 이영준 | 시스템 설계, 프로토타입, GitHub, 발표 | Founder / Product Architect | 전체 구조 설계, 개발 방향, 문서화, 팀 운영 | | 류종걸 | AI 개발, 의료 관심, 의료 데이터 관심 | AI / Medical Data Lead | AI 기능 기획, 공개 데이터 탐색, 의료 데이터 구조 설계 | -| 주수빈 | 디자인 지원 후보 | UI/UX Designer | 화면 디자인, 발표자료 디자인, 서비스 시각화 | -| 이민준 | 디자인 지원 후보 | UI/UX Designer | UI 흐름 개선, 프로토타입 시각 개선 | +| ??? | 디자인 지원 후보 | UI/UX Designer | UI 흐름 개선, 프로토타입 시각 개선 | | 이상목 | LLM 관심, 빅데이터 분석, 사업 감각 | Business / Data Strategy | 시장성 분석, 데이터 전략, LLM 서비스 검토 | -| 이찬규 | 의대 경험, 경영/사업, 회계 | Business / Finance / Healthcare Strategy | 사업모델, 예산, 회계, 의료 비즈니스 전략 | +| 이찬규 | 경영/사업, 회계 | Business / Finance / Healthcare Strategy | 사업모델, 예산, 회계, 의료 비즈니스 전략 | --- @@ -49,6 +48,21 @@ BioDockLab은 의료·바이오 데이터를 역할별로 안전하게 보여주 --- +## 3-1. Recruiting Priority + +| 우선순위 | 포지션 | 필요 인원 | 이유 | +|---:|---|---:|---| +| P0 | Backend / Security Developer | 1명 | BioDockLab의 핵심인 권한제어, 감사 로그, API 구조를 실제로 구현해야 함 | +| P0 | Clinical Workflow Advisor | 1~2명 | 병원 현장 관점에서 간호사·의사·약사·원무 화면을 검토해야 함 | +| P0/P1 | Bio / Research Advisor | 1명 | Protein Atlas와 Research Lab이 과학적으로 과장되지 않도록 검토해야 함 | +| P1 | Frontend Developer | 1명 | 현재 화면을 더 안정적이고 상용화 가능한 UI로 개선해야 함 | +| P1 | QA / Documentation | 1명 | 의료 표현, 개인정보, 권한 테스트, 문서화를 체계적으로 관리해야 함 | +| P1 | AI / Data Engineer | 1명 | 설명 요약, 유사 사례 검색, 사전문진 구조를 안전하게 설계해야 함 | +| P2 | DevOps / Infra | 1명 | 배포, 서버, Docker, 로그, 백업 구조가 필요함 | +| P2 | Legal / Privacy Advisor | 외부 자문 1명 | 실제 상용화 전 개인정보·의료법·원격상담 규제 검토가 필요함 | + +--- + ## 4. Required Recruiting Next 현재 후보군은 초기 기획·AI·디자인·사업 쪽은 어느 정도 구성 가능하다. diff --git a/package-lock.json b/package-lock.json index dffc337..a863f04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,457 +1,912 @@ { - "name": "BioDockLab", + "name": "biodocklab", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "biodocklab", + "version": "1.0.0", + "license": "UNLICENSED", "dependencies": { - "lucide-react": "^1.16.0", - "recharts": "^3.8.1" + "@vitejs/plugin-react": "latest", + "react": "latest", + "react-dom": "latest", + "vite": "latest" + }, + "devDependencies": {} + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@reduxjs/toolkit": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", - "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", "license": "MIT", + "optional": true, "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@standard-schema/utils": "^0.3.0", - "immer": "^11.0.0", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" + "@tybys/wasm-util": "^0.10.2" }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@reduxjs/toolkit/node_modules/immer": { - "version": "11.1.8", - "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.8.tgz", - "integrity": "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==", + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", - "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", - "license": "MIT" + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@types/d3-color": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@types/d3-time": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/d3-path": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", - "license": "MIT" + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, "dependencies": { - "internmap": "1 - 2" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", + "node_modules/@vitejs/plugin-react": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", + "license": "MIT", "dependencies": { - "d3-color": "1 - 3" + "@rolldown/pluginutils": "^1.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", "dependencies": { - "d3-path": "^3.1.0" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" } }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", - "license": "MIT" + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/es-toolkit": { - "version": "1.46.1", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.46.1.tgz", - "integrity": "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "license": "MIT" + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/immer" + "url": "https://opencollective.com/parcel" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/lucide-react": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.16.0.tgz", - "integrity": "sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/react": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", - "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/react-dom": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", - "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "peer": true, "dependencies": { - "scheduler": "^0.27.0" + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, - "peerDependencies": { - "react": "^19.2.6" + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/react-is": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", - "peer": true + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/react-redux": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", - "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "use-sync-external-store": "^1.4.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "@types/react": "^18.2.25 || ^19", - "react": "^18.0 || ^19", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } + "react": "^19.2.7" } }, - "node_modules/recharts": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.1.tgz", - "integrity": "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==", + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", "license": "MIT", - "workspaces": [ - "www" - ], "dependencies": { - "@reduxjs/toolkit": "^1.9.0 || 2.x.x", - "clsx": "^2.1.1", - "decimal.js-light": "^2.5.1", - "es-toolkit": "^1.39.3", - "eventemitter3": "^5.0.1", - "immer": "^10.1.1", - "react-redux": "8.x.x || 9.x.x", - "reselect": "5.1.1", - "tiny-invariant": "^1.3.3", - "use-sync-external-store": "^1.2.2", - "victory-vendor": "^37.0.2" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, - "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", - "license": "MIT" - }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT", - "peer": true - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/victory-vendor": { - "version": "37.3.6", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", - "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", - "license": "MIT AND ISC", + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "license": "MIT", "dependencies": { - "@types/d3-array": "^3.0.3", - "@types/d3-ease": "^3.0.0", - "@types/d3-interpolate": "^3.0.1", - "@types/d3-scale": "^4.0.2", - "@types/d3-shape": "^3.1.0", - "@types/d3-time": "^3.0.0", - "@types/d3-timer": "^3.0.0", - "d3-array": "^3.1.6", - "d3-ease": "^3.0.1", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.1.0", - "d3-time": "^3.0.0", - "d3-timer": "^3.0.1" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } } } diff --git a/package.json b/package.json index 4423737..23aca5d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,18 @@ { + "name": "biodocklab", + "version": "1.0.0", + "private": true, + "license": "UNLICENSED", + "scripts": { + "dev": "vite --host 0.0.0.0", + "build": "vite build", + "preview": "vite preview --host 0.0.0.0" + }, "dependencies": { - "lucide-react": "^1.16.0", - "recharts": "^3.8.1" + "@vitejs/plugin-react": "latest", + "vite": "latest", + "react": "latest", + "react-dom": "latest" }, - "private": true, - "license": "UNLICENSED" -}\n \ No newline at end of file + "devDependencies": {} +} diff --git a/sample_data/access_policies.json b/sample_data/access_policies.json new file mode 100644 index 0000000..370d1a4 --- /dev/null +++ b/sample_data/access_policies.json @@ -0,0 +1,9 @@ +{ + "nurse": [ + "dashboard", + "nurse", + "patient_limited", + "reports_limited", + "consent_status" + ] +} diff --git a/sample_data/audit_logs.json b/sample_data/audit_logs.json index 7412db6..00b3c7e 100644 --- a/sample_data/audit_logs.json +++ b/sample_data/audit_logs.json @@ -8,5 +8,2805 @@ "patient_id": null, "allowed": true, "reason": "seed log" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:55:18", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T00:55:31", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T00:55:31", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T00:55:32", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:57:18", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T00:59:13", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T00:59:45", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:01", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:02", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:02", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:00:03", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "data_hub", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:03", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:00:07", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:09", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:00:10", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:11", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "data_hub", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:12", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:12", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:00:12", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:00:12", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:14", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:15", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:16", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:17", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "data_hub", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:00:18", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:00:22", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:02:13", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:10:43", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:11:11", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:11:28", + "actor": "정다은 간호사", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:13:21", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:13:30", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:15:41", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:18:10", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:25:37", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:25:37", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:25:44", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:25:45", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:25:45", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:25:52", + "actor": "김서연 박사", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:25:53", + "actor": "김서연 박사", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:00", + "actor": "김서연 박사", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:00", + "actor": "보안관리자", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:00", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:26:00", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:26:01", + "actor": "보안관리자", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:01", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:26:01", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:26:07", + "actor": "보안관리자", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:07", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": null, + "allowed": true, + "reason": "platform admin console open" + }, + { + "timestamp": "2026-05-17T01:26:08", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": null, + "allowed": true, + "reason": "platform admin console open" + }, + { + "timestamp": "2026-05-17T01:26:18", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:18", + "actor": "이준호 의사", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:19", + "actor": "이준호 의사", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:50", + "actor": "이준호 의사", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:50", + "actor": "박민지 약사", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:26:51", + "actor": "박민지 약사", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:10", + "actor": "박민지 약사", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:10", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:11", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:19", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:19", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:19", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:27:19", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:27:20", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:20", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:27:20", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:27:39", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:27:39", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:27:40", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:28:00", + "actor": "바이오 보안 아키텍트", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:28:00", + "actor": "바이오 보안 아키텍트", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Patient", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Doctor", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Nurse", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Pharmacist", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "AdminStaff", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Researcher", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Security", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "PlatformAdmin", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "BioSecurityArchitect", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "VirtualLabDeveloper", + "role": "virtual_lab_developer", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "smoke test" + }, + { + "timestamp": "2026-05-17T01:28:53", + "actor": "Security", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T01:29:05", + "actor": "바이오 보안 아키텍트", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:29:06", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T01:29:06", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:34:35", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:11", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:11", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:17", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:17", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:18", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:43", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:35:44", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:36:07", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:36:14", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:36:15", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:36:42", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:36:57", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:36:58", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "patient", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:09", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:09", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:10", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "nurse", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:20", + "actor": "이준호 의사", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:21", + "actor": "이준호 의사", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "doctor", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:26", + "actor": "이준호 의사", + "role": "doctor", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:27", + "actor": "박민지 약사", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:27", + "actor": "박민지 약사", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "prescription", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:35", + "actor": "박민지 약사", + "role": "pharmacist", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:35", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:36", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "admin", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:47", + "actor": "최하늘 원무", + "role": "admin_staff", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:47", + "actor": "김서연 박사", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:47", + "actor": "김서연 박사", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "research_lab", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:55", + "actor": "김서연 박사", + "role": "researcher", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:55", + "actor": "보안관리자", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:55", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:37:55", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:37:56", + "actor": "보안관리자", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:37:56", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:37:56", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:38:02", + "actor": "보안관리자", + "role": "security", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:38:02", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": null, + "allowed": true, + "reason": "platform admin console open" + }, + { + "timestamp": "2026-05-17T02:38:03", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": null, + "allowed": true, + "reason": "platform admin console open" + }, + { + "timestamp": "2026-05-17T02:38:09", + "actor": "이영준 관리자", + "role": "super_admin", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:38:10", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:38:10", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:38:10", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:38:10", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "security", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:38:10", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_AUDIT_LOGS", + "resource": "audit_logs", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:38:10", + "actor": "보안관리자", + "role": "security", + "action": "VIEW_RISK_EVENTS", + "resource": "risk_events", + "patient_id": null, + "allowed": true, + "reason": "security center" + }, + { + "timestamp": "2026-05-17T02:38:16", + "actor": "환자 사용자", + "role": "patient", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "clinical_v3 navigation" + }, + { + "timestamp": "2026-05-17T02:38:16", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T02:38:17", + "actor": "간호학과 검토자 A", + "role": "nurse", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": false, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T02:38:24", + "actor": "바이오 보안 아키텍트", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" + }, + { + "timestamp": "2026-05-17T02:38:25", + "actor": "바이오 보안 아키텍트", + "role": "bio_security_architect", + "action": "ACCESS_CHECK", + "resource": "dashboard", + "patient_id": "PT-2025-0520-0017", + "allowed": true, + "reason": "role workspace open" } ] diff --git a/sample_data/risk_events.json b/sample_data/risk_events.json index 43cad5d..cdc2132 100644 --- a/sample_data/risk_events.json +++ b/sample_data/risk_events.json @@ -6,5 +6,645 @@ "description": "원무 역할 사용자가 처방 상세 데이터 화면에 접근하려 했습니다.", "status": "needs_review", "recommended_action": "접근 사유 확인 및 권한 정책 점검" + }, + { + "id": "RISK-002", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-003", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-004", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-005", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-006", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-007", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-008", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-009", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-010", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-011", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-012", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-013", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-014", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-015", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-016", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-017", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-018", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-019", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-020", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-021", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-022", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-023", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-024", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-025", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-026", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-027", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-028", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-029", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-030", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-031", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-032", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-033", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-034", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "정다은 간호사(nurse) tried to access dashboard for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-035", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-036", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-037", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-038", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-039", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-040", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-041", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-042", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-043", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access dashboard for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-044", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-045", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-046", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-047", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-048", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-049", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-050", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-051", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-052", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-053", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-054", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-055", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-056", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-057", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-058", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-059", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-060", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-061", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-062", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "환자 사용자(patient) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-063", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "환자 사용자(patient) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-064", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access dashboard for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-065", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access dashboard for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-066", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Patient(patient) tried to access research_lab for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-067", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Doctor(doctor) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-068", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-069", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Nurse(nurse) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-070", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Pharmacist(pharmacist) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-071", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "AdminStaff(admin_staff) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-072", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Researcher(researcher) tried to access patient for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-073", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "Security(security) tried to access prescription for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-074", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-075", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-076", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-077", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access nurse for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-078", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "환자 사용자(patient) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-079", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "환자 사용자(patient) tried to access security for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-080", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access dashboard for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" + }, + { + "id": "RISK-081", + "severity": "high", + "title": "권한 없는 화면 접근 시도", + "description": "간호학과 검토자 A(nurse) tried to access dashboard for patient PT-2025-0520-0017", + "status": "needs_review", + "recommended_action": "접근권한, 접근 사유, 반복 열람 여부 확인" } ] diff --git a/scripts/build_final_review_pdf.py b/scripts/build_final_review_pdf.py new file mode 100644 index 0000000..7374b38 --- /dev/null +++ b/scripts/build_final_review_pdf.py @@ -0,0 +1,254 @@ +from pathlib import Path +from reportlab.lib.pagesizes import A4, landscape +from reportlab.lib import colors +from reportlab.lib.units import mm +from reportlab.pdfgen import canvas +from PIL import Image + +BASE = Path(".") +SHOT_DIR = BASE / "docs/review/screenshots" +OUT_DIR = BASE / "docs/review/output" +OUT_DIR.mkdir(parents=True, exist_ok=True) + +OUTPUT = OUT_DIR / "BioDockLab_화면자료_전체13장_ProteinAtlas확장기획포함.pdf" + +SCREENS = [ + ( + "00_integrated_bio_platform_dashboard.png", + "00. Integrated Bio Platform Dashboard", + "BioDockLab 전체 플랫폼 개요", + "환자 설명, 연구 실험, 보안 감사, 역할 기반 접근 구조가 하나의 플랫폼으로 연결된다는 첫인상을 보여주는 통합 대시보드 화면입니다." + ), + ( + "01_login_role_based_access.png", + "01. Login Screen", + "역할 기반 로그인 화면", + "환자·간호사·의사·약사·원무·연구자·보안관리자가 서로 다른 권한으로 접속한다는 구조를 보여주는 진입 화면입니다." + ), + ( + "02_patient_explanation_report.png", + "02. Patient Explanation Report", + "환자/의사용 결과 설명 리포트", + "복잡한 검사 결과와 후보 치료제 정보를 환자와 의료진이 이해하기 쉽게 확인할 수 있도록 구성한 설명 보조 화면입니다." + ), + ( + "03_nurse_handoff_workspace.png", + "03. Nurse Workspace", + "간호사용 바이탈·인수인계 보조 화면", + "바이탈 요약, 투약 전 확인, 인수인계 요약을 제공하지만 EMR이나 간호기록을 대체하지 않는 보조 화면입니다." + ), + ( + "04_doctor_result_summary.png", + "04. Doctor Workspace", + "의사용 결과 요약 화면", + "환자 상태, 검사 결과, 설명 리포트, 상담 준비 정보를 의료진 관점에서 확인하는 화면입니다." + ), + ( + "05_pharmacist_prescription_review.png", + "05. Pharmacist Workspace", + "약사용 처방 검토 화면", + "처방량, 병용약, 약물상호작용, 유전자 적합성 정보를 중심으로 검토하는 화면입니다." + ), + ( + "06_admin_consent_document_view.png", + "06. Administration View", + "원무용 예약·동의서·서류 상태 화면", + "원무는 예약, 동의서, 서류 발급 상태 등 업무에 필요한 최소 정보만 확인하고 진단·처방 상세는 제한되는 구조입니다." + ), + ( + "07_research_virtual_docking_lab.png", + "07. Research Lab", + "연구자용 단백질-화합물 가상 도킹 실험 화면", + "타겟 단백질, 후보 화합물, 3D 구조, 도킹 점수, 실험 파라미터를 확인하는 연구 워크플로우 화면입니다." + ), + ( + "08_security_audit_center.png", + "08. Security Center", + "보안관리자용 접근 감사 로그 화면", + "누가 어떤 정보에 접근했는지, 권한 밖 접근이 있었는지, 내부자 과다열람 의심 이벤트가 있는지 확인하는 화면입니다." + ), + ( + "09_platform_admin_policy_matrix.png", + "09. Platform Admin Console", + "플랫폼 관리자용 권한 정책 매트릭스 화면", + "역할별 접근 가능 화면, 차단 정책, 계정 관리, 상용화 보안 체크리스트를 확인하는 관리자 화면입니다." + ), + ( + "10_access_denied_audit_log.png", + "10. Access Denied", + "권한 없는 접근 차단 화면", + "사용자가 허용되지 않은 화면에 접근하려 할 때 차단하고, 해당 시도를 보안 감사 로그에 기록한다는 구조를 보여주는 화면입니다." + ), + ( + "11_nurse_role_workspace.png", + "11. My Workspace - Nurse", + "간호사 역할별 워크스페이스 화면", + "간호사가 수행하는 주요 업무, 접근 가능한 데이터, 제한되는 데이터, 생성 산출물을 정리한 역할 설명 화면입니다." + ), + ( + "12_bio_security_architect_workspace.png", + "12. My Workspace - Bio Security Architect", + "Bio Security Architect 워크스페이스 화면", + "바이오그래머 직무 중 보안·권한·감사 로그·내부자 위험 탐지를 설계하는 역할을 보여주는 화면입니다." + ), +] + +def wrap_text(text, max_chars): + words = text.split() + lines = [] + line = "" + for word in words: + if len(line + " " + word) > max_chars: + lines.append(line) + line = word + else: + line = (line + " " + word).strip() + if line: + lines.append(line) + return lines + +def draw_image_page(c, image_path, title, subtitle, caption): + w, h = landscape(A4) + + c.setFillColor(colors.HexColor("#0f172a")) + c.setFont("Helvetica-Bold", 18) + c.drawString(16 * mm, h - 15 * mm, title) + + c.setFillColor(colors.HexColor("#2563eb")) + c.setFont("Helvetica-Bold", 11) + c.drawString(16 * mm, h - 23 * mm, subtitle) + + c.setFillColor(colors.HexColor("#475569")) + c.setFont("Helvetica", 9) + + y_caption_top = h - 31 * mm + for line in wrap_text(caption, 115): + c.drawString(16 * mm, y_caption_top, line) + y_caption_top -= 5 * mm + + top = h - 43 * mm + bottom = 14 * mm + left = 13 * mm + right = w - 13 * mm + + max_w = right - left + max_h = top - bottom + + with Image.open(image_path) as img: + iw, ih = img.size + + scale = min(max_w / iw, max_h / ih) + draw_w = iw * scale + draw_h = ih * scale + + x = (w - draw_w) / 2 + y = bottom + (max_h - draw_h) / 2 + + c.setStrokeColor(colors.HexColor("#e2e8f0")) + c.setLineWidth(1) + c.roundRect(x - 2 * mm, y - 2 * mm, draw_w + 4 * mm, draw_h + 4 * mm, 4 * mm, stroke=1, fill=0) + + c.drawImage(str(image_path), x, y, width=draw_w, height=draw_h, preserveAspectRatio=True, mask="auto") + + c.setFillColor(colors.HexColor("#64748b")) + c.setFont("Helvetica", 8) + c.drawString(16 * mm, 7 * mm, "※ 샘플 데이터 기반 프로토타입 화면이며, 실제 진단·처방·임상 판단 기능이 아닙니다.") + + c.showPage() + +def draw_protein_atlas_page(c): + w, h = landscape(A4) + + c.setFillColor(colors.HexColor("#0f172a")) + c.setFont("Helvetica-Bold", 20) + c.drawString(16 * mm, h - 16 * mm, "13. BioDockLab Protein Atlas 확장기획") + + c.setFillColor(colors.HexColor("#2563eb")) + c.setFont("Helvetica-Bold", 11) + c.drawString(16 * mm, h - 25 * mm, "교육·연구용 단백질 구조·변이·질환 탐색 기능") + + y = h - 40 * mm + + sections = [ + ("기능 정의", [ + "Protein Atlas는 환자 진료용 기능이 아니라, 학생·연구자·비전공자가 단백질 구조, 주요 변이, 관련 질환, 후보 리간드 정보를 이해하도록 돕는 교육·연구 보조 기능입니다.", + "BioDockLab의 핵심인 역할 기반 접근제어와 설명 보조 기능을 연구자·교육용 화면으로 확장하는 방향입니다." + ]), + ("핵심 기능", [ + "단백질 기본 정보 카드: 단백질명, PDB ID, 주요 기능, 관련 질환, 구조 유형, 주요 변이", + "3D 구조 미리보기: 단백질 표면, 활성 부위, 결합 리간드, 변이 위치 강조", + "질환·변이·리간드 연결: 단백질 → 주요 변이 → 관련 질환 → 후보 리간드/화합물 → 연구 실험", + "용어 설명: 활성 부위, 리간드, 도킹, 결합 친화도, RMSD, 변이, 표적치료, 비식별 데이터" + ]), + ("추천 샘플 단백질", [ + "EGFR L858R: 폐암 표적치료 예시", + "KRAS G12D: 암 표적 연구 예시", + "BRAF V600E: 변이 기반 표적치료 설명", + "ALK: 융합유전자 및 표적치료 예시", + "HER2: 유방암/위암 관련 표적 예시", + "SARS-CoV-2 Main Protease: 감염병·항바이러스제 연구 예시" + ]), + ("활용 가능성", [ + "간호학과·생명과학·보건계열 학생 교육", + "바이오그래머 직무 설명 자료", + "연구자용 실험 전 사전 탐색 화면", + "환자 설명 리포트의 배경 이해 자료", + "단백질-화합물 도킹 실험 흐름의 시각자료" + ]), + ("주의할 점", [ + "이 기능은 실제 진단, 처방, 치료 결정 기능이 아닙니다.", + "Protein Atlas는 교육·연구 보조 화면이며, 실제 의료 판단은 의료진이 수행해야 합니다.", + "단백질 구조나 도킹 점수는 실제 임상 효능을 보장하지 않습니다." + ]), + ] + + for heading, lines in sections: + c.setFillColor(colors.HexColor("#1d4ed8")) + c.setFont("Helvetica-Bold", 13) + c.drawString(16 * mm, y, heading) + y -= 8 * mm + + c.setFillColor(colors.HexColor("#334155")) + c.setFont("Helvetica", 9.5) + for item in lines: + wrapped = wrap_text("• " + item, 105) + for line in wrapped: + c.drawString(20 * mm, y, line) + y -= 5 * mm + y -= 1 * mm + + y -= 4 * mm + + c.setFillColor(colors.HexColor("#0f172a")) + c.setFont("Helvetica-Bold", 11) + c.drawString(16 * mm, 14 * mm, "한 줄 요약") + c.setFillColor(colors.HexColor("#334155")) + c.setFont("Helvetica", 9.5) + c.drawString(16 * mm, 8 * mm, "BioDockLab Protein Atlas는 단백질 구조·변이·질환·후보 화합물 정보를 연결해 보여주는 교육·연구용 단백질 도감 기능입니다.") + + c.showPage() + +def main(): + missing = [] + for filename, *_ in SCREENS: + if not (SHOT_DIR / filename).exists(): + missing.append(filename) + + if missing: + print("Missing screenshot files:") + for filename in missing: + print(" -", SHOT_DIR / filename) + raise SystemExit(1) + + c = canvas.Canvas(str(OUTPUT), pagesize=landscape(A4)) + + for filename, title, subtitle, caption in SCREENS: + draw_image_page(c, SHOT_DIR / filename, title, subtitle, caption) + + draw_protein_atlas_page(c) + + c.save() + print("created:", OUTPUT) + +if __name__ == "__main__": + main() diff --git a/scripts/build_review_screen_pdf.py b/scripts/build_review_screen_pdf.py new file mode 100644 index 0000000..dcbc20c --- /dev/null +++ b/scripts/build_review_screen_pdf.py @@ -0,0 +1,258 @@ +from pathlib import Path +from reportlab.lib.pagesizes import A4, landscape +from reportlab.lib import colors +from reportlab.lib.units import mm +from reportlab.pdfgen import canvas +from PIL import Image + +BASE = Path(".") +SHOT_DIR = BASE / "docs/review/screenshots" +OUT_DIR = BASE / "docs/review/output" +OUT_DIR.mkdir(parents=True, exist_ok=True) + +OUTPUT = OUT_DIR / "BioDockLab_화면자료_전체12장_확장기획포함.pdf" + +SCREENS = [ + ( + "01_login_role_based_access.png", + "01. Login Screen", + "역할 기반 시스템이라는 첫인상", + "로그인 전에는 내부 화면에 접근할 수 없고, 환자·간호사·의사·약사·원무·연구자·보안관리자 등 역할에 따라 진입합니다." + ), + ( + "02_patient_explanation_report.png", + "02. Patient View", + "환자 설명 보조 방향", + "환자는 진단을 받는 것이 아니라, 의료진 상담을 준비하기 위한 쉬운 설명 리포트를 확인합니다." + ), + ( + "03_nurse_handoff_workspace.png", + "03. Nurse Workspace", + "간호학과 검토 요청의 핵심", + "간호사 화면은 바이탈, 인수인계, 투약 전 확인을 보조하며 EMR이나 간호기록을 대체하지 않습니다." + ), + ( + "04_doctor_result_summary.png", + "04. Doctor Workspace", + "의사용 결과 요약 및 설명 연결", + "의사는 환자 설명 리포트와 전문가용 해석을 함께 확인하여 상담 준비를 보조받습니다." + ), + ( + "05_pharmacist_prescription_review.png", + "05. Pharmacist Workspace", + "처방량·상호작용 검토", + "약사는 처방량, 병용약, 약물상호작용, 유전자 적합성 정보를 중심으로 검토합니다." + ), + ( + "06_admin_consent_document_view.png", + "06. Administration View", + "예약·동의서·서류 상태", + "원무는 예약, 동의서, 서류 상태 등 업무에 필요한 최소 정보만 확인하고 진단·처방 상세는 제한됩니다." + ), + ( + "07_research_virtual_docking_lab.png", + "07. Research Lab", + "바이오그래머/연구자 포인트", + "연구자는 비식별 연구 데이터와 단백질-화합물 가상 도킹 실험 흐름을 확인합니다." + ), + ( + "08_security_audit_center.png", + "08. Security Center", + "보안·접근 로그 차별점", + "보안관리자는 누가 어떤 정보에 접근했는지, 권한 밖 접근이 있었는지 감사 로그와 위험 이벤트로 확인합니다." + ), + ( + "09_platform_admin_policy_matrix.png", + "09. Platform Admin Console", + "상용화형 권한 정책 구조", + "플랫폼 관리자는 역할별 권한 매트릭스와 접근 정책을 확인하고 관리합니다." + ), + ( + "10_access_denied_audit_log.png", + "10. Access Denied", + "권한 없는 접근 차단", + "권한 없는 화면 접근은 차단되고, 해당 시도는 보안 감사 로그에 기록됩니다." + ), + ( + "11_nurse_role_workspace.png", + "11. My Workspace - Nurse", + "간호사 역할별 업무 정리", + "역할별 워크스페이스는 각 직군이 수행하는 업무, 접근 가능한 데이터, 제한되는 데이터를 정리합니다." + ), + ( + "12_bio_security_architect_workspace.png", + "12. My Workspace - Bio Security Architect", + "바이오그래머 보안 직무 예시", + "Bio Security Architect는 의료·바이오 데이터의 접근권한, 감사 로그, 내부자 과다열람 탐지 구조를 설계하는 역할입니다." + ), +] + +def draw_header(c, title, subtitle): + w, h = landscape(A4) + c.setFillColor(colors.HexColor("#0f172a")) + c.setFont("Helvetica-Bold", 18) + c.drawString(18 * mm, h - 18 * mm, title) + + c.setFillColor(colors.HexColor("#2563eb")) + c.setFont("Helvetica-Bold", 11) + c.drawString(18 * mm, h - 26 * mm, subtitle) + +def draw_caption(c, caption): + w, h = landscape(A4) + c.setFillColor(colors.HexColor("#334155")) + c.setFont("Helvetica", 10) + text = c.beginText(18 * mm, 15 * mm) + text.setLeading(13) + + max_chars = 118 + words = caption.split() + line = "" + for word in words: + if len(line + " " + word) > max_chars: + text.textLine(line) + line = word + else: + line = (line + " " + word).strip() + if line: + text.textLine(line) + + c.drawText(text) + +def draw_image_page(c, image_path, title, subtitle, caption): + w, h = landscape(A4) + + draw_header(c, title, subtitle) + + top = h - 34 * mm + bottom = 27 * mm + left = 14 * mm + right = w - 14 * mm + + max_w = right - left + max_h = top - bottom + + with Image.open(image_path) as img: + iw, ih = img.size + + scale = min(max_w / iw, max_h / ih) + draw_w = iw * scale + draw_h = ih * scale + + x = (w - draw_w) / 2 + y = bottom + (max_h - draw_h) / 2 + + c.setStrokeColor(colors.HexColor("#e2e8f0")) + c.setLineWidth(1) + c.roundRect(x - 2 * mm, y - 2 * mm, draw_w + 4 * mm, draw_h + 4 * mm, 5 * mm, stroke=1, fill=0) + + c.drawImage(str(image_path), x, y, width=draw_w, height=draw_h, preserveAspectRatio=True, mask="auto") + draw_caption(c, caption) + c.showPage() + +def draw_protein_atlas_page(c): + w, h = landscape(A4) + + draw_header( + c, + "13. BioDockLab Protein Atlas", + "교육·연구용 단백질 구조·변이·질환 탐색 확장기획" + ) + + c.setFillColor(colors.HexColor("#0f172a")) + c.setFont("Helvetica-Bold", 22) + c.drawString(18 * mm, h - 45 * mm, "Protein Atlas Extension Concept") + + c.setFillColor(colors.HexColor("#475569")) + c.setFont("Helvetica", 11) + + intro = ( + "BioDockLab Protein Atlas는 환자 진료용 기능이 아니라, 학생·연구자·비전공자가 " + "단백질 구조, 주요 변이, 관련 질환, 후보 리간드 정보를 한 화면에서 이해할 수 있도록 돕는 " + "교육·연구 보조 기능입니다." + ) + + text = c.beginText(18 * mm, h - 58 * mm) + text.setLeading(15) + for line in [ + "Purpose", + intro, + "", + "Core Functions", + "- 단백질 기본 정보: 이름, PDB ID, 기능, 구조 유형", + "- 질환 연계: 관련 암/감염병/유전 변이 정보", + "- 변이 정보: EGFR L858R, KRAS G12D, BRAF V600E 등", + "- 3D 구조 미리보기: 활성 부위, 결합 리간드, 변이 위치 강조", + "- 대표 리간드/후보 화합물: 연구자용 도킹 실험 화면과 연결", + "- Glossary: 활성 부위, 리간드, 도킹, RMSD, 결합 친화도 등 용어 설명", + "", + "Recommended Protein Samples", + "- EGFR L858R", + "- KRAS G12D", + "- BRAF V600E", + "- ALK", + "- HER2", + "- SARS-CoV-2 Main Protease", + "", + "Positioning", + "이 기능은 진단·처방을 위한 화면이 아니라, BioDockLab의 연구자 화면과 연결되는 교육·연구용 탐색 기능입니다." + ]: + text.textLine(line) + + c.drawText(text) + + # right side concept cards + x = 180 * mm + y = h - 60 * mm + card_w = 95 * mm + card_h = 23 * mm + + cards = [ + ("EGFR L858R", "비소세포폐암(NSCLC) 관련 변이 예시"), + ("KRAS G12D", "암 표적 연구와 도킹 실험 예시"), + ("BRAF V600E", "표적치료와 변이 이해 교육 예시"), + ("Protein → Disease → Ligand", "단백질-질환-후보화합물 연결 탐색") + ] + + for title, desc in cards: + c.setFillColor(colors.HexColor("#f8fafc")) + c.setStrokeColor(colors.HexColor("#dbeafe")) + c.roundRect(x, y, card_w, card_h, 5 * mm, fill=1, stroke=1) + + c.setFillColor(colors.HexColor("#1d4ed8")) + c.setFont("Helvetica-Bold", 12) + c.drawString(x + 6 * mm, y + 13 * mm, title) + + c.setFillColor(colors.HexColor("#475569")) + c.setFont("Helvetica", 9) + c.drawString(x + 6 * mm, y + 6 * mm, desc) + + y -= 30 * mm + + c.showPage() + +def main(): + missing = [] + for filename, *_ in SCREENS: + if not (SHOT_DIR / filename).exists(): + missing.append(filename) + + if missing: + print("Missing screenshot files:") + for f in missing: + print(" -", SHOT_DIR / f) + print() + print("먼저 캡처 파일명을 위 목록에 맞춰 docs/review/screenshots/ 폴더에 넣어주세요.") + raise SystemExit(1) + + c = canvas.Canvas(str(OUTPUT), pagesize=landscape(A4)) + + for filename, title, subtitle, caption in SCREENS: + draw_image_page(c, SHOT_DIR / filename, title, subtitle, caption) + + draw_protein_atlas_page(c) + c.save() + + print("created:", OUTPUT) + +if __name__ == "__main__": + main() diff --git a/scripts/capture_fixed_12_screens.sh b/scripts/capture_fixed_12_screens.sh new file mode 100755 index 0000000..b2673e9 --- /dev/null +++ b/scripts/capture_fixed_12_screens.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +set -e + +BASE_DIR="$HOME/Documents/001.개발/BioDockLab" +SHOT_DIR="$BASE_DIR/docs/review/screenshots" + +mkdir -p "$SHOT_DIR" + +echo "======================================" +echo "BioDockLab 01~12 화면 캡처" +echo "======================================" +echo "저장 위치: $SHOT_DIR" +echo "" +echo "각 화면이 열리면 화면이 완전히 뜬 뒤 Enter를 누르세요." +echo "그 다음 마우스로 캡처 영역을 드래그하면 됩니다." +echo "" + +capture() { + local filename="$1" + local url="$2" + local title="$3" + local desc="$4" + + echo "" + echo "--------------------------------------" + echo "$filename" + echo "$title" + echo "$desc" + echo "--------------------------------------" + echo "" + open "$url" + + echo "화면이 완전히 뜨면 Enter를 누르세요." + read -r + + echo "캡처 영역을 드래그하세요." + screencapture -i "$SHOT_DIR/$filename" + + echo "저장 완료: $SHOT_DIR/$filename" +} + +capture \ +"01_login_role_based_access.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=login" \ +"01. 역할 기반 로그인 화면" \ +"환자·간호사·의사·약사·원무·연구자·보안관리자가 서로 다른 권한으로 접속하는 진입 화면" + +capture \ +"02_patient_explanation_report.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=patient&view=patient" \ +"02. 환자/의사용 결과 설명 리포트" \ +"복잡한 검사 결과와 후보 치료제 정보를 환자와 의료진이 이해하기 쉽게 확인하는 설명 보조 화면" + +capture \ +"03_nurse_handoff_workspace.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=nurse&view=nurse" \ +"03. 간호사용 바이탈·인수인계 보조 화면" \ +"바이탈 요약, 투약 전 확인, 인수인계 요약을 제공하지만 EMR이나 간호기록을 대체하지 않는 보조 화면" + +capture \ +"04_doctor_result_summary.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=doctor&view=doctor" \ +"04. 의사용 결과 요약 화면" \ +"환자 상태, 검사 결과, 설명 리포트, 상담 준비 정보를 의료진 관점에서 확인하는 화면" + +capture \ +"05_pharmacist_prescription_review.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=pharmacist&view=prescription" \ +"05. 약사용 처방 검토 화면" \ +"처방량, 병용약, 약물상호작용, 유전자 적합성 정보를 중심으로 검토하는 화면" + +capture \ +"06_admin_consent_document_view.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=admin_staff&view=admin" \ +"06. 원무용 예약·동의서·서류 상태 화면" \ +"원무는 예약, 동의서, 서류 발급 상태 등 업무에 필요한 최소 정보만 확인하고 진단·처방 상세는 제한되는 구조" + +capture \ +"07_research_virtual_docking_lab.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=researcher&view=research_lab" \ +"07. 연구자용 단백질-화합물 가상 도킹 실험 화면" \ +"타겟 단백질, 후보 화합물, 3D 구조, 도킹 점수, 실험 파라미터를 확인하는 연구 워크플로우 화면" + +capture \ +"08_security_audit_center.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=security&view=security" \ +"08. 보안관리자용 접근 감사 로그 화면" \ +"누가 어떤 정보에 접근했는지, 권한 밖 접근이 있었는지, 내부자 과다열람 의심 이벤트가 있는지 확인하는 화면" + +capture \ +"09_platform_admin_policy_matrix.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=super_admin&view=admin_console" \ +"09. 플랫폼 관리자용 권한 정책 매트릭스 화면" \ +"역할별 접근 가능 화면, 차단 정책, 계정 관리, 상용화 보안 체크리스트를 확인하는 관리자 화면" + +capture \ +"10_access_denied_audit_log.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=patient&view=security" \ +"10. 권한 없는 접근 차단 화면" \ +"사용자가 허용되지 않은 화면에 접근하려 할 때 차단하고, 해당 시도를 보안 감사 로그에 기록하는 화면" + +capture \ +"11_nurse_role_workspace.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=nurse&view=role_workspace" \ +"11. 간호사 역할별 워크스페이스 화면" \ +"간호사가 수행하는 주요 업무, 접근 가능한 데이터, 제한되는 데이터, 생성 산출물을 정리한 역할 설명 화면" + +capture \ +"12_bio_security_architect_workspace.png" \ +"http://127.0.0.1:5500/clinical_v3.html?capture=1&role=bio_security_architect&view=role_workspace" \ +"12. Bio Security Architect 워크스페이스 화면" \ +"바이오그래머 직무 중 보안·권한·감사 로그·내부자 위험 탐지를 설계하는 역할을 보여주는 화면" + +echo "" +echo "======================================" +echo "01~12 캡처 완료" +echo "저장 위치: $SHOT_DIR" +echo "======================================" + +ls -lh "$SHOT_DIR"/0*.png "$SHOT_DIR"/1*.png 2>/dev/null || true diff --git a/scripts/smoke_test.py b/scripts/smoke_test.py index be70509..5fbfeb8 100755 --- a/scripts/smoke_test.py +++ b/scripts/smoke_test.py @@ -64,6 +64,8 @@ def main(): ("doctor", "Doctor", "doctor", True), ("doctor", "Doctor", "security", False), ("pharmacist", "Pharmacist", "prescription", True), + ("nurse", "Nurse", "nurse", True), + ("nurse", "Nurse", "security", False), ("pharmacist", "Pharmacist", "security", False), ("admin_staff", "AdminStaff", "admin", True), ("admin_staff", "AdminStaff", "prescription", False),