Files
tessera-ctl/.planning/ROADMAP.md
T

35 KiB

Roadmap: Tessera

Overview

Tessera delivers a modular portal platform where tenants activate workflow modules from a marketplace, interact through a configurable dashboard, and optionally use a desktop wrapper. The roadmap builds foundation-first (Docker + DB + shell), layers in authentication and multi-tenancy, establishes the module system with a proof-of-concept module, adds marketplace and portal navigation, delivers the dashboard experience, and wraps up with desktop client and CI/CD integration. The v1.1 Ausschreibungs-Radar milestone (Phases 10-14) adds a new module that aggregates German public tenders from DÖE OpenData plus AI-AG NetServer, cosinex, RSS, and email-alert sources into one normalized, filterable, notifiable catalog -- shipped DÖE-first as a legally-clean, demoable MVP, then layered with scraping adapters and finally the long-tail RSS/email sources.

Milestones

  • ✅ v1.0 MVP - Phases 1-9 (shipped 2026-07-02)
  • 🚧 v1.1 Ausschreibungs-Radar - Phases 10-14 (in progress)
  • 🚧 v1.2 Plattform-Berechtigungen - Phase 15+ (in progress)

Phases

Phase Numbering:

  • Integer phases (1, 2, 3): Planned milestone work
  • Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)

Decimal phases appear between their surrounding integers in numeric order.

  • Phase 1: Foundation & Portal Shell - Docker infrastructure, database with RLS, frontend shell with i18n and theming (completed 2026-06-18)
  • [~] Phase 2: Authentication & Multi-Tenancy - User accounts, sessions, RBAC, tenant isolation per request (4/5 plans; 02-05 visual verification never run)
  • Phase 3: Module System & Domaincheck - Module SDK, registry, lazy loading, and first proof-of-concept module (completed 2026-06-20)
  • Phase 4: Marketplace & Portal Navigation - Module catalog, licensing, activation, and sidebar integration (completed 2026-06-23)
  • Phase 5: Dashboard & Calendar - Configurable widget grid with drag-and-drop, core widgets, and calendar integration (completed 2026-06-24)
  • Phase 6: Desktop Client & CI/CD - Tauri wrapper for Windows/Linux and automated Gitea integration (completed 2026-06-25)
  • Phase 7: DKV Fleet Module - Automated DKV invoice processing via email monitoring, PDF parsing, and Excel export with driver mapping (completed 2026-06-27)
  • Phase 8: Dashboard Widgets Vollimplementierung - Calculator, Favorites, and Stopwatch widgets plus unified grid constraints across all dashboard widgets (completed 2026-07-01)
  • Phase 9: Cert Manager Module - Server-side certificate toolkit: upload/paste, inspect, split chains, merge/bundle, convert formats, password-protected PFX support (completed 2026-07-02)
  • Phase 10: Ausschreibungs-Radar Foundation & DÖE Ingestion - Normalized DÖE tender ingestion on a multi-tenant-safe shared schedule, module activatable from the marketplace (completed 2026-07-21)
  • Phase 11: Filter Engine, Results UI & Saved Searches - Searchable/filterable tender results, personal saved search profiles, per-user read/favourite triage
  • Phase 12: Tender Notifications - Configurable digest and instant email alerts without duplicate sends or backfill floods
  • Phase 13: Scraping Adapters & Cross-Source Deduplication - AI-AG NetServer + cosinex adapters with fuzzy cross-source dedup and a hard denylist for banned portals
  • Phase 14: RSS, Email-Alert Ingestion & Module Rollout - RSS + email-alert long tail, admin source/mailbox config, excluded-portal transparency, i18n
  • Phase 15: Modul-Berechtigungen: Gruppen & User-Grants - Modulzugriff pro Gruppe und pro Benutzer zusätzlich zur Mandanten-Aktivierung, Gruppen mit optionaler AD-Bindung
  • Phase 16: AD-Gruppen-Synchronisation - Ausgewählte AD-Gruppen werden als Tessera-Gruppen übernommen und in Name, Bestand und Mitgliedschaft nachgeführt

Phase Details

Phase 1: Foundation & Portal Shell

Goal: Users can access a running portal application with responsive layout, theme switching, and bilingual interface -- the structural frame into which all features will be placed. Mode: mvp Depends on: Nothing (first phase) Requirements: INFRA-01, INFRA-02, INFRA-03, PRTAL-01, PRTAL-04, UI-01, UI-02, UI-03 Success Criteria (what must be TRUE):

  1. User can access the portal in a browser served from a Docker Compose stack with PostgreSQL
  2. User sees a responsive layout with header (branding area) and sidebar frame that adapts to screen size
  3. User can toggle between light and dark theme and the preference persists
  4. User can switch between German and English interface language
  5. All UI strings are rendered through the i18n framework (no hardcoded text)

