Skip to content

feat(notification): add service-owned data-rights contributor - #198

Open
seonghobae wants to merge 151 commits into
mainfrom
feat/notification-data-rights-contributor-v2
Open

feat(notification): add service-owned data-rights contributor#198
seonghobae wants to merge 151 commits into
mainfrom
feat/notification-data-rights-contributor-v2

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • compose a Notification-owned life-os.data-rights-contributor.v1 participant for tenant export, erasure preflight, erasure, and verification
  • add bounded deterministic export evidence that omits claim/idempotency hashes
  • add atomic replay-safe PostgreSQL erasure with service-owned receipts, advisory locking, UUIDv4 checks, SHA-256 evidence, and explicit privilege boundaries
  • preserve reminder-outcome immutability for ordinary callers while allowing only the owner-controlled erasure function to perform reviewed deletion
  • cover runtime composition, malformed evidence, bounded JSON, privilege blockers, replay migration invariants, and credential-free failure mapping

Test-first evidence

The branch preserves the initial RED contract commit d68a0c557bb42143690d07a6071887818f25df6a, which required production runtime composition before the implementation commit.

Branch lineage

This clean branch starts from protected main a56ccbf898d43208fc2f7fc6b591588109e60726 and supersedes the stale, incomplete, no-PR branch feat/notification-data-rights-contributor-v1, which only carried a migration based on an older main.

Advances #55 and the data-portability portion of #21. It does not close either issue because other service-owned contributors remain.

Summary by CodeRabbit

  • 새 기능

    • 알림 서비스에 데이터 권리 내보내기, 삭제 사전 점검·실행·검증 기능을 추가했습니다.
    • 테넌트 단위 데이터 삭제와 재시도 시 안전한 멱등 처리를 지원합니다.
    • 삭제 결과로 처리 건수와 SHA-256 증거를 제공합니다.
  • 보안

    • 요청 형식, 권한, 식별자 및 데이터 범위를 검증합니다.
    • 삭제 권한을 분리하고 민감한 데이터 접근을 제한했습니다.
  • 테스트

    • 정상 처리, 오류 상황, 권한 분리, 재실행 및 다른 테넌트 데이터 보호를 검증했습니다.

Open in Devin Review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Notification 서비스에 데이터 권리 contributor와 workspace 데이터 삭제 함수를 추가했습니다. 삭제 영수증, 멱등성, 권한 검증, mutation guard를 구현했습니다. 런타임 연결, 배포 권한 설정, 단위·계약·통합 테스트도 추가했습니다.

Changes

Notification 데이터 권리 처리

Layer / File(s) Summary
계약 및 요청 검증
apps/notification-service/src/notification-data-rights.ts, apps/notification-service/src/notification-data-rights.behavior.test.ts
버전화된 요청·응답 계약과 UUID, JSON, 정수, 권한, SHA-256 검증을 추가했습니다. SQL 오류와 잘못된 결과를 일반 오류로 처리합니다.
Export 및 런타임 연결
apps/notification-service/src/notification-data-rights.ts, apps/notification-service/src/notification-runtime.ts, apps/notification-service/src/notification-data-rights.test.ts
세 Notification 데이터 유형을 workspace 범위로 조회하고 정렬된 export 응답을 생성합니다. 삭제 사전 확인·실행·검증을 제공하고 contributor를 런타임에 연결합니다.
원자적 삭제 프로시저
apps/notification-service/migrations/0002_data_rights_erasure.sql, apps/notification-service/src/notification-data-rights-migration.test.ts
삭제 영수증과 트랜잭션별 삭제 권한을 추가했습니다. erase_workspace_data가 advisory lock, 멱등성, 삭제 순서, SHA-256 영수증을 처리합니다. mutation guard가 reminder outcome 변경을 제한합니다.
삭제 실행 및 통합 검증
apps/notification-service/src/notification-data-rights.integration.test.ts
통합 테스트가 재실행, 충돌, UUID 오류, tenant 격리 및 런타임 역할 권한을 확인합니다.
마이그레이션 및 런타임 권한 연결
.env.example, .github/workflows/deploy.yml, infra/kubernetes/run-migrations.sh, infra/tests/notification-migration-role.spec.ts, apps/notification-service/package.json
Notification 마이그레이션 URL과 런타임 역할을 배포 설정에 연결했습니다. 마이그레이션 역할과 런타임 역할의 권한 분리를 검증합니다. lint 스크립트는 Prettier 쓰기 모드를 사용합니다.

Estimated code review effort: 5 (Critical) | ~100 minutes

Mergeability Score: 🔵 Low · up to 909c5

The PR’s lint command can modify files outside src while still succeeding, which may create unnoticed repository changes. The PR is mergeable with explicit owner awareness and should follow up by making lint read-only or verifying all modified paths.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant NotificationRuntime
  participant NotificationDataRightsContributor
  participant PostgreSQL
  Client->>NotificationRuntime: 데이터 권리 요청 전달
  NotificationRuntime->>NotificationDataRightsContributor: handle(request) 호출
  NotificationDataRightsContributor->>PostgreSQL: export 또는 삭제 요청 실행
  PostgreSQL-->>NotificationDataRightsContributor: 데이터 또는 삭제 증거 반환
  NotificationDataRightsContributor-->>Client: 데이터 권리 응답 반환
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 81.25% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 Notification 서비스의 데이터 권리 기여자 추가라는 변경의 핵심을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/notification-data-rights-contributor-v2

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

❤️ Share

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

@seonghobae
seonghobae marked this pull request as ready for review August 12, 2026 08:43
coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the unchanged exact head b7bec140695a12eb39d537dacb3644581603daf1. Fresh source verification shows @life-os/notification-service lint is read-only (prettier --check, not write mode), so the current summary warning about lint mutating files is stale and must not be carried forward as a current-head finding. Review current-head code and tests only; predecessor findings/checks are evidence, not acceptance.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

requested_head='b7bec140695a12eb39d537dacb3644581603daf1'
actual_head="$(git rev-parse HEAD)"
printf 'HEAD=%s\nREQUESTED=%s\n' "$actual_head" "$requested_head"
git diff --check "${requested_head}^" "$requested_head"
git diff --name-status "${requested_head}^" "$requested_head"

printf '\n--- notification package lint ---\n'
jq -r '.scripts.lint // empty' apps/notification-service/package.json

printf '\n--- outlines ---\n'
ast-grep outline apps/notification-service/src/notification-data-rights.ts --items all
ast-grep outline apps/notification-service/src/notification-runtime.ts --items all

printf '\n--- migration sections ---\n'
cat -n apps/notification-service/migrations/0002_data_rights_erasure.sql

printf '\n--- contributor sections ---\n'
cat -n apps/notification-service/src/notification-data-rights.ts

printf '\n--- runtime sections ---\n'
cat -n apps/notification-service/src/notification-runtime.ts

printf '\n--- migration runner relevant sections ---\n'
rg -n -C 8 'apply_service_migrations|NOTIFICATION|runtime_role|GRANT|REVOKE' infra/kubernetes/run-migrations.sh

printf '\n--- test assertion map ---\n'
for f in \
  apps/notification-service/src/notification-data-rights.behavior.test.ts \
  apps/notification-service/src/notification-data-rights.integration.test.ts \
  apps/notification-service/src/notification-data-rights-migration.test.ts \
  apps/notification-service/src/notification-data-rights.test.ts \
  infra/tests/notification-migration-role.spec.ts
do
  echo "--- $f ---"
  ast-grep outline "$f" --items all
done

Length of output: 80049


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='b7bec140695a12eb39d537dacb3644581603daf1'
base="$(git merge-base "$head" origin/main 2>/dev/null || git merge-base "$head" main)"
printf 'MERGE_BASE=%s\n' "$base"
printf '%s\n' '--- complete PR files ---'
git diff --name-status "$base" "$head"
printf '%s\n' '--- complete PR diff check ---'
git diff --check "$base" "$head"

printf '%s\n' '--- data-rights authority code map ---'
fd -t f 'notification-data-rights' apps/notification-service/src
ast-grep outline apps/notification-service/src/notification-data-rights-authority-replay.ts --items all
cat -n apps/notification-service/src/notification-data-rights-authority-replay.ts

printf '%s\n' '--- existing notification migrations and schema references ---'
fd -t f -e sql . apps/notification-service/migrations | sort
rg -n -C 5 'CREATE TABLE.*(reminder_occurrences|reminder_outcomes|inbox_messages|data_rights_authority_replay)|CREATE (OR REPLACE )?FUNCTION|CREATE TRIGGER|ALTER.*OWNER|GRANT|REVOKE' apps/notification-service/migrations

printf '%s\n' '--- complete changed tests ---'
for f in \
  apps/notification-service/src/notification-data-rights.behavior.test.ts \
  apps/notification-service/src/notification-data-rights.integration.test.ts \
  apps/notification-service/src/notification-data-rights-migration.test.ts \
  apps/notification-service/src/notification-data-rights.test.ts \
  infra/tests/notification-migration-role.spec.ts
do
  echo "--- $f ---"
  cat -n "$f"
done

printf '%s\n' '--- deployment configuration and environment changes ---'
git diff --unified=80 "$base" "$head" -- .env.example .github/workflows/deploy.yml infra/kubernetes/run-migrations.sh apps/notification-service/package.json

printf '%s\n' '--- runtime references to contributor and replay guard ---'
rg -n -C 4 '\b(dataRightsContributor|dataRightsAuthorityReplayGuard|NotificationDataRightsContributor|PostgresNotificationDataRightsAuthorityReplayGuard)\b' --glob '*.ts' .

Length of output: 177345


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- HTTP and controller source maps ---'
for f in \
  apps/notification-service/src/notification-data-rights-controller.ts \
  apps/notification-service/src/notification-data-rights-http-boundary.ts \
  apps/notification-service/src/notification-http.ts \
  apps/notification-service/src/server.ts \
  packages/contracts/src/data-rights.ts
do
  echo "--- $f ---"
  ast-grep outline "$f" --items all
  cat -n "$f"
done

printf '%s\n' '--- focused authority and HTTP tests ---'
for f in \
  apps/notification-service/src/notification-data-rights-controller.test.ts \
  apps/notification-service/src/notification-data-rights-http-boundary.test.ts \
  apps/notification-service/src/notification-http.test.ts \
  apps/notification-service/src/server.test.ts \
  apps/notification-service/src/notification-data-rights-authority-replay.test.ts \
  apps/notification-service/src/notification-data-rights-authority-replay.integration.test.ts \
  apps/notification-service/src/notification-data-rights-pagination.test.ts \
  apps/notification-service/src/notification-data-rights-preflight-regression.test.ts \
  apps/notification-service/src/notification-data-rights-preflight-verification.test.ts
do
  echo "--- $f ---"
  cat -n "$f"
done

printf '%s\n' '--- data-rights endpoint and authority helper definitions ---'
rg -n -C 5 'verifyDataRights|authorityClaimDigest|verify.*Authority|data-rights/contributor|NOTIFICATION_DATA_RIGHTS_CONTEXT_SECRET' \
  apps packages --glob '*.{ts,js,mjs}'

printf '%s\n' '--- migration 0003 and runtime provisioning ---'
cat -n apps/notification-service/migrations/0003_data_rights_authority_replay.sql
cat -n infra/postgres/provision/notification-runtime.psql

printf '%s\n' '--- CI changes and package workspace commands ---'
git diff --unified=50 f8559bf31dc098bdd58473747805a229bf860cc7 b7bec140695a12eb39d537dacb3644581603daf1 -- .github/workflows/ci.yml packages/contracts/src/data-rights.ts packages/contracts/src/data-rights-contract.typecheck.ts

Length of output: 167208


@seonghobae Review complete for b7bec140695a12eb39d537dacb3644581603daf1.

I found no current-head findings.

I verified that @life-os/notification-service lint uses prettier --check. It is read-only. I did not carry forward the stale lint write-mode warning.

I reviewed the full PR diff from merge base f8559bf31dc098bdd58473747805a229bf860cc7. This included the Notification contributor, erasure and replay migrations, runtime-role privileges, HMAC-bound HTTP boundary, replay guard, runtime composition, and focused tests.

git diff --check passed. The sandbox could not execute repository tests.

You are interacting with an AI system.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.


/** Creates the same least-privilege replay-table grant required from deployment. */
async function grantRuntimeReplayAuthority(pool: Pool): Promise<void> {
await pool.query(`
application_name: 'life-os-notification-replay-admin',
max: 2,
});
await administrativePool.query(`DO $$
.query('DROP SCHEMA IF EXISTS notification_service CASCADE')
.catch(() => undefined);
await administrativePool
.query(`DROP OWNED BY ${RUNTIME_ROLE}`)
.query(`DROP OWNED BY ${RUNTIME_ROLE}`)
.catch(() => undefined);
await administrativePool
.query(`DROP ROLE IF EXISTS ${RUNTIME_ROLE}`)
);
}

/** Requires one ordinary JSON object so prototypes cannot add hidden authority fields. */
await expect(
bootstrapNotificationService(
{
NOTIFICATION_DATABASE_URL: 'postgresql://runtime.invalid/life_os',
await expect(
bootstrapNotificationService(
{
NOTIFICATION_DATABASE_URL: 'postgresql://runtime.invalid/life_os',
await expect(
bootstrapNotificationService(
{
NOTIFICATION_DATABASE_URL: 'postgresql://runtime.invalid/life_os',
\gexec

ALTER ROLE :"runtime_role"
WITH LOGIN PASSWORD :'runtime_password'
'${NOTIFICATION_RUNTIME_DATABASE_PASSWORD:?Set NOTIFICATION_RUNTIME_DATABASE_PASSWORD}',
);
expect(legacyUpgrade).toContain("POSTGRES_PASSWORD must not remain 'lifeos'");
expect(legacyUpgrade).toContain("ALTER ROLE lifeos PASSWORD :'next_admin_password';");
devin-ai-integration[bot]

This comment was marked as resolved.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

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

Devin Review found 2 new potential issues.

Devin Review

Comment thread infra/postgres/provision/upgrade-legacy-local.sh

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

Devin Review

Comment thread infra/postgres/provision/upgrade-legacy-local.sh
Comment thread infra/postgres/provision/upgrade-legacy-local.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants