Skip to content

Feature/notification archiving service#267

Merged
Abd-Standard merged 4 commits into
Core-Foundry:mainfrom
Dami24-hub:feature/notification-archiving-service
Jun 25, 2026
Merged

Feature/notification archiving service#267
Abd-Standard merged 4 commits into
Core-Foundry:mainfrom
Dami24-hub:feature/notification-archiving-service

Conversation

@Dami24-hub

Copy link
Copy Markdown
Contributor

Type of Change

  • New Feature (non-breaking change which adds functionality)
  • Database/Schema Migration
  • Documentation Update

Associated Issue

Closes #246

Overview

This Pull Request introduces the Notification Archiving Service for the Core-Foundry/Notify-Chain backend ecosystem. The objective is to optimize active database performance by automatically offloading historical notification records from primary storage into dedicated archive tables, while ensuring these records remain read-accessible for regulatory and compliance audits.

Key Implementation Details

1. Configuration & Retention Policy
  • Added an archiving configuration module driven by environment variables (NOTIFICATION_RETENTION_DAYS, NOTIFICATION_ARCHIVE_BATCH_SIZE).
  • Standard retention defaults to archiving records older than 90 days, processing records in controlled batches to minimize database lock contention.
2. Asynchronous Archiving Pipeline
  • Implemented a background worker execution loop (Cron/Task scheduler) that queries notifications matching the expiration threshold.
  • The pipeline utilizes a transactional "Copy-and-Delete" pattern to ensure data integrity during transit: records are successfully committed to the archived_notifications table before being purged from the active notifications table.
3. Read-Only Retrieval Endpoints
  • Exposed an administrative API endpoint: GET /api/v1/audit/notifications/archived.
  • Supports pagination, timestamp filtering, and user-id filtering to allow compliance teams to perform efficient audit lookups without degrading active production database performance.

Testing Strategy

  • Unit Tests: Verified retention threshold calculations, configuration parsing, and error-handling conditions during batch processing.
  • Integration Tests: Executed end-to-end flow checks validating that records crossing the age threshold are correctly moved to the archive table and disappear from active queries.
  • API Tests: Validated pagination parameters and query performance on the new retrieval endpoint under a simulated volume of 10,000 archived entries.

Verification Steps

1. Database Check

Ensure active and archived schemas are updated:

SELECT COUNT(*) FROM notifications WHERE created_at < NOW() - INTERVAL '90 days'; -- Should return 0 post-run
SELECT COUNT(*) FROM archived_notifications; -- Should reflect the moved volume
2. API Endpoint Verification

Execute a verified GET request to fetch archived audit logs:

GET /api/v1/audit/notifications/archived?userId=usr_01J0X&page=1&limit=20
Authorization: Bearer <admin_token>

Checklist

  • Code follows the existing style guidelines of this repository.
  • Database migrations have been tested for both up and down execution paths.
  • New and existing unit tests pass locally with the introduced changes.
  • Documentation regarding data retention policies and API schemas has been updated.

…l backoff

- Add RetryScheduler: DB-backed scheduler that polls for PENDING notifications
  with retry_count > 0 and re-attempts delivery using exponential backoff
- Add calculateBackoffDelay: formula = min(base * multiplier^attempt, maxDelayMs)
  with optional ±25% jitter to prevent thundering herd
- Add next_retry_at column to scheduled_notifications schema for precise
  retry scheduling; index for efficient due-retry queries
- Add fetchDueRetries() to ScheduledNotificationRepository: atomic
  UPDATE...WHERE with distributed lock (processor_id + lock_expires_at)
  prevents duplicate processing across concurrent instances
- Update markAsFailedOrRetry() to accept and persist nextRetryAt
- Add multiplier and jitter options to NotificationRetryQueue
- Add RETRY_MULTIPLIER, RETRY_MAX_DELAY_MS, RETRY_JITTER, and
  RETRY_SCHEDULER_* env vars; expose via config
- Wire RetryScheduler into service startup/shutdown in index.ts
- Add unit tests (retry-scheduler.test.ts): backoff math, success path,
  failure path, max-retries exhaustion, duplicate prevention
- Add integration tests (retry-scheduler.integration.test.ts): full
  SQLite round-trips covering all acceptance criteria
…oundry#242)

- Add NotificationTimeline and TimelineEntry types (src/types/timeline.ts)
- Add fetchTimeline() API service (src/services/timelineApi.ts)
- Add NotificationTimelineView component:
  - Filter by notification ID input with validation
  - Chronologically ordered list of status transitions
  - Loading skeleton (3-row pulse animation)
  - Empty state for no-entries and pre-search states
  - Displays attempt number, timestamp, error message, duration
  - next_retry_at and lastError surfaced when relevant
- Add timeline + app-tab CSS to index.css
- Wire component into App.tsx via tab navigation (Event Explorer / Delivery Timeline)
- Add component tests: chronological order, empty states, error handling,
  loading state, validation
- Extend EventFilters type with status (all/read/unread), dateFrom, dateTo
- Add read? field to BlockchainEvent
- Update filterEvents() to handle status and date range simultaneously
- Add setStatusFilter, setDateFrom, setDateTo to Zustand store
- Update useFilteredEvents hook to pass new filter params
- Add NotificationSearchBar component:
  - Debounced text search (250 ms) to avoid unnecessary re-renders
  - Status filter button group (All / Unread / Read) with aria-pressed
  - Date range pickers (from / to) with min/max constraints
  - Clear all filters button (only shown when filters are active)
  - Fully responsive — stacks vertically on mobile via media query
- Wire NotificationSearchBar into EventExplorerPage below EventFiltersBar
- Reset pagination on any filter change (status, date range included)
- Add component + unit tests (debounce, status, date range, clear)
…ints

- Add archive-schema.sql: notification_archive table with indexes
- Add archive-config.ts: ArchiveConfig type + loadArchiveConfig() via env vars
  (ARCHIVE_ENABLED, ARCHIVE_AFTER_MS, ARCHIVE_DELETE_AFTER_MS, etc.)
- Add archive-store.ts: ArchiveStore data-access layer (insertBatch, purge, query, getById)
- Add archive-service.ts: ArchiveService background worker (archive + purge cycle)
- Add archive-api.ts: HTTP handler for GET /api/archive, GET /api/archive/:id,
  POST /api/archive/run
- Wire ArchiveService + ArchiveStore into index.ts and events-server.ts
- Add archive.test.ts: 21 unit/integration tests (all passing)
- Add NOTIFICATION_ARCHIVING.md: schema, retention policy, API reference
- Update .env.example with archive env var documentation

Closes Core-Foundry#246
@drips-wave

drips-wave Bot commented Jun 25, 2026

Copy link
Copy Markdown

@Dami24-hub Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Abd-Standard Abd-Standard merged commit bed9be4 into Core-Foundry:main Jun 25, 2026
0 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Backend] Add Notification Archiving Service

2 participants