diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 1edb57b3..8b0fba65 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -33,7 +33,7 @@ jobs: - name: Stage runtime files run: | mkdir -p _site/docs - cp index.html 404.html app.js styles.css wbs.json _site/ + cp index.html 404.html app.js cloud-sync.js analytics.js styles.css toast-state.css wbs.json _site/ cp docs/user-guide.md _site/docs/ - name: Upload static artifact diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3006c74b..4688d27b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -4,7 +4,9 @@ - `index.html`: app shell and modal structure. - `styles.css`: responsive layout, table, badges, gantt, and modal - presentation. + presentation. `.toast.show` is the standalone producer state. +- `toast-state.css`: cloud overlay `.toast.visible` rendering so SaaS + status messages stay visually observable. - `app.js`: state, rendering, editing, validation, persistence, import/export, and Gantt logic. - `analytics.js`: EVM, S-curve, CPM, workload, cost, and requirements/RFI/RFP diff --git a/CHANGELOG.md b/CHANGELOG.md index bc41a659..8f784cc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 conversion identifiers from responses, reports attempted, changed, failed, skipped-data, and deferred-budget counters separately, and exposes fixed low-cardinality timeout, lookup, validation, and persistence failure counters. +- Toast notifications and synchronization feedback now expose advisory updates + as explicit polite, atomic WAI-ARIA status regions without adding keyboard + stops, and cloud toast feedback now has a shipped visual state so the same + message remains visible to sighted users. +- GitHub Pages, both Docker images, and the SaaS static allowlist now ship + `cloud-sync.js`, `analytics.js`, and `toast-state.css` with the documents + that load them, so share-error and cloud status toasts stay visible after + deploy. - 프로젝트 이름 입력 필드에 입력 예시(placeholder)를 추가하여 사용자 편의성을 개선했습니다. - 데이터 테이블의 반복되는 액션 버튼에 컨텍스트 정보(작업명)를 포함한 명시적인 ARIA 레이블을 추가하고, 유효성 검사 에러를 폼 필드에 연결하여 접근성을 개선했습니다. - `createGanttBarElement`, `renderGantt`, `buildWeekdayTimeline`에서 반복적으로 호출되던 `compareDateStrings`를 직접적인 문자열 비교 연산(`>=`, `<=`)으로 교체하여 O(N*D) 복잡도의 캐시 스레싱과 정규식 검사를 방지했습니다. diff --git a/CLAUDE.md b/CLAUDE.md index b1f11c4d..81c1a819 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,8 +56,8 @@ deploy guide is `docs/deploy.md`. ### Client (repo root) -- `index.html` — app shell + modals, strict CSP meta tag; loads `cloud-sync.js`, - `analytics.js`, then `app.js`. +- `index.html` — app shell + modals, strict CSP meta tag; loads `styles.css`, + `toast-state.css`, `cloud-sync.js`, `analytics.js`, then `app.js`. - `app.js` — all state, rendering, editing, validation, persistence, CSV import/export, and Gantt logic. The single global `tasks` array is the source of truth and `renderAll()` is the only rerender path (see `AGENTS.md`). diff --git a/Dockerfile b/Dockerfile index 8f39e187..ebc14bc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM nginx:1.25-alpine@sha256:516475cc129da42866742567714ddc681e5eed7b9ee0b9e9c015e464b4221a00 COPY infra/nginx/default.conf /etc/nginx/conf.d/default.conf -COPY index.html 404.html app.js styles.css wbs.json /usr/share/nginx/html/ +COPY index.html 404.html app.js cloud-sync.js analytics.js styles.css toast-state.css wbs.json /usr/share/nginx/html/ COPY docs/user-guide.md /usr/share/nginx/html/docs/ # Strix security scan recommendation: switch to non-root user diff --git a/Dockerfile.server b/Dockerfile.server index 579360f1..4f162de7 100644 --- a/Dockerfile.server +++ b/Dockerfile.server @@ -12,7 +12,7 @@ RUN npm ci --omit=dev && npm cache clean --force # Server + the static client files the allowlist serves. COPY server ./server -COPY index.html 404.html app.js cloud-sync.js analytics.js styles.css wbs.json ./ +COPY index.html 404.html app.js cloud-sync.js analytics.js styles.css toast-state.css wbs.json ./ ENV PORT=8787 ENV SCOPEWEAVE_DB=/data/scopeweave.db diff --git a/README.md b/README.md index ea8bb77a..6340c1f4 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ two modes: ## Architecture ``` -index.html + app.js + styles.css ← static client (eval-safe; no top-level imports) +index.html + app.js + styles.css + toast-state.css ← static client (eval-safe; no top-level imports) ├─ analytics.js ← EVM/S-curve/CPM (window.ScopeWeaveAnalytics) └─ cloud-sync.js ← opt-in cloud overlay (window.ScopeWeaveCloud) server/ diff --git a/docs/doctoring/toast-status-accessibility.md b/docs/doctoring/toast-status-accessibility.md new file mode 100644 index 00000000..cb684e53 --- /dev/null +++ b/docs/doctoring/toast-status-accessibility.md @@ -0,0 +1,95 @@ +# Toast and sync status accessibility and visibility evidence + +## Status and decision + +ScopeWeave treats transient toast text and synchronization feedback as +advisory status messages. The shipped contract is: + +- `#toast` has `role="status"`, `aria-live="polite"`, and + `aria-atomic="true"` and does not receive focus when its content + changes; +- `#sync-status` uses the same explicit status/polite/atomic semantics + without becoming a synthetic keyboard stop; and +- the cloud/SaaS toast producer's `.visible` state is backed by shipped + CSS that raises opacity to `1` and restores the translated element. + +The visual-state control matters because the base application producer +uses `.show` while `cloud-sync.js` adds and removes `.visible`. +`styles.css` renders `.toast.show`, so a cloud message can update its +live-region text while remaining visually transparent unless +`.toast.visible` is also rendered. After a share link fails, the next +action is to request a fresh share URL from the project owner. + +## Standards boundary + +WAI-ARIA 1.2 defines `status` as advisory live-region content and gives +the role implicit `aria-live="polite"` and `aria-atomic="true"` +semantics. It also advises authors not to move focus to a status message +as a result of the update. WCAG 2.2 Success Criterion 4.1.3 requires +status messages to be programmatically determinable so assistive +technology can present them without receiving focus. ScopeWeave keeps +the explicit live-region attributes in addition to the role so the +intended contract remains visible in markup and executable regression +evidence. + +The `.visible` compatibility rule is a product-integrity control, not a +separate WCAG success criterion. It prevents the same advisory toast +from being available to screen-reader users while remaining transparent +for sighted users. + +## Repair boundary + +PR #491 head `794ecbdf1416e883942dac2b836859ba6f9ac0f9` titled a CI +re-kick but deleted this slice and reverted already-landed orchestrator +and Microsoft Project XML hardening. This repair replays only the toast +and sync-status contract onto current `develop`. It does not change +orchestrator, XML import, authentication, or workflow files. + +`toast-state.css` must stay on every production serve path: the SaaS +static allowlist, both Docker images, and the GitHub Pages stage list. +A share-error toast that updates the live region while remaining +transparent is the buyer-visible failure this lock prevents. + +Do not use empty `ci: re-kick` commits to mutate the tree. Rollback must +remove the status semantics, `toast-state.css`, its production link, +allowlist and image copies, both focused toast regressions and their +test registrations, this doctoring record, and the CHANGELOG entry +together. + +## Executable acceptance evidence + +`tests/unit/toast-accessibility.test.mjs` reads the shipped +`index.html`, `cloud-sync.js`, and `toast-state.css`. It proves that: + +- the production toast exposes status/polite/atomic semantics; +- the production synchronization feedback exposes the same explicit + advisory status semantics; +- neither advisory status region becomes a synthetic keyboard stop; +- the cloud producer actually activates `.visible`; +- the production document loads `toast-state.css`; and +- `.toast.visible` is rendered with visible opacity and transform. + +`tests/e2e/toast-accessibility.spec.js` drives the production cloud +share-error path in Chromium using a valid-shaped but unavailable share +token. It requires the real toast to contain the customer-facing failure +guidance, retain the status semantics, carry `.visible`, reach computed +opacity of at least `0.99`, be visually visible, and leave keyboard +focus elsewhere. + +## Scope and security boundary + +This change does not alter toast or synchronization content, timing, +persistence, authentication, authorization, API semantics, credential +handling, tenant isolation, attachment behavior, Clearfolio integration, +database state, dependencies, workflows, or application +focus-management code. Urgent blocking errors that require immediate +interruption need a separate interaction design rather than silently +changing these advisory status regions to assertive alerts. + +## References + +World Wide Web Consortium. (2023). *Accessible Rich Internet +Applications (WAI-ARIA) 1.2*. https://www.w3.org/TR/wai-aria-1.2/ + +World Wide Web Consortium. (2023). *Web Content Accessibility Guidelines +(WCAG) 2.2*. https://www.w3.org/TR/WCAG22/ diff --git a/index.html b/index.html index a7f4b49c..d24b2a88 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,7 @@ + @@ -44,7 +45,7 @@

ScopeWeave Planner

0.00%
- 브라우저 로컬 자동저장 사용 중 + 브라우저 로컬 자동저장 사용 중
@@ -95,7 +96,7 @@

ScopeWeave Planner

-
+