Plans: 3 plans Wave 1

  • 01-01-PLAN.md -- Walking Skeleton: Monorepo + Docker Compose stack with NestJS, Next.js, PostgreSQL, Traefik

Wave 2 (blocked on Wave 1 completion)

  • 01-02-PLAN.md -- Portal Shell: Design tokens, i18n (DE/EN), theme switching, responsive layout with header + sidebar

Wave 3 (blocked on Wave 2 completion)

  • 01-03-PLAN.md -- Visual Verification: Human confirms portal appearance and interactions

UI hint: yes

Phase 2: Authentication & Multi-Tenancy

Goal: Users can securely log in, manage accounts, and operate within isolated tenant boundaries -- every request is scoped to the correct tenant with data fully separated at the database level. Mode: mvp Depends on: Phase 1 Requirements: AUTH-01, AUTH-02, AUTH-03, AUTH-04, AUTH-05, AUTH-06, TNNT-01, TNNT-02, TNNT-03 Success Criteria (what must be TRUE):

  1. Initial admin account is created automatically from Docker environment variables on first startup
  2. Admin can create, edit, and delete user accounts with role assignment (Admin/User)
  3. User can log in and log out, with session surviving browser refresh
  4. Admin can create and manage tenants, and each user's data is isolated per tenant via RLS
  5. Users can be imported from an LDAP/AD directory

Plans: 5 plans

Wave 1

  • 02-01-PLAN.md -- Backend Auth Foundation: Prisma schema, RLS migration, JWT Passport auth, admin seed, tenant middleware

Wave 2 (blocked on Wave 1 completion)

  • 02-02-PLAN.md -- Frontend Auth & CRUD: Login page, Next.js middleware, user/tenant management UI, auth-wired portal
  • 02-03-PLAN.md -- Password Reset & Mail: SUS package verification, MailModule, password reset flow, force-change interceptor

Wave 3 (blocked on Wave 2 completion)

  • 02-04-PLAN.md -- LDAP Integration: LDAP sync service, per-tenant config, field mapping, admin UI

Wave 4 (blocked on Wave 3 completion)

  • 02-05-PLAN.md -- Visual Verification: Human confirms complete auth and multi-tenancy flow (never executed — no summary)

UI hint: yes

Phase 3: Module System & Domaincheck

Goal: The platform can discover, register, and load modules dynamically -- validated end-to-end by a working Domaincheck module that users can interact with. Mode: mvp Depends on: Phase 2 Requirements: MOD-01, MOD-02, MOD-03, MOD-04, DCHK-01, DCHK-02, DCHK-03 Success Criteria (what must be TRUE):

  1. Modules are registered in a database-driven registry with a versioned SDK interface
  2. An admin can activate and deactivate a module without restarting the application
  3. Module UIs load on demand (lazy loading) -- no bundle bloat from inactive modules
  4. User can open the Domaincheck module, enter a domain, and see whether it is registered or available

Plans: 4 plans

Wave 1

  • 03-01-PLAN.md -- Module SDK, Prisma Registry, Activation API

Wave 2 (blocked on Wave 1 completion)

  • 03-02-PLAN.md -- Domaincheck Module: Backend DNS + Frontend UI
  • 03-03-PLAN.md -- Lazy Loading, Category Pages, Expanded Module View

Wave 3 (blocked on Wave 2 completion)

  • 03-04-PLAN.md -- Visual Verification: Human confirms module system

UI hint: yes

Phase 4: Marketplace & Portal Navigation

Goal: Users can browse available modules in a categorized marketplace, admins can activate modules per tenant, and activated modules appear in the sidebar for navigation. Mode: mvp Depends on: Phase 3 Requirements: MRKT-01, MRKT-02, MRKT-03, MRKT-04, PRTAL-02, PRTAL-03, PRTAL-05 Success Criteria (what must be TRUE):

  1. User can browse a marketplace view showing all available modules with descriptions and categories
  2. Admin can activate or deactivate modules for their tenant from the marketplace
  3. Only activated modules appear in the left sidebar, grouped by category
  4. User can select a module from the sidebar and it opens in the main content area
  5. User can search and filter modules in the sidebar

Plans: 4 plans

Wave 1

  • 04-01-PLAN.md -- Test infra (Vitest) + marketplace i18n + Marketplace page slice: card grid browse + activate (MRKT-01/02/04)

Wave 2 (blocked on Wave 1 completion)

  • 04-02-PLAN.md -- Marketplace refinements: search/category/status filters, deactivation dialog, toast, Super-Admin tenant context, module detail page
  • 04-03-PLAN.md -- Sidebar enhancement: Next.js Link + usePathname active state, per-module links, sidebar search, live refresh (PRTAL-02/03/05, MRKT-03)

