Skip to content

Bootstrap: PostgreSQL cloud ERD MVP#6

Closed
seonghobae wants to merge 7 commits into
review-basefrom
main
Closed

Bootstrap: PostgreSQL cloud ERD MVP#6
seonghobae wants to merge 7 commits into
review-basefrom
main

Conversation

@seonghobae

Copy link
Copy Markdown
Collaborator

Summary

  • PostgreSQL 전문 클라우드 ERD 웹 앱(MVP): 리버스(pg_catalog) → 스냅샷(JSONB) 저장 → ERD 캔버스(React Flow) 렌더
  • 포워드: 스냅샷 기반 PostgreSQL DDL(export.sql) 생성
  • 공유/협업: 프로젝트 멤버십(권한) + 공유 링크(viewer)

Key features

  • Reverse engineering: schemas/tables/columns + PK/FK(컬럼 매핑 포함) + indexes
  • Index types: pg_am.amname + pg_get_indexdef()로 DB에 존재하는 access method(확장 포함) 손실 없이 보존
  • Forward export: GET /api/snapshots/{snapshot_uuid}/export.sql

Notes

  • Auth: OIDC-ready(issuer/audience 설정 시) + dev fallback(X-Dev-User)
  • Workflows: CodeQL / dependency review / scorecard / CI included (pinned SHAs)

Cast pg_catalog single-char codes to text and sanitize bytes/memoryview so introspection results can be stored in JSONB reliably.
Provide a basic forward-engineering path by exporting CREATE TABLE/constraints/indexes from stored snapshot JSON as PostgreSQL DDL.
Introduce OIDC-ready auth with a dev-user fallback, enforce project membership on APIs, add member invites and share links, and enrich ERD rendering with PK columns and FK column mappings.
Add nginx-served frontend build and a prod compose file that proxies /api to the backend, defaulting the frontend API base to same-origin.
Add pinned GitHub Actions for CI (typecheck/tests/build), CodeQL, dependency review, and OSSF Scorecard, plus Dependabot for action updates.
@coderabbitai

coderabbitai Bot commented Feb 1, 2026

Copy link
Copy Markdown
📝 Walkthrough

PostgreSQL 클라우드 ERD MVP 부트스트랩 - 프로덕션 기능 완성

핵심 기능 요약

이 PR은 PostgreSQL 데이터베이스 역공학을 통해 ERD(Entity Relationship Diagram)를 웹상에서 시각화하고 관리하는 클라우드 애플리케이션의 MVP(최소 생존 제품) 단계를 완성합니다.

1. 인증 및 접근 제어 시스템

  • OIDC 기반 인증: OpenID Connect 표준을 사용하여 엔터프라이즈급 인증 지원 (설정 가능한 발급자/청중)
  • 개발 모드 폴백: X-Dev-User 헤더를 통한 개발 환경용 간편 인증
  • 프로젝트 멤버십 검증: 모든 API 엔드포인트에 멤버십 확인 로직 추가로 권한 없는 접근 차단
  • 새로운 권한 검사 모듈 (permissions.py): 프로젝트별 사용자 역할 확인 기능

2. 공유 및 협업 기능

  • 공유 링크 생성: 프로젝트 소유자가 뷰어 전용 공유 링크 발급 가능
  • 임시 공유 지원: 만료 시간 설정 가능한 공유 링크 (보안성 강화)
  • 멤버 초대 시스템:
    • 프로젝트 소유자가 사용자 OIDC subject로 팀원 초대 가능
    • 자동 사용자 계정 생성 (없는 경우)
    • 역할 기반 접근 제어 (owner/viewer 등)
  • 멤버 관리 API: 프로젝트 멤버 조회 및 추가 엔드포인트

3. 순방향 엔지니어링 (DDL 내보내기)

  • SQL 스냅샷 내보내기: 저장된 데이터베이스 구조를 PostgreSQL CREATE TABLE 문으로 변환
  • 완전한 DDL 재구성:
    • 스키마 생성 문
    • 테이블 정의 (칼럼, 기본키, 제약조건)
    • 외래키 제약조건
    • 인덱스 정의 (원본 pg_get_indexdef() 결과 유지)
  • 공유 스냅샷 내보내기: 공유 링크를 통한 DDL 내보내기 지원

4. ERD 시각화 개선

  • 칼럼별 기본키 표시: 테이블 노드에서 각 칼럼의 PK 여부를 배지로 표시
  • 외래키 상세 매핑:
    • fk_edges 쿼리로 외래키 칼럼 간 정확한 매핑 정보 수집
    • 단일 칼럼 외래키: 자식칼럼 → 부모칼럼 형태로 표시
    • 다중 칼럼 외래키: 제약조건 이름과 칼럼 개수 표시

5. 데이터베이스 스키마 개선

  • 외래키 제약조건 추가:
    • 프로젝트-사용자, 프로젝트-멤버, 연결-프로젝트 등 모든 테이블 간 관계 명시
    • CASCADE 삭제로 데이터 일관성 보장
  • 공유 링크 테이블: 새로운 share_link 테이블로 공유 기능 지원
  • 마이그레이션 스크립트: Alembic을 통한 데이터베이스 버전 관리 (0002_auth_share)

6. 프로덕션 배포 설정

  • 프로덕션 Docker 구성 (compose.prod.yaml):
    • PostgreSQL 서비스 (자동 헬스체크, 지속 볼륨)
    • Python 백엔드 (자동 마이그레이션 실행)
    • Nginx 기반 프론트엔드 정적 호스팅
  • Nginx 리버스 프록시: /api/ 요청을 백엔드로 포워딩, SPA 지원
  • 프로덕션 Dockerfile: 멀티스테이지 빌드로 최적화된 이미지 생성

7. CI/CD 및 보안

  • GitHub Actions 워크플로우:
    • ci.yml: 백엔드 Python 타입체크/테스트, 프론트엔드 빌드
    • codeql.yml: JavaScript/Python 코드 분석
    • dependency-review.yml: 의존성 보안 검토
    • scorecard.yml: OSSF 보안 점수 평가
  • 의존성 자동 업데이트: Dependabot으로 GitHub Actions 자동 업데이트
  • 보안 강화: 모든 action SHA 고정으로 공급망 공격 방지

8. 기술적 개선사항

  • JSON 안전성: pg_catalog 출력의 특수 문자(바이너리 데이터 등) 안전하게 처리
  • 쿼리 최적화: PostgreSQL 인트로스펙션에서 인덱스 접근 메서드 동적 조회 (pg_am.amname)
  • 프론트엔드 API 통합:
    • getMe(): 현재 사용자 정보 조회
    • 개발/프로덕션 환경별 API 엔드포인트 자동 선택
    • 인증 헤더 일관성 유지

프로젝트 사용 흐름 (최종 사용자 관점)

  1. 사용자 가입/로그인: OIDC 또는 개발 모드 인증
  2. 프로젝트 생성: 새로운 ERD 프로젝트 생성 (본인이 소유자)
  3. 데이터베이스 연결: PostgreSQL 연결 정보 저장
  4. 자동 구조 분석: 데이터베이스에서 스키마/테이블/관계 자동 추출
  5. ERD 시각화: 웹에서 대화형 다이어그램 확인
  6. 팀 협업: 공유 링크 생성하여 팀원에게 읽기 전용 공유
  7. DDL 내보내기: 분석한 구조를 SQL 스크립트로 내보내기

CI/CD 및 배포 상태

현재 PR의 자동화 검사 일부가 실패 상태이나, Dependabot 및 의존성 검증은 통과했습니다. 주요 워크플로우(타입체크, 테스트, 빌드)가 설정되어 있어 지속적인 품질 관리가 가능한 상태입니다.

개요

이 PR은 OIDC 기반 인증 시스템, 프로젝트 멤버십 관리, 그리고 공유 가능한 스냅샷 링크 기능을 도입합니다. GitHub Actions CI/CD 워크플로우, 데이터베이스 마이그레이션, 백엔드 API 엔드포인트, 프론트엔드 통합이 추가되며, DDL 내보내기 및 외래 키 제약 조건이 구현됩니다.

주요 변경사항

Cohort / File(s) 요약
GitHub Actions 및 CI/CD 구성
.github/dependabot.yml, .github/workflows/ci.yml, .github/workflows/codeql.yml, .github/workflows/dependency-review.yml, .github/workflows/scorecard.yml
의존성 자동 업데이트 및 포괄적인 CI/CD 파이프라인 추가: 백엔드 Python 및 프론트엔드 Node.js 검사, CodeQL 보안 분석, OpenSSF Scorecard 평가.
인증 및 권한 관리
backend/app/auth.py, backend/app/permissions.py, backend/app/api/me.py
OIDC 토큰 검증, 사용자 지속성, 현재 사용자 추출을 위한 인증 시스템. 프로젝트 멤버십 확인 및 /api/me 엔드포인트 추가.
프로젝트 멤버십 및 초대
backend/app/api/projects.py, backend/app/models.py (ProjectMember FK 추가)
프로젝트 소유자 초대 흐름, 멤버 목록 조회, 데이터베이스 레벨 외래 키 제약 조건으로 데이터 무결성 강화.
공유 링크 및 스냅샷 접근
backend/app/api/share.py, backend/alembic/versions/0002_auth_share.py, backend/app/models.py (ShareLink 클래스)
공유 링크 생성, 스냅샷 조회, SQL 내보내기를 위한 독립적인 라우터. 새로운 share_link 테이블 및 외래 키 마이그레이션.
데이터베이스 스키마 및 외래 키
backend/app/models.py, backend/alembic/versions/0002_auth_share.py
모든 엔티티에 외래 키 제약 조건 추가: ProjectSpace, ProjectMember, DbConnection, SchemaSnapshot, SchemaSnapshotData. CASCADE 삭제 정책 포함.
DDL 내보내기 및 쿼리 강화
backend/app/ddl/export.py, backend/app/pg_introspect/queries.py, backend/app/pg_introspect/introspect.py
스냅샷 JSON을 PostgreSQL DDL로 변환. 기본 키 및 외래 키 엣지 쿼리 추가.
API 엔드포인트 인증 추가
backend/app/api/connections.py, backend/app/api/snapshots.py, backend/app/main.py
기존 엔드포인트에 현재 사용자 의존성 주입, 멤버십 확인, 새로운 /api/snapshots/{uuid}/export.sql 엔드포인트.
프로젝트 스키마 및 유틸리티
backend/app/schemas.py, backend/app/sanitize.py, backend/app/db.py
ProjectMemberAddIn, ProjectMemberOut, MeOut 스키마 추가. 바이트 문자열 처리 개선, psycopg v3 마이그레이션 URL 업데이트.
프론트엔드 인증 및 UI
frontend/src/App.tsx, frontend/src/api.ts
getMe() API 호출, devUser 상태 관리, 사용자 정보 UI 표시. API 헤더 표준화.
프론트엔드 ERD 및 스냅샷
frontend/src/erd/TableNode.tsx, frontend/src/erd/convert.ts
pk_columns 및 fk_edges 필드 추가, 테이블 노드에 칼럼별 기본 키 배지 렌더링.
프로덕션 Docker 및 배포
compose.prod.yaml, frontend/Dockerfile.prod, frontend/nginx.conf
다단계 프론트엔드 빌드, Nginx SPA 라우팅 및 API 프록시, 프로덕션급 Docker Compose 설정.
문서 및 구성
.gitignore, README.md, backend/pyproject.toml
opencode 아티팩트 gitignore 항목 추가. SQL 내보내기, 공유 워크플로우, 프로덕션 Docker 실행 문서화. setuptools 패키지 발견 업데이트.

