642c1b7c36
docsrv-viewer-publish 발행 인프라 — 뷰어가 read API로 당길 published projection + transactional outbox + 단일 라이터 발행 워커. study_publish_enabled=false 기본 (저자/4-A enqueue 결선 P0-1b 전까지 inert). read-only 경로·additive·소프트락 무관. - migrations 365~370: published(kind·pub_id opaque+stable·rev·payload_hash·deleted·schema_version) + UNIQUE(kind,pub_id)/(kind,source_id) + rev idx + publish_outbox + 미처리 부분 idx - models/published.py: Published·PublishOutbox (관계 없음=mapper 안전) - services/study/publish_projection.py: project_question/explanation + payload_hash(정렬 sha256) - services/study/publish_enqueue.py: enqueue_publish/question + backfill(bounded page) - workers/study_publish_worker.py: outbox drain → pg_advisory_xact_lock 단일라이터 rev 부여 + (payload_hash,deleted) 디둡 + 배치내 중복 flush - config: study_publish_enabled(기본 false) · main: publish_outbox_consumer 1m max_instances=1 plan: plans/2026-06-23-study-to-viewer-slice1-plan.html (P0-1, 3R 적대리뷰 통과) 검증: py_compile·payload_hash 단위·마이그 1문/파일·매퍼 standalone. 전체 매퍼/마이그 apply=배포 게이트. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
16 lines
823 B
SQL
16 lines
823 B
SQL
-- 369_publish_outbox.sql
|
|
-- transactional outbox — 저작/4-A 트랜잭션이 같은 tx에서 여기 INSERT(P0-1 규율),
|
|
-- 단일 발행 워커가 id(커밋순) 순으로 drain 하며 published 에 rev 부여(소스 updated_at 폴링 금지=갭 재발).
|
|
-- processed_at = 워커 drain 시 스탬프(NULL=미처리). payload/hash 는 enqueue 시점 스냅샷.
|
|
CREATE TABLE IF NOT EXISTS publish_outbox (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
kind VARCHAR(40) NOT NULL,
|
|
source_id BIGINT NOT NULL,
|
|
payload JSONB NOT NULL,
|
|
payload_hash TEXT NOT NULL,
|
|
schema_version SMALLINT NOT NULL DEFAULT 1,
|
|
deleted BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
processed_at TIMESTAMPTZ
|
|
);
|