Skip to content

feat: align live Figma, harden sharing, and establish architecture authority - #824

Draft
seonghobae wants to merge 12 commits into
mainfrom
codex/figma-live-alignment
Draft

seonghobae wants to merge 12 commits into
mainfrom
codex/figma-live-alignment

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 9, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

  • Aligned the workspace/editor, modal system, responsive behavior, tokens, Korean typography, and read-only /share/{id} viewer to the live Figma authority.
  • Hardened public sharing with successful-only reads, a fail-closed public-v1 field projection, generic errors, no paid public live-LLM path, no-store SPA delivery, configurable expiry, owner-only project-scoped revocation, and exact expiry display.
  • Added the canonical documentation graph: Architecture, PRD, TRD, API, UML, current/planned ERD, threat model, test strategy, operations/release plans, traceability/coverage matrices, research references, Forward Engineering support matrix, ADR-0001 through ADR-0006, and the external commercial-loop contract.
  • Separated implemented_on_main, active_pr, planned, research_only, downstream, deprecated, and out_of_scope evidence. Governed Forward Engineering remains planned; current export/diff/migration/apply paths are explicitly partial precursors.
  • Closed review/security gaps: CORS PUT/DELETE parity, fixed-hop trusted-proxy resolution for rate limiting/observability, bearer-auth schema-drift CI without SQL leakage, static-share cache controls, and the Strix-reported nanoid path pinned to 3.3.17.
  • Corrected the public-share llm-draft boundary, pinned package-facing Apache-2.0 evidence to protected main@8dc746920c12988f082e914879d95e13c9693535, and added docs/product-technical-gap-baseline.md with PRD/TRD/UML/ERD, Context Map, Gap/Action/Status, release, Pages, SBOM/provenance, and third-party notice boundaries.

Documentation sufficiency verdict

Before this update the repository was insufficient: it had no canonical Architecture/PRD/TRD/ADR graph/UML/ERD/threat/test/traceability authority set.

At exact head 2d743448f76c28e6c4f28baaab1e789adfb203cd the set is structurally sufficient for review, with machine-checked links, ADR inventory, lifecycle vocabulary, diagrams, requirement traceability, naming-debt inventory, planned integrity constraints, and explicit residual gaps. It is not evidence that planned Forward Engineering is implemented or that the PR is release-ready.

The hourly ChatGPT automation is enabled and externally authoritative for runtime scheduling. ADR-0006 and docs/automation-contract.md mirror its non-secret hourly review → fix → verify → PR/check → guarded merge → next-item / no-empty-queue-stop contract without claiming Git history proves execution.

Exact-head verification

  • RED test-only head 1b6da5ea3a4ff93fc622433dd112f29b9fb23203: public LLM boundary, mutable license link, and missing Gap baseline contracts all failed.
  • GREEN exact head 2d743448f76c28e6c4f28baaab1e789adfb203cd: the same three focused document contracts pass locally with warnings treated as errors.
  • Remote blobs: docs/index.md@1bb4c018cc1db71b104b7fe74208c08bf321b0ca, docs/product-technical-gap-baseline.md@76bf84ffccfb68b9e1dc9325fc17f4050dc1acbb, backend/tests/test_documentation_contract.py@4d4f58b14cacedfd78256ef92c9a3cdae01f680a, docs/README.md@a1a718f2778871b80143c97012985241ac9ed505.
  • Predecessor full-tree CI results are retained only as history and are not reused for this head.
  • Current-head CI 35478205660, Security 35478205729, SAST 35478205898, and CodeQL 35478205728 are queued.
  • The actionable docs/index.md review thread is resolved by the exact-head content; four information-only implementation threads remain open.
  • Fresh remote graph verification found 21/21 canonical authorities substantive, exact authority-index equality, and 0 broken relative links.

Evidence and remaining gates

  • Documentation authority: docs/README.md
  • Architecture: ARCHITECTURE.md
  • Coverage verdict: docs/documentation-coverage-matrix.md
  • Traceability: docs/traceability-matrix.md
  • Live Figma contract: docs/ui-ux/figma-contract.md
  • QA ledger: design-qa.md
  • Automation contract: docs/automation-contract.md

