Ausschreibungs-Radar (v1.1) STACK/FEATURES/ARCHITECTURE/PITFALLS research plus SUMMARY.md synthesis.
23 KiB
Feature Research
Domain: Tender / public-procurement monitoring & aggregation (German "Ausschreibungs-Radar" module, Tessera v1.1)
Researched: 2026-07-17
Confidence: MEDIUM-HIGH (domain patterns cross-checked against live tender-monitoring SaaS products — Stotles, Tendium, TenderAlerts, Jorpex — plus OCDS standard docs and the project's own portal feasibility research; German-specific integration details inherit the HIGH confidence already established in ausschreibungs-portale-feasibility.md)
Scope note: This supersedes the v1.0 platform-level
FEATURES.md(portal shell, auth, multi-tenancy, marketplace, dashboard widgets) for roadmap purposes — those features already shipped and are not part of this milestone. This document covers ONLY the new Ausschreibungs-Radar tender module.
How This Category Works
Every mature tender-monitoring product (Stotles, Tendium, TenderAlerts, deutsche-eVergabe, vergabe24) follows the same shape, regardless of market:
- Ingest from N sources (APIs, scrapers, RSS, email alerts) into a normalized schema.
- Deduplicate across sources — the same tender is frequently published on 2-3 portals plus a central feed (DÖE/TED equivalent).
- Let each user/tenant define saved-search profiles (keyword + geography + classification code + deadline + value filters).
- Show a searchable results list + detail view linking back to the source portal/documents.
- Track per-user state (read/unread, shortlisted/favourite) on top of the shared tender catalog.
- Notify: a configurable periodic digest email, plus an instant alert the moment a new tender matches a saved search.
Tessera's module maps directly onto this shape. The only domain-specific complexity is #1-2 (many incompatible German portal formats, see feasibility doc) — #3-6 are standard SaaS patterns Tessera already has adjacent infrastructure for (DKV inbox ingestion, MailModule/SMTP, NestJS @nestjs/schedule, multi-tenant config).
Feature Landscape
Table Stakes (Users Expect These)
Features users assume exist. Missing these = product feels incomplete.
| Feature | Why Expected | Complexity | Notes |
|---|---|---|---|
| Central tender ingestion (DÖE OpenData API) | This is the reason the module exists — without it there's no data | MEDIUM | Auth-free eForms-DE/OCDS/CSV, single API, ~75% market value by € — see feasibility doc. No scraping risk. MVP foundation. |
| Normalized tender schema (OCDS-oriented) | Every source has a different shape; UI/filters need one consistent model | MEDIUM | Store title, buyer, CPV code(s), region/PLZ, deadline, estimated value, procedure type, source URL(s), raw payload |
| Full-text keyword search | Users think in free text ("Straßenbau Ludwigsburg"), not structured codes alone | LOW-MEDIUM | Postgres tsvector/GIN index on title+description is sufficient at this scale; no need for Elasticsearch |
| Region / PLZ / Bundesland filter | German public buyers are geographically scoped; users only want their operating radius | LOW-MEDIUM | PLZ → Bundesland/Landkreis mapping table (static reference data); PLZ range or radius filter |
| CPV code / branch filter | CPV (Common Procurement Vocabulary) is the industry-standard classification for tenders — OCDS confirms this is the canonical item classification | MEDIUM | Needs a static CPV code list (~9,400 codes, hierarchical, EU-published) with autocomplete/browse, not just free-text code entry |
| Submission deadline filter | Deadline is the single most decision-critical field — "can we even respond in time" | LOW | Simple date range filter; must also drive UI sort/highlighting (see below) |
| Estimated contract value min/max filter | Filters out tenders too small/large to be worth pursuing | LOW | Optional field — many Unterschwelle notices omit value; filter must handle NULL gracefully |
| Saved-search / filter profiles | Users don't want to re-enter the same 5 filters every day — every competitor product treats "saved search" as the core object, not the raw search | MEDIUM | Per-user (not just per-tenant) — colleagues in the same tenant often watch different branches/regions |
| Searchable/sortable results list | Baseline UX for any list-based tool; sort by deadline (most common), value, publish date | LOW-MEDIUM | Standard data-table pattern, consistent with rest of Tessera portal UI |
| Detail view with source link + document access | Users must reach the actual Vergabeunterlagen to bid — the module is a radar, not a bidding platform | LOW-MEDIUM | For DÖE/eForms: link to source portal + any document URLs present in the notice; do not attempt to mirror/host bid documents |
| Read/unread marking | Universal "inbox" pattern — users triage a daily list of new matches | LOW | Per-user state table, not a tenant-shared flag |
| Favourite/shortlist marking | Lets users bookmark tenders they intend to pursue, separate from the read/unread triage state | LOW | Per-user state table; simple boolean + optional "shortlist view" filter |
| Periodic email digest | Every native portal alert (see feasibility doc, portals 2,3,4,6,7,8,9,10) already trains users to expect an inbox digest, not "log in and check" | MEDIUM | Reuses existing MailModule/SMTP infra. Configurable interval (daily/weekly) per saved search or per user, sent via existing scheduler pattern (dkv-scheduler.service.ts precedent) |
| Instant alert on new match | Deadline-sensitive tenders lose value if a digest arrives after a same-day cutoff was missed; competitors (Stotles, Tendium, native portal Suchprofile) all offer immediate notification as an alternative to digest | MEDIUM | Event-driven: at ingestion time, run new tenders against active saved searches, queue+send immediately. Reuses MailModule. |
Differentiators (Competitive Advantage)
Features that set the product apart. Not required, but valuable — align with Tessera's core value ("one platform instead of switching between tools").
| Feature | Value Proposition | Complexity | Notes |
|---|---|---|---|
| Cross-source deduplication with merged source links | The single most-cited "must-have but hard" feature in every tender-aggregator review (Stotles, EU Tenders Monitor) — same Vergabe published on DÖE + AI-AG portal + RSS should appear once, not 3 times | HIGH | No shared ID across sources — needs fuzzy match on buyer+title+CPV+deadline+value within a time window. Only relevant once ≥2 sources are active — defer past DÖE-only MVP |
| Dashboard widget: upcoming deadlines | Tessera already has a configurable drag-and-drop dashboard with a Calendar widget — an "Ausschreibungen mit nahender Frist" widget reuses that framework directly instead of forcing users into the module | LOW-MEDIUM (once dashboard widget SDK exists) | Direct synergy with the already-built Phase 8 dashboard-widgets work; high leverage, low net-new complexity |
| Per-tenant + per-user saved searches with team visibility | Multiple colleagues at one tenant can watch overlapping-but-different regions/branches without duplicating ingestion work | LOW (data-model addition on top of table-stakes saved search) | Natural fit given Tessera's existing multi-tenant architecture |
| CSV/Excel export of filtered results | Procurement/BD teams routinely need to hand a tender list to someone outside the tool (management, partner companies) | LOW | Reuse existing export patterns if any exist elsewhere in Tessera; otherwise trivial with the normalized schema |
| Relevance ranking within a saved search | Once keyword+CPV+region filters return more than a handful of hits, a simple recency sort undersells partial matches; competitors (Stotles "Signal Score") rank rather than just filter | MEDIUM-HIGH | Defer — only valuable once ingestion volume is large enough that plain filtering feels noisy; not needed for DÖE-only MVP |
| "Manual watch" flag for anti-scraping portals (vergabe24, aumass) | Rather than silently having no coverage, the UI can list these portals as "nicht automatisch überwacht — manuell prüfen" with a direct bookmark link, so users aren't surprised by a coverage gap | LOW | Cheap trust-building feature; prevents users assuming full coverage when 2 portals are deliberately excluded per ToS |
Anti-Features (Commonly Requested, Often Problematic)
Features that seem good but create problems.
| Feature | Why Requested | Why Problematic | Alternative |
|---|---|---|---|
| Scraping vergabe24.de / aumass.de directly | "We already pay for these, just pull the data automatically" | Both portals' AGB explicitly prohibit automated/scripted access; aumass additionally paywalls its alert feature. Legal/ToS risk for a product Tessera intends to resell to customers | Their Oberschwellen notices already flow through DÖE (both are confirmed DÖE data suppliers per feasibility doc); for Unterschwellen coverage, register a native portal Suchprofil manually and ingest the resulting alert emails like any other Unterschwellen source |
| Generic "scrape any portal the user pastes a URL for" framework | Feels maximally flexible — "just point it at any Vergabeportal" | German portal landscape has ≥3 incompatible platform families (cosinex, AI-AG NetServer, subreport, bespoke); a generic scraper is either fragile (breaks on every portal redesign) or a permanent maintenance sink. Also raises ToS risk per-portal at scale | Ship a small, fixed set of well-understood adapters (DÖE API, one AI-AG adapter, one cosinex adapter, 2 RSS feeds) as scoped in PROJECT.md; treat any further portal as a deliberate, individually-evaluated addition |
| Real-time (sub-hourly) polling of every source | "Instant alert" sounds like it needs constant polling | Tender lifecycles run days-to-weeks; native portal alert emails themselves are typically daily-batch. Sub-hourly polling multiplies scraping load/ToS exposure for near-zero user value | Poll DÖE/RSS on an hourly-to-daily schedule (source-dependent); "instant alert" means instant relative to the last poll/ingestion, not sub-minute real-time |
| Full bid-management / CRM (proposal drafting, submission tracking, win/loss pipeline) | "While we're in the tool, why not manage the whole bid lifecycle" | That is a different product category (bid-management software, e.g. Loopio-class tools) — much larger scope, and out of step with the module's stated goal ("durchsuchen, filtern, anzeigen, versenden") | Keep the module a radar: discovery + filtering + notification + shortlisting. Document-heavy bid workflow can be a future, separate module if ever justified |
| AI-generated tender summaries / bid-fit scoring | Sounds like a strong differentiator, "let AI tell us if this tender is worth pursuing" | Real value requires per-tenant scoring criteria/training data that doesn't exist yet; premature AI feature adds cost/complexity/hallucination risk before the basic radar has been validated in production | Defer to v2+; if pursued later, treat as its own AI-SPEC-gated phase per Tessera's dev workflow, not part of the v1.1 module |
| Mirroring/hosting original Vergabeunterlagen (PDFs) locally | "One-stop shop, don't make users leave the app" | Legal ambiguity around redistributing third-party procurement documents; storage/sync burden keeping mirrors current as portals update documents | Link out to the source portal's document URL; only cache what's needed for parsing (e.g. eForms XML), not full bid document sets |
Feature Dependencies
Normalized tender schema (OCDS-oriented)
└──requires──> DÖE OpenData ingestion (MVP source)
└──enables──> Filter engine (keyword, region, CPV, deadline, value)
└──requires──> Saved-search / filter profiles
├──requires──> Instant alert (needs Mail infra)
└──requires──> Periodic digest (needs Mail infra + Scheduler)
Read/unread marking ──requires──> per-user tender state table (independent of shared tender catalog)
Favourite/shortlist marking ──requires──> per-user tender state table (same table as read/unread)
Cross-source deduplication ──requires──> ≥2 active ingestion sources
(portal adapters or RSS) └──blocks──> "Portal-Adapter (AI-AG/cosinex)" phase
└──blocks──> "RSS-Quellen" phase
└──blocks──> "E-Mail-Alert-Ingestion" phase
E-Mail-Alert-Ingestion (Unterschwellen) ──reuses──> DKV inbox infra (ImapProvider / ExchangeInboxProvider)
Dashboard "upcoming deadlines" widget ──enhances──> Saved-search / filter profiles
(reuses existing dashboard widget framework, Phase 8)
Instant alert ──conflicts-with-if-unthrottled──> Periodic digest
(same match sent twice — needs a "already alerted" flag on the per-user tender state
so a tender doesn't also appear in the next digest as if new)
Dependency Notes
- Filter engine requires the normalized schema, which requires at least the DÖE source to exist: there is nothing to filter until data is flowing. This is why DÖE-only ingestion is the correct MVP anchor — everything else (saved search, results UI, notifications) can be built and validated against real live data from day one, without waiting on portal-adapter scraping work.
- Cross-source dedup requires ≥2 sources: building dedup logic against a single source is meaningless (nothing to deduplicate against). This confirms dedup belongs strictly after the first portal adapter or RSS source ships, not in the MVP.
- Instant alert and periodic digest both require Mail infra, but need a shared "already notified" state to avoid double-notifying the same user about the same tender (once instantly, once again in the next digest). This is a small but easy-to-miss data-model requirement — flag for the phase that builds notifications.
- Read/unread and favourite/shortlist state must be per-user, not per-tenant: the tender catalog itself is shared reference data (a public tender exists independent of which tenant is looking at it), but triage state is personal. This is architecturally different from the DKV module, where nearly everything is tenant-scoped by nature. Worth flagging explicitly for the data-model design in this phase.
- E-Mail-Alert-Ingestion reuses DKV's inbox provider interface (
apps/api/src/dkv/providers/inbox-provider.interface.ts, withImapProvider/ExchangeInboxProviderimplementations) rather than building new inbox-polling code — the DKV module already solved "watch a mailbox, parse structured content out of incoming mail" for a different structured format (fleet PDFs). The tender module needs the same mailbox-watching mechanics, different parser. - Periodic digest and instant alert reuse the existing
MailModule/SMTP (apps/api/src/mail/mail.module.ts,mail.service.ts) and the scheduler pattern already established bydkv-scheduler.service.tsandldap-sync.scheduler.ts— no new mail-sending or cron infrastructure needed, only new templates and trigger logic.
MVP Definition
Launch With (v1 / MVP — DÖE-API-only)
Minimum viable product — validates the whole module concept against real, legally unambiguous, single-source data before any scraping work begins.
- DÖE OpenData API ingestion (eForms/OCDS/CSV, auth-free) — the only data source needed to prove the concept
- Normalized tender schema (OCDS-oriented) — required so later sources slot in without a schema rewrite
- Filter engine: keyword full-text, region/PLZ/Bundesland, CPV code, deadline range, value range
- Saved-search / filter profiles (per user, tenant-aware)
- Searchable/sortable UI results list, sortable by deadline/value/publish date
- Detail view with source link + any document URLs present in the DÖE notice
- Read/unread marking (per-user)
- Favourite/shortlist marking (per-user)
- Periodic email digest, interval configurable in the webinterface — reuses
MailModule - Instant email alert on new match against an active saved search — reuses
MailModule
Add After Validation (v1.x)
Features to add once the DÖE-only MVP is live and validated in production use.
- AI-AG NetServer portal adapter (covers portals lhs-vpbw, tender24, vergabe.landbw + other AI-AG-hosted portals) — trigger: MVP validated, Unterschwellen coverage gap confirmed as a real pain point
- cosinex VMP adapter (DTVP, reusable across other cosinex-hosted Länder-Marktplätze) — trigger: same as above
- RSS ingestion (subreport-elvis, service.bund.de) — trigger: lowest-effort source expansion, can land alongside or before the scraping adapters
- E-Mail-Alert-Ingestion for remaining Unterschwellen portals, reusing DKV inbox infra — trigger: once ≥1 scraping adapter or RSS source exists, so there's a reason to worry about cross-source overlap
- Cross-source deduplication (fuzzy match on buyer+title+CPV+deadline+value) — trigger: mandatory as soon as a second source goes live, otherwise duplicate tenders will visibly degrade the results list
- "Manual watch" indicator for vergabe24/aumass (excluded portals) — trigger: first user question about "why don't I see X"
Future Consideration (v2+)
Features to defer until the core radar has proven its value.
- TED API v3 (EU-wide redundancy) — defer: largely redundant to DÖE for DE-only scope, only relevant if cross-border tenders become a requirement
- Relevance/ranking scoring within saved searches — defer: only needed once match volume per saved search is large enough that plain filtering feels noisy
- Dashboard "upcoming deadlines" widget — defer: high-leverage but depends on prioritizing dashboard-widget-SDK reuse work; not core to validating the radar itself
- CSV/Excel export — defer: cheap to add later, not needed to validate core value
- Team/collaboration features (assign tender to colleague, internal notes) — defer: turns the module toward bid-management scope creep; only pursue if users explicitly ask post-launch
Feature Prioritization Matrix
| Feature | User Value | Implementation Cost | Priority |
|---|---|---|---|
| DÖE OpenData ingestion + normalized schema | HIGH | MEDIUM | P1 |
| Filter engine (keyword/region/CPV/deadline/value) | HIGH | MEDIUM | P1 |
| Saved-search profiles | HIGH | MEDIUM | P1 |
| Results list + detail view | HIGH | LOW-MEDIUM | P1 |
| Read/unread + favourite marking | MEDIUM | LOW | P1 |
| Periodic digest + instant alert (via MailModule) | HIGH | MEDIUM | P1 |
| AI-AG NetServer adapter | MEDIUM-HIGH | HIGH | P2 |
| cosinex DTVP adapter | MEDIUM | MEDIUM-HIGH | P2 |
| RSS ingestion (subreport, service.bund.de) | MEDIUM | LOW-MEDIUM | P2 |
| E-Mail-Alert-Ingestion (Unterschwellen) | MEDIUM | MEDIUM (reuses DKV infra) | P2 |
| Cross-source deduplication | HIGH (once ≥2 sources) | HIGH | P2 |
| Dashboard "upcoming deadlines" widget | MEDIUM | LOW-MEDIUM | P3 |
| Relevance ranking | LOW-MEDIUM | MEDIUM-HIGH | P3 |
| CSV/Excel export | LOW-MEDIUM | LOW | P3 |
| Team/collaboration (notes, assignment) | LOW | MEDIUM-HIGH | P3 |
Priority key:
- P1: Must have for launch (DÖE-only MVP)
- P2: Should have, add when possible (portal-adapter / multi-source phases)
- P3: Nice to have, future consideration
Competitor Feature Analysis
| Feature | Native German portals (DTVP, subreport, deutsche-eVergabe) | Modern SaaS aggregators (Stotles, Tendium, TenderAlerts) | Tessera's approach |
|---|---|---|---|
| Saved search + alert | Yes — "Suchprofil" per portal, daily email | Yes — core object of the product | Yes — single unified saved-search model across all sources, not one per portal |
| Multi-source coverage | No — each portal only shows its own listings | Yes — 50-1,000+ sources aggregated centrally | Yes, phased: DÖE (central feed) → 2 portal adapters → RSS → email-ingestion for the long tail |
| Deduplication | N/A (single source) | Yes — explicitly marketed as a core feature (Stotles, EU Tenders Monitor) | Deferred to v1.x, once ≥2 sources are live (see dependency notes) |
| Read/unread + shortlist | Rare — most native portals only offer a flat list | Yes — standard inbox-style triage pattern | Yes, in MVP — per-user state table |
| Deadline-aware notification | Digest only, no distinction between digest and instant | Some distinguish instant vs. digest | Both instant alert and periodic digest, user-configurable, in MVP |
| Bid-management/CRM add-ons | No | Some upsell into full bid-management (Stotles) | Explicitly out of scope (anti-feature) — module stays a radar |
Sources
.planning/research/ausschreibungs-portale-feasibility.md— project-internal, HIGH confidence (already-verified portal-by-portal capability matrix, native alert features, ToS constraints, DÖE/TED coverage stats)- Open Contracting Data Standard — Codelists & Schema Reference — CPV classification usage, deadline/timezone handling, currency-attached values (MEDIUM-HIGH, official standard docs)
- Open Contracting Data Standard — official site — schema/building-blocks overview (MEDIUM-HIGH)
- Stotles — Tender Alerts & Tracker — unified feed from 1,000+ portals, Signal Score relevance ranking, saved searches (MEDIUM, vendor marketing but consistent with independent sources)
- Tendium — Tender Monitoring — monitoring/alert pattern confirmation (MEDIUM)
- TenderAlerts.eu — EU tender aggregation, notification dashboard pattern (MEDIUM)
- EU Tenders Monitor (Apify) — explicit confirmation that "relevance scoring, deduplication and new-only alerts" are treated as a standard feature set for this category (MEDIUM)
- deepbloo — What Is a Tender Monitoring Platform — category definition, deduplication described as critical (MEDIUM)
- Codebase inspection:
apps/api/src/dkv/providers/inbox-provider.interface.ts,dkv-scheduler.service.ts,apps/api/src/mail/mail.service.ts,apps/api/src/mail/mail.module.ts— confirms reusable infra for email-ingestion, scheduling, and outbound mail (HIGH — direct codebase read)
Feature research for: German public-procurement tender monitoring/aggregation module (Ausschreibungs-Radar) Researched: 2026-07-17