feat(notifications): центр уведомлений о системных событиях
Добавлена система уведомлений о системных и фоновых событиях (новые записи журнала, обработка фото, авто-проверка текста, блокировки IP, бэкапы). - backend (server.js, worker.js): - каталог NOTIFY_TYPES с метаданными и уровнями - таблицы notifications и notification_reads в db/init.sql и db/migration.sql - SSE-стрим GET /api/notifications/stream через Redis pub/sub с in-memory fallback - REST API: список, счётчик непрочитанных, отметка о прочтении, удаление, очистка - настройки уведомлений в settings (notify_enabled, notify_retention_days, notify_<тип>) - автоматическая очистка старых уведомлений по расписанию - frontend: - колокольчик со счётчиком непрочитанных в шапке (admin.js) - страница списка уведомлений public/notifications.html и public/js/notifications.js - секция настроек уведомлений в public/settings.html и public/js/settings.js - стили для уведомлений в public/admin.css - тесты и документация: - добавлены проверки в api.smoketest.js - обновлены README.md и AGENTS.md
This commit is contained in:
+48
@@ -252,3 +252,51 @@ CREATE TABLE IF NOT EXISTS audit_log (
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log(created_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id SERIAL PRIMARY KEY,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
level VARCHAR(20) NOT NULL DEFAULT 'info',
|
||||
title VARCHAR(200) NOT NULL,
|
||||
body TEXT,
|
||||
link VARCHAR(255),
|
||||
target JSONB,
|
||||
admin_only BOOLEAN NOT NULL DEFAULT false,
|
||||
branch_id INT REFERENCES branches(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_created_at ON notifications(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_branch_id ON notifications(branch_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notification_reads (
|
||||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
notification_id INT NOT NULL REFERENCES notifications(id) ON DELETE CASCADE,
|
||||
read_at TIMESTAMPTZ DEFAULT now(),
|
||||
PRIMARY KEY (user_id, notification_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notification_reads_user ON notification_reads(user_id);
|
||||
|
||||
INSERT INTO settings (key, value) VALUES ('notify_enabled', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_retention_days', '30')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_entry_new', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_entry_ai_corrected', 'false')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_entry_ai_error', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_photo_job_done', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_photo_job_error', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_ip_ban', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_backup_restore', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_backup_create', 'false')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_system_test', 'true')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
@@ -258,3 +258,40 @@ CREATE TABLE IF NOT EXISTS student_photos (
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_student_photos_student_id ON student_photos(student_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id SERIAL PRIMARY KEY,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
level VARCHAR(20) NOT NULL DEFAULT 'info',
|
||||
title VARCHAR(200) NOT NULL,
|
||||
body TEXT,
|
||||
link VARCHAR(255),
|
||||
target JSONB,
|
||||
admin_only BOOLEAN NOT NULL DEFAULT false,
|
||||
branch_id INT REFERENCES branches(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_created_at ON notifications(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_branch_id ON notifications(branch_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notification_reads (
|
||||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
notification_id INT NOT NULL REFERENCES notifications(id) ON DELETE CASCADE,
|
||||
read_at TIMESTAMPTZ DEFAULT now(),
|
||||
PRIMARY KEY (user_id, notification_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notification_reads_user ON notification_reads(user_id);
|
||||
|
||||
INSERT INTO settings (key, value) VALUES ('notify_enabled', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_retention_days', '30') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_entry_new', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_entry_ai_corrected', 'false') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_entry_ai_error', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_photo_job_done', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_photo_job_error', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_ip_ban', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_backup_restore', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_backup_create', 'false') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_system_test', 'true') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
Reference in New Issue
Block a user