시퀀스 다이어그램

sequenceDiagram
    participant Client
    participant Auth as FastAPI<br/>Auth Module
    participant OIDC as OIDC<br/>Provider
    participant DB as Database<br/>(User)
    participant API as FastAPI<br/>Endpoint

    Client->>Auth: GET /api/me<br/>(Authorization: Bearer {token})
    Auth->>Auth: Extract token from header
    Auth->>OIDC: Validate token signature<br/>(fetch JWKS)
    OIDC-->>Auth: JWKS & Claims
    Auth->>Auth: Verify signature & exp
    Auth->>DB: Query/Create UserAccount<br/>by oidc_subject
    DB-->>Auth: CurrentUser object
    Auth-->>API: Inject CurrentUser
    API-->>Client: { user_account_uuid,<br/>subject, display_name }
Loading
sequenceDiagram
    participant Owner as Project<br/>Owner
    participant API as Share<br/>API
    participant DB as Database
    participant Viewer as Share Link<br/>Viewer
    participant Share as Share Info<br/>API

    Owner->>API: POST /api/projects/{uuid}/share<br/>(authenticated)
    API->>API: Verify owner role
    API->>DB: Create ShareLink<br/>(permission=viewer, expires_at)
    DB-->>API: ShareLink UUID
    API-->>Owner: { share_link_uuid,<br/>permission_kind, url }

    Viewer->>Share: GET /api/share/{link_uuid}
    Share->>DB: Validate ShareLink<br/>(check expiry)
    DB-->>Share: Link valid & project_space_uuid
    Share->>DB: Fetch recent 20 snapshots
    DB-->>Share: Snapshot metadata
    Share-->>Viewer: { snapshots[],<br/>permission_kind }
Loading
sequenceDiagram
    participant Viewer as Viewer via<br/>Share Link
    participant Share as Share<br/>Snapshot API
    participant DB as Database
    participant Export as DDL<br/>Export Module
    participant Client as Browser

    Viewer->>Share: GET /api/share/{link_uuid}/<br/>snapshot/{snap_uuid}/export.sql
    Share->>DB: Validate ShareLink & expiry
    DB-->>Share: Valid (project_uuid matches)
    Share->>DB: Fetch snapshot data<br/>(relations, columns, constraints)
    DB-->>Share: Snapshot JSON
    Share->>Export: snapshot_json_to_sql()
    Export->>Export: Generate CREATE TABLE,<br/>FK constraints, indexes
    Export-->>Share: SQL text
    Share-->>Client: Content-Type: text/plain<br/>SQL DDL
Loading

예상 코드 리뷰 노력

🎯 4 (복잡함) | ⏱️ ~60분

설명: 이 PR은 인증, 권한 관리, 공유 기능에 걸친 광범위한 기능 추가입니다. 데이터베이스 마이그레이션(외래 키 제약), 새로운 모델/스키마, API 엔드포인트, 프론트엔드 통합이 이질적으로 분산되어 있습니다. 각 섹션은 고유한 논리를 요구하며, 보안-관련 OIDC 검증, 권한 확인, SQL 생성 로직이 포함됩니다. 마이그레이션 순서, 외래 키 제약 무결성, 토큰 검증 흐름을 세심하게 검토해야 합니다.

관련 PR

시인

🔐 인증의 문을 열고
🤝 공유의 손을 맞잡으며
🗝️ 안전한 링크로 길을 닦네
📊 스키마는 외래 키로 든든하고
🚀 프로덕션은 Compose로 품에 안긴다.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore
❌ Failed checks (3 errors, 1 warning)
Check name Status Explanation Resolution
Title check ❌ Error 제목은 영문으로 작성되었으나, 요구사항에서 '제목만 봐도 이해하기 쉬운 한국어여야 합니다'라고 명시되어 있습니다. 제목을 한국어로 변경하세요. 예: '부트스트랩: PostgreSQL 클라우드 ERD MVP' 또는 '초기구축: PostgreSQL 클라우드 ERD MVP'
Docstring Coverage ❌ Error Docstring coverage is 4.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Sast ❌ Error SAST 분석 결과 OIDC Subject 검증 부재(CRITICAL)와 Race Condition(HIGH) 2개의 심각한 보안 위협이 확정되었습니다. member invitation 로직을 변경하여 OIDC 인증 후 접근 가능하도록 수정 또는 초대 토큰 기반 플로우 도입, auth.py에 IntegrityError 예외 처리 추가.
Sbom ⚠️ Warning Docker 베이스 이미지(python:3.12-slim, node:20-alpine, nginx:1.27-alpine)가 다이제스트 없이 태그로만 지정되어 있어 공급망 공격 위험 존재. GitHub Actions는 commit SHA로 고정하나 Docker는 정책 불일치. 모든 Dockerfile의 베이스 이미지를 digest로 고정(예: python:3.12-slim@sha256:...). compose.prod.yaml의 DATABASE_URL에 비밀번호 검증 추가. Docker secrets 또는 _FILE 패턴 도입으로 평문 비밀번호 노출 제거.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명은 PostgreSQL 클라우드 ERD MVP의 주요 기능(역공학, 포워드 내보내기, 공유/협업, 인증)을 포괄적으로 설명하고 있으며 변경사항과 관련이 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch main

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

@seonghobae

Copy link
Copy Markdown
Collaborator Author

PR checks evidence

Required checks

gh pr checks --required --watch --fail-fast
no required checks reported on the 'main' branch

Merge state

gh pr view --json mergeStateStatus,mergeable
{"mergeStateStatus":"UNSTABLE","mergeable":"MERGEABLE"}

Rulesets / Branch policy

gh api "repos/seonghobae/pg-erd-cloud/rules/branches/review-base" || gh api "repos/seonghobae/pg-erd-cloud/branches/review-base/protection"
[]

Code scanning

gh api "/repos/seonghobae/pg-erd-cloud/code-scanning/analyses?pr=6"
gh api "/repos/seonghobae/pg-erd-cloud/code-scanning/alerts?pr=6&state=open"
{"message":"no analysis found","documentation_url":"https://docs.github.com/rest/code-scanning/code-scanning#list-code-scanning-analyses-for-a-repository","status":"404"}gh: no analysis found (HTTP 404)
gh: This API operation needs the "delete_repo" scope. To request it, run:  gh auth refresh -h github.com -s delete_repo
{"message":"no analysis found","documentation_url":"https://docs.github.com/rest/code-scanning/code-scanning#list-code-scanning-alerts-for-a-repository","status":"404"}gh: no analysis found (HTTP 404)
gh: This API operation needs the "delete_repo" scope. To request it, run:  gh auth refresh -h github.com -s delete_repo

Code quality / Check-runs