Wave 3 (blocked on Wave 2 completion)

  • 04-04-PLAN.md -- Visual Verification: Human confirms marketplace, activation, tenant context, and sidebar navigation

UI hint: yes

Phase 5: Dashboard & Calendar

Goal: Users have a personal, configurable start page with freely arrangeable widgets -- including clock, search, notes, and calendar with external calendar source integration. Mode: mvp Depends on: Phase 4 Requirements: DASH-01, DASH-02, DASH-03, DASH-04, DASH-05, DASH-06, DASH-07, CAL-01, CAL-02, CAL-03 Success Criteria (what must be TRUE):

  1. User sees a configurable dashboard as their start page with a drag-and-drop grid
  2. User can add, reposition, and resize widgets (clock, search bar, calendar, notes)
  3. Dashboard layout is saved per user and restored on next login
  4. User can configure external calendar sources (WebDAV, Exchange, ICS) in settings
  5. Calendar widget shows upcoming events from selected calendar sources

Plans: 5 plans

Wave 1

  • 05-01-PLAN.md -- Dashboard foundation: Prisma models, CRUD API, grid, edit-mode, clock widget, settings shell, header link, i18n (DASH-01/02/03/07)

Wave 2 (blocked on Wave 1 completion)

  • 05-02-PLAN.md -- Search + Notes widgets, widget settings panel, SearchProvider backend (DASH-04/06)

Wave 3 (blocked on Wave 2 completion)

  • 05-03-PLAN.md -- Calendar backend: Prisma model, AES-256-GCM crypto, source CRUD, CalDAV/ICS/Exchange providers, DB push (CAL-01/02/03, DASH-05)

Wave 4 (blocked on Wave 3 completion)

  • 05-04-PLAN.md -- Calendar frontend: calendar widget, calendar settings page, API client (CAL-01/02/03, DASH-05)

Wave 5 (blocked on Wave 4 completion)

  • 05-05-PLAN.md -- Visual Verification: Human confirms dashboard, widgets, calendar, settings

UI hint: yes

Phase 6: Desktop Client & CI/CD

Goal: Users can install and run Tessera as a native desktop application, and the development workflow includes automated version control via Gitea. Mode: mvp Depends on: Phase 5 Requirements: DESK-01, DESK-02, INFRA-04 Success Criteria (what must be TRUE):

  1. User can install a Tauri-based desktop app on Windows or Linux
  2. Desktop app connects to the existing web backend (no standalone server)
  3. Code changes are automatically committed and pushed to Gitea with minimal manual intervention

Plans: 3 plans

Wave 1 (parallel — disjoint files)

  • 06-01-PLAN.md -- Desktop foundation: Tauri toolchain, apps/desktop scaffold, URL-loading WebView + first-run server URL setup (DESK-01/02)
  • 06-03-PLAN.md -- CI/CD: Gitea remote, act_runner, multi-stage Gitea Actions pipeline (lint+type-check -> tests -> docker build+deploy) (INFRA-04)

Wave 2 (blocked on 06-01)

  • 06-02-PLAN.md -- Desktop native: tray + close-to-tray, window-state, autostart, notifications + version check, branded icon, AppImage+NSIS bundles, /health/version API (DESK-01/02)

Phase 7: DKV Fleet Module

Goal: Administrators can automatically process DKV fuel card invoices by monitoring an email inbox, parsing PDF attachments, mapping license plates to drivers, and exporting structured Excel reports via SMTP. Mode: mvp Depends on: Phase 6 Requirements: DKV-01, DKV-02, DKV-03, DKV-04, DKV-05 Success Criteria (what must be TRUE):

  1. System automatically detects DKV invoice PDFs from a configured email inbox (IMAP or Exchange)
  2. All transactions are parsed per vehicle with: date, service station, km reading, product, quantity, unit, net/gross amounts
  3. License plate → driver mapping is importable as CSV and manually editable in the UI
  4. Processed data is exported as Excel file and sent to a configurable recipient via SMTP
  5. SMTP settings are configurable in general settings (shared with other modules)
  6. Module configuration (inbox, sender filter, folder, recipient) is editable in the module settings UI

Plans: 6 plans

Wave 0

  • 07-01-PLAN.md -- Backend foundation: deps install, Prisma models, ScheduleModule, crypto export, validated DKV PDF parser (DKV-02)

Wave 1 (blocked on Wave 0 completion)

  • 07-02-PLAN.md -- Inbox-access layer: InboxProvider interface, IMAP + Exchange providers, config/vehicle/history DTOs (DKV-01)
  • 07-03-PLAN.md -- Export + delivery + SMTP backend: SettingsModule (SMTP CRUD + test), DkvExportService (xlsx + prune), DkvMailService, MailModule DB-SMTP migration (DKV-04/05, D-06)

