From 345fffd28242e7ff748426dae447cda36e2e0492 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 15:33:36 +0900 Subject: [PATCH 1/9] docs: reconcile agent guidance with shipped dual runtime --- AGENTS.md | 132 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7a5b65ac..bdb8bca2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,72 +1,76 @@ # AGENTS.md -## Project overview +## Product boundary -- ScopeWeave Planner is a pure HTML/CSS/JavaScript WBS planning web app. -- Runtime dependencies are forbidden; development-only tooling is allowed. +ScopeWeave is one product with two independently usable runtime profiles: -## Defaults +- **Standalone** — static `index.html`/CSS/JavaScript, local-first persistence, no server or runtime package requirement, deployable to GitHub Pages or any static host. +- **Cloud/SaaS** — the same client with `cloud-sync.js` plus the Node server under `server/`, multi-tenant persistence, authentication, collaboration, analytics and integrations. -- Keep the runtime static-host compatible for GitHub Pages. -- Preserve the single global `tasks` array as the source of truth. -- Use a single `renderAll()` integration path for user-visible rerenders. -- Prefer browser-native APIs only. +Protected `develop` is the authority for what is shipped. PR bodies, issue text, plans and chat are evidence only. Never describe behavior that exists only on an open PR as shipped. + +## Architecture invariants + +- Preserve standalone static-host compatibility even when changing cloud behavior. +- Preserve the client `tasks` array as the canonical in-browser work-item state and `renderAll()` as the user-visible rerender integration path unless an accepted ADR supersedes that contract. +- `app.js` must remain eval-safe: no top-level `import` or `export`. Optional browser modules bridge through explicit `window.ScopeWeave*` interfaces. +- Cloud code may use the runtime dependencies already declared in `package.json`; adding or replacing production dependencies requires a bounded justification, supply-chain review and compatible standalone behavior. +- `server/db.mjs` currently owns SQLite persistence. PostgreSQL is a migration target, not shipped truth until an integrated adapter and migration evidence exist. +- Cross-service integrations such as Clearfolio and contextual-orchestrator are replaceable adapters. ScopeWeave owns its validation, authorization and failure boundary; it does not duplicate another CWL service's internal authority. +- Do not silently promote development mocks or deterministic fallbacks to production readiness. When a production boundary is incomplete, document it as a current gap or active PR. + +## Database contract + +- New owned database objects use descriptive two-or-more-word `snake_case` names. +- Keep relational designs in third normal form unless a documented, measured exception is accepted. +- Schema changes require migration, rollback/recovery and populated-database tests; request-time DDL is not a migration strategy. +- Preserve tenant isolation and optimistic-concurrency semantics across persistence adapters. ## Verification -- Serve locally with `python3 -m http.server 4173`. -- Run end-to-end verification with `npm run test:e2e`. -- Run workflow ownership checks with `python3 -m pytest tests/config`. - -## CI / security workflow notes - -- OpenCode Review, Strix Security Scan, and PR Review Merge Scheduler are - organization-level required workflows from `ContextualWisdomLab/.github`. - Do not copy them into this repository. -- Keep companion SCA workflows development-only; do not add runtime - dependencies. -- If GitHub CLI output emits Projects(classic) deprecation warnings, - prefer `gh api` or explicit `--json` field selection over default - human-formatted `gh issue view` / `gh pr view` output. - - -## Agent guidance (CWL governance) - -Cross-agent conventions for any agent working in this repo (Claude, Codex, -Cursor, opencode, ...). Distilled from ContextualWisdomLab governance. - -### Security & review gate - -- Every PR runs a central **Security Scan** required gate: `osv-scan` + - `dependency-review` (diff-scoped) and `trivy-fs` (repo-wide, CRITICAL/HIGH, - fixable only). It runs against every PR base, **including stacked PRs**. -- A failing `trivy-fs` is a **REAL finding, not a flake.** Read the job log and - the uploaded SARIF/code-scanning results to identify each rule id, severity, - file, and line before changing code. SARIF-mode Trivy logs may only show the - scanner configuration and exit code, so use code scanning or the SARIF - artifact when the log does not enumerate findings. Then **remediate**: bump - the offending dependency, fix the misconfig in - `Dockerfile` or `infra/k8s/*.yaml`, or add a narrow, documented - `.trivyignore` (`.trivyignore.yaml`) entry only for a genuine false positive. - Never weaken, skip, or disable the gate. -- A local scan with a stale DB misses findings. Run - `trivy --download-db-only` first, then scan the **merge ref**, not just the PR - head, e.g. `trivy fs --severity CRITICAL,HIGH --ignore-unfixed .`. -- Worked example from the historical PR queue: the misconfig scan flagged - **KSV-0020 / KSV-0021** (UID/GID `<= 10000` — `infra/k8s/deployment.yaml` - uses `runAsUser/runAsGroup: 101`), **KSV-0110** (no explicit `namespace`, so - the manifests land in `default`), and **DS-0026** (no `HEALTHCHECK` in the - `Dockerfile`). Fix these in-tree; do not ignore them. -- The org `code_scanning` ruleset is intentionally **CodeQL-only** (multiple - code-scanning tools cannot converge on one PR ref). Gating is by the Security - Scan **job result**, not the `code_scanning` rule — do not add tools to that - rule. - -### Code exploration - -- Initialize and sync CodeGraph before review or edits, then keep it current - after rebases and source changes. Use CodeGraph (`codegraph status`, - `codegraph sync`, `codegraph explore ""`, or the code-review-graph MCP - tools) as the first structural map, with ripgrep/find as a fast companion for - exact text search. - +Run the applicable repository-native paths before requesting merge: + +```bash +npm run test:unit +npm run test:api +npm run test:coverage +npm run test:e2e +npm run test:e2e:cloud +npm run fuzz +python3 -m pytest tests/config +``` + +`server-tests.yml`, Fuzz, Dependency Review, OSV Scanner and repository security workflows are source evidence only for the exact commit they checked out. Organization-required OpenCode/Noema/Strix/Security/SAST/merge-policy evidence is inherited from `ContextualWisdomLab/.github` and must not be copied into this repository. + +## Review and merge discipline + +- Refetch the exact PR head and the current protected `develop` tip before every source, docs, ref or PR-state mutation. +- Verify review findings against the current source. Fix valid findings test-first; resolve only addressed threads. +- A queued, skipped, cancelled, failed, neutral-required, missing, predecessor-head or stale-base check is not passing evidence. +- COMMENTED reviews, status checks and model text are not a qualifying formal approval. +- Never self-approve, manufacture approval, weaken rulesets, force-push, destructively rebase or move a branch to make stale evidence appear current. +- If a check or reviewer is waiting, rotate to another non-conflicting lane rather than churning a clean head. +- Compare moved/old branches against protected `develop` for unintended deletion or weakening of already-shipped authentication, session revocation, attachment/Clearfolio boundaries, coverage contracts, persistence and operability behavior. + +## Security and privacy + +- Treat every external provider response, imported document, persisted identifier and review body as untrusted data. +- Bound network time, redirects, response bytes, parsing and concurrency at the owning adapter boundary. +- Keep secrets out of browser responses, logs, metrics labels and model context. +- PII required for legitimate work is protected with purpose-bound authorization, least privilege, tenant/context isolation, encryption, retention and auditable access rather than indiscriminate masking. +- A failing security gate is a real blocker until evidence proves a false positive; never disable or weaken a gate to merge. +- Design for CSAP/SOC 2 evidence readiness without claiming certification. + +## LLM and automation + +- Model-backed development/tests use `NVIDIA_NIM_API_KEY`, preferably through contextual-orchestrator/OpenCode. Do not introduce `COPILOT_GITHUB_TOKEN` for development-model execution and do not disturb independent reviewer credentials. +- Model output is untrusted proposal data. Deterministic authorization, security, merge and release gates remain independent of model judgment. +- Initialize/sync CodeGraph or code-review-graph when available before structural edits; use exact text search as a companion, not a substitute for source verification. + +## Documentation authority + +Keep `README.md`, `ARCHITECTURE.md`, `CLAUDE.md`, product/technical requirements, ADRs, security/threat model, test strategy, operability/recovery, traceability and `CHANGELOG.md` aligned with protected code. Clearly label active-PR, planned, research-only and superseded behavior. Documentation is product memory, not proof that implementation exists. + +## Release discipline + +Version/tag/publish only from one exact integrated protected head after all applicable CI, security, coverage/docstrings, package/build, SBOM/provenance, compatibility, review, migration/rollback/recovery, accessibility and operational acceptance gates pass together. \ No newline at end of file From cd42985a3fa5b8adacdbb1bb278be20563e51682 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 15:34:11 +0900 Subject: [PATCH 2/9] docs: describe protected dual-mode architecture --- ARCHITECTURE.md | 167 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 45 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3006c74b..6ae90bae 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,45 +1,122 @@ -# ARCHITECTURE.md - -## Runtime structure - -- `index.html`: app shell and modal structure. -- `styles.css`: responsive layout, table, badges, gantt, and modal - presentation. -- `app.js`: state, rendering, editing, validation, persistence, - import/export, and Gantt logic. -- `analytics.js`: EVM, S-curve, CPM, workload, cost, and requirements/RFI/RFP - WBS-estimation readiness analysis. -- `wbs.json`: seed data in the user-specified JSON array format. - -## CI and security structure - -- `.github/workflows/pages.yml`: GitHub Pages deployment workflow for the - static app. -- OpenCode Review, Strix Security Scan, and PR Review Merge Scheduler: - organization-level required workflows from `ContextualWisdomLab/.github`. -- `.github/workflows/dependency-review.yml`: authoritative manifest-diff - review workflow for repository dependency changes. -- `.github/workflows/osvscanner.yml`: authoritative OSV/SARIF workflow - for dependency scanning. -- `tests/e2e/scopeweave.spec.js`: Playwright coverage for the user-facing - app flows. -- `tests/config/`: repository governance and workflow ownership checks. - -## Core decisions - -- One global `tasks` array holds canonical task records. -- `renderAll()` owns all UI updates. -- Browser persistence uses `localStorage` for guaranteed autosave and - optional File System Access API sync for `wbs.json` where supported. -- Static hosting treats repository `wbs.json` as seed data; - export/manual save remains the portability path. -- Imported flat JSON may synthesize hierarchy wrapper nodes internally, - but external `wbs.json` sync strips synthetic rows so the saved array - stays in the requested user schema. -- Same-level drag-and-drop moves the whole subtree block, not a single - row, to preserve tree-table integrity. -- Central Strix scans the repository surface without implying Kubernetes - deployment ownership or blocking on absent IaC that this repo does not - contain. -- Kubernetes/IaC security coverage remains a follow-up design lane for - any future `infra/` or container packaging surface. +# ScopeWeave Architecture + +This document describes the architecture **implemented on protected `develop`**. Open pull requests and issue designs are not shipped truth until they integrate through the repository rulesets. + +## 1. Product contexts + +ScopeWeave deliberately supports two deployment profiles over one planning model. + +### Standalone planner + +The standalone profile requires only a browser and static files. It keeps the original WBS workflow usable from GitHub Pages or any static host. + +- `index.html` — application shell and modal structure. +- `styles.css` — responsive layout and presentation. +- `app.js` — canonical in-browser task state, rendering, editing, validation, persistence, import/export and Gantt integration. +- `analytics.js` — deterministic schedule analytics including EVM/S-curve, CPM, workload, cost and PM-readiness analysis. +- `cloud-sync.js` — optional cloud adapter; when cloud is not active the standalone planner remains usable. +- `wbs.json` — seed/portable data, not server persistence. + +The global `tasks` array is the client-side work-item source of truth and `renderAll()` remains the user-visible rerender integration path. `app.js` stays eval-safe and optional modules use explicit `window.ScopeWeave*` bridges rather than top-level imports. + +### Cloud/SaaS overlay + +Protected `develop` also contains a Node cloud runtime under `server/`. + +- `server/server.mjs` — `@hono/node-server` process entry and static/API serving boundary. +- `server/app.mjs` — Hono API composition: authentication, organizations/projects, tenancy/RBAC, collaboration, billing, baselines/revisions, comments, attachments, webhooks, search, metrics and related orchestration. +- `server/auth.mjs` — password/JWT/PAT security primitives and session checks. +- `server/db.mjs` — current `node:sqlite` persistence and schema bootstrap. +- `server/billing.mjs` — plan/entitlement and Stripe-facing integration logic. +- `server/clearfolio.mjs` — replaceable document-conversion adapter. +- `server/attachment_status.mjs` — bounded attachment-status refresh logic. +- `server/orchestrator.mjs` — contextual-orchestrator client; on the protected base it still contains a deterministic fallback when no endpoint is configured. The active hardening PR must not be described as shipped before integration. + +The cloud profile is additive: a change that improves SaaS behavior may not make the standalone planner require the server, a database, credentials, or a model. + +## 2. Runtime and trust boundaries + +```mermaid +flowchart LR + U[Browser user] --> C[Static client] + C --> L[(localStorage / optional wbs.json)] + C -. authenticated cloud mode .-> A[Hono API] + A --> D[(SQLite on protected develop)] + A --> O[OIDC / identity provider] + A --> S[Stripe boundary] + A --> F[Clearfolio adapter] + A --> R[contextual-orchestrator adapter] + + subgraph ScopeWeave authority + C + A + D + end + + subgraph Replaceable external authorities + O + S + F + R + end +``` + +ScopeWeave validates and authorizes requests before crossing an integration boundary. External responses are untrusted input. Provider implementation details remain owned by the provider repository/service; ScopeWeave owns only the versioned adapter and failure contract it consumes. + +## 3. Persistence model + +### Standalone + +Browser mutations autosave to `localStorage`. Optional File System Access API support can synchronize a user-selected `wbs.json`. Imported flat records may create synthetic hierarchy wrappers internally; externally synchronized JSON strips those synthetic rows so the portable contract stays user-facing. + +### Cloud + +The protected cloud runtime persists tenant/application state in SQLite. Server-side authorization determines which organization/project data may be read or changed; optimistic version checks protect concurrent project saves and revision history supports recovery. + +SQLite is the **current implementation**, not a promise that production must always use SQLite. The database migration and PostgreSQL-adapter work is tracked separately. New owned relational objects use descriptive two-or-more-word `snake_case` names and new schema work must preserve 3NF unless an accepted ADR documents a measured exception. + +## 4. Security model + +Important shipped boundaries include: + +- scrypt password handling, pinned JWT verification and hashed personal-access-token handling; +- server-side organization/project authorization rather than browser-supplied tenancy authority; +- database-backed session-revocation checks across supported JWT transports; +- bounded attachment status refresh with request/concurrency budgets and sanitized failure categories; +- Clearfolio tenant HMAC and response/status validation already present on protected `develop`. + +Open hardening work is not silently promoted to this list. In particular, the current protected orchestrator and Clearfolio behavior must be evaluated against the exact protected source rather than an open PR description. + +PII needed for legitimate planning/collaboration workflows is governed by purpose-bound authorization, least privilege, tenant isolation, retention and audit controls; the architecture does not assume blanket masking is operationally viable. + +## 5. Deployment surfaces + +- GitHub Pages / any static host: standalone client. +- `Dockerfile`: static nginx image used by the static deployment surface. +- `Dockerfile.server`: Node cloud runtime. +- `docker-compose.yml`: self-hosted cloud composition. +- `infra/`: infrastructure manifests where present; security scanners must evaluate the actual deployed surface rather than inventing a deployment topology. + +Deployment documentation is in `docs/deploy.md`. A document that describes a target architecture must label it as target/planned and must not overwrite the as-built truth above. + +## 6. CI, review and release authority + +Repository-native workflows provide ScopeWeave-specific execution evidence such as Server Tests, Fuzz, Dependency Review, OSV scanning, SAST/security lanes and Pages deployment. Organization-required OpenCode, Noema, Strix, Security/SAST and merge-policy workflows are inherited from `ContextualWisdomLab/.github`; they are not copied into this repository. + +Evidence is commit-specific. A predecessor-head result, skipped/neutral required check, status-only signal or model comment cannot be substituted for the exact-head gate required by live rulesets. Protected `develop` requires a qualifying independent approval and resolved review threads in addition to required checks. + +A release may be cut only from an integrated protected revision after applicable CI, security, coverage/docstrings, packaging/SBOM/provenance, compatibility, migration/rollback/recovery, accessibility and operational acceptance evidence agree on that revision. + +## 7. Current architectural gaps + +The following are intentionally tracked as gaps rather than implied shipped capabilities: + +- scoped ephemeral access grants replacing broad session JWT query transport; +- zero-downtime canonical database-object naming and PostgreSQL adapter parity; +- cleanup of orphaned GitHub Actions registry identities through an authorized operator surface; +- monotonic, auditable Stripe subscription lifecycle; +- fail-closed production-grade Clearfolio transport/artifact/readiness policy; +- hardened contextual-orchestrator production boundary and cost attribution; +- decision-ready schedule intelligence and Waterfall/Agile/Hybrid projections. + +The live issues and PRs are the work queue for these gaps. This document remains the as-built architectural baseline until those changes reach protected `develop`. \ No newline at end of file From 9e307e559e8daa4aa0309b2e9aa62d301b452d91 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 15 Aug 2026 15:34:53 +0900 Subject: [PATCH 3/9] docs: replace historical SaaS merge map with shipped truth --- README.md | 282 +++++++++++++++++++++--------------------------------- 1 file changed, 109 insertions(+), 173 deletions(-) diff --git a/README.md b/README.md index ea8bb77a..2249fa01 100644 --- a/README.md +++ b/README.md @@ -1,200 +1,136 @@ # ScopeWeave -Schedule-control (공정관리) tool: a WBS planner with cumulative progress, EVM -(SPI·SV) + S-curve, CPM critical path, and a weekly Gantt overlay — usable in -two modes: - -- **Standalone (static)** — the original zero-dependency HTML/CSS/JS planner. - Works from any static host; data stays in `localStorage`/`wbs.json`. -- **Cloud (SaaS)** — an opt-in Node backend adds accounts + SSO, multi-tenant - workspaces, real-time collaboration, team roles, billing, baselines/history, - webhooks, and a public API. The static client is the frontend; cloud features - layer on without breaking standalone mode. - -> The SaaS pivot lands as a stacked PR train (see **Merge order** below). On -> `develop` as of this branch, only standalone mode exists. - -## Standalone features - -- Pure static runtime: HTML, CSS, JavaScript only -- 3-level WBS hierarchy (`단계 > Activity > Task`) with expand/collapse -- Inline add/edit/delete, row-click edit, and same-level drag-and-drop - subtree reorder -- Automatic day, weight, planned progress, actual progress, and weighted - progress calculations -- CSV import/export using the screen column contract -- Local autosave with optional File System Access API sync to `wbs.json` -- Weekly Gantt modal with planned (`#333333`) and actual (`#34cb03`) overlays -- Responsive column reduction for screens under 800px - -## Cloud (SaaS) features - -- **Auth**: email/password (scrypt) + JWT (7d, revocable via logout-everywhere), - SSO (OIDC + PKCE, built-in mock IdP for dev), personal access tokens (`swk_`, - hash-stored) -- **Multi-tenancy**: workspaces (orgs) with owner/admin/member/viewer roles — - enforced server-side; invites (revocable), member removal, leave, rename, - ownership transfer -- **Collaboration**: SSE live sync, optimistic concurrency (409 on stale - version), task comments -- **Schedule control**: EVM (SPI·SV) + S-curve, CPM critical path with slack, - predecessors, baselines (freeze/compare — slip table), revision history + - restore -- **PM analysis**: deterministic requirements/RFI/RFP readiness, WBS estimation - coverage, inter-event dependency risk, and procurement package section checks - from the existing WBS fields -- **Billing**: Free (2 projects / 3 members) vs Pro ₩19,000/mo — server-enforced - 402 caps; Stripe when configured, mock otherwise -- **Platform**: signed webhooks (HMAC-SHA256, retry + delivery log, secret - rotation), audit log, workspace export (JSON), cross-project search, - project duplicate (templates), rate limiting (opt-in), metrics - (JSON + Prometheus), structured logs -- **Docs**: complete API reference at [`docs/api.md`](docs/api.md) (served at - `/docs/api.md`); deploy guide at [`docs/deploy.md`](docs/deploy.md) +ScopeWeave is a schedule-control (공정관리) WBS planner with two independently usable profiles over the same planning model: + +- **Standalone** — static HTML/CSS/JavaScript, local-first persistence, no server required, deployable to GitHub Pages or any static host. +- **Cloud/SaaS** — the same client with a Node/Hono backend for accounts, multi-tenant workspaces, collaboration, schedule-control history, integrations and a public API. + +Both profiles are present on protected `develop`. Standalone compatibility is a product invariant: cloud work must not make local planning depend on a server, database, credential or model. + +## What is implemented on protected `develop` + +### Planning and analysis + +- three-level WBS hierarchy (`단계 > Activity > Task`) with expand/collapse; +- inline create/edit/delete and same-level subtree drag/reorder; +- planned/actual/weighted progress; +- CSV/JSON portability and optional File System Access API sync; +- weekly Gantt overlay; +- deterministic EVM/S-curve, CPM, workload, cost and PM-readiness analysis; +- responsive browser UI and Playwright regression coverage. + +### Cloud/SaaS + +- email/password authentication, JWT/PAT security and database-backed session revocation; +- organization/project tenancy and server-side RBAC; +- optimistic project versioning, revisions, baselines, comments and SSE collaboration; +- billing/entitlement, webhooks, audit/export/search and observability surfaces; +- attachment conversion/status integration through a replaceable Clearfolio adapter; +- contextual-orchestrator client integration; +- Node/SQLite self-host profile and container deployment surfaces. + +Open PRs may harden or extend these capabilities. Their behavior is **not** shipped truth until the change reaches protected `develop`. In particular, do not infer production readiness from an open Clearfolio/orchestrator PR, a PR description or a development mock. ## Architecture -``` -index.html + app.js + styles.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) +```text +index.html + styles.css + app.js static planner / canonical browser state + ├─ analytics.js deterministic schedule analytics + └─ cloud-sync.js optional authenticated cloud overlay + server/ - ├─ server.mjs ← @hono/node-server entry (PORT, default 8787) - ├─ app.mjs ← Hono routes: auth/SSO, projects, teams, billing, - │ webhooks, baselines, revisions, comments, search… - ├─ auth.mjs ← scrypt + pinned-HS256 JWT + PAT hashing (node:crypto) - ├─ billing.mjs ← plans/caps; Stripe via dynamic import - └─ db.mjs ← node:sqlite schema (Postgres-portable) + ├─ server.mjs @hono/node-server entry + ├─ app.mjs HTTP/API composition and authorization + ├─ auth.mjs password/JWT/PAT security + ├─ db.mjs current node:sqlite persistence + ├─ billing.mjs plan/billing boundary + ├─ clearfolio.mjs replaceable document adapter + ├─ attachment_status.mjs bounded attachment refresh engine + └─ orchestrator.mjs contextual-orchestrator adapter ``` -Only two runtime dependencies (`hono`, `@hono/node-server`); everything else is -Node built-ins. `node:sqlite` is for dev/self-host — swap the driver for managed -Postgres in production. +See [`ARCHITECTURE.md`](ARCHITECTURE.md) for the as-built authority and trust boundaries. `CLAUDE.md` contains detailed development commands; `AGENTS.md` is the canonical agent/governance guide. + +## Runtime contract + +The standalone client has no runtime package dependency. The cloud process uses only the production dependencies declared in `package.json` (currently Hono and `@hono/node-server`) plus Node built-ins. New production dependencies require a bounded product/security justification and may not break standalone operation. + +`node:sqlite` is the persistence implementation on protected `develop`. PostgreSQL is a migration target and must not be described as shipped until an adapter, migration and recovery evidence integrate. ## Local development Standalone: ```bash -python3 -m http.server 4173 # open http://127.0.0.1:4173 +python3 -m http.server 4173 +# open http://127.0.0.1:4173 ``` -Cloud (Node 22.13+ or 23.4+): +Cloud: ```bash -npm install -# Persist this across restarts (do not re-mint every boot — that invalidates JWTs). -export SCOPEWEAVE_JWT_SECRET="${SCOPEWEAVE_JWT_SECRET:-$(openssl rand -base64 32)}" -npm run server # serves the API + the static client on :8787 +npm ci +export SCOPEWEAVE_JWT_SECRET="$(openssl rand -base64 32)" +npm run server +# API + static client on http://127.0.0.1:8787 ``` -Docker: set a **persistent** `SCOPEWEAVE_JWT_SECRET` first, then run `docker compose up` -(see `Dockerfile.server` / `docs/deploy.md`). - -### Environment - -| Var | Purpose | -| --- | --- | -| `SCOPEWEAVE_JWT_SECRET` | **Required** — JWT signing secret (at least 32 non-whitespace characters; startup fails closed otherwise) | -| `SCOPEWEAVE_DB` | SQLite path (default `data.db`; `:memory:` for tests) | -| `PORT` | API port (default 8787) | -| `OIDC_ISSUER/CLIENT_ID/CLIENT_SECRET/REDIRECT_URI` | Real SSO IdP (mock when unset) | -| `STRIPE_SECRET_KEY` | Real checkout (mock URL when unset) | -| `SCOPEWEAVE_RATE_LIMIT_MAX` (+`_WINDOW_MS`) | Opt-in per-IP rate limiting | -| `SCOPEWEAVE_DEV=1` | Dev-only endpoints (activate-pro) | +Persist the JWT signing secret across restarts in real environments; regenerating it invalidates existing sessions. Deployment configuration and optional integrations are documented in [`docs/deploy.md`](docs/deploy.md). ## Verification +Run the paths applicable to the change: + ```bash -npm run test:api # API smoke (auth, tenancy, RBAC, billing, webhooks, …) + rate limit -npm run test:unit # EVM/S-curve, CPM, baseline-compare (pure math) -npm run test:e2e # Playwright UI suite +npm run test:unit +npm run test:api +npm run test:coverage +npm run test:e2e +npm run test:e2e:cloud +npm run fuzz python3 -m pytest tests/config ``` -`app.js` must stay eval-safe (no top-level `import`/`export`) — the e2e harness -evaluates it with `new Function`. Optional modules bridge via `window.*` globals. - -## Merge order (SaaS PR stack) - -`#233` first — it fixes pre-existing infra misconfigs that fail the required -`trivy-fs` gate on **every** PR. Then the stack in order (each PR is based on -the previous; merging in order auto-retargets the next): - -| Order | PR | Slice | -| --- | --- | --- | -| 0 | #233 | fix(ci): trivy-fs misconfigs (Dockerfile HEALTHCHECK, k8s uid/gid + namespace) | -| 1 | #212 | multi-tenant backend foundation (auth·projects·SSE·isolation) | -| 2 | #214 | client wiring (login UI, cloud save, live sync) | -| 3 | #215 | EVM (SPI·SV) + S-curve | -| 4 | #216 | teams + RBAC | -| 5 | #217 | billing + plan gating | -| 6 | #218, #219 | CPM engine + UI | -| 7 | #220 | public API + PAT | -| 8 | #221 | predecessors (editor + CSV) | -| 9 | #222 | Dockerfile + compose | -| 10 | #223 | landing page | -| 11 | #224 | audit log | -| 12 | #225 | workspace export | -| 13 | #226 | onboarding (샘플로 시작) | -| 14 | #227 | observability (metrics + logs) | -| 15 | #228 | signed webhooks | -| 16 | #230 | English landing (i18n) | -| 17 | #231 | SSO (OIDC) | -| 18 | #232 | webhook retry + delivery log | -| 19 | #234 | lifecycle (delete project / change pw / delete account) | -| 20 | #236 | baselines | -| 21 | #237 | rate limiting | -| 22 | #238 | create workspaces | -| 23 | #239 | baseline-vs-actual comparison UI | -| 24 | #240 | project duplicate | -| 25 | #241 | Prometheus metrics | -| 26 | #242 | webhook secret rotation | -| 27 | #243 | invite revocation | -| 28 | #244 | leave + rename workspace | -| 29 | #245 | complete API docs | -| 30 | #246 | ownership transfer | -| 31 | #247 | cross-project search | -| 32 | #248 | logout everywhere | -| 33 | #249 | revision history + restore | -| 34 | #250 | task comments | -| 35 | #251 | SEO (OG cards, hreflang, robots, sitemap) | -| 36 | (this PR) | README: architecture + merge map | - -## Repository contract - -- The static client stays static-host compatible for GitHub Pages - (standalone mode is preserved). -- Runtime dependencies are minimized (`hono`, `@hono/node-server` only, added - by the SaaS stack); CI/dev-only automation under `.github/`, `scripts/`, - `tests/`, and `docs/` is allowed. -- OpenCode Review, Strix Security Scan, and PR Review Merge Scheduler are - inherited from the organization-level required workflows in - `ContextualWisdomLab/.github`, not copied into this repository. - -## Persistence model - -- Standalone: every mutation autosaves to `localStorage`; `wbs.json` seeds - static hosting; File System Access API can sync a writable `wbs.json`. -- Cloud: projects live server-side with versioned saves (last 20 revisions), - SSE fan-out to collaborators, and offline fallback to the standalone model. -- Synthetic hierarchy wrapper rows generated from imported flat records are - excluded from external `wbs.json` sync so the saved JSON remains in the - user-facing schema. -- Requirements/RFI/RFP and WBS-estimation analysis is computed locally from the - single `tasks` array. It is a readiness signal over evidence already present - in the plan, not an external estimator or LLM judgment. - -## Security workflow - -- Organization required workflows provide OpenCode Review, Strix Security - Scan, PR Review Merge Scheduler, failed-check explanation, and coverage - evidence. -- Repository-local workflows remain for ScopeWeave-specific static delivery - and companion SCA lanes, including dependency review, OSV, Trivy, - Scorecard, and Pages. -- Server hardening: pinned-HS256 JWT (no header-alg trust), scrypt passwords, - hash-only PAT/webhook-secret storage (secrets shown once), server-side RBAC, - secrets never logged. - -See `docs/user-guide.md` for operator guidance and `docs/api.md` for the API. +`app.js` must remain eval-safe: no top-level `import` or `export`. Optional browser modules bridge through explicit `window.ScopeWeave*` interfaces. + +## Persistence and data ownership + +- Standalone mutations autosave to `localStorage`; `wbs.json` remains the seed/portable format and can be synchronized through the File System Access API where supported. +- Synthetic hierarchy wrappers used internally for imported flat data are removed from external JSON synchronization. +- Cloud state is server-owned and tenant-authorized. Browser metadata does not become tenancy authority. +- New database objects use descriptive two-or-more-word `snake_case` names and new schema work follows 3NF by default. +- Cross-service application databases are not shared: ScopeWeave talks to external CWL services through explicit adapter/API boundaries. + +## Security and review + +- Organization-required OpenCode, Noema, Strix, Security/SAST and merge-policy workflows come from `ContextualWisdomLab/.github`; do not copy those workflows into this repository. +- Repository-native Server Tests, Fuzz, Dependency Review, OSV and related workflows provide ScopeWeave-specific evidence. +- Required evidence is exact-commit evidence. Pending, skipped, cancelled, failed, missing, predecessor-head or stale-base results do not count as passing. +- Protected `develop` requires current-head checks, resolved review threads and a qualifying independent approval under the live rulesets. Do not self-approve or weaken protection. +- Secrets, provider payloads and sensitive identifiers must not leak through browser errors, logs, metrics labels or model context. + +## Current development priorities + +The live GitHub PR/issue queue is the authoritative development plan. Current commercial gaps include: + +- replacing broad session-JWT query transport with scoped ephemeral access grants; +- completing zero-downtime canonical database-object naming and PostgreSQL parity; +- disabling orphaned GitHub Actions registry identities through an authorized operator path; +- hardening Stripe lifecycle and entitlement reconciliation; +- completing fail-closed Clearfolio production transport/artifact/readiness policy; +- completing contextual-orchestrator production hardening and cost attribution; +- decision-ready schedule intelligence and Waterfall/Agile/Hybrid projections. + +Do not maintain a hard-coded historical PR merge table in this README. Always read the live PR base/head relationships and current protected branch before deciding integration order. + +## Documentation + +- [User guide](docs/user-guide.md) +- [API reference](docs/api.md) +- [Deployment guide](docs/deploy.md) +- [Security notes](docs/security.md) +- [Architecture authority](ARCHITECTURE.md) +- [Agent rules](AGENTS.md) +- [Change log](CHANGELOG.md) + +Customer-facing explanations should state what is available now, what action the customer/operator can take next, and what remains gated rather than presenting active-PR or planned behavior as already delivered. \ No newline at end of file From 0c5f28b98b20b39a1e8e17433ef6d615f3e6a905 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 18 Aug 2026 07:58:56 +0900 Subject: [PATCH 4/9] fix(docs): preserve NIM-only credential contract --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index cf3851a8..87e140e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -63,7 +63,7 @@ python3 -m pytest tests/config ## LLM and automation -- Model-backed development/tests use `NVIDIA_NIM_API_KEY`, preferably through contextual-orchestrator/OpenCode. Do not introduce `COPILOT_GITHUB_TOKEN` for development-model execution and do not disturb independent reviewer credentials. +- Model-backed development/tests use `NVIDIA_NIM_API_KEY`, preferably through contextual-orchestrator/OpenCode. Keep development-model execution on the NVIDIA NIM credential path and preserve independent reviewer credentials. - ScopeWeave's repository-local `opencode.jsonc` is development configuration, not a replacement for the organization review workflow. It uses NVIDIA NIM only and reads the process-local `NVIDIA_API_KEY` binding; organization CI owns secret injection and maps the organization `NVIDIA_NIM_API_KEY` secret into that process binding. Do not add a repository-local OpenCode workflow or restore GitHub Models/COPILOT credentials to this configuration. - Model output is untrusted proposal data. Deterministic authorization, security, merge and release gates remain independent of model judgment. - Initialize/sync CodeGraph or code-review-graph when available before structural edits; use exact text search as a companion, not a substitute for source verification. From 9dc7d6fcc2aac21702117699f7acf622b4c29e42 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 12:53:20 -0700 Subject: [PATCH 5/9] test(docs): fail on stale merge-order guidance --- package.json | 4 +-- tests/unit/documentation-authority.test.mjs | 28 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/unit/documentation-authority.test.mjs diff --git a/package.json b/package.json index 8cefdc74..e30127eb 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coverage": "npm run test:coverage", "server": "node server/server.mjs", "test:api": "node tests/api/auth-secret.test.mjs && node tests/api/smoke.mjs && node tests/api/ratelimit.test.mjs && node tests/api/attachment-status.test.mjs && node tests/api/session-revocation.test.mjs && node tests/api/orchestrator-attribution.test.mjs", - "test:unit": "node tests/unit/opencode-config.test.mjs && node tests/unit/changelog-release-notes.test.mjs && node tests/unit/analytics.test.mjs && node tests/unit/cpm.test.mjs && node tests/unit/baseline-compare.test.mjs && node tests/unit/workload.test.mjs && node tests/unit/cost-evm.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && node tests/unit/dep-types.test.mjs && node tests/unit/weekly-report.test.mjs && node tests/unit/clearfolio.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/sprint-stats.test.mjs && node tests/unit/burndown.test.mjs && node tests/unit/pm-analysis.test.mjs && node tests/unit/cloud-sync-security.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/coverage-script-contract.test.mjs && node tests/unit/toast-accessibility.test.mjs", + "test:unit": "node tests/unit/opencode-config.test.mjs && node tests/unit/changelog-release-notes.test.mjs && node tests/unit/documentation-authority.test.mjs && node tests/unit/analytics.test.mjs && node tests/unit/cpm.test.mjs && node tests/unit/baseline-compare.test.mjs && node tests/unit/workload.test.mjs && node tests/unit/cost-evm.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && node tests/unit/dep-types.test.mjs && node tests/unit/weekly-report.test.mjs && node tests/unit/clearfolio.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/sprint-stats.test.mjs && node tests/unit/burndown.test.mjs && node tests/unit/pm-analysis.test.mjs && node tests/unit/cloud-sync-security.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/coverage-script-contract.test.mjs && node tests/unit/toast-accessibility.test.mjs", "test:coverage": "c8 --all --include=app.js --include=cloud-sync.js --include=scripts/ci/static_coverage_evidence.mjs --include=server/attachment_status.mjs --include=server/app.mjs --include=server/auth.mjs --include=server/clearfolio.mjs --include=server/orchestrator.mjs --reporter=json --reporter=json-summary npm run test:coverage:cases", "test:coverage:cases": "node tests/unit/coverage-script-contract.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && npm run test:api", "test:e2e": "playwright test", @@ -31,4 +31,4 @@ "c8": "12.0.0", "fast-check": "4.9.0" } -} +} \ No newline at end of file diff --git a/tests/unit/documentation-authority.test.mjs b/tests/unit/documentation-authority.test.mjs new file mode 100644 index 00000000..526e5f0a --- /dev/null +++ b/tests/unit/documentation-authority.test.mjs @@ -0,0 +1,28 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; + +const claudeGuide = readFileSync(new URL('../../CLAUDE.md', import.meta.url), 'utf8'); +const readme = readFileSync(new URL('../../README.md', import.meta.url), 'utf8'); + +assert.doesNotMatch( + readme, + /^##\s+Merge order\b/im, + 'README must not restore a hard-coded historical merge-order table', +); +assert.match( + readme, + /Always read the live PR base\/head relationships and current protected branch before deciding integration order\./, + 'README must direct integration decisions to live ancestry and protected-branch evidence', +); +assert.doesNotMatch( + claudeGuide, + /see\s+["“]?Merge order["”]?\s+in\s+`README\.md`/i, + 'CLAUDE.md must not point to the removed README Merge order section', +); +assert.match( + claudeGuide, + /Before retargeting or merging stacked work, refetch the live protected `develop` tip, each PR's exact base\/head ancestry, and current required evidence/, + 'CLAUDE.md must direct stacked-PR integration to fresh protected-head, ancestry, and evidence checks', +); + +console.log('✓ canonical merge-guidance documentation contract passed'); From a6df3bd7d6c47af6b061dfd25a7492afeb3fc48e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 12:55:58 -0700 Subject: [PATCH 6/9] fix(docs): use live ancestry for stacked PR guidance --- CLAUDE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 81c1a819..686af40a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -103,8 +103,7 @@ deploy guide is `docs/deploy.md`. ## Git and CI -- **Default branch is `develop`.** SaaS work lands as a stacked PR train — see - "Merge order" in `README.md` before retargeting or merging PRs. +- **Default branch is `develop`.** Before retargeting or merging stacked work, refetch the live protected `develop` tip, each PR's exact base/head ancestry, and current required evidence; do not rely on a hard-coded merge order. - Repo-local PR gates: `server-tests.yml` (unit + API + eval-safe check + cloud e2e), `fuzz.yml`, `codeql.yml`, `dependency-review.yml`. - OpenCode Review, Strix Security Scan, and PR Review Merge Scheduler are From 39c9834cd8cb7803716dcafe15a3467fcc12d754 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 13:02:32 -0700 Subject: [PATCH 7/9] test(docs): reject dangling canonical guidance --- tests/unit/documentation-authority.test.mjs | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/unit/documentation-authority.test.mjs b/tests/unit/documentation-authority.test.mjs index 526e5f0a..c21b2cdb 100644 --- a/tests/unit/documentation-authority.test.mjs +++ b/tests/unit/documentation-authority.test.mjs @@ -3,11 +3,12 @@ import { readFileSync } from 'node:fs'; const claudeGuide = readFileSync(new URL('../../CLAUDE.md', import.meta.url), 'utf8'); const readme = readFileSync(new URL('../../README.md', import.meta.url), 'utf8'); +const deployGuide = readFileSync(new URL('../../docs/deploy.md', import.meta.url), 'utf8'); assert.doesNotMatch( readme, - /^##\s+Merge order\b/im, - 'README must not restore a hard-coded historical merge-order table', + /^\s{0,3}#{1,6}\s+Merge order\b/im, + 'README must not restore a hard-coded historical merge-order section at any Markdown heading level', ); assert.match( readme, @@ -24,5 +25,20 @@ assert.match( /Before retargeting or merging stacked work, refetch the live protected `develop` tip, each PR's exact base\/head ancestry, and current required evidence/, 'CLAUDE.md must direct stacked-PR integration to fresh protected-head, ancestry, and evidence checks', ); +assert.doesNotMatch( + claudeGuide, + /Environment variables[\s\S]{0,240}are tabled in `README\.md`/i, + 'CLAUDE.md must not point environment-variable guidance at the removed README table', +); +assert.match( + claudeGuide, + /Environment variables[\s\S]{0,240}(?:are documented in|see) `docs\/deploy\.md`/i, + 'CLAUDE.md must direct environment-variable guidance to the deployment guide', +); +assert.match( + deployGuide, + /^## Required \/ optional environment$/m, + 'deployment guide must retain the environment-variable destination referenced by CLAUDE.md', +); -console.log('✓ canonical merge-guidance documentation contract passed'); +console.log('✓ canonical documentation authority contract passed'); From abc9639ffd7a6bd835a0f8206854185722d60965 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 13:08:39 -0700 Subject: [PATCH 8/9] docs: point env guidance to deploy reference --- CLAUDE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 686af40a..52bf4deb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,8 +49,7 @@ docker compose up --build # Dockerfile.server → :8787 ``` Environment variables (`SCOPEWEAVE_JWT_SECRET`, `SCOPEWEAVE_DB`, `PORT`, OIDC/Stripe -config, rate limiting) are tabled in `README.md`; API reference is `docs/api.md`, -deploy guide is `docs/deploy.md`. +config, rate limiting) are documented in `docs/deploy.md`; API reference is `docs/api.md`. ## Architecture From a2f8963bca0149f00efadeb950c60ee5353c23f7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 01:55:05 +0900 Subject: [PATCH 9/9] docs: add Ask DeepWiki badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 86f279c8..59dab598 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ScopeWeave +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/ContextualWisdomLab/scopeweave) + ScopeWeave is a schedule-control (공정관리) WBS planner with two independently usable profiles over the same planning model: - **Standalone** — static HTML/CSS/JavaScript, local-first persistence, no server required, deployable to GitHub Pages or any static host.