This remains a draft. Current-head hosted Checks and qualifying independent approval are still required. Queued state is incomplete evidence, and no predecessor validation is transferred. Same-viewport runtime/Figma browser signoff also remains unproven; no historical screenshot is presented as current evidence.


Open in Devin Review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae seonghobae changed the title feat: align Cloud ERD with live Figma and harden public sharing feat: align live Figma, harden sharing, and establish architecture authority Aug 9, 2026
@seonghobae

Copy link
Copy Markdown
Collaborator Author

@OpenCode review

Please review exact current head db59f97 after resolving both current-main conflicts. Snapshot polling now preserves project-epoch stale-response isolation and immediate sequential polling; full frontend tests 33 files/309 tests, typecheck, build, and npm audit pass. The nanoid override is 3.3.18 to clear the HIGH advisory. Re-evaluate this head only; do not transfer predecessor evidence. Current-head checks are queued.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Resolved the only current-main merge conflict at current head e34f69c by normal merge: retained the live-Figma font dependencies and adopted main's @xyflow/react 12.11.3 plus Node 26.7 image pins. Frontend typecheck and focused SharedDiagram/design-token/style-contract tests pass (59). Review/check this exact head.

@seonghobae
seonghobae marked this pull request as ready for review August 20, 2026 12:39
@seonghobae
seonghobae enabled auto-merge August 20, 2026 12:39

Copy link
Copy Markdown
Collaborator Author

Validation update for exact HEAD 4c1991d6031c2a995c7883585695141181f28392:

  • Revalidated Figma file csnpEEJfmqFWB0vNUoTkWA through live metadata on 2026-08-21: current top-level page is 0:1 Cover, with frame 8:2 Cover / pg-erd-cloud Design System. The previous 18-page / Screen Templates inventory is now explicitly dated historical evidence in docs/ui-ux/figma-contract.md and ADR-0001; the ADR retains the required Figma file ID.
  • Updated the documentation contract test to assert current live authority plus historical-node labeling.
  • Removed the unused relationship-inference local, made backend root imports reproducible via pythonpath = ["."], and made frontend Vitest deterministic with serial file execution and a 15-second test timeout.
  • Local proof on this tree: backend 436 passed; Ruff and mypy passed; frontend 309 passed; typecheck, production build, and npm audit --package-lock-only (0 vulnerabilities) passed; git diff --check and CodeGraph sync passed.

The required Actions are queued on this exact head (Security Scan, SAST Semgrep, and ci); Devin Review is pending and CodeRabbit is successful. No qualifying independent approval is present, so this PR remains unmerged pending exact-head checks and review gate completion.

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@opencode-agent opencode-agent Bot added area: auth Authentication, authorization, identity, or tenant isolation area: security Security boundary, hardening, or vulnerability prevention area: ui-ux Frontend, interaction, design, or user experience priority: medium Normal-priority or P2 work status: blocked Blocked by conflict, dependency, or required prerequisite type: feature New or expanded product capability labels Aug 22, 2026
@opencode-agent
opencode-agent Bot disabled auto-merge August 31, 2026 06:28

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 4 new potential issues.

Devin Review

Comment thread backend/app/api/share.py
Comment on lines +207 to +234
def _redact_sensitive_snapshot_fields(data: object) -> dict[str, object]:
"""Project snapshot JSON onto the path-scoped public DTO v1."""
if not isinstance(data, dict):
return {}

projected: dict[str, object] = {}
for key in _PUBLIC_SNAPSHOT_V1_ROOT_KEYS:
if key not in data:
continue
public_value = _project_public_value(data[key])
if public_value is not _DROP_PUBLIC_VALUE:
projected[key] = public_value

for collection, allowed_keys in _PUBLIC_SNAPSHOT_V1_ROW_KEYS.items():
rows = data.get(collection)
if not isinstance(rows, list):
continue
projected_rows = [
row
if collection == "schemas" and isinstance(row, str)
else _project_public_row(row, allowed_keys)
for row in rows
]
projected[collection] = [
row for row in projected_rows if row is not _DROP_PUBLIC_VALUE
]