gh api "/repos/seonghobae/pg-erd-cloud/commits/4df21f2002282b2943cda7592c276af9ecc2fb75/check-runs"
{"total_count":12,"check_runs":[{"id":62106210817,"name":"Analyze (javascript-typescript)","node_id":"CR_kwDORF0XDs8AAAAOddGSAQ","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"3ab31b99-36ff-514c-8903-d1d4f48b232a","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210817","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630249/job/62106210817","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630249/job/62106210817","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:42:58Z","completed_at":"2026-02-01T00:43:00Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210817/annotations"},"check_suite":{"id":56026696283},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106210816,"name":"Analyze (python)","node_id":"CR_kwDORF0XDs8AAAAOddGSAA","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"87fcf550-5fa6-5d80-839d-f6af11bb61fa","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210816","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630249/job/62106210816","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630249/job/62106210816","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:42:58Z","completed_at":"2026-02-01T00:43:00Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210816/annotations"},"check_suite":{"id":56026696283},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106210811,"name":"frontend","node_id":"CR_kwDORF0XDs8AAAAOddGR-w","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"5586485e-2f72-5cc5-a7c0-4cb91c4a5a1b","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210811","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630251/job/62106210811","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630251/job/62106210811","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:42:58Z","completed_at":"2026-02-01T00:43:00Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210811/annotations"},"check_suite":{"id":56026696284},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106210810,"name":"dependency-review","node_id":"CR_kwDORF0XDs8AAAAOddGR-g","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"d0a7aa4c-279b-5c33-878c-990cdec93ead","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210810","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630278/job/62106210810","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630278/job/62106210810","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:42:58Z","completed_at":"2026-02-01T00:43:00Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210810/annotations"},"check_suite":{"id":56026696331},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106210800,"name":"backend","node_id":"CR_kwDORF0XDs8AAAAOddGR8A","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"9c79e03a-ac7a-52a1-8bbd-cc4b0e2691d9","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210800","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630251/job/62106210800","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553630251/job/62106210800","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:42:58Z","completed_at":"2026-02-01T00:43:00Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62106210800/annotations"},"check_suite":{"id":56026696284},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104927131,"name":"Dependabot","node_id":"CR_kwDORF0XDs8AAAAOdb37mw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"497a75f2-b782-5d44-a4f5-c1e402611743","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104927131","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553150127/job/62104927131","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553150127/job/62104927131","status":"completed","conclusion":"success","started_at":"2026-02-01T00:07:29Z","completed_at":"2026-02-01T00:08:36Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104927131/annotations"},"check_suite":{"id":56025402854},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925961,"name":"analysis","node_id":"CR_kwDORF0XDs8AAAAOdb33CQ","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"6fb9327d-1b44-567f-aa7c-759ca2c57903","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925961","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149765/job/62104925961","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149765/job/62104925961","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:07:25Z","completed_at":"2026-02-01T00:07:28Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925961/annotations"},"check_suite":{"id":56025402030},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925875,"name":"backend","node_id":"CR_kwDORF0XDs8AAAAOdb32sw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"1276e68d-4d3e-5e33-8151-c5d298914be5","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925875","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149768/job/62104925875","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149768/job/62104925875","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:07:25Z","completed_at":"2026-02-01T00:07:28Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925875/annotations"},"check_suite":{"id":56025402022},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925871,"name":"frontend","node_id":"CR_kwDORF0XDs8AAAAOdb32rw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"a0f3e367-8f36-5c2f-b108-0d5a7a53d879","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925871","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149768/job/62104925871","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149768/job/62104925871","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:07:25Z","completed_at":"2026-02-01T00:07:27Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925871/annotations"},"check_suite":{"id":56025402022},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925840,"name":"Analyze (python)","node_id":"CR_kwDORF0XDs8AAAAOdb32kA","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"98efd6ff-204a-5586-aba5-38a6c5a94f1c","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925840","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149763/job/62104925840","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149763/job/62104925840","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:07:25Z","completed_at":"2026-02-01T00:07:27Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925840/annotations"},"check_suite":{"id":56025402029},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925838,"name":"Analyze (javascript-typescript)","node_id":"CR_kwDORF0XDs8AAAAOdb32jg","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"b3ee62b7-0c56-5b34-861f-2561b583a95b","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925838","html_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149763/job/62104925838","details_url":"https://github.com/seonghobae/pg-erd-cloud/actions/runs/21553149763/job/62104925838","status":"completed","conclusion":"failure","started_at":"2026-02-01T00:07:25Z","completed_at":"2026-02-01T00:07:27Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925838/annotations"},"check_suite":{"id":56025402029},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925223,"name":".github/dependabot.yml","node_id":"CR_kwDORF0XDs8AAAAOdb30Jw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"","url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925223","html_url":"https://github.com/seonghobae/pg-erd-cloud/runs/62104925223","details_url":"https://dependabot-api.githubapp.com","status":"completed","conclusion":"success","started_at":"2026-02-01T00:07:24Z","completed_at":"2026-02-01T00:07:24Z","output":{"title":"Dependabot config file validation","summary":"All changes look good","text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/check-runs/62104925223/annotations"},"check_suite":{"id":56025401686},"app":{"id":29110,"client_id":"Iv1.4f9a6346434f815e","slug":"dependabot","node_id":"MDM6QXBwMjkxMTA=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"Dependabot","description":"GitHub Dependabot","external_url":"https://dependabot-api.githubapp.com","html_url":"https://github.com/apps/dependabot","created_at":"2019-04-16T22:34:25Z","updated_at":"2025-06-11T21:07:45Z","permissions":{"actions":"write","checks":"write","contents":"write","issues":"write","members":"read","metadata":"read","pull_requests":"write","statuses":"read","vulnerability_alerts":"read","workflows":"write"},"events":["check_suite","issues","issue_comment","label","pull_request","pull_request_review","pull_request_review_comment","repository"]},"pull_requests":[{"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/seonghobae/pg-erd-cloud","name":"pg-erd-cloud"}}}]}]}

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4df21f2002

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +20 to +28
def upgrade() -> None:
# Add FK constraints (MVP: best-effort for fresh DB)
op.create_foreign_key(
"fk_project_space__created_by_user",
"project_space",
"user_account",
["created_by_user_uuid"],
["user_account_uuid"],
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Backfill before adding FK on project_space.created_by_user_uuid

Adding the foreign key on project_space.created_by_user_uuid will fail during migration if there are any pre-existing projects whose created_by_user_uuid does not exist in user_account. The previous implementation created projects with a random UUID and never created a matching user_account, so any real deployment with existing data will hit a FK violation and the migration will abort. Consider backfilling user rows or relaxing/deferring the constraint before applying it.

Useful? React with 👍 / 👎.

Comment on lines +148 to +154
m = ProjectMember(
project_space_uuid=project_space_uuid,
user_account_uuid=u.user_account_uuid,
project_role=body.project_role,
created_at=dt.datetime.now(dt.timezone.utc),
)
session.add(m)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid 500 on duplicate project member invites

The endpoint inserts a project_member row unconditionally. Because (project_space_uuid, user_account_uuid) is the primary key, inviting a user who is already a member will raise an integrity error and surface as a 500. This is a common user flow (re-invite/role change), so it should be handled explicitly (e.g., check for existing membership and return 409 or update the role).

Useful? React with 👍 / 👎.

@github-advanced-security

Copy link
Copy Markdown

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

Comment thread .github/workflows/ci.yml
- name: Install backend deps
working-directory: backend
run: |
python -m pip install -U pip

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 4: pipCommand not pinned by hash
Click Remediation section below to solve this issue
Comment thread .github/workflows/ci.yml
working-directory: backend
run: |
python -m pip install -U pip
python -m pip install -e ".[dev]"

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 4: pipCommand not pinned by hash
Click Remediation section below to solve this issue
Comment thread frontend/Dockerfile.prod
@@ -0,0 +1,15 @@
FROM node:20-alpine AS build

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 4: containerImage not pinned by hash
Click Remediation section below to solve this issue
Comment thread frontend/Dockerfile.prod
COPY . /app
RUN npm run build

FROM nginx:1.27-alpine

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 4: containerImage not pinned by hash
Remediation tip: pin your Docker image by updating nginx:1.27-alpine to nginx:1.27-alpine@sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10
Click Remediation section below for further remediation help
@seonghobae

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Feb 1, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

PR checks evidence (post-transfer rerun)

Checks list

Analyze (javascript-typescript)	fail	1m33s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149763/job/62107198723	
Analyze (python)	fail	1m13s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149763/job/62107198715	
.github/dependabot.yml	pass	0	https://dependabot-api.githubapp.com	
Analyze (actions)	pass	48s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089265	
Analyze (javascript-typescript)	pass	1m16s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630249/job/62107016689	
Analyze (javascript-typescript)	pass	1m21s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089264	
Analyze (python)	pass	59s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630249/job/62107016691	
Analyze (python)	pass	1m4s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089274	
Scorecard	pass	4s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62107078362	
analysis	pass	25s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149765/job/62107067435	
Adjust Configuration	skipping	0	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107135652	
CodeQL	skipping	2s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62107048791	
CodeRabbit	pass	0		Review skipped
backend	pass	42s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149768/job/62107168686	
backend	pass	38s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630251/job/62106960428	
dependency-review	pass	7s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630278/job/62107006119	
frontend	pass	31s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149768/job/62107168696	
frontend	pass	20s	https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630251/job/62106960425	

Required checks

gh pr checks --required --fail-fast
cannot use `--fail-fast` flag without `--watch` flag

Usage:  gh pr checks [<number> | <url> | <branch>] [flags]

Flags:
      --fail-fast         Exit watch mode on first check failure
  -i, --interval int      Refresh interval in seconds in watch mode (default 10)
  -q, --jq expression     Filter JSON output using a jq expression
      --json fields       Output JSON with the specified fields
      --required          Only show checks that are required
  -t, --template string   Format JSON output using a Go template; see "gh help formatting"
      --watch             Watch checks until they finish
  -w, --web               Open the web browser to show details about checks
  

Merge state

gh pr view --json mergeStateStatus,mergeable
{"mergeStateStatus":"UNSTABLE","mergeable":"MERGEABLE"}

Rulesets / Branch policy

gh api "repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/rules/branches/review-base" || gh api "repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/branches/review-base/protection"
[{"type":"file_path_restriction","parameters":{"restricted_file_paths":[".github/agents/*.md","agents/*.md"]},"ruleset_source_type":"Enterprise","ruleset_source":"hyosung-itx","ruleset_id":10761435}]

Code scanning (API)

gh api "/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/code-scanning/analyses?pr=6"
gh api "/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/code-scanning/alerts?pr=6&state=open"
[{"ref":"refs/pull/6/merge","commit_sha":"244607250c7df0a0f960c87a5f03d427b48e945f","analysis_key":".github/workflows/codeql.yml:analyze","environment":"{\"language\":\"javascript-typescript\"}","category":".github/workflows/codeql.yml:analyze/language:javascript-typescript","error":"","created_at":"2026-02-01T01:05:44Z","results_count":0,"rules_count":86,"id":940768191,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/code-scanning/analyses/940768191","sarif_id":"2233b882-ff0a-11f0-9be0-9110fd0881ab","tool":{"name":"CodeQL","guid":null,"version":"2.24.0"},"deletable":true,"warning":""},{"ref":"refs/pull/6/merge","commit_sha":"244607250c7df0a0f960c87a5f03d427b48e945f","analysis_key":".github/workflows/codeql.yml:analyze","environment":"{\"language\":\"python\"}","category":".github/workflows/codeql.yml:analyze/language:python","error":"","created_at":"2026-02-01T01:05:23Z","results_count":0,"rules_count":43,"id":940767762,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/code-scanning/analyses/940767762","sarif_id":"15a5d2a8-ff0a-11f0-800b-9ecea3b84643","tool":{"name":"CodeQL","guid":null,"version":"2.24.0"},"deletable":true,"warning":""}]
[]

Check-runs (API)

gh api "/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/commits/4df21f2002282b2943cda7592c276af9ecc2fb75/check-runs"
{"total_count":19,"check_runs":[{"id":62107198723,"name":"Analyze (javascript-typescript)","node_id":"CR_kwDORF0XDs8AAAAOdeClAw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"372ebd46-a245-5c07-8a57-f5821d9d4f0e","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107198723","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149763/job/62107198723","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149763/job/62107198723","status":"completed","conclusion":"failure","started_at":"2026-02-01T01:09:45Z","completed_at":"2026-02-01T01:11:18Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107198723/annotations"},"check_suite":{"id":56025402029},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107198715,"name":"Analyze (python)","node_id":"CR_kwDORF0XDs8AAAAOdeCk-w","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"80eba2a0-2055-55ed-bb4a-73c1b0e07d69","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107198715","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149763/job/62107198715","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149763/job/62107198715","status":"completed","conclusion":"failure","started_at":"2026-02-01T01:09:45Z","completed_at":"2026-02-01T01:10:58Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107198715/annotations"},"check_suite":{"id":56025402029},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107168696,"name":"frontend","node_id":"CR_kwDORF0XDs8AAAAOdeAvuA","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"9fdb9f71-3aff-54f8-ba98-60ec20144970","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107168696","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149768/job/62107168696","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149768/job/62107168696","status":"completed","conclusion":"success","started_at":"2026-02-01T01:08:55Z","completed_at":"2026-02-01T01:09:26Z","output":{"title":null,"summary":null,"text":null,"annotations_count":2,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107168696/annotations"},"check_suite":{"id":56025402022},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107168686,"name":"backend","node_id":"CR_kwDORF0XDs8AAAAOdeAvrg","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"7cfbb2f7-0072-51cb-b287-942a78efce84","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107168686","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149768/job/62107168686","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149768/job/62107168686","status":"completed","conclusion":"success","started_at":"2026-02-01T01:08:54Z","completed_at":"2026-02-01T01:09:36Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107168686/annotations"},"check_suite":{"id":56025402022},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107135652,"name":"Adjust Configuration","node_id":"CR_kwDORF0XDs8AAAAOdd-upA","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"99616646-b98c-584c-a639-5c1a76bb6d5a","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107135652","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107135652","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107135652","status":"completed","conclusion":"skipped","started_at":"2026-02-01T01:07:55Z","completed_at":"2026-02-01T01:07:55Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107135652/annotations"},"check_suite":{"id":56027589070},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107089274,"name":"Analyze (python)","node_id":"CR_kwDORF0XDs8AAAAOdd75eg","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"e8794524-63f3-547d-b014-c0207cc28220","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107089274","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089274","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089274","status":"completed","conclusion":"success","started_at":"2026-02-01T01:06:35Z","completed_at":"2026-02-01T01:07:39Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107089274/annotations"},"check_suite":{"id":56027589070},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107089265,"name":"Analyze (actions)","node_id":"CR_kwDORF0XDs8AAAAOdd75cQ","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"e81b16aa-af69-5856-b11e-578b1a969da2","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107089265","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089265","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089265","status":"completed","conclusion":"success","started_at":"2026-02-01T01:06:34Z","completed_at":"2026-02-01T01:07:22Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107089265/annotations"},"check_suite":{"id":56027589070},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107089264,"name":"Analyze (javascript-typescript)","node_id":"CR_kwDORF0XDs8AAAAOdd75cA","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"e85843eb-dd37-5572-ad8b-892687bbaa0f","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107089264","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089264","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553947992/job/62107089264","status":"completed","conclusion":"success","started_at":"2026-02-01T01:06:34Z","completed_at":"2026-02-01T01:07:55Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107089264/annotations"},"check_suite":{"id":56027589070},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107078362,"name":"Scorecard","node_id":"CR_kwDORF0XDs8AAAAOdd7O2g","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107078362","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62107078362","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62107078362","status":"completed","conclusion":"success","started_at":"2026-02-01T01:06:13Z","completed_at":"2026-02-01T01:06:17Z","output":{"title":"4 new alerts including 4 medium severity security vulnerabilities","summary":"### New alerts in code changed by this pull request\n\nSecurity Alerts:\n * 4 medium\n\n\nSee annotations below for details.\n\n[View all branch alerts](/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/security/code-scanning?query=pr%3A6+tool%3AScorecard+is%3Aopen).","text":null,"annotations_count":4,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107078362/annotations"},"check_suite":{"id":56027548919},"app":{"id":57789,"client_id":"Iv1.4643383dd86f00de","slug":"github-advanced-security","node_id":"MDM6QXBwNTc3ODk=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Advanced Security","description":"","external_url":"https://github.com/features/security","html_url":"https://github.com/apps/github-advanced-security","created_at":"2020-03-17T21:25:09Z","updated_at":"2024-07-11T07:30:47Z","permissions":{"actions":"read","checks":"write","contents":"read","metadata":"read"},"events":[]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107067435,"name":"analysis","node_id":"CR_kwDORF0XDs8AAAAOdd6kKw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"70f228cb-7230-5f9c-b85d-629ffd922bf9","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107067435","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149765/job/62107067435","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553149765/job/62107067435","status":"completed","conclusion":"success","started_at":"2026-02-01T01:05:56Z","completed_at":"2026-02-01T01:06:21Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107067435/annotations"},"check_suite":{"id":56025402030},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107048791,"name":"CodeQL","node_id":"CR_kwDORF0XDs8AAAAOdd5bVw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107048791","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62107048791","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62107048791","status":"completed","conclusion":"neutral","started_at":"2026-02-01T01:05:22Z","completed_at":"2026-02-01T01:05:24Z","output":{"title":"Error when processing the SARIF file","summary":"[View all branch alerts](/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/security/code-scanning?query=pr%3A6+tool%3ACodeQL+is%3Aopen).","text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107048791/annotations"},"check_suite":{"id":56027548919},"app":{"id":57789,"client_id":"Iv1.4643383dd86f00de","slug":"github-advanced-security","node_id":"MDM6QXBwNTc3ODk=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Advanced Security","description":"","external_url":"https://github.com/features/security","html_url":"https://github.com/apps/github-advanced-security","created_at":"2020-03-17T21:25:09Z","updated_at":"2024-07-11T07:30:47Z","permissions":{"actions":"read","checks":"write","contents":"read","metadata":"read"},"events":[]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107016691,"name":"Analyze (python)","node_id":"CR_kwDORF0XDs8AAAAOdd3d8w","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"fb44644c-89da-5c59-8704-589ff14b3c6b","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107016691","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630249/job/62107016691","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630249/job/62107016691","status":"completed","conclusion":"success","started_at":"2026-02-01T01:04:32Z","completed_at":"2026-02-01T01:05:31Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107016691/annotations"},"check_suite":{"id":56026696283},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107016689,"name":"Analyze (javascript-typescript)","node_id":"CR_kwDORF0XDs8AAAAOdd3d8Q","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"4d4fff6a-7a57-5764-bdbe-69e328d6a46b","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107016689","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630249/job/62107016689","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630249/job/62107016689","status":"completed","conclusion":"success","started_at":"2026-02-01T01:04:32Z","completed_at":"2026-02-01T01:05:48Z","output":{"title":null,"summary":null,"text":null,"annotations_count":1,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107016689/annotations"},"check_suite":{"id":56026696283},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62107006119,"name":"dependency-review","node_id":"CR_kwDORF0XDs8AAAAOdd20pw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"526d62fc-08a9-5902-bb67-560a4cd74cf9","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107006119","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630278/job/62107006119","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630278/job/62107006119","status":"completed","conclusion":"success","started_at":"2026-02-01T01:04:15Z","completed_at":"2026-02-01T01:04:22Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62107006119/annotations"},"check_suite":{"id":56026696331},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106960428,"name":"backend","node_id":"CR_kwDORF0XDs8AAAAOdd0CLA","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"dc3cfd7b-88bf-5779-aa1c-1ee64d8bc29e","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62106960428","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630251/job/62106960428","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630251/job/62106960428","status":"completed","conclusion":"success","started_at":"2026-02-01T01:03:01Z","completed_at":"2026-02-01T01:03:39Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62106960428/annotations"},"check_suite":{"id":56026696284},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106960425,"name":"frontend","node_id":"CR_kwDORF0XDs8AAAAOdd0CKQ","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"fc6e4fc5-6ebb-5a54-b5a6-56ba4029e50e","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62106960425","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630251/job/62106960425","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553630251/job/62106960425","status":"completed","conclusion":"success","started_at":"2026-02-01T01:03:01Z","completed_at":"2026-02-01T01:03:21Z","output":{"title":null,"summary":null,"text":null,"annotations_count":2,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62106960425/annotations"},"check_suite":{"id":56026696284},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62106880455,"name":"Dependabot","node_id":"CR_kwDORF0XDs8AAAAOddvJxw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"99a6427c-6f7d-521c-96f6-2c5a59b0d5fb","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62106880455","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553871324/job/62106880455","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553871324/job/62106880455","status":"completed","conclusion":"success","started_at":"2026-02-01T01:00:57Z","completed_at":"2026-02-01T01:01:34Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62106880455/annotations"},"check_suite":{"id":56027380015},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104927131,"name":"Dependabot","node_id":"CR_kwDORF0XDs8AAAAOdb37mw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"497a75f2-b782-5d44-a4f5-c1e402611743","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62104927131","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553150127/job/62104927131","details_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/actions/runs/21553150127/job/62104927131","status":"completed","conclusion":"success","started_at":"2026-02-01T00:07:29Z","completed_at":"2026-02-01T00:08:36Z","output":{"title":null,"summary":null,"text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62104927131/annotations"},"check_suite":{"id":56025402854},"app":{"id":15368,"client_id":"Iv1.05c79e9ad1f6bdfa","slug":"github-actions","node_id":"MDM6QXBwMTUzNjg=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"GitHub Actions","description":"Automate your workflow from idea to production","external_url":"https://help.github.com/en/actions","html_url":"https://github.com/apps/github-actions","created_at":"2018-07-30T09:30:17Z","updated_at":"2025-12-02T18:13:15Z","permissions":{"actions":"write","administration":"read","artifact_metadata":"write","attestations":"write","checks":"write","contents":"write","copilot_requests":"write","deployments":"write","discussions":"write","issues":"write","merge_queues":"write","metadata":"read","models":"read","packages":"write","pages":"write","pull_requests":"write","repository_hooks":"write","repository_projects":"write","security_events":"write","statuses":"write","vulnerability_alerts":"read"},"events":["branch_protection_rule","check_run","check_suite","create","delete","deployment","deployment_status","discussion","discussion_comment","fork","gollum","issues","issue_comment","label","merge_group","milestone","page_build","public","pull_request","pull_request_review","pull_request_review_comment","push","registry_package","release","repository","repository_dispatch","status","watch","workflow_dispatch","workflow_run"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]},{"id":62104925223,"name":".github/dependabot.yml","node_id":"CR_kwDORF0XDs8AAAAOdb30Jw","head_sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","external_id":"","url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62104925223","html_url":"https://github.com/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/runs/62104925223","details_url":"https://dependabot-api.githubapp.com","status":"completed","conclusion":"success","started_at":"2026-02-01T00:07:24Z","completed_at":"2026-02-01T00:07:24Z","output":{"title":"Dependabot config file validation","summary":"All changes look good","text":null,"annotations_count":0,"annotations_url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/check-runs/62104925223/annotations"},"check_suite":{"id":56025401686},"app":{"id":29110,"client_id":"Iv1.4f9a6346434f815e","slug":"dependabot","node_id":"MDM6QXBwMjkxMTA=","owner":{"login":"github","id":9919,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5MTk=","avatar_url":"https://avatars.githubusercontent.com/u/9919?v=4","gravatar_id":"","url":"https://api.github.com/users/github","html_url":"https://github.com/github","followers_url":"https://api.github.com/users/github/followers","following_url":"https://api.github.com/users/github/following{/other_user}","gists_url":"https://api.github.com/users/github/gists{/gist_id}","starred_url":"https://api.github.com/users/github/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github/subscriptions","organizations_url":"https://api.github.com/users/github/orgs","repos_url":"https://api.github.com/users/github/repos","events_url":"https://api.github.com/users/github/events{/privacy}","received_events_url":"https://api.github.com/users/github/received_events","type":"Organization","user_view_type":"public","site_admin":false},"name":"Dependabot","description":"GitHub Dependabot","external_url":"https://dependabot-api.githubapp.com","html_url":"https://github.com/apps/dependabot","created_at":"2019-04-16T22:34:25Z","updated_at":"2025-06-11T21:07:45Z","permissions":{"actions":"write","checks":"write","contents":"write","issues":"write","members":"read","metadata":"read","pull_requests":"write","statuses":"read","vulnerability_alerts":"read","workflows":"write"},"events":["check_suite","issues","issue_comment","label","pull_request","pull_request_review","pull_request_review_comment","repository"]},"pull_requests":[{"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud/pulls/6","id":3231940343,"number":6,"head":{"ref":"main","sha":"4df21f2002282b2943cda7592c276af9ecc2fb75","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}},"base":{"ref":"review-base","sha":"167d530c372864d4f259612eec38351bff3ec9e5","repo":{"id":1146951438,"url":"https://api.github.com/repos/HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud","name":"pg-erd-cloud"}}}]}]}

Notes

  • Org repo has Code Scanning default setup enabled (org-controlled). Advanced CodeQL workflow uploads can fail with:
    "CodeQL analyses from advanced configurations cannot be processed when the default setup is enabled".
  • PR Fix: avoid CodeQL default-setup conflict #7 proposes making the pinned advanced CodeQL workflow manual-only to avoid conflicts.

@coderabbitai coderabbitai 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.

Actionable comments posted: 30

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
backend/pyproject.toml (1)

27-34: ⚠️ Potential issue | 🔴 Critical

python-jose 버전 제약을 3.4.0 이상으로 상향 조정하세요.

backend/pyproject.toml의 python-jose[cryptography]>=3.3.0 제약은 여러 보안 취약점이 있는 3.3.0 버전을 허용합니다:

  • CVE-2024-33663: ECDSA 키 알고리즘 혼동 공격
  • CVE-2024-33664: 높은 압축률 JWE를 이용한 DoS 공격
  • CVE-2024-29370: jwe.decrypt의 리소스 고갈 DoS

추가로 신규 추가된 types-python-jose>=3.5.0 (type stub)은 python-jose 3.3.0과 호환되지 않습니다. 스텁이 런타임보다 앞서가면서 mypy 타입 검사 시 오류가 발생할 수 있습니다.

해결책:

  • python-jose[cryptography]>=3.4.0 이상으로 제약 상향 (또는 최신 3.5.0 이상)
  • types-python-jose는 업그레이드된 python-jose와의 호환성 확인 후 추가

이 프로젝트가 Monorepo 구조인 점을 감안하면, backend 패키지의 보안 업데이트가 전체 시스템에 미치는 영향을 검토하고 진행하세요.

frontend/src/erd/TableNode.tsx (1)

10-11: 🧹 Nitpick | 🔵 Trivial

React Flow 컴포넌트에 React.memo 적용을 권장합니다.

외부 도구 컨텍스트에서 언급된 대로, React Flow에 props로 전달되는 커스텀 노드 컴포넌트는 React.memo로 감싸야 불필요한 리렌더링을 방지할 수 있습니다. 대규모 스키마를 렌더링할 때 성능 저하가 발생할 수 있습니다.

♻️ React.memo 적용 제안
+import { memo } from 'react'
 import type { NodeProps } from '@xyflow/react'

 type Column = {
   column_name: string
   data_type: string
   is_not_null: boolean
   is_pk?: boolean
 }

-export default function TableNode(props: NodeProps) {
+function TableNode(props: NodeProps) {
   const data = props.data as { title: string; columns: Column[]; badges?: { pk?: boolean; fk?: boolean } }
   // ... rest of component
 }
+
+export default memo(TableNode)
backend/app/main.py (1)

42-46: 🧹 Nitpick | 🔵 Trivial

@app.on_event("startup")은 FastAPI에서 deprecated된 패턴입니다.

FastAPI 공식 문서에서 @app.on_event() 메서드를 deprecated로 명시하고, 대신 lifespan 컨텍스트 관리자 사용을 권장합니다. 현재 코드는 동작하지만, 향후 호환성을 위해 마이그레이션을 권장합니다.

♻️ lifespan 패턴으로 리팩토링 제안
+from contextlib import asynccontextmanager
+
+@asynccontextmanager
+async def lifespan(app: FastAPI):
+    handlers = {"snapshot": handle_snapshot_job}
+    task = asyncio.create_task(run_worker_forever(SessionLocal, handlers))
+    yield
+    task.cancel()
+
-app = FastAPI(title="pg-erd-cloud backend")
+app = FastAPI(title="pg-erd-cloud backend", lifespan=lifespan)

-@app.on_event("startup")
-async def start_worker() -> None:
-    handlers = {"snapshot": handle_snapshot_job}
-    # Background worker loop. For production, run as separate process.
-    asyncio.create_task(run_worker_forever(SessionLocal, handlers))
backend/app/models.py (2)

11-12: 🧹 Nitpick | 🔵 Trivial

선택적 개선: relationship() 정의 추가 고려

현재 모델들은 ForeignKey 제약조건만 정의하고 SQLAlchemy의 relationship() 매핑이 없습니다. 이는 명시적 쿼리를 선호하는 유효한 설계 선택입니다.

향후 ORM 관계 탐색이 필요해지면, relationship()back_populates를 추가할 때 데이터베이스 레벨 CASCADE 설정과 ORM 레벨 cascade 설정이 일치하도록 주의해주세요.

# 예시: ProjectSpace에 members 관계 추가 시
from sqlalchemy.orm import relationship

class ProjectSpace(Base):
    # ... existing columns ...
    members: Mapped[list["ProjectMember"]] = relationship(
        back_populates="project_space",
        cascade="all, delete-orphan",
        passive_deletes=True  # DB-level CASCADE 사용 시
    )

47-67: ⚠️ Potential issue | 🟡 Minor

모델의 ForeignKey 정의에 ondelete 파라미터를 추가하세요.

마이그레이션 파일 0002_auth_share.py에서 project_member 테이블의 두 ForeignKey 모두 ondelete="CASCADE"로 정의되어 있습니다. 모델의 일관성을 위해 52-54줄과 57-59줄의 ForeignKey 정의에도 ondelete="CASCADE" 파라미터를 추가해야 합니다.

🤖 Fix all issues with AI agents
In @.github/workflows/codeql.yml:
- Around line 21-24: Replace the hardcoded CodeQL language matrix with the
dynamic detector action: add the advanced-security/set-codeql-language-matrix
action (e.g., advanced-security/set-codeql-language-matrix@v1) in the workflow
before the job that uses the matrix, capture its outputs (outputs.languages) and
feed that into the job strategy.matrix instead of the literal language array; if
needed use the action's exclude input to filter out languages (and remember
special-case Swift requiring macOS). Target the existing strategy/matrix block
and any references to "language" so the job consumes the detected languages
output rather than the hardcoded values.

In `@backend/alembic/versions/0002_auth_share.py`:
- Around line 22-28: The foreign key fk_project_space__created_by_user on table
project_space is missing an ondelete option while fk_share_link__created_by_user
on share_link uses ondelete="CASCADE"; update the
fk_project_space__created_by_user FK definition to include ondelete="CASCADE"
(i.e., when creating the FK for created_by_user_uuid -> user_account_uuid) to
make deletion behavior consistent with fk_share_link__created_by_user, or if the
differing behavior is intentional, add a clarifying comment explaining why
project_space should not cascade on user deletion.

In `@backend/app/api/projects.py`:
- Around line 148-155: When adding a new ProjectMember (the block that
constructs ProjectMember m and calls session.add/await session.commit), avoid
IntegrityError by first querying for an existing ProjectMember with the same
project_space_uuid and user_account_uuid; if found, update its project_role (and
updated_at) and commit, otherwise create and commit the new ProjectMember.
Alternatively, wrap the commit in a try/except for IntegrityError to handle race
conditions and return a proper conflict or perform an upsert; reference the
ProjectMember model and the code that builds m, session.add(m), and await
session.commit() to locate where to implement the check/update or error
handling.
- Line 151: Update the ProjectMemberAddIn schema so project_role is validated
against allowed values instead of a free string: change the project_role field
to a Literal["owner","editor","viewer"] (or use an Enum) and add the necessary
import from typing (or enum) and pydantic Field; keep default "viewer". Then
ensure all places using ProjectMemberAddIn.project_role (for example where
project_role=body.project_role is passed in the project creation API) continue
to accept the validated value and adjust any callers/tests that passed arbitrary
strings to use the allowed role names.
- Around line 138-146: The code currently auto-creates a UserAccount when u is
None using oidc_subject=subject; instead, require a pre-created invite token and
strict subject validation: when u is None, look up an Invitation (or similar)
record tied to the intended member_subject/token, verify the token exists, is
not expired/used, and the OIDC-validated subject matches the Invitation before
creating UserAccount (UserAccount(...), session.add(u), await session.flush());
if valid, mark the Invitation used/consumed; otherwise reject creation.
Add/update an Invitation model and helper (e.g., find_invitation_by_token,
mark_invitation_used) and ensure the OIDC authentication flow validates that the
authenticated subject equals the invite’s subject prior to creating the account.

In `@backend/app/api/share.py`:
- Around line 61-64: Duplicate share-link expiration/validation logic found in
backend.app.api.share across three endpoints; extract a helper function (e.g.,
_get_valid_share_link(session: AsyncSession, share_link_uuid: uuid.UUID) ->
ShareLink) that fetches the ShareLink from the DB, raises HTTPException(404) if
missing and HTTPException(410) if expired (use dt.datetime.now(dt.timezone.utc)
for comparison), return the valid ShareLink, and replace the repeated blocks in
the three endpoints (where link lookup/expiry checks occur) with await
_get_valid_share_link(session, share_link_uuid).
- Around line 137-140: The handler currently returns a SQL comment string when
no snapshot is found; change it to raise an HTTP 404 to match
export_snapshot_sql behavior in snapshots.py. In the function that fetches
SchemaSnapshotData (the code using session.get(SchemaSnapshotData,
schema_snapshot_uuid)), detect when data is None and raise FastAPI's
HTTPException with status_code=404 and a concise detail message (e.g., "snapshot
not found") instead of returning "-- snapshot data not found\n", leaving the
successful path to call snapshot_json_to_sql(data.snapshot_json).

In `@backend/app/api/snapshots.py`:
- Around line 31-38: The current check returning a SnapshotOut with a random
schema_snapshot_uuid on missing/incorrect connection is confusing; instead
import HTTPException from fastapi and raise an HTTPException (e.g., 404 or 403
with a clear message) when conn is None or conn.project_space_uuid !=
project_space_uuid in the code around the session.get(DbConnection,
body.db_connection_uuid) check; remove the fallback SnapshotOut return for that
error path so callers receive a proper HTTP error rather than a fake UUID
(ensure references to DbConnection, session.get, and SnapshotOut are updated
accordingly).
- Around line 103-118: export_snapshot_sql currently returns plain SQL comment
strings on missing resources, which is inconsistent with get_snapshot/
SnapshotDetailOut; instead, when snap is None or data is None raise an
HTTPException with a 404 status and a JSON detail matching SnapshotDetailOut
(e.g., status="not_found" and a descriptive message) so clients can
programmatically handle the error; keep the require_project_member check after
confirming snap exists and ensure export_snapshot_sql, SchemaSnapshot,
SchemaSnapshotData, get_snapshot, and SnapshotDetailOut are used to generate the
consistent 404 response.

In `@backend/app/auth.py`:
- Around line 125-151: The _ensure_user function can race when two requests
insert the same oidc_subject; modify it to catch database unique-constraint
failures: when creating/saving UserAccount (the session.add + await
session.flush() block), wrap the insert/flush in a try/except that catches
sqlalchemy.exc.IntegrityError (or the DB-specific integrity exception), rollback
the session/transaction state, re-query UserAccount by oidc_subject (using the
same select(UserAccount).where(UserAccount.oidc_subject == subject)) and return
a CurrentUser built from that existing row; only re-raise the error if the
re-query still finds no user. Ensure you reference _ensure_user, UserAccount,
oidc_subject, session.flush(), and CurrentUser in the fix so the retry-path
returns the already-created user instead of failing.
- Around line 91-111: Wrap the caught exceptions in the two try/except blocks
with explicit exception chaining so the original error is preserved: change the
first except around jwt.get_unverified_header(token) to "except Exception as
err:" and re-raise the HTTPException for "invalid token header" using "raise ...
from err", and likewise change the second except around jwt.decode(...) to
"except Exception as err:" and re-raise the HTTPException for "token
verification failed" using "raise ... from err"; this keeps original tracebacks
for jwt.get_unverified_header, _get_jwks/_pick_jwk usage, and jwt.decode while
preserving the HTTPException API.
- Around line 52-69: The JWKS cache is updated in _get_jwks but _oidc_expires_at
is never refreshed; after successfully fetching jwks you should set the global
_oidc_expires_at to the same expiry used by the OIDC config so JWKS shares the
config TTL. Concretely: inside _get_jwks (after r.json() and before returning)
assign the fetched jwks to _oidc_jwks and update _oidc_expires_at to match the
config cache expiry provided by _get_oidc_config (or compute now + the same TTL
used by _get_oidc_config if that function exposes a TTL), ensuring the globals
_oidc_jwks and _oidc_expires_at are both updated atomically.

In `@backend/app/ddl/export.py`:
- Around line 74-105: The code currently builds CREATE TABLE statements from
col_defs and table_cons (combined into all_defs) and will emit an invalid
"CREATE TABLE ... ()" when all_defs is empty; modify the logic in the block that
uses all_defs (around variables col_defs, table_cons, all_defs, _qname, lines)
to first check if all_defs is empty and if so skip emitting the CREATE TABLE
block (or emit a valid fallback such as a COMMENT/skip note) instead of
appending "CREATE TABLE IF NOT EXISTS {_qname(...)} ()"; ensure the
early-return/continue prevents adding the opening "CREATE TABLE..." line, the
column/constraint lines, and the closing ");" for tables with no definitions.

In `@backend/app/models.py`:
- Around line 50-58: The junction table ProjectMember should apply DB-level
cascade deletes: update the ForeignKey declarations for project_space_uuid and
user_account_uuid in class ProjectMember to include ondelete="CASCADE" (i.e.,
modify the ForeignKey(...) passed to mapped_column for project_space_uuid and
user_account_uuid) so that deleting a ProjectSpace or UserAccount automatically
removes the join rows at the database level.
- Around line 99-101: The db_connection_uuid mapped column lacks an index which
hurts lookup performance for queries by DB connection; update the
db_connection_uuid Mapped field declaration (the mapped_column call for
db_connection_uuid) to include index=True (mirroring project_space_uuid) and
create/run the corresponding DB migration so the new index is applied to the
underlying table.
- Around line 76-78: Update the ForeignKey on the project_space_uuid column in
the DbConnection model so that deletions of the related ProjectSpace cascade:
modify the mapped_column definition for project_space_uuid (the
UUID(as_uuid=True), ForeignKey("project_space.project_space_uuid")) to include
ondelete="CASCADE" on the ForeignKey; ensure the DbConnection model and any
related relationship configuration will honor the database-level cascade
behavior.
- Around line 119-123: SchemaSnapshotData의 schema_snapshot_uuid 외래키에
ondelete="CASCADE"를 추가해 스냅샷 삭제 시 관련 데이터가 함께 삭제되도록 하고, SchemaSnapshot 쪽 관계(예:
SchemaSnapshot.schema_snapshot_data 또는 유사한 relationship 정의)에 cascade="all,
delete-orphan" 또는 적절한 삭제 cascade 옵션을 설정해 ORM 레벨에서도 고아 레코드가 생성되지 않도록 처리하세요; 구체적으로
SchemaSnapshotData.schema_snapshot_uuid의 ForeignKey를
ForeignKey("schema_snapshot.schema_snapshot_uuid", ondelete="CASCADE")로 변경하고
SchemaSnapshot 클래스의 relationship 설정을 검토·수정하세요.
- Around line 157-175: The ShareLink model should enforce cascade deletes for
project-space removals and clarify policy for user deletions and expires_at
nullability: update the ForeignKey on project_space_uuid in class ShareLink to
include ondelete="CASCADE" so linked share rows are removed when a ProjectSpace
is deleted; decide whether created_by_user_uuid should cascade or be nullable
and use ondelete="CASCADE" to remove shares with user deletion or set
ondelete="SET NULL" and make created_by_user_uuid nullable to preserve shares;
lastly confirm whether expires_at nullable is intentional for indefinite links
and, if not, remove nullable or add validation logic in the model or service
layer to enforce expiration policy.
- Around line 39-41: The ForeignKey on created_by_user_uuid lacks an explicit
ondelete behavior; update the ForeignKey(...) in the created_by_user_uuid
mapped_column to include the appropriate ondelete value (e.g., "SET NULL",
"RESTRICT", or "CASCADE") that matches your business rules, and if you choose
"SET NULL" make the mapped_column nullable (e.g., set nullable=True) so the DB
can accept nulls after user deletion; ensure changes are applied to the
created_by_user_uuid definition in models.py.

In `@backend/app/permissions.py`:
- Line 26: The return in permissions.py currently wraps role with str()
unnecessarily; since ProjectMember.project_role is already a Mapped[str] (see
ProjectMember.project_role in models.py), remove the str() call and return role
directly from the function (update the line returning str(role) to return role)
so the function returns the mapped string without redundant casting.

In `@backend/app/schemas.py`:
- Line 21: project_role currently accepts any string; restrict it to allowed
values by changing the type and Field declaration to use a Literal (e.g.
Literal["owner","editor","viewer"]) or a small Enum class, import typing.Literal
or enum.Enum as needed, and update the project_role annotation (the Field(...)
for project_role) so validation rejects other strings; ensure any references to
this attribute (constructors, deserialization points) still pass the allowed
values.

In `@compose.prod.yaml`:
- Around line 5-8: 현재 compose.prod.yaml에서 POSTGRES_PASSWORD를 환경변수로 직접 전달하고 있어
프로덕션에서 노출 위험이 있으니 POSTGRES_PASSWORD를 Docker secrets 또는 _FILE 패턴으로 전환하세요: 생성된
secret 이름(예: postgres_password)을 사용해 서비스의 environment에서 POSTGRES_PASSWORD 대신
POSTGRES_PASSWORD_FILE 환경변수를 사용하도록 변경하고, 관련 코드/이미지(데이터베이스 초기화 스크립트나 애플리케이션)가 파일
경로(/run/secrets/postgres_password)를 읽도록 조정하세요; 또한 동일한 변경이 언급된 다른 항목들(예: 파일 내
25-27번 항목)에 대해서도 동일한 _FILE/secret 패턴을 적용해 비밀이 환경변수로 노출되지 않도록 보장하세요.
- Line 27: The DATABASE_URL in the backend service uses ${POSTGRES_PASSWORD}
without validation, which can silently expand to an empty string and break
connections; update the DATABASE_URL definition (the DATABASE_URL env var in the
backend block) to use the same mandatory expansion used by the postgres service
(e.g., ${POSTGRES_PASSWORD:?set in .env}) so the compose parser will fail early
when POSTGRES_PASSWORD is missing, ensuring consistent validation between the
postgres service and the backend.

In `@frontend/Dockerfile.prod`:
- Around line 10-15: Add a Docker HEALTHCHECK to the Dockerfile to allow
orchestration systems to probe the nginx container; update the prod Dockerfile
(the block with FROM nginx:1.27-alpine, COPY ... /usr/share/nginx/html, COPY
nginx.conf ..., EXPOSE 80) to include a HEALTHCHECK instruction that
periodically requests http://localhost:80/ (or a specific health route) and
returns non-zero on failure, and if the nginx image lacks a probe tool add
installation of curl/wget in the build stage or use a shell probe (e.g., sh -c
'curl -f ... || exit 1') so the healthcheck reliably reflects service readiness.
- Line 1: Replace the mutable base image reference in the Dockerfile (the FROM
node:20-alpine line) with a digest-pinned reference (the same
node:20-alpine@sha256:<digest>) so the build uses an immutable, verifiable
image; lookup the current digest for node:20-alpine from the official Node image
registry (or docker pull && docker inspect) and update the FROM line
accordingly, and apply the same digest-pinning pattern to other Dockerfiles to
keep consistency.

In `@frontend/nginx.conf`:
- Around line 10-18: 현재 nginx의 location /api/ 블록에 명시적 타임아웃이 없어 긴 실행의 API 호출이
기본(60초) 타임아웃으로 끊길 수 있습니다; 수정하려면 location /api/ 블록(식별자: location /api/)에
proxy_connect_timeout, proxy_send_timeout, proxy_read_timeout(예: 300s 또는 서비스 요구에
맞는 값)과 필요하면 proxy_set_header Connection "" 또는 proxy_http_version 1.1 관련 설정을 보강하여
연결/전송/응답 대기 시간을 늘리고 안정적인 프록시 동작을 보장하세요.

In `@frontend/src/api.ts`:
- Around line 15-19: Add a Me type to frontend/src/types.ts (export type Me = {
subject: string; display_name: string | null; user_account_uuid: string }) and
update the getMe function in frontend/src/api.ts to return Promise<Me> and use
that imported Me type instead of the current inline type; ensure you import { Me
} from './types' at the top of api.ts and keep the existing fetch/error handling
and r.json() return.

In `@frontend/src/App.tsx`:
- Around line 107-111: The input bound to devUser (input id "dev-user" using
value={devUser} and onChange={e => setDevUser(e.target.value)}) currently
updates state on every keystroke and causes immediate side effects; introduce
debouncing by deriving a deferred/debounced value (e.g.,
useDeferredValue(devUser) or a custom useDebounce hook) and change any effects
or API calls that currently depend on devUser to depend on the debounced value
instead (for example, move localStorage.setItem and network requests into a
useEffect watching the deferred/debounced value) so rapid typing does not
trigger repeated requests.
- Line 42: The assignment to selectedProjectId uses a logical OR that can
mistakenly treat falsy but valid values as absent; update the call to
setSelectedProjectId so it uses nullish coalescing with the projects array
access (replace the expression p[0]?.project_space_uuid || null with
p[0]?.project_space_uuid ?? null) – modify the expression where
setSelectedProjectId(...) is invoked (refer to setSelectedProjectId and the
local variable p in App.tsx) to ensure undefined/null become null while
preserving legitimate falsy values.

In `@README.md`:
- Line 65: Replace the bare URL in the README entry "Frontend:
http://localhost:8080" with a Markdown link to satisfy markdownlint MD034;
specifically update the line so the URL is wrapped as a link like Frontend:
[http://localhost:8080](http://localhost:8080) (or use a descriptive label
linking to http://localhost:8080) to remove the bare URL.

Comment on lines +21 to +24
strategy:
fail-fast: false
matrix:
language: ["javascript-typescript", "python"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🌐 Web query:

advanced-security/set-codeql-language-matrix GitHub Action documentation

💡 Result:

advanced-security/set-codeql-language-matrix is a GitHub Action that calls your repository’s Languages API endpoint and emits a CodeQL-ready job matrix containing the CodeQL-supported languages detected in the repo—so you don’t have to manually keep strategy.matrix.language in sync as the repo evolves. [1][2]

How to use

  1. Run the action in a first job (commonly create-matrix) and expose its output.
  2. In your CodeQL analyze job, set strategy.matrix to that JSON output via fromJSON(...). [1][2]

Example pattern (from the action docs): [1][2]

  • matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
  • then pass languages: ${{ matrix.language }} to github/codeql-action/init [1]

Inputs

  • access-token (required): token to call the API (often ${{ secrets.GITHUB_TOKEN }}). [1][2]
  • endpoint (required): the repo languages API URL (often ${{ github.event.repository.languages_url }}). [1][2]
  • exclude (optional): comma-separated languages to omit (example: java, python). [1][2]
  • build-mode-manual-override (optional): comma-separated languages that should use manual build-mode in the generated matrix. [1][2]

Notes called out by the docs

  • Swift: CodeQL Swift analysis requires running that matrix entry on macOS (the docs show a conditional runs-on for swift). [1][2]
  • GitHub Actions (YAML): The repo Languages API may not include workflow YAML by default; the docs suggest adding .gitattributes rules to make workflows “linguist-detectable” so they appear for inclusion. [1][2]
  • GitHub’s CodeQL “advanced setup” commonly uses a matrix.language value passed to github/codeql-action/init (languages: ${{ matrix.language }}). [3]

Sources: Action repository docs / README and Marketplace listing [1][2], and GitHub Docs on CodeQL advanced setup language matrices [3].

[1] https://github.com/advanced-security/set-codeql-language-matrix
[2] https://github.com/marketplace/actions/set-codeql-languages
[3] https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning


🌐 Web query:

GitHub CodeQL dynamic language matrix detection best practices 2025

💡 Result:

Best practices (2025) for dynamic CodeQL language-matrix detection in GitHub Actions

  1. Prefer an explicit strategy.matrix.language (parallel, predictable)

    • GitHub recommends using a language matrix; when you use it, CodeQL analyzes only those languages, so it’s the right place to control coverage. [1][2]
  2. Don’t rely on implicit auto-detection for compiled-language repos

    • In advanced setup, if you don’t explicitly specify languages, CodeQL may analyze only the compiled language with the most source files (among compiled languages), which surprises many multi-language repos. Use a matrix to force all desired languages to run. [3]
  3. Generate the matrix dynamically from the repo’s detected languages

    • Use the GitHub “List repository languages” API (via a helper action) to build a matrix each run so new languages added later get scanned automatically. [4][5]
  4. Make “GitHub Actions workflows” (actions) detectable (common gotcha)

    • The languages API often won’t include workflow YAML unless you mark them detectable via .gitattributes, otherwise your “dynamic matrix” won’t ever add actions. [5]
  5. Handle per-language runtime/build requirements in the matrix

    • Use build-mode per language (many repos need manual for compiled languages), and use conditional runners for Swift (macOS). [5][6]
  6. Use correct CodeQL language identifiers

    • For example: javascript-typescript, java-kotlin, c-cpp, and actions. (Alternatives like javascript don’t exclude TypeScript—use path filtering instead.) [1][7]

Reference pattern (dynamic matrix + CodeQL)

jobs:
  create-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        uses: advanced-security/set-codeql-language-matrix@v1
        with:
          access-token: ${{ secrets.GITHUB_TOKEN }}
          endpoint: ${{ github.event.repository.languages_url }}

  analyze:
    needs: create-matrix
    strategy:
      fail-fast: false
      matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
    runs-on: ${{ matrix.language == 'swift' && 'macos-latest' || 'ubuntu-latest' }}
    steps:
      - uses: github/codeql-action/init@v4
        with:
          languages: ${{ matrix.language }}
          build-mode: ${{ matrix.build-mode }}
      - uses: github/codeql-action/analyze@v4
        with:
          category: "/language:${{ matrix.language }}"

Sources: GitHub Docs on advanced setup customization and language identifiers [1][2][3], and the matrix-generation action guidance (including .gitattributes, exclusions, build-mode defaults, Swift runner note) [4][5][6], plus CodeQL supported languages/frameworks reference. [7]


CodeQL 언어 매트릭스를 동적으로 감지하여 유지보수 비용을 줄이세요.

현재 언어가 하드코딩되어 있어 새로운 언어가 추가되면 워크플로우도 수정해야 합니다. advanced-security/set-codeql-language-matrix 액션을 사용하면 저장소의 언어를 자동으로 감지하고, 감지된 언어만 분석하게 되어 불필요한 실행을 줄일 수 있습니다.

♻️ 적용 예시
 jobs:
+  set-matrix:
+    runs-on: ubuntu-latest
+    outputs:
+      matrix: ${{ steps.set-matrix.outputs.matrix }}
+    steps:
+      - name: CodeQL 언어 매트릭스 생성
+        id: set-matrix
+        uses: advanced-security/set-codeql-language-matrix@v1
+        with:
+          access-token: ${{ secrets.GITHUB_TOKEN }}
+          endpoint: ${{ github.event.repository.languages_url }}
+
   analyze:
+    needs: set-matrix
     strategy:
       fail-fast: false
-      matrix:
-        language: ["javascript-typescript", "python"]
+      matrix: ${{ fromJSON(needs.set-matrix.outputs.matrix) }}
     runs-on: ubuntu-latest

필요시 exclude 옵션으로 특정 언어를 제외할 수 있고, Swift 분석 시 macOS 실행 환경이 필요하다는 점도 참고하세요.

🤖 Prompt for AI Agents
In @.github/workflows/codeql.yml around lines 21 - 24, Replace the hardcoded
CodeQL language matrix with the dynamic detector action: add the
advanced-security/set-codeql-language-matrix action (e.g.,
advanced-security/set-codeql-language-matrix@v1) in the workflow before the job
that uses the matrix, capture its outputs (outputs.languages) and feed that into
the job strategy.matrix instead of the literal language array; if needed use the
action's exclude input to filter out languages (and remember special-case Swift
requiring macOS). Target the existing strategy/matrix block and any references
to "language" so the job consumes the detected languages output rather than the
hardcoded values.

Comment on lines +22 to +28
op.create_foreign_key(
"fk_project_space__created_by_user",
"project_space",
"user_account",
["created_by_user_uuid"],
["user_account_uuid"],
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check the file exists and view the foreign key definitions
cat -n backend/alembic/versions/0002_auth_share.py | head -150

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 5187


🏁 Script executed:

# Search for user deletion patterns in the codebase
rg -n 'delete.*user|cascade|ondelete' backend --type=py -i -A 2 -B 2 | head -100

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 2949


🏁 Script executed:

# Look for any migration files that handle user deletion
fd -e py 'migration|alembic' backend --type f | head -20

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Search for application-level user deletion logic or soft deletes
rg -n 'class.*User|def.*delete.*user' backend --type=py -i -A 3 | head -80

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 502


🏁 Script executed:

# Check if user_account has a soft delete or is_deleted column
rg -n 'is_deleted|deleted_at|is_archived|status.*delete' backend --type=py

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Search for any user deletion business logic or permissions check
rg -n 'def.*delete|cannot.*delete|prevent.*delete' backend --type=py -i -A 3

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Look for any comments or documentation about user deletion constraints
rg -n 'TODO|FIXME|NOTE|BUG|HACK' backend/alembic/versions/0002_auth_share.py

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Check if there's a pattern where ondelete is intentionally omitted
rg -n 'MVP|best-effort|fresh DB' backend/alembic --type=py -B 2 -A 5

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 702


fk_project_space__created_by_userfk_share_link__created_by_user FK의 ondelete 옵션 불일치

project_spaceshare_link 모두 created_by_user_uuiduser_account를 참조하지만, 삭제 정책이 다릅니다:

  • fk_project_space__created_by_user (22-28행): ondelete 없음
  • fk_share_link__created_by_user (102-107행): ondelete="CASCADE" 있음

두 관계가 동일한 의미(사용자가 생성)이므로 동일한 삭제 정책을 적용해야 합니다. 주석의 "MVP: best-effort"는 이 FK 정의가 미완성임을 시사하므로, fk_project_space__created_by_user에도 ondelete="CASCADE"를 추가하거나 의도적인 차이라면 명확한 설명을 추가하세요.

🤖 Prompt for AI Agents
In `@backend/alembic/versions/0002_auth_share.py` around lines 22 - 28, The
foreign key fk_project_space__created_by_user on table project_space is missing
an ondelete option while fk_share_link__created_by_user on share_link uses
ondelete="CASCADE"; update the fk_project_space__created_by_user FK definition
to include ondelete="CASCADE" (i.e., when creating the FK for
created_by_user_uuid -> user_account_uuid) to make deletion behavior consistent
with fk_share_link__created_by_user, or if the differing behavior is
intentional, add a clarifying comment explaining why project_space should not
cascade on user deletion.

Comment on lines +138 to +146
if u is None:
u = UserAccount(
user_account_uuid=uuid.uuid4(),
oidc_subject=subject,
display_name=None,
created_at=dt.datetime.now(dt.timezone.utc),
)
session.add(u)
await session.flush()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

OIDC user invitation best practices automatic account creation security

💡 Result:

Best practices: OIDC invitations + automatic account creation (JIT) + security

1) Prefer provisioning over “anyone can self-signup”

  • If you can, treat an HR/CRM/partner directory as the source of truth and provision/deprovision users automatically (commonly via SCIM) to reduce orphaned access and manual errors. [7]

2) If you use invitation-based onboarding, bind identity to the invite

  • Use an invite flow where the user must authenticate with the exact email address that was invited; don’t allow accepting an invite with a different email. Auth0’s Org invitations enforce this, and mark email verified upon acceptance. [10]
  • If you build your own invite flow, create the user with email_verified=false, set a random password that is never revealed, and force a password reset link—so nobody (including admins/systems) knows the user’s password. [3]

3) For “automatic account creation”, use JIT provisioning but scope it tightly

  • JIT provisioning is “create user on first successful authentication.” It’s convenient, but only safe when the upstream IdP is trusted and controlled. Okta documents this model (create user on first auth) for JIT. [2]
  • If you enable JIT, combine it with policy controls (e.g., only for certain groups/apps/contexts) and keep strong auditability. Okta notes you can apply granular rules/policies around linking + JIT. [8]

4) Be careful with account linking (common account-takeover pitfall)

  • Auto-linking based on email can be risky if an attacker can authenticate at an external IdP that asserts the victim’s email, or if emails aren’t strongly verified upstream.
  • Okta explicitly recommends disabling account linking after your initial population/migration is done, then relying on JIT only for new users. [5]

5) Require strong proof of control for the identifier you use (usually email)

  • Invitations: require accepting the invite via the invited mailbox (token delivered there) and/or ensure the IdP returns the same email as invited. [10]
  • Don’t “trust” an email claim from an IdP unless you also trust that IdP’s identity proofing and email verification process.

6) Don’t run “open” dynamic features unless you constrain them

