Architecture

معماری Core API

مستند زنده معماری پیاده‌سازی‌شده: monolith ماژولار Django، مرز workerها، outbox/inbox، projection گردش‌کار پرونده، layering عمل‌گرا و topology Docker فعلی.

اجزای اصلی

Core مالک داده محصول و orchestration است. workerهای AI، RabbitMQ و Object Storage وابستگی‌های بیرونی این repository هستند.

جزء نقش رابط رفتار مهم
Django REST API مالک پرونده، RBAC، orchestration و projection وضعیت گردش‌کار /api/v1/* · SSE workflow-events Monolith ماژولار با DRF؛ viewها نازک و منطق در services/selectors/policies.
capabilities کاتالوگ قابلیت، workflow version، ProductFeature و projection ناوبری apps.capabilities · workflow_projection CaseModuleInstance + trusted substep providers؛ ADR-0011 تا ADR-0013.
PostgreSQL منبع حقیقت داده‌های محصول و جداول outbox/inbox Core DB OutboxEvent و InboxEvent در common؛ workerها هرگز مستقیماً به DB Core نمی‌نویسند.
Outbox publisher انتشار durable رویدادهای درخواست به RabbitMQ command: outbox-publisher از OutboxEvent خوانده و document/context/prior-art requested را publish می‌کند.
Inbox consumers مصرف رویدادهای completed/failed/questions_required از workerها document/context/prior-art inbox consumers InboxEvent را idempotent پردازش و state محصول (summary، snapshot، executions) را به‌روز می‌کند.
Object Storage (S3/Ceph) فایل اصلی، متن نرمال‌شده و artifactهای worker OBJECT_STORAGE_* · apps.common.storage آداپتر provider-neutral؛ کلید artifact در رویدادها منتقل می‌شود نه payload حجیم.
Information Extraction worker پارس سند، OCR/ASR، chunking و متن نرمال‌شده queue: document.extraction.requested محلی: extraction-mock؛ تولید: worker مستقل. Core فقط orchestrate و summary را نگه می‌دارد.
Context Extraction worker استخراج InventionContext و چرخه سؤال‌های تکمیلی queue: context.extraction.requested محلی: context-extraction-mock یا ai-workflow؛ snapshot در inbox Core پایدار می‌شود.
Prior-Art workers جستجو و گزارش پیشینه فنی prior_art.search/report.requested ai-workflow یا prior-art-mock؛ Core مالک PriorArtRun و artifact pointerهاست.
RabbitMQ اتوبوس رویداد بین Core و workerهای بیرونی exchange: patent_genie.events · DLX: patent_genie.dlx Topic exchange؛ صف‌های durable؛ reject خطای مدیریت‌نشده به DLQ.
Redis / Celery کش و jobهای async داخلی Core (نه مسیر اصلی workerهای AI) CELERY_BROKER_URL استخراج/context/prior-art از outbox/inbox عبور می‌کنند، نه Celery به‌عنوان مسیر اصلی.

مرز سرویس در پلتفرم

core-api مالک پرونده، workspace، RBAC، projection وضعیت گردش‌کار و orchestration کارهای AI است. workerهای بیرونی فقط محاسبه می‌کنند و از RabbitMQ + Object Storage با Core یکپارچه می‌شوند.

  • Frontend از REST و SSE (workspace-navigation، workflow-state، workflow-events، conversation stream) با Core صحبت می‌کند.
  • Core هرگز مدل Django workerها را import نمی‌کند و workerها هرگز مستقیماً به PostgreSQL Core نمی‌نویسند.
  • فایل اصلی در S3 ذخیره می‌شود؛ رویداد درخواست فقط metadata و کلید artifact را حمل می‌کند.
  • ناوبری سلسله‌مراتبی UI از GET .../workspace-navigation/ و GET .../workflow/steps/{step_key}/substeps/ تغذیه می‌شود (ADR-0012).
  • workflow-state و workflow-events برای polling/SSE سازگار باقی می‌مانند؛ readiness endpointها برای tooling هستند.
  • ماژول‌های آینده (stages، entitlements، packages، exports) فقط پس از vertical slice واقعی نصب می‌شوند.
flowchart TB
  frontend["Frontend MVP"]
  core["core-api<br/>Django modular monolith"]
  db[("PostgreSQL<br/>OutboxEvent · InboxEvent")]
  store[("S3 / Ceph<br/>source + artifacts")]
  rmq[("RabbitMQ<br/>patent_genie.events")]

  frontend -->|"REST + SSE"| core
  core --> db
  core --> store
  core -->|"OutboxEvent"| rmq

  subgraph workers ["Workerهای بیرونی"]
    ie["Information Extraction<br/>extraction-mock"]
    ctx["Context Extraction<br/>ai-workflow / mock"]
    pa["Prior-Art<br/>ai-workflow / mock"]
  end

  rmq --> ie & ctx & pa
  store -->|"read/write artifacts"| ie & ctx & pa
  ie & ctx & pa -->|"completed / failed / questions_required"| rmq
  rmq -->|"InboxEvent"| core

Monolith ماژولار Django

هر Django app یک bounded context است: models برای schema، services برای mutation، selectors برای read، policies برای authorization. وابستگی بین appها یک‌طرفه است.

  • apps نصب‌شده: common، accounts، organizations، workspaces، access_control، invention_cases، capabilities، documents، internal_context، prior_art، workflow_products، conversations، workflows، audit.
  • capabilities مالک کاتالوگ Capability، WorkflowDefinitionVersion، ProductFeature و CaseModuleInstance است (ADR-0011/0013).
  • common فقط زیرساخت generic دارد: storage، messaging، OutboxEvent، pagination، SSE helpers.
  • نوشتن cross-app از service API مالک انجام می‌شود؛ import مدل app دیگر برای mutation ممنوع.
  • audit append-only است و از services حساس emit می‌شود؛ operational_logs هنوز app جدا نیست.
  • نمودار ORM زنده در /models/graph/ تمام مدل‌های نصب‌شده را نشان می‌دهد.
flowchart TB
  common["common<br/>storage · messaging · outbox"]
  accounts["accounts"]
  orgs["organizations"]
  workspaces["workspaces"]
  access["access_control"]
  cases["invention_cases"]
  caps["capabilities<br/>features · modules · projection"]
  docs["documents"]
  ctx["internal_context"]
  pa["prior_art"]
  wfprod["workflow_products"]
  conv["conversations"]
  runs["workflows"]
  audit["audit"]

  common --> accounts & workspaces & orgs
  accounts --> workspaces
  workspaces --> access
  access --> cases & docs & ctx & pa
  cases --> caps
  caps --> docs & ctx & pa
  cases --> wfprod
  wfprod --> conv & runs
  audit -.->|"emit from services"| cases & docs & ctx & pa

مسیر ناهمزمان (Outbox / Inbox)

Mutation در transaction Django یک OutboxEvent می‌سازد. sidecar outbox-publisher به RabbitMQ publish می‌کند. inbox consumerها رویداد terminal worker را idempotent در PostgreSQL Core اعمال می‌کنند.

  • document.extraction.requested پس از آپلود SourceDocument؛ completed/failed در document-extraction-inbox-consumer.
  • context.extraction.requested با کلید artifact متن نرمال‌شده؛ questions_required برای Q&A تکمیلی.
  • prior_art.search.requested و prior_art.report.requested جداگانه؛ report پس از search.completed orchestrate می‌شود.
  • رویدادهای context ممکن است snapshot inline داشته باشند؛ prior-art فقط pointer + manifest برمی‌گرداند.
  • schema_version در envelope رویداد؛ consumer نامعتبر را reject و به DLQ می‌فرستد.
  • پس از inbox، CaseWorkflowEvent و revision ناوبری/workflow-state برای invalidate کردن کش frontend bump می‌شود.
flowchart LR
  api["Django API<br/>service + transaction"]
  outbox[("OutboxEvent")]
  pub["outbox-publisher"]
  ex[("patent_genie.events")]
  worker["External worker"]
  inbox[("InboxEvent")]
  cons["inbox consumer"]
  state["Product state<br/>summary · snapshot · executions"]

  api --> outbox --> pub --> ex --> worker
  worker --> ex --> inbox --> cons --> state

Case Workflow و SSE

CaseWorkflowStateService projection واحد UI را از intake، context و prior-art می‌سازد. CaseWorkflowEvent + SSE revision bump برای به‌روزرسانی زنده frontend.

  • information_collection از SourceDocument + DocumentProcessingSummary تغذیه می‌شود.
  • context_completion از internal_context runs/snapshots/questions می‌آید.
  • prior_art_collection از PriorArtRun و search/report executions.
  • InventionCase.current_stage اشاره‌گر legacy مرحله است؛ پیشرفت محصول از CaseModuleInstance و capabilities مشتق می‌شود (ADR-0011).
  • POST transition-stage حذف شده است؛ tooling از GET progress و projectionها استفاده می‌کند.
  • WorkflowRun و Conversation لایه product shell هستند؛ source of truth دامنه در invention_cases / documents / prior_art می‌ماند.
flowchart TB
  ui["Case Workflow UI"]
  sse["GET .../workflow-events/<br/>SSE"]
  state["GET .../workflow-state/"]
  svc["CaseWorkflowStateService"]
  intake["DocumentProcessingSummary"]
  context["Context runs / snapshots"]
  prior["PriorArtRun / executions"]
  modules["CaseModuleInstance"]

  ui --> state & sse
  state --> svc
  intake & context & prior & modules --> svc
  svc -->|"revision bump"| sse --> ui

ناوبری سلسله‌مراتبی و Product Features

Frontend ناوبری پرونده را از projectionهای نرمال‌شده می‌گیرد، نه از اسمبلی سخت‌کدشده. ProductFeature نسخه‌بندی‌شده substepها را تعریف می‌کند؛ trusted providers مدل دامنه را به DTO تبدیل می‌کنند (ADR-0012/0013).

  • GET .../workspace-navigation/ مراحل سطح‌بالا + feature {key, version} + revision را برمی‌گرداند.
  • GET .../workflow/steps/{step_key}/substeps/ زیرمراحل یک step را از FeatureSubstepBinding و providerها می‌سازد.
  • Providerها فقط با کلید trusted در کد ثبت می‌شوند؛ مسیر import پایتون در DB ذخیره نمی‌شود.
  • زیرمراحل پویا (مثلاً DraftDocumentSection) فقط metadata دارند؛ محتوای ProseMirror در projection نیست.
  • CaseModuleInstance تنها runtime instance برای step/feature است؛ جدول عمومی CaseSubstepInstance وجود ندارد.
  • SSE با event_type و revision کش navigation و substeps را هدفمند invalidate می‌کند.
flowchart TB
  shell["Frontend case workspace"]
  nav["GET .../workspace-navigation/"]
  sub["GET .../steps/{step_key}/substeps/"]
  proj["WorkflowNavigationProjectionService"]
  reg["Trusted provider registry"]
  feat["ProductFeatureVersion<br/>+ FeatureSubstepBinding"]
  mod["CaseModuleInstance"]
  domain["Domain models<br/>docs · context · prior_art · draft sections"]

  shell --> nav & sub
  nav & sub --> proj
  proj --> feat & mod & reg
  reg --> domain
  proj -->|"normalized DTOs + revision"| shell

Clean Architecture عمل‌گرا

بدون ceremony DDD: view نازک، service برای workflow، selector برای read، policy برای authorization. mutation حساس حتماً audit emit می‌کند.

  • accounts: JWT + UserSession؛ workspaces/access_control: RBAC و CaseAccessGrant.
  • documents: WorkspaceDocument + SourceDocument + extraction + DraftDocument/template metadata.
  • capabilities: catalog، feature versions، workflow projection؛ بدون import مدل worker.
  • internal_context: opaque snapshot payload؛ Core schema worker را mirror نمی‌کند.
  • prior_art: staleness وقتی snapshot جدید ready شود؛ policies قبل از start/retry.
  • API responses UUID عمومی expose می‌کنند؛ workspace scoping در selectors پیش‌فرض است.
flowchart LR
  req["HTTP request"]
  view["View / Serializer"]
  policy["Policy"]
  service["Service"]
  selector["Selector"]
  model[("Django Model")]
  audit["audit service"]

  req --> view --> policy
  view --> selector --> model
  view --> service --> model
  service --> audit

استقرار Docker Compose

Compose سرویس api، sidecarهای outbox/inbox، PostgreSQL و Redis را از یک image می‌سازد. RabbitMQ و S3 از stack infra روی شبکه patent-genie-local در دسترس هستند.

  • سرویس‌ها: api، outbox-publisher، document-extraction-inbox-consumer، context-extraction-inbox-consumer، prior-art-inbox-consumer.
  • Celery worker اختیاری برای jobهای داخلی؛ مسیر اصلی AI از RabbitMQ sidecarها عبور می‌کند.
  • تست‌ها OBJECT_STORAGE_BACKEND=local_filesystem؛ بدون نیاز به ceph-rgw.
  • extraction-mock، context-extraction-mock و ai-workflow/prior-art-mock برای E2E محلی.
  • مستندات زنده: BACKEND_ARCHITECTURE.md، service-boundaries.md، lifecycle و ADRهای 0001–0013.
flowchart TB
  subgraph compose ["core-api docker-compose"]
    api["api<br/>Django + DRF + SSE"]
    pub["outbox-publisher"]
    dInbox["document-extraction-inbox-consumer"]
    cInbox["context-extraction-inbox-consumer"]
    pInbox["prior-art-inbox-consumer"]
    pg[("PostgreSQL")]
    redis[("Redis")]
  end
  net[["patent-genie-local"]]
  rmq[("RabbitMQ")]
  s3[("S3 / Ceph")]
  workers["extraction / context / prior-art workers"]

  api --> pg & redis
  pub & dInbox & cInbox & pInbox --> pg
  api & pub & dInbox & cInbox & pInbox --- net
  net --- rmq & s3
  pub --> rmq
  rmq --> workers --> s3
  rmq --> dInbox & cInbox & pInbox

Patent Genie Core API · Django modular monolith