CIR Insolvency Monitor (.NET 8) on Raspberry Pi 5 (Linux) + Keyword Filtering
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
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
Related categories:
Python
.NET
Linux
Software Architecture
Ubuntu
Debian
Raspberry Pi
Backend Development
Automation