return projected

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Public snapshot redaction switched from denylist to strict path-scoped allowlist

_redact_sensitive_snapshot_fields (share.py) was rewritten from a recursive denylist (replacing comment/example_value with *** while preserving all other structure) into a strict allowlist projection. Any root key not in _PUBLIC_SNAPSHOT_V1_ROOT_KEYS and any collection row key not in _PUBLIC_SNAPSHOT_V1_ROW_KEYS is now dropped entirely, and _project_public_value drops any nested object value. This is a fail-closed security improvement, but it is also a behavioral contract change: any legitimate snapshot field that is a dict (e.g. if source is actually an object rather than a scalar) will be silently omitted from the public JSON/exports. The public read-only viewer only relies on relations/columns/pk_columns/fk_edges/indexes, which are all allowlisted, so rendering is unaffected. Worth confirming the real snapshot shape for root keys like source/captured_at matches the scalar assumption so nothing needed by downstream public exports is unexpectedly dropped.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread backend/app/rate_limit.py
Comment on lines 51 to +61
if trust_x_forwarded_for:
xff = request.headers.get("X-Forwarded-For")
if xff:
# Use the right-most value (nearest trusted proxy), trimming whitespace.
# This is safer than the left-most which can be spoofed by the client.
ip = xff.split(",")[-1].strip()
if ip:
return ip
forwarded_hops = [part.strip() for part in xff.split(",") if part.strip()]
if trusted_proxy_hops >= 1 and len(forwarded_hops) >= trusted_proxy_hops:
return forwarded_hops[-trusted_proxy_hops]

client = request.client
if client is None:
ip = "unknown"
else:
ip = client.host or "unknown"
return "unknown"
return client.host or "unknown"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Rate-limit trusted-proxy-hop fallback aggregates callers under the Docker gateway

resolve_client_ip (rate_limit.py) returns X-Forwarded-For[-trusted_proxy_hops] only when the header contains at least the configured number of hops; otherwise it falls back to the direct peer (client.host). With the production config API_RATE_LIMIT_TRUSTED_PROXY_HOPS=2 and Traefik reached through Docker NAT, any request whose forwarded chain is shorter than 2 hops falls back to the shared bridge-gateway address, collapsing all such callers into one rate-limit bucket. This is the documented safe fallback, not a bug, but it means a misconfigured or non-conforming edge (e.g. a request that bypasses the terminator, or a terminator that does not append a second hop) silently degrades per-client isolation into a single shared bucket. Operators should run the two-address proxy-hop preflight described in the operations runbook before relying on it.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread frontend/src/types.ts
Comment on lines 33 to 38
export function toPlainText(value: unknown): PlainText | null {
if (typeof value !== 'string' || value.length === 0) return null

return value
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, ' ')
.replace(/[&<>"']/g, (char) => HTML_TEXT_ENTITIES[char])
.trim() as PlainText

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Removal of client-side HTML entity escaping relies on React text rendering

toPlainText (types.ts) and the various sanitizeHtml(...) call sites in App.tsx were removed so display strings (project names, snapshot status, error messages) are now rendered as raw text. Because React escapes text children by default this is not an XSS regression and actually fixes previously double-escaped display (e.g. &lt;Billing... shown literally). The residual risk would only be if any of these values are ever passed to dangerouslySetInnerHTML or concatenated into HTML/attributes elsewhere; a quick audit confirms these values flow only into JSX text nodes and value/textContent, so the change is safe. Noting it because it is a security-adjacent behavior change touching many call sites.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread frontend/src/App.tsx
Comment on lines +476 to +507
const pollSnapshot = async () => {
try {
const s = await getSnapshot(snapshotId as string);
if (!isCurrent) return;
setSnapshot(s);

if (s.status === "succeeded" || s.status === "failed" || s.status === "not_found") {
if (selectedProjectId) {
try {
const snaps = await listSnapshots(selectedProjectId);
if (isCurrent) setSnapshots(snaps);
} catch (e) {
if (isCurrent) setError(String(e));
}
}
const nextSnapshot = await getSnapshot(snapshotId);
if (!isCurrent || projectEpochRef.current !== projectEpoch) return;
setSnapshot(nextSnapshot);
if (TERMINAL_SNAPSHOT_STATUSES.has(nextSnapshot.status)) {
void loadProjectSnapshots(
selectedProjectId,
projectEpoch,
"스냅샷 목록을 새로고침하지 못했습니다. 잠시 후 다시 시도해 주세요.",
);
return;
}

if (isCurrent) {
timer = window.setTimeout(poll, 1000);
}
} catch (e) {
if (isCurrent) {
setError(String(e));
timer = window.setTimeout(poll, 1000);
}
} catch {
if (!isCurrent || projectEpochRef.current !== projectEpoch) return;
setError(
"스냅샷 상태를 확인하지 못했습니다. 잠시 후 다시 시도해 주세요.",
);
}
}

poll();
timer = window.setTimeout(() => {
void pollSnapshot();
}, 1000);
};

void pollSnapshot();

return () => {
isCurrent = false;
if (timer !== null) {
clearTimeout(timer);
}
if (timer !== null) window.clearTimeout(timer);
};
}, [selectedProjectId, snapshotId]);
}, [loadProjectSnapshots, selectedProjectId, snapshotId]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Snapshot polling reschedules on error but stops on terminal/stale states

