diff --git a/AGENTS.md b/AGENTS.md index d1613bb0..87e140e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,78 +1,77 @@ # 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. -- 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. -- 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. 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. + +## 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. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4688d27b..34c429ac 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,47 +1,124 @@ -# ARCHITECTURE.md - -## Runtime structure - -- `index.html`: app shell and modal structure. -- `styles.css`: responsive layout, table, badges, gantt, and modal - 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 - 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. +- `toast-state.css` — cloud-overlay toast presentation shipped with static deployment surfaces. +- `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 and provider-facing billing boundary; the open billing hardening stack is not shipped truth. +- `server/clearfolio.mjs` — replaceable document-conversion adapter; open production-configuration/provider-hardening work remains separate until integrated. +- `server/attachment_status.mjs` — bounded attachment-status refresh logic. +- `server/orchestrator.mjs` — contextual-orchestrator client. Protected `develop` fails closed when production provider configuration is absent or unsafe; deterministic briefing behavior is restricted to explicit `SCOPEWEAVE_DEV=1` development mode. Open cost-attribution/adaptive-orchestration PR behavior is not shipped truth. + +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. 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 preserves 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`; +- fail-closed contextual-orchestrator production configuration, bounded provider messages/responses, canonical provider-origin validation and development-only deterministic behavior. + +Open hardening work is not silently promoted to this list. Current protected Clearfolio and billing behavior must be evaluated against 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 evaluate the actual deployed surface rather than inventing a deployment topology. + +All static deployment surfaces must ship every asset referenced by the client, including `cloud-sync.js`, `analytics.js`, and `toast-state.css`. 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 and trusted Checkout/provider configuration; +- fail-closed production-grade Clearfolio transport/artifact/readiness policy; +- contextual-orchestrator business cost attribution and adaptive orchestration selection; +- 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`. diff --git a/CLAUDE.md b/CLAUDE.md index 81c1a819..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 @@ -103,8 +102,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 diff --git a/README.md b/README.md index 6340c1f4..59dab598 100644 --- a/README.md +++ b/README.md @@ -1,200 +1,138 @@ # 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) +[![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. +- **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; +- fail-closed contextual-orchestrator client integration in production, with deterministic behavior restricted to explicit development mode; +- 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, billing, access-grant, schedule-intelligence or orchestrator-attribution PR. ## Architecture -``` -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) +```text +index.html + styles.css + toast-state.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` 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, verified SQLite backup/recovery guidance when integrated, 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 Checkout and lifecycle/entitlement reconciliation; +- completing fail-closed Clearfolio production transport/artifact/readiness policy; +- adding contextual-orchestrator business cost attribution and adaptive orchestration selection; +- 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. 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..c21b2cdb --- /dev/null +++ b/tests/unit/documentation-authority.test.mjs @@ -0,0 +1,44 @@ +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'); +const deployGuide = readFileSync(new URL('../../docs/deploy.md', import.meta.url), 'utf8'); + +assert.doesNotMatch( + readme, + /^\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, + /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', +); +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 documentation authority contract passed');