CIR Insolvency Monitor (.NET 8) on Raspberry Pi 5 (Linux) + Keyword Filtering

Job ID: 40175744

Budget: €30 – €250 EUR

CIR Insolvency Monitor (.NET 8) on Raspberry Pi 5 (Linux) + Keyword Filtering
Goal

Build a reliable .NET 8 application that runs continuously on a Raspberry Pi 5 and, every 5 minutes, retrieves CIR insolvency publications for the last 30 days across all courts, then:

fetches details for new items,

stores ONLY records that match configured keywords into a SQLite database,

for each new database insert, sends a Telegram message and shows a popup notification.

Note: Telegram bot is already set up (token + chat id available).

Platform / Constraints

Hardware/OS: Raspberry Pi 5, Raspberry Pi OS (Linux, arm64)

Runtime: .NET 8 (linux-arm64)

App type: Console daemon / long-running process

Service: must run as a systemd service (auto-start + restart)

DB: SQLite (single file)

CIR request rate limit: max 10 requests/second (implement throttling, e.g., 8 r/s)

Auth: WS-Security UsernameToken (same approach as official CIR DemoClient)

Credentials: hardcoded in code (for now)

Functional Requirements
1) Scheduling

Runs continuously

Executes a full cycle every 5 minutes

Uses a rolling time window: last 30 days

2) “All courts”

Service can return: “Court may not be empty” → so the implementation must query all courts

At minimum include all Dutch district courts; if additional courts are attempted and rejected, log and continue

Any court-specific exception must not crash the run

3) Index retrieval (IDs)

Use CIR index operations such as:

searchByDate (per day) and/or

searchModifiedSince

Index response yields a list of publicatieKenmerk (string IDs) and/or an exception object

Collect all IDs across days and courts and deduplicate

4) Detail retrieval

For each candidate ID, call:

getCaseWithReports(publicatieKenmerk)

Extract at least:

publicatieKenmerk (unique ID)

publication date

court

insolvency type

insolvent name + city (if available)

raw payload (store as JSON or XML string)

5) Keyword filtering — IMPORTANT

Maintain a configurable list of keywords (hardcoded array is fine)

The system must ONLY insert into SQLite when keyword match is true

Keyword matching is case-insensitive and is evaluated against:

insolvent name

city

title/summary if available

and/or raw payload text (fallback)

6) Notifications

When a record is inserted into the database (i.e., it was new AND matched keywords):

Send a Telegram message

Show a popup notification

Dedup notifications:

Never notify twice for the same publicatieKenmerk

Important note about “popup” on Raspberry Pi

A real on-screen popup requires the Pi to run a GUI session (X11/Wayland).

If the Pi is headless, the “popup” should degrade to a desktop notification alternative or log-only.

If GUI is available, use Linux notification tools (e.g., notify-send) or another suitable approach.

(Freelancer should implement a best-effort popup strategy for Linux GUI and document requirements.)

Database (SQLite) requirements

SQLite file location e.g.: /opt/cir/data/cir.db

Table: cases

publicatieKenmerk TEXT PRIMARY KEY

insertedAtUtc TEXT NOT NULL

publicationDate TEXT

court TEXT

type TEXT

name TEXT

city TEXT

rawPayload TEXT NOT NULL

Table: notifications

publicatieKenmerk TEXT UNIQUE

notifiedAtUtc TEXT NOT NULL

channel TEXT (telegram/popup)

reason TEXT

Reliability / Non-functional

Must be robust: failures for one court or one detail call must not stop the cycle

Must respect rate limit

Logging to stdout (systemd journal) + optional file logging

Provide clear configuration section in code for:

keyword list

courts list

telegram token/chat id

polling interval/window

Deliverables

Working .NET 8 solution that builds for linux-arm64

systemd unit file + installation steps

SQLite schema auto-created

Telegram alerts working

Popup behavior documented (GUI requirements)

README:

how to build/publish

how to run as service

where to edit keywords/courts

how to view logs (journalctl -u ... -f)

Acceptance criteria (testable)

Service starts and runs every 5 minutes

If a matching insolvency appears:

it is inserted into SQLite once

Telegram message is received once

Popup is shown once (if GUI available)

Non-matching items are not inserted into SQLite