Technical documentation

TenderLens

Where things are in the code, how to run it and what was checked.
Version a618d1e7be8a · prepared on 7 September 2026

About the project

Search over a fixed document set. Answers need links to the source chunks. If there are no relevant matches, the response says so.

HTML is split into chunks and indexed through a queue. Search runs in pgvector; answers link to the retrieved chunks. The demo has four test documents. Embeddings and the LLM are mocked; the external crawler is disabled.

  • Four synthetic documents and 16 chunks form a demonstration corpus, not a database of real procurement records.
  • Cosine scores and template answers are not an evaluation of a production model's quality.
  • Up to 30 requests per minute per session and 1,000 active demo keys. User queries are not stored.
  • Worker health confirms the connection at startup; a separate stalled-computation detector is not implemented.

Screenshots, diagrams and source evidence retain their original language; captions and descriptions are translated.

Architecture and diagrams

  • Seed sends a real TenderChangedV1 event through NATS; the indexer extracts HTML and creates chunks.
  • PostgreSQL VECTOR(1024) performs cosine search. FakeAIProvider creates embeddings using the hashing trick.
  • Event replay uses content_hash: an unchanged document does not duplicate chunks.
  • Answers use an explicitly labeled template based on retrieved passages; the external crawler and Ollama are disabled.
Components of the published demo
Components of the published demo · Mermaid ↓
Main workflow
Main workflow · Mermaid ↓
Deployment of the published version
Deployment of the published version · Mermaid ↓
Data structure and storage boundaries
Data structure and storage boundaries · Mermaid ↓
Original project integrations. Disabled in the demo.
Original project integrations. Disabled in the demo. · Mermaid ↓

Code map: files and dependencies

This map is tied to version a618d1e7be8a. The table lists the screen or API, related module and data.

FeatureScreen / APIModuleData / verification
Initial indexingCLI portfoliocli._upsert_demo_record, NatsBroker, IndexerServicesources, tenders, attachments, chunks
Search / answerapi/v1/search, askSearchService, FakeAIProviderchunks VECTOR(1024)
Sourceslocal HTMLweb/demooriginal corpus
Event replayapi/demo/replayNatsBroker / hash guardshared read-only corpus
Session and rate limitcookie / middlewareportfolio, auth, rate_limitapi_keys (hash and counters only)

Using the code map

  1. Before making a change, find the feature and trace its links to the API, state and storage.
  2. Check inputs, errors, repeated events and dependent workflows.
  3. After making a change, update the map and affected diagrams alongside the code.
  4. Run the related checks and link the new evidence to the source version.

Workflows and API

  1. Find a document about servers or an Angular portal.
  2. Ask a question and open the answer's sources.
  3. Enter a query outside the corpus and check the missing-context response.
  4. Replay indexing events: the four documents and 16 chunks should remain without duplication.

Verification of the published version

CI: CI ↗ · 84c37f0f · historical run of a different version · 2026-08-27T06:43:00Z

CI: Documentation ↗ · 84c37f0f · historical run of a different version · 2026-08-27T06:43:00Z

  • 118 unit tests passed; 18 integration/external checks were excluded from this run.
  • Search and Ask return sources; unrelated query returns no context
  • Queue replay preserves 16 chunks and ready status
  • Independent signed expiring HttpOnly sessions
  • No verified GitHub CI run is available for this SHA; the listed evidence covers local checks and published-version scenarios. Historical CI links, where available, are labeled separately.

These checks apply to the listed version. Business metrics and model quality on an independent dataset were not measured.

Measurements

Total project container resources · 2026-09-07T01:08:27 — 01:11:22 UTC
Total project container resources · 2026-09-07T01:08:27 — 01:11:22 UTC · Source data ↓
Measured scenario repetitions over HTTPS · 2026-09-07T01:08:36 UTC; methodology limitations in JSON
Measured scenario repetitions over HTTPS · 2026-09-07T01:08:36 UTC; methodology limitations in JSON · Source data ↓
  • 12 meaningful screenshots of the actual interface retained.
  • Each screenshot includes its date, scenario and code revision.
  • Peak container RAM in the short test: 127.04 MiB. Shared services are counted separately; the shop includes its own database.
  • 6 scenario repetitions measured; median 997.0 ms, maximum 2738 ms. Timing includes the browser and HTTPS; methodology and limitations are included.
  • Four ready documents, 16 chunks. Replaying four NATS events created no duplicates.

Running and operating

The original project has a crawler and an AI provider integration. The demo disables live AI in its config and only accepts documents from the test corpus.

Dockerfile.portfolio is built outside the VPS; the API and worker share one pinned image with separate limits. PostgreSQL and NATS are accessible only on the internal network; the API is served through localhost:18403 and Nginx.

Run migrations and the portfolio seed CLI at startup. API readiness checks its dependencies. Reindexing is safe because of content_hash; after a restart, verify four ready documents and 16 chunks. Session ApiKeys expire by TTL and are cleaned up every five minutes.

Builds run outside the VPS; the server receives static files and versioned images. Secrets are kept separately. Logs rotate; changing log options requires recreating the container. No server-wide docker prune.

The code map links a screen or API to its module and data. A change needs those links checked, the map updated and the affected flows rerun: normal path, error, retry and reset. Diagrams can go stale, so their version is listed alongside them.

Rollback checked at 2026-09-07T01:04:24.534304+00:00: 20260907-verified → 20260907c → 20260907-verified. HTTPS, readiness and SHA were confirmed after each switch. This checks configuration and artifacts at one verified SHA; no reverse database migration was performed.

Stack

FastAPI / PydanticHTTP contracts, validation and search responses.
NATS JetStreamEvent delivery to the indexer and replay.
PostgreSQL / pgvectorDocuments, attachments, chunks and cosine search.
SQLAlchemy / PythonNormalization, extraction, chunking and content_hash verification.

Materials and source code

Implementation history: since 20 August 2026. Public demo: 7 September 2026.

The evidence archive retains its original language.