Tender platform ingestion and alerts

CLIENT

Achizito

TECHNOLOGIES

  • TypeScript
  • Node.js
  • RabbitMQ
  • Redis
  • .NET
  • CQRS

WEBSITE

Preview

Case studies

Other usecases

Description

Achizito helps companies win Romanian public tenders by tracking notices published on SEAP and alerting users as soon as something relevant appears.

The product promise is simple and strict: real time alerts in under one second. If an alert is late, the customer loses bidding time.

This engagement focused on keeping the ingestion edge separate from the core domain model so the team could move fast on source intake while the modular monolith stayed clean and predictable.

Key achievements:

  • Sub second alert flow from source update to alert dispatch
  • Node.js ingestion reuse from an existing project the team already had
  • Modular monolith boundaries preserved in the .NET core domains
  • RabbitMQ based event flow between ingestion and business domains
  • Redis based caching for LLM and repeated lookups
  • Single database for speed and consistency across the platform

Original context

The platform is a .NET modular monolith with Procedures, Documents, Requirements, Notifications, and Analytics.

Solution approach

SEAP public sourcesRabbitMQ QueueRedis CacheCore systemsDomain modulesTypeScript Ingestion Edge (Node.js).NET Modular MonolithProceduresDocumentsRequirementsNotificationsAnalytics

1. Reuse the Node.js ingestion project

We found an existing Node.js ingestion project that already solved the source intake problem, so we reused it as the ingestion edge.

That let us focus on integration, module boundaries, and event flow instead of rebuilding source intake from scratch.

2. Keep the .NET modular monolith as the domain model

The core stays as one modular monolith.

Each domain owns its own rules and data, and the business logic stays in one place where the team can reason about it.

3. Use RabbitMQ for real time handoff

The ingestion edge sends real time work through RabbitMQ queues.

That gives the platform a clean boundary between intake and processing.

4. Use Redis for repeated reads

Redis is used to cache LLM-related data and repeated reads that do not need to hit the core every time.

That keeps the platform responsive while the core continues to own the business truth.

5. Single database on purpose

The platform keeps one shared database on purpose.

That gives the team faster development, simpler querying, and a consistent view across ingestion and core domains.

The modules still keep separate responsibilities in code. The shared database is only the practical persistence layer that lets the monolith stay simple to evolve.

6. Explicit division of responsibilities

ConcernOwner
Ingesting SEAP updates and normalizationTypeScript / Node.js
Queueing and real time handoffRabbitMQ
Subscriptions and business rules.NET
Market analytics.NET
AI extraction and eligibility.NET + Microsoft Agent Framework
Notification policy and delivery decisions.NET

The TypeScript ingestion edge owns intake behavior. The .NET core owns the domain model, analytics, and decisioning.

Requirements and domain interaction

The platform needed a few non-negotiable behaviors:

  • Alerts must be generated quickly enough to preserve bidding time.
  • Ingestion must stay separate from procurement rules.
  • Analytics must remain consistent with the same procedure data that drives alerts.
  • Notifications must be driven by domain behavior, not by raw source noise.
  • AI workflows must stay in the core where procedure, requirement, and notification context already exists.

The important point is that ingestion feeds the model, but does not absorb it.

Modular monolith boundaries

The core is split into clear subdomains with separate responsibilities:

  • Procedures - the main procurement lifecycle and state of a tender.
  • Documents - procedure files, attachments, and extracted content.
  • Requirements - matching and evaluation of what the procedure asks for.
  • Notifications - alert decisions and delivery triggers.
  • Companies - business entities and their identity in the platform.
  • Analytics - reporting, trends, and market intelligence.

These subdomains do not call each other directly for business changes. They interact through domain events, which keeps each responsibility narrow and makes the modular monolith easier to change safely.

Ingestion EdgeRabbitMQProceduresDocumentsRequirementsNotificationsCompaniesAnalyticsRedis Cache

Results

OutcomeImpact
Real time alertingIngestion remains optimized for low-latency source updates
Domain clarityCore business logic stays in explicit .NET bounded contexts
Coupling reductionIngestion and core interact through queues and shared domain contracts
MaintainabilityTypeScript ingestion can evolve independently from core domain rules
Platform resilienceDomain boundaries make failures easier to isolate and recover

Conclusions

This project delivered real-time procurement alerts for a tender platform while improving domain boundaries instead of eroding them. The architecture balances ingestion speed, modular ownership, and long-term maintainability.

The next phase is controlled evolution: keep the modular monolith clean, keep the single database as the practical source of truth, and preserve sub-second user-facing alert behavior.