Contract Renewal & Deadline Tracker is a backend that turns contract information into verifiable tracking dates. It accepts documents, proposes facts with source evidence, and requires human review before scheduling reminders.
An extracted date alone is not enough to decide when to notify someone. The system must identify the current term end, renewal type, and notice period, resolve ambiguity, and preserve the reasoning behind each decision.
From document to reviewed fact#
The workflow starts with a text PDF or an Excel workbook. For PDFs, the system detects duplicates by content and runs parsing in a bounded subprocess. In Excel, each row represents a contract and evidence retains references to original cells; the entire workbook is validated before the import is committed.
Review focuses on four facts: counterparty, current term end, renewal type, and notice period. Extraction proposes values; an operator confirms or corrects them with evidence. Missing facts and unsupported clauses remain visible.
PDF or Excel → evidence → human review → dates → reminder
This separation prevents an extraction suggestion from immediately becoming an operational decision.
A modular backend with clear responsibilities#
The API uses FastAPI. PostgreSQL stores metadata, normalized text, findings, reviewed facts, alerts, and audit records. SQLAlchemy models persistence and Alembic manages migrations; original files live in a configured directory or volume.
The API and periodic worker share the domain model and database. Modules separate document intake, extraction, review, date arithmetic, and alert publication. An independent webhook service handles HTTP transport.
The current interface is the API with OpenAPI. Docker Compose starts PostgreSQL and the API; the worker runs as a separate process. This architecture supports the local scope without introducing another queue for contract tracking.
Review and audit in one transaction#
A review locks the contract, checks its version, and updates canonical facts alongside an append-only audit history. The same transaction cancels obsolete reminders that have not yet been sent.
Version checks detect stale reviews. The transaction prevents a correction from being saved without its audit record or leaving a pending alert based on earlier facts.
Dates and idempotency#
Calculations use calendar days and distinguish the notice deadline from the reminder date. A configurable offset determines how far in advance the reminder is scheduled. Business-day clauses are not automatically converted into calendar-day deadlines.
The worker uses the same contract lock and a PostgreSQL uniqueness constraint to preserve one logical alert across repeated or concurrent runs. Publication identity survives retries, and failures remain visible.
This guarantee has a specific boundary: one alert in the database does not guarantee one external receipt. The webhook service handles transport retries, and the receiver needs deduplication. Without that service configured, the worker creates logical alerts but does not send them.
Documented verification#
The repository includes automated coverage for API review, migrations, transaction boundaries, date arithmetic, and worker idempotency. It also documents startup and restart checks that preserved the database and original PDFs, plus signed HTTP receipt after an injected receiver failure and retry.
Two load runs processed 1,000 generated PDFs each with two concurrent uploads, zero ingestion errors, and throughput of 201–210 PDFs per minute. These figures cover one-to-five-page test documents: they measure that ingestion scenario, not extraction accuracy on real contracts.
The acceptance evidence, execution walkthrough, and load measurements document the scope of those checks.
Scope and lessons#
The project implements a local API and review workflow. OCR, a dedicated frontend, multi-user authentication, and broad contractual-language coverage are outside its implemented scope. Reviewer identity is self-declared, history is not paginated, and per-process parser limits do not establish a service-wide concurrency budget.
The main lesson is to separate guarantees: extraction is not confirmation, confirmation is not delivery, and persisting an alert does not mean delivering it exactly once. Modeling these boundaries makes it possible to preserve evidence, correct decisions, and recover from failures while keeping the system's limitations visible.
Code and documentation are available in the Contract Renewal repository.