Wave 2 (blocked on Wave 1 completion)

  • 07-04-PLAN.md -- Pipeline integration: DkvService orchestration, dynamic scheduler, DkvController REST, module registry seed, i18n keys (DKV-01/03/04/05)
  • 07-05-PLAN.md -- Module frontend: dkv-api client, main page (history + export download + "Jetzt prüfen"), inbox settings form, vehicle CRUD + CSV import (DKV-01/03/04)
  • 07-06-PLAN.md -- SMTP settings frontend: settings-api client, SMTP config form + connection test, settings-sidebar "Allgemein" category (DKV-05)

UI hint: yes

Phase 8: Dashboard Widgets Vollimplementierung

Goal: Users have a complete dashboard widget set — Calculator, Favorites (with backend persistence), and Stopwatch added alongside existing widgets. All widgets share unified grid constraints for a consistent layout experience. Mode: mvp Depends on: Phase 5 Requirements: DASH-08, DASH-09, DASH-10, DASH-11 Success Criteria (what must be TRUE):

  1. User can open a Calculator widget and perform basic arithmetic operations with keyboard support
  2. User can manage favorite links (add, edit, delete) in the Favorites widget; links persist across sessions via a backend DB table (FavoriteLink)
  3. User can start, stop, and reset a Stopwatch widget with lap time recording
  4. All dashboard widgets share the same minW, minH, defaultW, defaultH grid constraint values
  5. Existing widgets (Clock, Search, Calendar, Notes) remain fully functional after constraint normalization

Plans: 4/4 plans complete

Wave 1

  • 08-01-PLAN.md — Foundation + Calculator slice: registry constraints for all 4 new types, catalog, DTO, i18n; working Calculator widget (DASH-08, DASH-11)

Wave 2 (blocked on Wave 1 completion)

  • 08-02-PLAN.md — Stopwatch widget: start/stop/reset/lap with config persistence + reload reconstruction (DASH-10)

Wave 3 (blocked on Wave 2 completion)

  • 08-03-PLAN.md — Favorites slice: FavoriteLink schema + FavoritesModule (SSRF icon discovery) + FavoritesWidget list/grid + inline CRUD (DASH-09)

Wave 4 (blocked on Wave 3 completion)

  • 08-04-PLAN.md — Link widget: single-link tile reusing favorites backend, row/tile views (DASH-09 / D-06)

UI hint: yes

Phase 9: Cert Manager Module

Goal: Users can upload or paste certificates in any common format, inspect their details, split fullchain/P7B bundles into individual certificates, merge certs into chains or PFX bundles, and convert between formats — all processed server-side with no database persistence. Mode: mvp Depends on: Phase 3 Requirements: CERT-01, CERT-02, CERT-03, CERT-04, CERT-05, CERT-06 Success Criteria (what must be TRUE):

  1. User can upload a cert file (PEM, DER, PFX/P12, CRT, CER, P7B) or paste PEM/CRT text and see parsed details (subject, issuer, validity, SANs, fingerprint)
  2. User can split a fullchain.pem or P7B bundle into individual certificate files (downloadable)
  3. User can merge multiple cert files into a PEM chain or a PFX bundle (with password)
  4. User can convert between PEM, DER, PFX/P12, P7B, CRT/CER formats
  5. Password-protected PFX/PKCS12 files can be opened (password prompt) and created (password input)
  6. Module appears in the module registry with slug cert-manager

Plans: 6/6 plans complete

Plans: Wave 1

  • 09-01-PLAN.md — API foundation: install node-forge + Vitest runner, scaffold module, seed registry (CERT-06), shared node-forge helpers
  • 09-02-PLAN.md — Frontend shell: tab page, DropZone, conditional password field, download helpers, certManager i18n (de/en)

Wave 2 (blocked on Wave 1 completion)

  • 09-03-PLAN.md — Inspect slice: parseCert (PEM/DER/PFX/P7B) + POST /parse + Inspect tab (CERT-01, CERT-05 read)

Wave 3 (blocked on Wave 2 completion)

  • 09-04-PLAN.md — Split slice: splitCerts (fullchain/P7B) + POST /split + Split tab download list (CERT-02)

Wave 4 (blocked on Wave 3 completion)

  • 09-05-PLAN.md — Convert slice: convertCert (PEM/DER/P7B round-trips) + POST /convert + Convert tab (CERT-04)

Wave 5 (blocked on Wave 4 completion)

  • 09-06-PLAN.md — Merge/PFX slice: mergeCerts (PEM chain + password PFX) + POST /merge + Merge tab + PFX convert option (CERT-03, CERT-05 write)

UI hint: yes

Phase 10: Ausschreibungs-Radar Foundation & DÖE Ingestion

