POSA_Copyrighter/docs/plans/2026-06-03-operator-console-quality-improvement-plan.md
유창욱 3f7b3a9cf2 chore: initial commit of copyrighter (rights_filter)
Image rights / copyright detection system: SQLite store, HTTP app,
search integrations (Naver, Google Custom Search, Google Cloud Vision
web detection), image analysis (fingerprints, face/person detection,
evidence enrichment, risk scoring), an admin/review layer, governance
and retention policies, batch jobs, and a browser-based operator GUI.

This baseline incorporates a full code-review remediation pass
(46 fixes; 358 tests passing). Highlights:

CRITICAL
- Prevent evidence cascade-delete during the schema-constraint
  migration by disabling FK enforcement around the table rebuild.

Security
- Sandbox served media (neutralize stored XSS from uploaded/collected
  SVGs) via CSP + nosniff on the untrusted media routes.
- Strip embedded EXIF/GPS from external image derivatives before they
  are sent to third-party APIs.
- Return a clean 404 (not an uncaught StopIteration) for PATCH on an
  unknown provider.

Correctness
- LLM-summary failures no longer add +30 to the risk score.
- Decode only explicit JS escapes so Korean image URLs are not mangled.
- Consume search quota only after a successful request.
- Naver/Google adapters map responses inside the failure boundary, so a
  malformed response degrades to evidence instead of crashing enrichment.
- Domain-aware provider attribution; face-box IoU de-duplication; count
  searches (not result items); per-box crop isolation; clamp evidence
  confidence and Google CSE num; real submittedEpoch; and more.

Robustness
- Offline LLM connect fast-fails (short connect timeout) so seed/reload
  requests are not stalled; full read timeout preserved for generation.
- Malformed numeric env vars fall back to defaults instead of crashing
  startup.

Performance
- Per-submission evidence reads (no full-table scan per rescore),
  audit-log LIMIT, lazy active-store lookup, hoisted timestamps.

Tests
- ~24 regression tests added pinning the above fixes.

Runtime data (data/, outputs/, *.sqlite3, *.log), secrets (.env), and
node_modules are gitignored.
2026-06-09 09:50:31 +09:00

161 lines
7.7 KiB
Markdown

