-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit.sql
More file actions
311 lines (284 loc) · 12.2 KB
/
Copy pathinit.sql
File metadata and controls
311 lines (284 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
-- =============================================================================
-- VideoVault – Vollständiges Datenbankschema
-- Zusammengeführt aus: 01-schema.sql, 02-extensions.sql, 03-blink.sql,
-- 04-blink-cameras.sql, 05-sync-jobs.sql, 06-live-stream.sql,
-- 07-retention-settings.sql, 08-live-recordings.sql
--
-- Wird automatisch beim ersten PostgreSQL-Start ausgeführt
-- (docker-entrypoint-initdb.d) wenn das Datenverzeichnis leer ist.
-- =============================================================================
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- ---------------------------------------------------------------------------
-- Benutzer
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(64) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
role VARCHAR(16) NOT NULL DEFAULT 'reader'
CHECK (role IN ('admin', 'operator', 'reader')),
can_download BOOLEAN NOT NULL DEFAULT TRUE,
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_login TIMESTAMPTZ
);
-- ---------------------------------------------------------------------------
-- Kategorien
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS categories (
id SERIAL PRIMARY KEY,
name VARCHAR(128) UNIQUE NOT NULL,
description TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
INSERT INTO categories (name, description)
VALUES ('Allgemein', 'Standardkategorie')
ON CONFLICT (name) DO NOTHING;
-- ---------------------------------------------------------------------------
-- Kameras
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS cameras (
id SERIAL PRIMARY KEY,
name VARCHAR(128) UNIQUE NOT NULL,
description TEXT,
location VARCHAR(255),
source VARCHAR(16) NOT NULL DEFAULT 'manual',
stream_url TEXT,
blink_camera_id TEXT,
blink_network_id TEXT,
blink_synced_at TIMESTAMPTZ,
snapshot_path TEXT,
snapshot_at TIMESTAMPTZ,
battery_powered BOOLEAN,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ---------------------------------------------------------------------------
-- Videos
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS videos (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
filename VARCHAR(255) NOT NULL,
storage_path TEXT NOT NULL,
thumbnail TEXT,
mime_type VARCHAR(64),
size_bytes BIGINT NOT NULL DEFAULT 0,
duration_sec NUMERIC(10,2),
width INTEGER,
height INTEGER,
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
camera_id INTEGER REFERENCES cameras(id) ON DELETE SET NULL,
uploaded_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
recorded_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ,
search_vector tsvector
);
CREATE INDEX IF NOT EXISTS idx_videos_recorded ON videos (recorded_at);
CREATE INDEX IF NOT EXISTS idx_videos_deleted ON videos (deleted_at);
CREATE INDEX IF NOT EXISTS idx_videos_category ON videos (category_id);
CREATE INDEX IF NOT EXISTS idx_videos_camera ON videos (camera_id);
CREATE INDEX IF NOT EXISTS idx_videos_search ON videos USING GIN (search_vector);
CREATE OR REPLACE FUNCTION videos_search_trigger() RETURNS trigger AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('simple', coalesce(NEW.title, '')), 'A') ||
setweight(to_tsvector('simple', coalesce(NEW.description, '')), 'B') ||
setweight(to_tsvector('simple', coalesce(NEW.filename, '')), 'C');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_videos_search ON videos;
CREATE TRIGGER trg_videos_search BEFORE INSERT OR UPDATE
ON videos FOR EACH ROW EXECUTE FUNCTION videos_search_trigger();
-- ---------------------------------------------------------------------------
-- Tags
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS tags (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS video_tags (
video_id INTEGER REFERENCES videos(id) ON DELETE CASCADE,
tag_id INTEGER REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (video_id, tag_id)
);
-- ---------------------------------------------------------------------------
-- API-Schlüssel
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS api_keys (
id SERIAL PRIMARY KEY,
label VARCHAR(128) NOT NULL,
key_hash TEXT NOT NULL,
prefix VARCHAR(12) NOT NULL,
owner_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_used TIMESTAMPTZ,
revoked BOOLEAN NOT NULL DEFAULT FALSE
);
-- ---------------------------------------------------------------------------
-- Sync-Log
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sync_log (
id SERIAL PRIMARY KEY,
started_at TIMESTAMPTZ NOT NULL DEFAULT now(),
finished_at TIMESTAMPTZ,
status VARCHAR(16) NOT NULL DEFAULT 'running'
CHECK (status IN ('running','success','error','interrupted')),
target TEXT,
files_synced INTEGER DEFAULT 0,
bytes_synced BIGINT DEFAULT 0,
message TEXT
);
-- ---------------------------------------------------------------------------
-- Lösch-Log
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS deletion_log (
id SERIAL PRIMARY KEY,
video_id INTEGER,
title VARCHAR(255),
reason VARCHAR(32) NOT NULL,
deleted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
performed_by INTEGER REFERENCES users(id) ON DELETE SET NULL
);
-- ---------------------------------------------------------------------------
-- Audit-Log
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS audit_log (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
action VARCHAR(64) NOT NULL,
detail TEXT,
ip VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ---------------------------------------------------------------------------
-- Netzwerkfreigaben
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS network_shares (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL,
protocol VARCHAR(8) NOT NULL CHECK (protocol IN ('smb','nfs')),
subpath VARCHAR(255) NOT NULL DEFAULT '',
writable BOOLEAN NOT NULL DEFAULT FALSE,
allowed TEXT,
guest_ok BOOLEAN NOT NULL DEFAULT FALSE,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ---------------------------------------------------------------------------
-- NAS-Ziele
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS nas_targets (
id SERIAL PRIMARY KEY,
name VARCHAR(128) NOT NULL,
protocol VARCHAR(8) NOT NULL CHECK (protocol IN ('smb','nfs','webdav')),
vendor VARCHAR(32) NOT NULL DEFAULT 'generic',
host VARCHAR(255) NOT NULL,
remote_path VARCHAR(255) NOT NULL DEFAULT '',
username VARCHAR(128),
password TEXT,
options TEXT,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ---------------------------------------------------------------------------
-- Einstellungen
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS settings (
key VARCHAR(64) PRIMARY KEY,
value TEXT,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
INSERT INTO settings (key, value) VALUES
('storage_mode', 'local'),
('active_nas_target', ''),
('nas_sync_cron', '0 */6 * * *'),
('nas_sync_enabled', 'false'),
('delete_local_after_sync', 'false'),
('retention_enabled', 'true'),
('retention_days', '90'),
('trash_retention_days', '14'),
('blink_last_clip_import', '')
ON CONFLICT (key) DO NOTHING;
-- ---------------------------------------------------------------------------
-- Blink-Konto
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS blink_account (
id INTEGER PRIMARY KEY DEFAULT 1 CHECK (id = 1),
email TEXT,
password_enc TEXT,
token_enc TEXT,
status VARCHAR(24) NOT NULL DEFAULT 'disconnected'
CHECK (status IN ('disconnected','connecting','twofa_required','connected','error')),
account_info JSONB,
last_login TIMESTAMPTZ,
token_updated_at TIMESTAMPTZ,
last_error TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ---------------------------------------------------------------------------
-- Blink-Clips
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS blink_clips (
clip_id TEXT PRIMARY KEY,
video_id INTEGER REFERENCES videos(id) ON DELETE SET NULL,
camera TEXT,
created_at TIMESTAMPTZ,
imported_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- ---------------------------------------------------------------------------
-- Sync-Jobs (geplante Aufgaben)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sync_jobs (
id SERIAL PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type VARCHAR(32) NOT NULL DEFAULT 'blink_check_all'
CHECK (type IN ('blink_check_all','hdd_sync','nas_sync')),
cron VARCHAR(64) NOT NULL DEFAULT '*/5 * * * *',
enabled BOOLEAN NOT NULL DEFAULT TRUE,
last_run TIMESTAMPTZ,
last_status VARCHAR(16),
last_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
INSERT INTO sync_jobs (name, type, cron, enabled)
SELECT 'Alle Kameras pruefen', 'blink_check_all', '*/5 * * * *', TRUE
WHERE NOT EXISTS (SELECT 1 FROM sync_jobs);
-- ---------------------------------------------------------------------------
-- Live-Aufnahmen
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS live_recordings (
id SERIAL PRIMARY KEY,
camera_id INTEGER REFERENCES cameras(id) ON DELETE SET NULL,
camera_name TEXT,
filename TEXT NOT NULL,
file_path TEXT NOT NULL,
size_bytes BIGINT DEFAULT 0,
duration_sec NUMERIC(10,2) DEFAULT 0,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
finished_at TIMESTAMPTZ,
title TEXT
);
CREATE INDEX IF NOT EXISTS idx_live_recordings_started ON live_recordings (started_at DESC);
CREATE INDEX IF NOT EXISTS idx_live_recordings_camera ON live_recordings (camera_id);
-- ---------------------------------------------------------------------------
-- Migration-Log (verhindert dass das Backend Migrationen doppelt ausführt)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS migration_log (
id TEXT PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
INSERT INTO migration_log (id) VALUES
('001_live_recordings'),
('002_cameras_stream_url'),
('003_cameras_blink_cols'),
('004_blink_clips'),
('005_retention_settings'),
('006_sync_jobs'),
('007_videos_search_vector')
ON CONFLICT DO NOTHING;