If you use OIDC Discovery and/or Dynamic Client Registration (DCR):

  • Enforce TLS for registration endpoints (spec requirement). [4]
  • Treat any client-supplied “displayable URLs” (logo/policy/etc.) as untrusted to prevent phishing/UI confusion; the spec calls this out. [4]
  • Consider disabling or tightly restricting Discovery/DCR to trusted issuers/registrants; published research shows Discovery/DCR can enable “malicious endpoint” / second-order attacks (e.g., SSRF, token theft, DoS) if not constrained. [12]

7) Operational controls that matter in practice

  • Maintain lifecycle governance: periodic access reviews, monitoring, and audit trails for provisioning/invite/JIT events. [7]

If you tell me your setup (B2B “organizations” vs internal workforce, which IdP(s), and whether you use SCIM), I can suggest a concrete “recommended flow” and a minimal policy set.


🏁 Script executed:

# First, let's examine the code context around the mentioned lines
# File: backend/app/api/projects.py, lines 138-146
head -c 10000 backend/app/api/projects.py 2>/dev/null | tail -c 5000 || wc -l backend/app/api/projects.py

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 5060


🏁 Script executed:

# Locate and examine the file with context around lines 138-146
if [ -f "backend/app/api/projects.py" ]; then
  echo "=== File found, showing lines 120-160 ===";
  sed -n '120,160p' backend/app/api/projects.py;
else
  echo "=== File location search ===";
  find . -name "projects.py" -type f 2>/dev/null | head -5;
fi

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 1498


🏁 Script executed:

# Search for the OIDC subject validation logic and user creation patterns
rg -A 15 -B 15 "oidc_subject" --type py | head -100

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 5880


프로덕션 환경을 위해 OIDC 토큰 기반 초대 플로우로 전환 필요

현재 구현에서 프로젝트 owner가 지정한 member_subject에 대해 OIDC 제공자로부터의 검증 없이 자동으로 UserAccount를 생성하고 있습니다. OIDC 모범 사례에 따르면 JIT(Just-In-Time) 프로비저닝은 업스트림 IdP가 신뢰할 수 있고 제어되는 경우에만 안전하며, 초대 기반 플로우에서는 사용자가 초대된 동일한 신원으로 직접 인증해야 합니다. 현재 방식은 IdP에서 검증되지 않은 subject로 계정이 생성될 수 있어 권한 상승이나 계정 탈취 위험이 있습니다.

권장 개선 사항: (1) 초대 토큰 기반 플로우 도입—owner가 subject를 지정할 때 고유 토큰 생성 및 해당 토큰으로만 계정 생성 허용, (2) 사용자가 OIDC로 인증한 후 토큰의 subject와 일치 확인.

🤖 Prompt for AI Agents
In `@backend/app/api/projects.py` around lines 138 - 146, The code currently
auto-creates a UserAccount when u is None using oidc_subject=subject; instead,
require a pre-created invite token and strict subject validation: when u is
None, look up an Invitation (or similar) record tied to the intended
member_subject/token, verify the token exists, is not expired/used, and the
OIDC-validated subject matches the Invitation before creating UserAccount
(UserAccount(...), session.add(u), await session.flush()); if valid, mark the
Invitation used/consumed; otherwise reject creation. Add/update an Invitation
model and helper (e.g., find_invitation_by_token, mark_invitation_used) and
ensure the OIDC authentication flow validates that the authenticated subject
equals the invite’s subject prior to creating the account.

Comment on lines +148 to +155
m = ProjectMember(
project_space_uuid=project_space_uuid,
user_account_uuid=u.user_account_uuid,
project_role=body.project_role,
created_at=dt.datetime.now(dt.timezone.utc),
)
session.add(m)
await session.commit()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

중복 멤버 추가 시 IntegrityError가 발생합니다.

ProjectMember의 복합 PK (project_space_uuid, user_account_uuid)로 인해 이미 존재하는 멤버를 추가하면 데이터베이스 오류가 발생합니다. 중복 검사를 추가하거나 역할 업데이트 로직을 구현하세요.

🐛 중복 멤버 검사 추가 제안
+    # Check for existing membership
+    existing = await session.execute(
+        select(ProjectMember).where(
+            ProjectMember.project_space_uuid == project_space_uuid,
+            ProjectMember.user_account_uuid == u.user_account_uuid,
+        )
+    )
+    if existing.scalars().first() is not None:
+        raise HTTPException(status_code=409, detail="user is already a member")
+
     m = ProjectMember(
         project_space_uuid=project_space_uuid,
         user_account_uuid=u.user_account_uuid,
         project_role=body.project_role,
         created_at=dt.datetime.now(dt.timezone.utc),
     )
🤖 Prompt for AI Agents
In `@backend/app/api/projects.py` around lines 148 - 155, When adding a new
ProjectMember (the block that constructs ProjectMember m and calls
session.add/await session.commit), avoid IntegrityError by first querying for an
existing ProjectMember with the same project_space_uuid and user_account_uuid;
if found, update its project_role (and updated_at) and commit, otherwise create
and commit the new ProjectMember. Alternatively, wrap the commit in a try/except
for IntegrityError to handle race conditions and return a proper conflict or
perform an upsert; reference the ProjectMember model and the code that builds m,
session.add(m), and await session.commit() to locate where to implement the
check/update or error handling.

m = ProjectMember(
project_space_uuid=project_space_uuid,
user_account_uuid=u.user_account_uuid,
project_role=body.project_role,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1. Find ProjectMemberAddIn schema
rg -n -A10 'class ProjectMemberAddIn' --type=py

# 2. Check the context around line 151 in projects.py
rg -n -B5 -A5 'project_role' backend/app/api/projects.py

# 3. Find any validation or enums related to project_role
rg -n 'project_role|ProjectRole' --type=py | head -30

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 3207


ProjectMemberAddIn 스키마에서 project_role 필드에 유효성 검사가 필요합니다.

현재 project_role은 단순 문자열(str = Field(default="viewer"))로 정의되어 있어 임의의 문자열을 허용합니다. "owner", "editor", "viewer" 등 허용된 역할만 받도록 Pydantic의 Literal 또는 Enum을 사용하여 스키마에서 검증하세요.

backend/app/schemas.py의 ProjectMemberAddIn 클래스를 다음과 같이 수정하면 됩니다:

project_role: Literal["owner", "editor", "viewer"] = Field(default="viewer")

또는 더 확장성이 필요하면 Enum을 사용하세요.

🤖 Prompt for AI Agents
In `@backend/app/api/projects.py` at line 151, Update the ProjectMemberAddIn
schema so project_role is validated against allowed values instead of a free
string: change the project_role field to a Literal["owner","editor","viewer"]
(or use an Enum) and add the necessary import from typing (or enum) and pydantic
Field; keep default "viewer". Then ensure all places using
ProjectMemberAddIn.project_role (for example where
project_role=body.project_role is passed in the project creation API) continue
to accept the validated value and adjust any callers/tests that passed arbitrary
strings to use the allowed role names.

Comment thread frontend/nginx.conf
Comment on lines +10 to +18
# Proxy API to backend
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

API 프록시에 타임아웃 설정 추가 권장

장시간 실행되는 API 호출(예: 대규모 스키마 인트로스펙션)에서 nginx 기본 타임아웃(60초)으로 인해 연결이 끊어질 수 있습니다. 명시적인 타임아웃 설정을 추가하면 이러한 상황을 방지할 수 있습니다.

⏱️ 프록시 타임아웃 설정 추가
   location /api/ {
     proxy_pass http://backend:8000/api/;
     proxy_http_version 1.1;
     proxy_set_header Host $host;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header X-Forwarded-Proto $scheme;
+    proxy_connect_timeout 60s;
+    proxy_read_timeout 120s;
+    proxy_send_timeout 60s;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Proxy API to backend
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Proxy API to backend
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 120s;
proxy_send_timeout 60s;
}
🤖 Prompt for AI Agents
In `@frontend/nginx.conf` around lines 10 - 18, 현재 nginx의 location /api/ 블록에 명시적
타임아웃이 없어 긴 실행의 API 호출이 기본(60초) 타임아웃으로 끊길 수 있습니다; 수정하려면 location /api/ 블록(식별자:
location /api/)에 proxy_connect_timeout, proxy_send_timeout,
proxy_read_timeout(예: 300s 또는 서비스 요구에 맞는 값)과 필요하면 proxy_set_header Connection ""
또는 proxy_http_version 1.1 관련 설정을 보강하여 연결/전송/응답 대기 시간을 늘리고 안정적인 프록시 동작을 보장하세요.

Comment thread frontend/src/api.ts
Comment on lines +15 to +19
export async function getMe(): Promise<{ subject: string; display_name: string | null; user_account_uuid: string }> {
const r = await fetch(`${API_BASE}/api/me`, { headers: devHeaders() })
if (!r.ok) throw new Error(`getMe failed: ${r.status}`)
return r.json()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

getMe() 반환 타입을 types.ts에 정의하는 것을 권장합니다.

다른 API 함수들은 types.ts에 정의된 타입(Project, Connection, Snapshot 등)을 사용하지만, getMe()는 인라인 타입을 사용합니다. 일관성을 위해 Me 타입을 추가하세요.

♻️ types.ts에 Me 타입 추가

frontend/src/types.ts에 추가:

export type Me = {
  subject: string
  display_name: string | null
  user_account_uuid: string
}

frontend/src/api.ts 수정:

-export async function getMe(): Promise<{ subject: string; display_name: string | null; user_account_uuid: string }> {
+export async function getMe(): Promise<Me> {
🤖 Prompt for AI Agents
In `@frontend/src/api.ts` around lines 15 - 19, Add a Me type to
frontend/src/types.ts (export type Me = { subject: string; display_name: string
| null; user_account_uuid: string }) and update the getMe function in
frontend/src/api.ts to return Promise<Me> and use that imported Me type instead
of the current inline type; ensure you import { Me } from './types' at the top
of api.ts and keep the existing fetch/error handling and r.json() return.

Comment thread frontend/src/App.tsx
setMe({ subject: m.subject, display_name: m.display_name })
setProjects(p)
if (p[0]) setSelectedProjectId(p[0].project_space_uuid)
setSelectedProjectId(p[0]?.project_space_uuid || null)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

빈 프로젝트 배열 시 selectedProjectIdundefined가 될 수 있습니다.

p[0]?.project_space_uuidundefined를 반환하면 || null로 폴백되지만, 타입 안전성을 위해 nullish coalescing(??)을 사용하는 것이 더 명확합니다.

🔧 nullish coalescing 사용
-        setSelectedProjectId(p[0]?.project_space_uuid || null)
+        setSelectedProjectId(p[0]?.project_space_uuid ?? null)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setSelectedProjectId(p[0]?.project_space_uuid || null)
setSelectedProjectId(p[0]?.project_space_uuid ?? null)
🤖 Prompt for AI Agents
In `@frontend/src/App.tsx` at line 42, The assignment to selectedProjectId uses a
logical OR that can mistakenly treat falsy but valid values as absent; update
the call to setSelectedProjectId so it uses nullish coalescing with the projects
array access (replace the expression p[0]?.project_space_uuid || null with
p[0]?.project_space_uuid ?? null) – modify the expression where
setSelectedProjectId(...) is invoked (refer to setSelectedProjectId and the
local variable p in App.tsx) to ensure undefined/null become null while
preserving legitimate falsy values.

Comment thread frontend/src/App.tsx
Comment on lines +107 to +111
<input
id="dev-user"
value={devUser}
onChange={(e) => setDevUser(e.target.value)}
placeholder="local"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

devUser 입력에 디바운싱 적용을 고려하세요.

현재 구현에서는 키 입력마다 devUser 상태가 변경되고 API 호출이 트리거됩니다. 빠른 타이핑 시 불필요한 네트워크 요청이 발생할 수 있습니다.

💡 디바운싱 예시
// useDeferredValue 또는 커스텀 debounce hook 사용
const deferredDevUser = useDeferredValue(devUser)

useEffect(() => {
  localStorage.setItem('devUser', deferredDevUser)
  // ... API calls
}, [deferredDevUser])
🤖 Prompt for AI Agents
In `@frontend/src/App.tsx` around lines 107 - 111, The input bound to devUser
(input id "dev-user" using value={devUser} and onChange={e =>
setDevUser(e.target.value)}) currently updates state on every keystroke and
causes immediate side effects; introduce debouncing by deriving a
deferred/debounced value (e.g., useDeferredValue(devUser) or a custom
useDebounce hook) and change any effects or API calls that currently depend on
devUser to depend on the debounced value instead (for example, move
localStorage.setItem and network requests into a useEffect watching the
deferred/debounced value) so rapid typing does not trigger repeated requests.

Comment thread README.md
docker compose -f compose.prod.yaml up -d --build
```

- Frontend: http://localhost:8080

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Bare URL을 Markdown 링크로 변환하세요.

markdownlint MD034 규칙에 따라, bare URL은 Markdown 링크 형식으로 감싸야 합니다.

📝 제안된 수정
-- Frontend: http://localhost:8080
+- Frontend: <http://localhost:8080>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Frontend: http://localhost:8080
- Frontend: <http://localhost:8080>
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 65-65: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In `@README.md` at line 65, Replace the bare URL in the README entry "Frontend:
http://localhost:8080" with a Markdown link to satisfy markdownlint MD034;
specifically update the line so the URL is wrapped as a link like Frontend:
[http://localhost:8080](http://localhost:8080) (or use a descriptive label
linking to http://localhost:8080) to remove the bare URL.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Superseded

I cannot push new commits to directly due to org ruleset (PR-only changes). To address the review/check blockers on this MVP, I created a follow-up PR against :

It includes:

  • python-jose min bump (CVE fixes)
  • idempotent member invites
  • migration backfill for created_by FK
  • CodeQL advanced workflow manual-only to avoid default-setup conflict
  • lifespan worker + React memo perf

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Superseded (note)

Org ruleset blocks direct pushes to protected branches; to address the review/check blockers I opened PR #8 against "main":

It includes: python-jose min bump (CVE fixes), idempotent member invites, migration backfill for created_by FK, CodeQL advanced workflow manual-only, lifespan worker, and React memo perf.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Closing as superseded by PR #8 (targets main and addresses review/check blockers).

@seonghobae seonghobae closed this Feb 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants