This repository was archived by the owner on Mar 31, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.sql
More file actions
255 lines (224 loc) · 7.23 KB
/
schema.sql
File metadata and controls
255 lines (224 loc) · 7.23 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
-- ============================================
-- Wild Lychee — Database Schema
-- All migrations are idempotent (safe to re-run)
-- ============================================
-- ============================================
-- SECTION: Core / Config
-- ============================================
CREATE TABLE IF NOT EXISTS site_config (
key TEXT PRIMARY KEY,
value JSONB NOT NULL,
category TEXT NOT NULL DEFAULT 'general'
);
CREATE TABLE IF NOT EXISTS pages (
id SERIAL PRIMARY KEY,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
content TEXT,
requires_auth BOOLEAN DEFAULT false,
show_in_nav BOOLEAN DEFAULT false,
nav_position INT,
published BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS sections (
id SERIAL PRIMARY KEY,
page_slug TEXT DEFAULT 'index',
section_type TEXT NOT NULL,
config JSONB NOT NULL,
position INT NOT NULL,
visible BOOLEAN DEFAULT true
);
-- ============================================
-- SECTION: Members
-- ============================================
CREATE TABLE IF NOT EXISTS membership_tiers (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
benefits TEXT[],
price_label TEXT,
position INT NOT NULL,
is_default BOOLEAN DEFAULT false
);
CREATE TABLE IF NOT EXISTS member_custom_fields (
id SERIAL PRIMARY KEY,
field_name TEXT NOT NULL,
field_label TEXT NOT NULL,
field_type TEXT NOT NULL,
options JSONB,
required BOOLEAN DEFAULT false,
visible_in_directory BOOLEAN DEFAULT true,
position INT NOT NULL
);
CREATE TABLE IF NOT EXISTS members (
id SERIAL PRIMARY KEY,
user_id UUID,
email TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL,
avatar_url TEXT,
bio TEXT,
tier_id INT REFERENCES membership_tiers(id),
role TEXT NOT NULL DEFAULT 'member',
status TEXT NOT NULL DEFAULT 'pending',
custom_fields JSONB DEFAULT '{}',
joined_at TIMESTAMPTZ DEFAULT now(),
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================
-- SECTION: Events (feature: events)
-- ============================================
CREATE TABLE IF NOT EXISTS events (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT,
location TEXT,
starts_at TIMESTAMPTZ NOT NULL,
ends_at TIMESTAMPTZ,
capacity INT,
image_url TEXT,
is_members_only BOOLEAN DEFAULT false,
created_by INT REFERENCES members(id),
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS event_rsvps (
id SERIAL PRIMARY KEY,
event_id INT REFERENCES events(id) ON DELETE CASCADE,
member_id INT REFERENCES members(id),
status TEXT NOT NULL DEFAULT 'going',
created_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(event_id, member_id)
);
-- ============================================
-- SECTION: Resources (feature: resources)
-- ============================================
CREATE TABLE IF NOT EXISTS resources (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT,
category TEXT,
file_url TEXT,
file_type TEXT,
is_members_only BOOLEAN DEFAULT true,
uploaded_by INT REFERENCES members(id),
created_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================
-- SECTION: Forum (feature: forum)
-- ============================================
CREATE TABLE IF NOT EXISTS forum_categories (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
position INT NOT NULL,
color TEXT DEFAULT '#6366f1'
);
CREATE TABLE IF NOT EXISTS forum_topics (
id SERIAL PRIMARY KEY,
category_id INT REFERENCES forum_categories(id),
title TEXT NOT NULL,
body TEXT NOT NULL,
author_id INT REFERENCES members(id),
is_pinned BOOLEAN DEFAULT false,
reply_count INT DEFAULT 0,
last_reply_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS forum_replies (
id SERIAL PRIMARY KEY,
topic_id INT REFERENCES forum_topics(id) ON DELETE CASCADE,
body TEXT NOT NULL,
author_id INT REFERENCES members(id),
created_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================
-- SECTION: Committees (feature: committees)
-- ============================================
CREATE TABLE IF NOT EXISTS committees (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS committee_members (
id SERIAL PRIMARY KEY,
committee_id INT REFERENCES committees(id) ON DELETE CASCADE,
member_id INT REFERENCES members(id),
role TEXT DEFAULT 'member',
joined_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(committee_id, member_id)
);
-- ============================================
-- SECTION: Announcements
-- ============================================
CREATE TABLE IF NOT EXISTS announcements (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
body TEXT NOT NULL,
is_pinned BOOLEAN DEFAULT false,
author_id INT REFERENCES members(id),
created_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================
-- SECTION: Activity Log
-- ============================================
CREATE TABLE IF NOT EXISTS activity_log (
id SERIAL PRIMARY KEY,
member_id INT REFERENCES members(id),
action TEXT NOT NULL,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================
-- SECTION: AI Features
-- ============================================
CREATE TABLE IF NOT EXISTS content_translations (
id SERIAL PRIMARY KEY,
content_type TEXT NOT NULL,
content_id INT NOT NULL,
language TEXT NOT NULL,
field TEXT NOT NULL,
translated_text TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(content_type, content_id, language, field)
);
CREATE TABLE IF NOT EXISTS moderation_log (
id SERIAL PRIMARY KEY,
content_type TEXT NOT NULL,
content_id INT NOT NULL,
action TEXT NOT NULL,
reason TEXT,
confidence REAL,
reviewed_by INT REFERENCES members(id),
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS member_insights (
id SERIAL PRIMARY KEY,
member_id INT REFERENCES members(id),
insight_type TEXT NOT NULL,
message TEXT NOT NULL,
priority TEXT DEFAULT 'medium',
status TEXT DEFAULT 'pending',
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS newsletter_drafts (
id SERIAL PRIMARY KEY,
subject TEXT NOT NULL,
body TEXT NOT NULL,
status TEXT DEFAULT 'draft',
period_start TIMESTAMPTZ,
period_end TIMESTAMPTZ,
sent_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================
-- SECTION: Schema Migrations (safe column additions)
-- ============================================
DO $$ BEGIN ALTER TABLE forum_topics ADD COLUMN hidden BOOLEAN DEFAULT false; EXCEPTION WHEN duplicate_column THEN NULL; END $$;
DO $$ BEGIN ALTER TABLE forum_topics ADD COLUMN locked BOOLEAN DEFAULT false; EXCEPTION WHEN duplicate_column THEN NULL; END $$;
DO $$ BEGIN ALTER TABLE forum_replies ADD COLUMN hidden BOOLEAN DEFAULT false; EXCEPTION WHEN duplicate_column THEN NULL; END $$;
DO $$ BEGIN ALTER TABLE forum_topics ADD COLUMN search_vector TSVECTOR; EXCEPTION WHEN duplicate_column THEN NULL; END $$;
CREATE INDEX IF NOT EXISTS idx_forum_topics_search ON forum_topics USING GIN (search_vector);