Goal: The platform ingests German public tenders from the DÖE OpenData API on a shared, multi-tenant-safe schedule into a normalized, platform-global schema, and the module can be activated per tenant from the marketplace. Mode: mvp Depends on: Phase 9 (existing platform infrastructure: module registry, multi-tenancy, mail/SMTP) Requirements: CONFIG-01, INGEST-01, INGEST-06, SCHEMA-01, SCHEMA-02 Success Criteria (what must be TRUE):

  1. Admin can find "Ausschreibungs-Radar" in the marketplace and activate it for a tenant, same as the DKV-Fleet/Cert-Manager modules
  2. New DÖE OpenData tenders appear as normalized records (title, buyer, CPV codes, region/PLZ, deadline, estimated value, procedure type, source URL) after a poll cycle -- tender data is platform-global, not tied to any one tenant
  3. A DÖE tender that changes on the source side (e.g. deadline extension, cancellation) updates the existing record via content-hash change detection instead of creating a duplicate
  4. DÖE is polled once on a shared, admin-configurable interval regardless of how many tenants have the module active -- never once per tenant (poll-once-fan-out-many, not the DKV single-tenant findFirst() pattern)
  5. Activating the module for a second tenant does not duplicate ingestion, re-trigger a redundant DÖE poll, or interfere with the first tenant's data

Plans: 6/6 plans complete

Wave 1

  • 10-01-PLAN.md — Foundation: install fast-xml-parser/adm-zip/csv-parse (adm-zip supply-chain checkpoint), add global Tender + TenderSourcePollConfig models, [BLOCKING] migration (SCHEMA-01)

Wave 2 (blocked on Wave 1 completion)

  • 10-02-PLAN.md — Marketplace registration slice: self-seed tender-radar module, module-loader whitelist entry, placeholder page, singleton doe-opendata poll config (CONFIG-01)

Wave 3 (blocked on Wave 2 completion)

  • 10-03-PLAN.md — DÖE adapter + normalizer (TDD): fetch/extract/parse day-export ZIP, D-02 open-tender filter, eForms-primary normalize with dedupKey + contentHash (INGEST-01, SCHEMA-01)

Wave 4 (blocked on Wave 3 completion)

  • 10-04-PLAN.md — Ingestion + shared scheduler: day-cursor gate, upsert change-detection, single global cron (poll-once-fan-out-many), 90-day retention, two-tenant safety test (SCHEMA-02, INGEST-06)

Wave 5 (blocked on Wave 4 completion)

  • 10-05-PLAN.md — Controller + admin source-config: global ModuleGuard-gated read, admin-configurable poll interval applied live to scheduler (INGEST-06)

Wave 6 (blocked on Wave 5 completion)

  • 10-06-PLAN.md — Admin config UI: tender-radar-api client + settings page SourceConfigForm reading/writing GET/PUT source-config, mirroring DKV InboxConfigForm (INGEST-06 admin-UI)

UI hint: yes (admin source-config settings form; results UI is Phase 11)

Phase 11: Filter Engine, Results UI & Saved Searches

Goal: Users can search, filter, and personally triage DÖE tender results, and save reusable filter combinations as personal search profiles, with the UI transparently communicating data coverage. Mode: mvp Depends on: Phase 10 Requirements: FILTER-01, FILTER-02, FILTER-03, FILTER-04, FILTER-05, FILTER-06, UI-01, UI-02, UI-03, UI-04, UI-05 Success Criteria (what must be TRUE):

  1. User sees a searchable, sortable results list (by deadline, value, publish date) and can filter by keyword, region/PLZ/Bundesland, CPV code (hierarchical, with autocomplete), deadline, and estimated value -- tenders with no value stated are handled gracefully, not excluded or errored
  2. User can open a detail view for any tender showing the source link and any document URLs present in the notice (no local mirroring of Vergabeunterlagen)
  3. User can save a combination of filter criteria as a named search profile and later edit or delete it -- profiles are personal (per user) and scoped to their own tenant
  4. User can mark a tender as read/unread and as favourite, and filter the results list to only favourites -- both states are per-user, not shared across the tenant
  5. The UI clearly indicates data coverage (Oberschwelle vs. Unterschwelle) so an empty or thin result set isn't mistaken for a bug

Plans: 6/6 plans executed

  • 11-01-PLAN.md — Trefferliste + Freitext + Sortierung + Coverage-Banner (FILTER-01/04/05, UI-01/05)
  • 11-02-PLAN.md — Bundesland-Ableitung (NUTS + Backfill) + Region/PLZ/Bundesland-Filter (FILTER-02)
  • 11-03-PLAN.md — CPV-Filter (Katalog + Divisionen) + Wert-Filter-UI (FILTER-03/05)
  • 11-04-PLAN.md — Detailansicht via ?tender= + Quell-Link (UI-02)
  • 11-05-PLAN.md — Triage: gelesen/ungelesen + Favorit + Merklisten-Filter (UI-03/04)
  • 11-06-PLAN.md — Suchprofile speichern/bearbeiten/löschen (FILTER-06)