---
status: active
created: 2026-06-03
type: quality
title: Operator console quality improvement plan
---
# Operator Console Quality Improvement Plan
## Scope
This plan responds to the concrete quality issues raised during review of the current operator console:
- static tests rely too heavily on string presence;
- visible Korean copy is partially corrupted;
- `web/operator-gui/app.js` carries too many responsibilities;
- the case workbench still needs stronger next-action guidance;
- submission upload and folder reload UX needs clearer operator feedback.
- the product purpose is not explicit enough in the UI.
## 1. Strengthen Tests Beyond String Presence
Problem:
The operator GUI tests catch missing selectors and accidental deletion, but they do not prove the main flows work in a browser.
Plan:
- Keep static tests as fast contract checks.
- Add server-backed behavior tests for upload, reload, and manual search.
- Add future browser smoke tests for queue selection, workbench tab switching, and suggested-query fill behavior.
Immediate action:
Completed:
- `tests/operator_gui/test_browser_smoke.py` now verifies the suggested-query browser flow: selecting a recommendation fills the manual query input without running a search.
- `tests/operator_gui/test_browser_smoke.py` now verifies the real browser upload flow through the local HTTP server: file selection, `/api/submissions/upload-image`, saved image file, new queue item, workbench navigation, and selected uploaded submission.
- `tests/rights_filter/server/test_http_app.py::test_http_server_uploads_submission_image_into_active_queue` verifies the upload HTTP contract saves the image into the active queue and returns the uploaded submission in the refreshed bootstrap payload.
- `tests/operator_gui/test_static_workbench.py` retains fast structural checks and now also protects module load order, mojibake prevention, product purpose copy, workflow guidance, and upload UX contracts.
## 2. Repair Corrupted Korean Copy
Problem:
Several operator-facing status strings in `app.js` are mojibake. This weakens trust in a review tool.
Plan:
- Prioritize visible workflow copy over legacy compatibility strings.
- Replace high-use status text first: reload, folder import, image upload, bulk rerun, manual search, and decision memo errors.
- Keep compatibility-only tokens isolated until tests can be rewritten around clean labels.
Immediate action:
Completed:
- Reload, folder import, upload, bulk rerun, manual search, evidence, provider, knowledge DB, candidate, correction, and empty-state copy were normalized to readable Korean.
- A mojibake regression check now scans the operator GUI files for common corrupted UTF-8 fragments.
- The operator GUI JavaScript files pass `node --check`.
## 3. Split `app.js` Responsibilities
Problem:
`app.js` owns queue rendering, workbench rendering, search, knowledge DB, provider controls, upload, and audit events.
Plan:
- First extract pure helpers: file payload reading, evidence sufficiency, query suggestions, and import status formatting.
- Then split rendering domains into small static modules if the deployment can safely move to module scripts.
- Avoid a broad framework migration.
Immediate action:
Completed:
- `web/operator-gui/operator-labels.js` owns visible label dictionaries.
- `web/operator-gui/submission-import.js` owns submission import/upload file payload helpers and import status message helpers.
- `web/operator-gui/evidence-guidance.js` owns evidence sufficiency checks, follow-up reasons, query seed normalization, and suggested evidence queries.
- `web/operator-gui/operator-search.js` owns query status labels, query strategy labels, and manual search provider normalization.
- `web/operator-gui/app.js` now delegates those concerns to the extracted helpers while retaining rendering and event orchestration.
Remaining:
- Rendering domains are still mostly in `app.js`. Further extraction should focus on evidence rendering and knowledge/candidate rendering only if needed, because the current no-framework static runtime is now split enough to reduce the most immediate risk.
## 4. Improve Next-Action Guidance
Problem:
The workbench shows evidence, but does not always tell the operator what to do when evidence is thin.
Plan:
- Keep the existing "근거 보강 추천" panel.
- Expand the sufficiency heuristic with clearer reasons: no direct match, too few searchable results, provider empty state, or duplicate queries.
- Add a browser smoke test to ensure clicking a recommendation fills the manual query form without running a search.
Immediate action:
Completed:
- The "근거 보강 추천" panel now explains concrete insufficiency reasons such as missing direct/page evidence, fewer than two searchable results, empty provider results, and failed provider history.
- Suggested queries fill the manual search input and switch to the query tab without automatically running a search.
- Browser smoke coverage verifies this non-automatic behavior.
## 5. Clarify Upload And Folder Reload UX
Problem:
Operators should not need to understand active queue internals. After adding a photo or changing folders, the UI should say what happened.
Plan:
- Provide a file picker for adding a photo to the active queue.
- Save uploaded files into the active queue folder and rescan immediately.
- Select the uploaded submission when available.
- Show clear status text for imported count, selected ID, upload progress, and active folder label.
Immediate action:
Completed:
- The upload endpoint and UI are implemented.
- Upload success selects the uploaded submission, resets queue filters, moves to the workbench evidence tab, and tells the operator the new case was selected.
- The queue header now explains that adding a photo creates a new review case and opens it for case review.
- Browser smoke coverage verifies the real upload flow end to end.
## 6. Clarify Product Purpose And Workflow
Problem:
The console exposed many implementation concepts and actions, but the product purpose and operator flow were not explicit enough.
Plan:
- State the product purpose in the top bar.
- Show the operator's expected flow on the queue screen.
- Keep this copy stable with static tests.
Completed:
- The top bar now states: "이미지 저작권 위험 심사" and explains that submitted images, external search evidence, and the internal criteria DB are reviewed together.
- The queue screen now shows a three-step operating flow: "심사 건 추가", "근거 보강", and "운영 결정".
- Static tests protect the purpose copy and workflow copy.
## Verification
Run:
```powershell
python -m pytest tests\operator_gui\test_static_workbench.py
python -m pytest tests\operator_gui\test_browser_smoke.py
python -m pytest tests\rights_filter\server\test_http_app.py::test_http_server_uploads_submission_image_into_active_queue
node --check web\operator-gui\app.js
node --check web\operator-gui\operator-labels.js
node --check web\operator-gui\submission-import.js
node --check web\operator-gui\evidence-guidance.js
node --check web\operator-gui\operator-search.js
```
Latest local verification:
- `python -m pytest tests\operator_gui\test_static_workbench.py tests\operator_gui\test_browser_smoke.py` -> 39 passed.
- `python -m pytest tests\rights_filter\server\test_http_app.py::test_http_server_uploads_submission_image_into_active_queue` -> 1 passed.
- `node --check` passed for `app.js`, `operator-labels.js`, `submission-import.js`, `evidence-guidance.js`, and `operator-search.js`.
Future verification:
- If more rendering code is extracted from `app.js`, add a browser smoke check for that affected flow before relying on static checks.
- If the visual layout changes again, refresh the `ui-overhaul-final-results.json` overflow audit and screenshots.