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>
22 lines
1.4 KiB
SQL
22 lines
1.4 KiB
SQL
-- 365_published.sql
|
|
-- 발행 레이어(docsrv-viewer-publish) projection 테이블. 뷰어가 read API로 당겨 자기 SQLite로 복제.
|
|
-- kind-discriminated 단일 테이블(study_question | study_explanation | ... 후속 news/document).
|
|
-- pub_id = opaque+stable(워커가 (kind,source_id)당 1회 부여, republish=rev bump에도 불변) = 뷰어 dedup키=progress키.
|
|
-- source_id = 내부 소스 행 id (pub_id→내부 역매핑, ingest write-back 해소용).
|
|
-- rev = 발행 워커 커밋순 gapless 커서(pg_advisory_lock 단일 라이터). 뷰어 feed = WHERE rev>since.
|
|
-- payload_hash = sha256(정렬 JSON). (payload_hash, deleted) 디둡 — no-op 재투영 억제, tombstone 보존.
|
|
-- deleted = tombstone(삭제/만료도 feed 1급 이벤트). schema_version = 엔벨로프 버전(미지원 가시거부).
|
|
CREATE TABLE IF NOT EXISTS published (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
kind VARCHAR(40) NOT NULL,
|
|
source_id BIGINT NOT NULL,
|
|
pub_id TEXT NOT NULL,
|
|
payload JSONB NOT NULL,
|
|
payload_hash TEXT NOT NULL,
|
|
schema_version SMALLINT NOT NULL DEFAULT 1,
|
|
rev BIGINT NOT NULL,
|
|
deleted BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|