UI hint: yes

Phase 12: Tender Notifications

Goal: Users are proactively notified by email about new matching tenders, via a configurable digest and/or instant alert, without duplicate sends or backfill floods, using the tenant's own SMTP configuration. Mode: mvp Depends on: Phase 11 Requirements: NOTIFY-01, NOTIFY-02, NOTIFY-03, NOTIFY-04 Success Criteria (what must be TRUE):

  1. User receives a periodic email digest of new matches for their active search profiles, with the interval configurable in the web interface
  2. User can enable an instant email alert per search profile and receives a single email shortly after a new match against that profile
  3. Activating a new search profile with many pre-existing historical matches does not flood the user with individual emails -- backfill is suppressed/batched on first activation, and a match already notified once (digest or instant) is never notified again for the same tender+profile pair (explicit matched-vs-notified state)
  4. Notification emails are sent through the tenant's own SMTP configuration (reusing the DKV mail pattern), not a shared/global system mailer

Plans: 4/4 plans executed UI hint: yes

Wave 1

  • 12-01-PLAN.md — Schema (TenderMatch/NotificationPref/instantAlert) + delta-only Matching in den Poll-Tick (NOTIFY-03)

Wave 2 (blocked on Wave 1)

  • 12-02-PLAN.md — TenderMailService (mandanten-SMTP) + globaler Digest-Cron (NOTIFY-01/04)

Wave 3 (blocked on Wave 2)

  • 12-03-PLAN.md — Sofort-Alerts am Poll-Tick + Ein-Mail-Garantie über beide Kanäle (NOTIFY-02/03)
  • 12-04-PLAN.md — Web-UI: Digest-Intervall + Sofort-Alert-Toggle, Pref-Backend (NOTIFY-01/02)

Phase 13: Scraping Adapters & Cross-Source Deduplication

Goal: The platform expands tender coverage with AI-AG NetServer and cosinex portal adapters and collapses tenders seen on multiple sources into a single entry, while structurally refusing to ever scrape the AGB-prohibited portals. Mode: mvp Depends on: Phase 12 Requirements: INGEST-02, INGEST-03, INGEST-07, SCHEMA-03 Success Criteria (what must be TRUE):

  1. Tenders from AI-AG NetServer portals (lhs-vpbw, tender24, vergabe.landbw) appear as additional, correctly normalized results via one config-driven adapter
  2. Tenders from the cosinex Vergabemarktplatz (DTVP) appear as additional, correctly normalized results via a separate config-driven adapter
  3. A tender that appears via both DÖE and a scraping adapter shows up once in the results list (fuzzy fingerprint dedup on buyer+title+CPV+deadline+value), with links to all of its source portals -- dedup logic only activates once a second source is live
  4. Attempting to register vergabe24 or aumass as a poll source is refused by the system itself (adapter registry denylist enforced in code), not just documented as forbidden

Plans: 6/6 plans executed

Plans:

  • 13-01-PLAN.md — TenderSource-Schema + Backfill + NULL-tolerante Fingerprint-Fn + SourceType-Union (SCHEMA-03 Datenschicht)
  • 13-02-PLAN.md — SourceRegistry + harte Denylist-Gate (vergabe24/aumass) + Adapter-Interface-Generalisierung (INGEST-07)
  • 13-03-PLAN.md — 3-Stufen-Dedup-Resolver + pollDueSources Fan-out (catch-per-source) + Modul-Wiring (SCHEMA-03)
  • 13-04-PLAN.md — NetServer-Adapter (config-getrieben, 3 Portale) + Package-Legitimacy-Checkpoint (INGEST-02)
  • 13-05-PLAN.md — cosinex/DTVP-Adapter (separat, best-effort) (INGEST-03)
  • 13-06-PLAN.md — Read-Endpoint include sources[] + TenderDetail Multi-Source-Links (SCHEMA-03 Anzeige)

Phase 14: RSS, Email-Alert Ingestion & Module Rollout

Goal: The platform rounds out Unterschwelle long-tail coverage via RSS feeds and per-tenant email-alert mailboxes (reusing a shared inbox module extracted from DKV), admins can manage source and mailbox configuration per tenant, excluded portals are shown transparently, and the whole module is bilingual. Mode: mvp Depends on: Phase 13 Requirements: INGEST-04, INGEST-05, CONFIG-02, CONFIG-03, UI-06 Success Criteria (what must be TRUE):

  1. Tenders from the RSS feeds subreport-elvis and service.bund.de appear automatically in the results list
  2. Tenders parsed from a configured mailbox's portal-alert emails appear automatically in the results list -- built on a shared inbox/ module, extracted as a one-time prerequisite refactor from DKV's ImapProvider/ExchangeInboxProvider (previously living inside dkv/)
  3. Admin can manage per-tenant source poll configuration and the email-alert ingestion mailbox, with credentials stored encrypted (same AES-256-GCM pattern as DkvModuleConfig)
  4. vergabe24 and aumass are shown in the UI as "manually monitor" with a direct link, instead of appearing as a silent coverage gap
  5. The entire module UI (results list, filters, saved searches, settings) is fully usable in both German and English