The rewritten poll loop in App.tsx schedules the next 1s tick after the try/catch when the request either succeeds with a non-terminal status or fails with a still-current error, and returns early (no reschedule) on terminal statuses or when the effect is stale (!isCurrent or projectEpochRef mismatch). This preserves the previous retry-on-error behavior while adding project-epoch guards so a late response after a project switch neither updates state nor keeps polling. The logic is correct, but it is subtle: the reschedule intentionally lives outside the try/catch, so any future early-return added inside the try must remember it also suppresses the next tick.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Collaborator Author

Repository-facing metadata coordination: this PR is the active README.md writer, so I extended its exact branch rather than creating a competing README lane. Commit 1c1de197101ad20bb355a1fd75a694ea44e509a8 adds exactly one badge near the title: [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/ContextualWisdomLab/pg-erd-cloud). No other README content was changed. Because this moved the PR head, predecessor-head checks/reviews are historical and must not be reused. The independent Pages-source lane is #1046 and touches only docs/index.md; neither source change is a claim that Pages is live.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Devin Review

Comment thread docs/index.md Resolved

Copy link
Copy Markdown
Collaborator Author

Current public-surface authority — 2026-09-02

The body’s prior exact-head/check snapshot is historical. Current canonical head is codex/figma-live-alignment@320e177ab314c2b7502530eecfab2b87f6de1a15 after folding the complete unique docs/index.md Pages source from superseded PR #1046. #1046 is closed without merge; its public landing is retained here.

All predecessor-head workflow/review evidence is non-transferable after this consolidation. Reacquire exact-head checks/reviews and current base/governance before integration. docs/index.md remains a Pages source candidate only, not evidence that Pages is live.

@seonghobae seonghobae added the enhancement New feature or request label Sep 7, 2026 — with ChatGPT Codex Connector

Copy link
Copy Markdown
Collaborator Author

Admission-state correction for exact head 320e177ab314c2b7502530eecfab2b87f6de1a15.

Finding: 5 review threads remain unresolved and no current APPROVED review exists.

This PR remains Open and is moved to Draft/Proposed. Commits, reviews, threads, and valid delta are preserved. Return it to Ready only after causal repair/non-force reconciliation and fresh exact-head evidence. No bypass, synthetic status/approval, manual rerun, Force Push, review dismissal, or Close is used.

@seonghobae
seonghobae marked this pull request as draft September 19, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: auth Authentication, authorization, identity, or tenant isolation area: security Security boundary, hardening, or vulnerability prevention area: ui-ux Frontend, interaction, design, or user experience enhancement New feature or request priority: medium Normal-priority or P2 work status: blocked Blocked by conflict, dependency, or required prerequisite type: feature New or expanded product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant