Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in
  • I intern-homework-was
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
    • Locked files
  • Issues 2
    • Issues 2
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 1
    • Merge requests 1
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Terraform modules
  • Monitor
    • Monitor
    • Metrics
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • mingyeong.cha
  • intern-homework-was
  • Issues
  • #6
Closed
Open
Issue created Sep 22, 2026 by mingyeong.cha@mingyeong.chaOwner

[feat] 대화 생성 API, ACL

name: Feature Request
labels: 'Type : Feature'

기능 요약

대화 생성, 조회 API와 PostgreSQL RLS 기반 공유 범위(ACL)를 추가한다.

상세 설명

대화 API

  • 대화 생성 POST /api/conversations
    • 팀 귀속(teamId)은 선택. 공유 상태는 항상 PRIVATE으로 시작
    • 귀속은 생성 후 변경할 수 없다 (DB 트리거로 고정)
  • 내 대화 목록 GET /api/conversations
    • updated_at 내림차순
  • 대화 + 메시지 이력 GET /api/conversations/{conversationId}
    • 메시지는 seq 순서로 복원
    • 볼 수 없으면 404 (403이 아니다 — 존재 여부를 알리지 않음)
  • 공유 상태 전환 PATCH /api/conversations/{conversationId}/visibility
    • 소유자만 가능 (아니면 403 NOT_CONVERSATION_OWNER)
    • PRIVATE(나만) / TEAM(팀 전체)
    • TEAM은 팀에 귀속된 대화만 가능 (아니면 400 CONVERSATION_NOT_TEAM_SCOPED)
  • 검색 폭 변경 PATCH /api/conversations/{conversationId}/retrieval-scope
    • OWN ⊂ CONVERSATION_TEAM ⊂ ALL (기본값)
    • 권한 기능이 아니라 RAG 검색 폭이다. 권한과 교집합으로 적용된다

RLS 기반 접근 제어 (acl 패키지)

  • 권한 판정을 애플리케이션이 아니라 DB 정책(RLS)이 한다
    • conversations·messages에 RLS + FORCE ROW LEVEL SECURITY
    • 정책: conv_select, conv_insert, conv_update, msg_select, msg_insert
    • acl_scope 생성 컬럼(compute_acl_scope)과 인덱스로 판정
  • 요청마다 범위를 계산해 커넥션에 주입 (캐싱하지 않음 - 팀 제거 즉시 차단되어야 함)
    • ScopeResolver → ScopeContext(GUC 5개) → AclContextInjector
    • AclContextAspect가 트랜잭션 진입 직후 주입. AclTransactionConfig로 트랜잭션을 바깥(order 0), 애스펙트를 안쪽(order 100)에 두어 set_config가 버려지지 않게 한다
    • AclScope는 DB의 compute_acl_scope()와 문자열이 일치해야 한다
    • AclContextOverride는 인증이 없는 경로(시드·테스트 픽스처) 전용
  • 개별 공유(share): ShareGrant, Permission, ResourceType
    • visibility와 독립이며 합집합. 회수는 soft(revokedAt)이고 재부여는 같은 행을 되돌린다

스키마 적용 순서

  1. schema.sql (ddl-auto 이전)
  2. ddl-auto 테이블 생성
  3. SchemaPostProcessor(@Order(100)) → post-schema.sql: 생성 컬럼·트리거·RLS·정책
  4. DevDataSeeder(@Order(200)): 사용자·팀 생성 후 AclContextOverride.runAs로 대화 시드
    • RLS 대상 테이블 쓰기는 SeedWriter로 분리 (애스펙트가 메서드 진입 시 돌기 때문)
sequenceDiagram
    autonumber
    participant C as 클라이언트
    participant TX as 트랜잭션 어드바이저<br/>(order 0 · 바깥)
    participant AS as AclContextAspect<br/>(order 100 · 안쪽)
    participant SR as ScopeResolver
    participant IN as AclContextInjector
    participant DB as PostgreSQL

    C->>TX: @Transactional 서비스 호출
    TX->>DB: BEGIN
    Note over TX,AS: 순서가 뒤집히면 set_config 가<br/>트랜잭션 밖에서 돌아 조용히 버려진다
    TX->>AS: 트랜잭션 안에서 실행
    AS->>SR: resolve()
    SR->>DB: team_members 조회 (내 팀)
    SR->>DB: share_grants 조회 (대화·문서 Grant)
    SR-->>AS: ScopeContext (GUC 5개)
    AS->>IN: injectCurrent()
    IN->>DB: set_config(app.*, LOCAL=true) × 5
    AS->>DB: 실제 쿼리
    DB-->>AS: RLS 정책이 걸러낸 행만
    TX->>DB: COMMIT (GUC 도 함께 사라짐)

오류 코드 추가

  • CONVERSATION_NOT_FOUND(404), NOT_CONVERSATION_OWNER(403), CONVERSATION_NOT_TEAM_SCOPED(400), NOT_TEAM_MEMBER(403)

참고 자료

  • PostgreSQL Row Security Policies
  • AOP의 개념과 @Aspect
Edited Sep 22, 2026 by mingyeong.cha
Assignee
Assign to
Time tracking