Skip to content

Data Model: Article Processing

Feature: Article ProcessingDate: 2026-05-29

Entities

Article

Core record representing a scraped piece of content.

FieldTypeConstraintsNotes
idUUIDPK, auto-generated
urlstrNOT NULLOriginal URL
url_hashstrNOT NULL, UNIQUE, 64 charsSHA-256 of URL; primary dedup key
sourcestrNOT NULL"rss", "arxiv", "blog"
titlestrNOT NULL
contentstrNOT NULLFull article text
published_atdatetimenullableFrom feed/scraper
scraped_atdatetimenullableSet at persistence time
topic_idUUIDnullable, FK → Topic
metadatadictNOT NULL, default {}Arbitrary source metadata

Dedup key: url_hash (unique constraint at DB level).

State transitions:

  • Created → exists without Analysis → needs_analysis() = True
  • Created → Analysis saved → needs_analysis() = False

UrlHash

Value object. Not persisted directly — its .value is stored as Article.url_hash.

FieldTypeConstraints
valuestr64-char hex string (SHA-256 digest)

Invariants:

  • Cannot be created from an empty URL.
  • Must be exactly 64 hex characters.

ArticleOutcome

Enum. Not persisted — returned from ProcessScrapedArticleUseCase.execute().

ValueMeaning
NEWArticle was just created and saved
DUPLICATEArticle exists and already has an Analysis
DUPLICATE_NEEDS_ANALYSISArticle exists but has no Analysis
FAILEDSave attempt raised an exception

ArxivMetadata

Supplementary record for ArXiv-sourced articles only.

FieldTypeConstraintsNotes
idUUIDPK, auto-generated
article_idUUIDFK → Article, NOT NULL
arxiv_idstrnullablee.g. "2501.12345"
authorslist[str]NOT NULL, default []
pdf_availableboolNOT NULL, default False
sectionsdictNOT NULL, default {}Section name → text body

Lifecycle: Created once when a NEW ArXiv article is saved. Read back when a DUPLICATE_NEEDS_ANALYSIS ArXiv article is re-queued (sections merged into article.metadata["sections"]).


ArticleProcessedEvent

Application event. Not persisted — published on the in-memory event bus.

FieldTypeNotes
articleArticleThe newly saved or re-queued Article

Published when: ArticleOutcome is NEW or DUPLICATE_NEEDS_ANALYSIS. Not published when: ArticleOutcome is DUPLICATE or FAILED.

Relationships

Topic 1──────────────────────────────────────── * Article
                                                   |
                                                   │ 0..1

                                              ArxivMetadata

Article 1──────────────────────────────────── 0..1 Analysis
         (checked by DedupService.needs_analysis)