···3030sha2 = "0.10.9"
3131sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "postgres", "uuid", "chrono", "json"] }
3232thiserror = "2.0.17"
3333-tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time"] }
3333+tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time", "signal", "process"] }
3434tracing = "0.1.43"
3535tracing-subscriber = "0.3.22"
3636uuid = { version = "1.19.0", features = ["v4", "fast-rng"] }
+9-3
TODO.md
···126126 - [ ] Implement caching layer for DID resolution (Redis or in-memory).
127127 - [ ] Handle cache invalidation/expiry.
128128- [ ] Background Jobs
129129- - [ ] Implement background queue for async tasks (crawler notifications, discord/telegram 2FA sending instead of email).
130129 - [ ] Implement `Crawlers` service (debounce notifications to relays).
131131-- [ ] Mailer equivalent
132132- - [ ] Implement code/notification sending service as a replacement for the mailer because there's no way I'm starting with email. :D
130130+- [x] Notification Service
131131+ - [x] Queue-based notification system with database table
132132+ - [x] Background worker polling for pending notifications
133133+ - [x] Extensible sender trait for multiple channels
134134+ - [x] Email sender via OS sendmail/msmtp
135135+ - [ ] Discord bot sender
136136+ - [ ] Telegram bot sender
137137+ - [ ] Signal bot sender
138138+ - [x] Helper functions for common notification types (welcome, password reset, email verification, etc.)
133139- [ ] Image Processing
134140 - [ ] Implement image resize/formatting pipeline (for blob uploads).
135141- [ ] IPLD & MST
+36
migrations/202512212000_notification_queue.sql
···11+CREATE TYPE notification_channel AS ENUM ('email', 'discord', 'telegram', 'signal');
22+CREATE TYPE notification_status AS ENUM ('pending', 'processing', 'sent', 'failed');
33+CREATE TYPE notification_type AS ENUM (
44+ 'welcome',
55+ 'email_verification',
66+ 'password_reset',
77+ 'email_update',
88+ 'account_deletion'
99+);
1010+1111+CREATE TABLE IF NOT EXISTS notification_queue (
1212+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
1313+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
1414+ channel notification_channel NOT NULL DEFAULT 'email',
1515+ notification_type notification_type NOT NULL,
1616+ status notification_status NOT NULL DEFAULT 'pending',
1717+ recipient TEXT NOT NULL,
1818+ subject TEXT,
1919+ body TEXT NOT NULL,
2020+ metadata JSONB,
2121+ attempts INT NOT NULL DEFAULT 0,
2222+ max_attempts INT NOT NULL DEFAULT 3,
2323+ last_error TEXT,
2424+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
2525+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
2626+ scheduled_for TIMESTAMPTZ NOT NULL DEFAULT NOW(),
2727+ processed_at TIMESTAMPTZ
2828+);
2929+3030+CREATE INDEX idx_notification_queue_status_scheduled
3131+ ON notification_queue(status, scheduled_for)
3232+ WHERE status = 'pending';
3333+3434+CREATE INDEX idx_notification_queue_user_id ON notification_queue(user_id);
3535+3636+ALTER TABLE users ADD COLUMN IF NOT EXISTS preferred_notification_channel notification_channel NOT NULL DEFAULT 'email';