Plans: 5/5 plans executed

Wave 1 (parallel — disjoint files)

  • 14-01-PLAN.md — Inbox-Modul-Extraktion (ImapProvider/ExchangeInboxProvider → apps/api/src/inbox/) + additive fetchMessages() (INGEST-05 prerequisite)
  • 14-02-PLAN.md — RSS-Ingestion-Slice: RssAdapter + globale Feed-Liste-CRUD (Denylist/SSRF-Guard) + pollGranularity-Tick-Gate + Admin-UI (INGEST-04, CONFIG-02)

Wave 2 (blocked on 14-01 + 14-02)

  • 14-03-PLAN.md — E-Mail-Alert-Slice: TenderEmailConfig (pro Mandant, verschlüsselt) + EmailAlertAdapter + per-Mandant Tender-Sichtbarkeit (D-13) + EWS-Human-Verify (INGEST-05, CONFIG-02)

Wave 3 (blocked on 14-03)

  • 14-04-PLAN.md — Denylist-Transparenz: denylisted-portals-Endpoint + CoverageBanner „manuell beobachten"-Block (UI-06)

Wave 4 (blocked on 14-02 + 14-03 + 14-04)

  • 14-05-PLAN.md — i18n-Rollout: tenderRadar-Namensraum (DE/EN) + Komponenten auf useTranslations + Key-Parity-Test (CONFIG-03)

UI hint: yes

Phase 15: Modul-Berechtigungen: Gruppen & User-Grants

Goal: Modulzugriff wird zweistufig: die bestehende Mandanten-Aktivierung bleibt Voraussetzung, darüber hinaus entscheiden Freigaben pro Gruppe und pro einzelnem Benutzer, wer ein Modul sieht und dessen API nutzen darf. Admins verwalten Gruppen (optional an eine AD-Gruppe gebunden) und eine Freigabe-Matrix pro Modul im Admin-UI. Depends on: Phase 14 Requirements: PERM-01, PERM-02, PERM-03, PERM-04, PERM-05, PERM-06, PERM-07 Success Criteria (what must be TRUE):

  1. Ein Admin kann im Admin-UI Gruppen anlegen, umbenennen und löschen sowie Benutzer manuell zuweisen und entfernen
  2. Eine Gruppe kann optional an einen AD-Gruppen-DN gebunden werden; der LDAP-Sync trägt die Mitglieder aus memberOf ein und entfernt dabei keine manuell gesetzten Mitglieder
  3. Ein Admin kann ein mandantenweit aktives Modul gezielt für Gruppen und/oder einzelne Benutzer freigeben und die Freigabe wieder entziehen
  4. Ohne Freigabe hat ein USER keinen Zugriff: das Modul fehlt in der Sidebar, die Modulseite ist gesperrt und die Modul-API antwortet mit 403 — Sidebar und API nutzen dieselbe Zugriffsauflösung
  5. ADMIN und SUPER_ADMIN sehen und nutzen innerhalb ihres Mandanten alle aktiven Module ohne Freigabe
  6. Nach der Migration hat kein bestehender Benutzer Zugriff verloren: pro Mandant existiert eine als Standardgruppe markierte Gruppe „Alle Benutzer" mit allen Bestandsbenutzern und Freigaben für alle zum Migrationszeitpunkt aktiven Module
  7. Ein Dashboard-Widget, dessen Modul dem Benutzer nicht freigegeben ist, erscheint nicht auf seinem Dashboard

Design-Entscheidungen (mit User geklärt am 2026-08-04):

  • Gruppenquelle: Tessera-eigene Gruppen mit optionaler AD-Bindung (Group.ldapDn), nicht reine AD-Spiegelung
  • Default: geschlossen — ohne Grant kein Zugriff (Migration verhindert Lockout)
  • Bypass: ADMIN + SUPER_ADMIN umgehen Grants innerhalb ihres Mandanten
  • Tiefe: nur Modulzugriff an/aus, keine Rechtestufen (read/write) innerhalb der Module

Neue Modelle: Group (tenantId, name, ldapDn?), GroupMembership (userId, groupId, source MANUAL|LDAP), ModuleGrant (tenantId, moduleId, groupId? | userId?)

Plans: 7/8 plans executed

Plans: Wave 1

  • 15-01-PLAN.md — Schema, Migration mit Bestandsübernahme und Zugriffsauflösung (Tracer)

Wave 2 (blocked on Wave 1 completion)

  • 15-02-PLAN.md — Gruppen-API und automatische Standardgruppen-Mitgliedschaft
  • 15-04-PLAN.md — AD-Gruppenbindung im bestehenden LDAP-Sync
  • 15-05-PLAN.md — Modulfilter für Dashboard-Widgets

Wave 3 (blocked on Wave 2 completion)

  • 15-03-PLAN.md — Freigabe-API für Gruppen und Benutzer plus Modulkatalog-Endpoint
  • 15-06-PLAN.md — Gruppenverwaltung im Admin-UI und alle i18n-Schlüssel der Phase

Wave 4 (blocked on Wave 3 completion)

  • 15-07-PLAN.md — Freigabe-Matrix, Benutzer-Detail und Aktivierungsdialog
  • 15-08-PLAN.md — Serverseitige 403-Modulsperre und Marketplace-Kennzeichnung

Wellen: 1 → 15-01 · 2 → 15-02, 15-04, 15-05 · 3 → 15-03, 15-06 · 4 → 15-07, 15-08

UI hint: yes

Phase 16: AD-Gruppen-Synchronisation

Goal: Ausgewählte AD-Gruppen werden als Tessera-Gruppen angelegt und dauerhaft nachgeführt, statt jede Gruppe von Hand anzulegen und zu binden. Der Admin wählt aus der AD-Gruppenliste aus, welche Gruppen übernommen werden; der bestehende Benutzer-Sync hält Bestand, Namen und Mitgliedschaften danach aktuell. Depends on: Phase 15 Requirements: TBD (werden in /gsd-plan-phase 16 vergeben) Success Criteria (what must be TRUE):

  1. Ein Admin wählt aus der AD-Gruppenliste einzelne Gruppen zur Übernahme aus; für jede ausgewählte Gruppe entsteht eine Tessera-Gruppe mit gesetzter AD-Bindung
  2. Nicht ausgewählte AD-Gruppen werden nicht angelegt — es gibt keine pauschale Übernahme einer ganzen OU
  3. Wird eine übernommene Gruppe im AD umbenannt, zieht der Name der Tessera-Gruppe beim nächsten Sync nach
  4. Verschwindet eine übernommene Gruppe aus dem AD, wird die Tessera-Gruppe samt ihrer Mitgliedschaften und Modulfreigaben entfernt
  5. Manuell angelegte Gruppen ohne AD-Bindung bleiben vom Gruppen-Sync unberührt

Design-Entscheidungen (mit User geklärt am 2026-08-05):

  • Umfang: nur ausdrücklich ausgewählte AD-Gruppen, keine OU-weite Automatik
  • Löschen im AD löscht die Tessera-Gruppe mit — inklusive der daran hängenden Modulfreigaben
  • Umbenennen im AD zieht in Tessera nach

Bekannte Folge, bewusst akzeptiert: Ein Löschvorgang im AD nimmt betroffenen Benutzern schlagartig die über diese Gruppe vergebenen Modulzugriffe, ohne den Warndialog aus D-17 zu durchlaufen — der greift nur beim Löschen über die Tessera-Oberfläche.

Offen für die Planung: ob ein Admin eine automatisch angelegte Gruppe in Tessera umbenennen darf (würde beim nächsten Sync überschrieben), und wie sich die Auswahl-Oberfläche zur bestehenden AD-Gruppenauswahl in /admin/groups verhält.

Plans: 0 plans

Plans:

  • TBD (run /gsd-plan-phase 16 to break down)

UI hint: yes

Progress

Execution Order: Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 -> 15

Phase Plans Complete Status Completed
1. Foundation & Portal Shell 3/3 Complete 2026-06-18
2. Authentication & Multi-Tenancy 4/5 Incomplete — 02-05 visual verification never run -
3. Module System & Domaincheck 4/4 Complete 2026-06-20
4. Marketplace & Portal Navigation 4/4 Complete 2026-06-23
5. Dashboard & Calendar 5/5 Complete 2026-06-24
6. Desktop Client & CI/CD 3/3 Complete 2026-06-25
7. DKV Fleet Module 6/6 Complete 2026-06-27
8. Dashboard Widgets Vollimplementierung 4/4 Complete 2026-07-01
9. Cert Manager Module 6/6 Complete 2026-07-02
10. Ausschreibungs-Radar Foundation & DÖE Ingestion 6/6 Complete 2026-07-21
11. Filter Engine, Results UI & Saved Searches 6/6 In Progress
12. Tender Notifications 4/4 In Progress
13. Scraping Adapters & Cross-Source Deduplication 6/6 In Progress
14. RSS, Email-Alert Ingestion & Module Rollout 5/5 In Progress
15. Modul-Berechtigungen: Gruppen & User-Grants 7/8 In Progress