@opengis/cms 0.0.44 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -98
- package/dist/{en-OTy187va.js → en-sWmaB9uu.js} +3 -1
- package/dist/index.html +29 -29
- package/dist/index.js +4208 -4125
- package/dist/index.umd.cjs +70 -65
- package/dist/{uk-Dy2psXBp.js → uk-rH4IPxG5.js} +4 -2
- package/input-types.json +9 -9
- package/module/cms/cls/content.status.json +17 -17
- package/module/cms/cls/user_type.json +9 -9
- package/module/cms/form/admin.users.form.json +77 -77
- package/module/cms/select/cms.page_type.sql +1 -1
- package/module/cms/select/news_tag_id.sql +11 -11
- package/module/cms/table/admin.users.table.json +53 -53
- package/module/cms/table/collection.default.table.json +96 -96
- package/module/cms/table/single.default.table.json +116 -116
- package/package.json +3 -3
- package/plugin.js +43 -43
- package/server/app.js +35 -35
- package/server/config.js +4 -4
- package/server/functions/getDraftKey.js +22 -22
- package/server/index.js +22 -22
- package/server/migrations/fixes.sql +124 -124
- package/server/migrations/site.sql +595 -595
- package/server/plugins/adminHook.js +78 -78
- package/server/plugins/hook.js +59 -59
- package/server/plugins/vite.js +75 -75
- package/server/routes/category/controllers/cms.category.delete.js +21 -21
- package/server/routes/category/controllers/cms.category.get.js +17 -17
- package/server/routes/category/controllers/cms.category.list.js +16 -16
- package/server/routes/category/controllers/cms.category.post.js +21 -21
- package/server/routes/category/controllers/cms.category.put.js +23 -23
- package/server/routes/category/index.mjs +22 -22
- package/server/routes/cms/controllers/cmsStat.js +55 -55
- package/server/routes/cms/controllers/cmsSuggest.js +57 -57
- package/server/routes/cms/controllers/deleteContent.js +113 -113
- package/server/routes/cms/controllers/deleteMedia.js +76 -76
- package/server/routes/cms/controllers/downloadMedia.js +84 -49
- package/server/routes/cms/controllers/getContent.js +110 -110
- package/server/routes/cms/controllers/getContentBySlug.js +93 -93
- package/server/routes/cms/controllers/getPermissions.js +15 -15
- package/server/routes/cms/controllers/insertContent.js +217 -217
- package/server/routes/cms/controllers/listMedia.js +108 -94
- package/server/routes/cms/controllers/metadataMedia.js +39 -39
- package/server/routes/cms/controllers/properties.get.js +53 -53
- package/server/routes/cms/controllers/properties.post.js +99 -99
- package/server/routes/cms/controllers/searchContent.js +205 -205
- package/server/routes/cms/controllers/setPermissions.js +49 -49
- package/server/routes/cms/controllers/translate.js +89 -89
- package/server/routes/cms/controllers/updateContent.js +238 -238
- package/server/routes/cms/controllers/uploadMedia.js +79 -79
- package/server/routes/cms/index.mjs +112 -112
- package/server/routes/cms/utils/additionalData.js +35 -35
- package/server/routes/cms/utils/getCollection.js +82 -82
- package/server/routes/cms/utils/getSingle.js +187 -187
- package/server/routes/cms/utils/inputTypes.js +5 -5
- package/server/routes/cms/utils/insertContentLocalization.js +86 -86
- package/server/routes/cms/utils/requestTranslation.js +85 -85
- package/server/routes/cms/utils/updateLocalization.js +47 -47
- package/server/routes/cmsSpace/controllers/deleteSpace.js +25 -25
- package/server/routes/cmsSpace/controllers/getSpaces.js +27 -27
- package/server/routes/cmsSpace/controllers/insertSpace.js +21 -21
- package/server/routes/cmsSpace/controllers/updateSpace.js +23 -23
- package/server/routes/cmsSpace/index.mjs +20 -20
- package/server/routes/contentType/controllers/addContentType.js +162 -162
- package/server/routes/contentType/controllers/contentTypeList.js +54 -54
- package/server/routes/contentType/controllers/delContentType.js +75 -75
- package/server/routes/contentType/controllers/editContentType.js +61 -61
- package/server/routes/contentType/controllers/getContentType.js +37 -37
- package/server/routes/contentType/index.mjs +35 -35
- package/server/routes/contentType/utils/updateContents.js +28 -28
- package/server/routes/contentType/utils/updateCustomContentTable.js +53 -53
- package/server/routes/feedback/controllers/email.list.js +24 -24
- package/server/routes/feedback/controllers/feedback.js +48 -48
- package/server/routes/feedback/controllers/feedback.list.js +37 -37
- package/server/routes/feedback/controllers/news.subscriptions.js +44 -44
- package/server/routes/feedback/index.mjs +71 -71
- package/server/routes/logs/controllers/export.user.logs.js +77 -77
- package/server/routes/logs/controllers/user.logs.js +44 -44
- package/server/routes/logs/index.mjs +9 -9
- package/server/routes/menu/controllers/addMenu.js +37 -37
- package/server/routes/menu/controllers/delMenu.js +31 -31
- package/server/routes/menu/controllers/editMenu.js +41 -41
- package/server/routes/menu/controllers/getMenu.js +42 -42
- package/server/routes/menu/index.mjs +13 -13
- package/server/routes/migration/controllers/collectionToCustom.js +137 -137
- package/server/routes/migration/index.mjs +8 -8
- package/server/routes/root.mjs +8 -8
- package/server/routes/tags/controllers/add.tags.js +24 -24
- package/server/routes/tags/controllers/del.tags.js +19 -19
- package/server/routes/tags/controllers/edit.tags.js +25 -25
- package/server/routes/tags/controllers/get.tags.js +15 -15
- package/server/routes/tags/index.mjs +14 -14
- package/server/templates/cls/cms.category_type.json +9 -9
- package/server/templates/cls/cms.content_review_status.json +9 -9
- package/server/templates/cls/cms.content_status.json +9 -9
- package/server/templates/cls/cms.content_type.json +9 -9
- package/server/templates/cls/cms.lang.json +9 -9
- package/server/templates/page/login.html +126 -126
- package/server/templates/select/core.user_mentioned.sql +1 -1
|
@@ -1,595 +1,595 @@
|
|
|
1
|
-
create schema if not exists admin;
|
|
2
|
-
create table if not exists admin.users (uid text primary key default next_id());
|
|
3
|
-
|
|
4
|
-
create schema if not exists site;
|
|
5
|
-
create schema if not exists data;
|
|
6
|
-
|
|
7
|
-
-- drop table if exists site.categories cascade;
|
|
8
|
-
create table if not exists site.categories (
|
|
9
|
-
category_id text primary key default next_id(),
|
|
10
|
-
name text not null,
|
|
11
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
12
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
13
|
-
created_by text REFERENCES admin.users(uid),
|
|
14
|
-
updated_by text REFERENCES admin.users(uid)
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
-- drop table if exists site.media cascade;
|
|
18
|
-
CREATE TABLE if not exists site.media (
|
|
19
|
-
media_id text PRIMARY KEY default next_id(),
|
|
20
|
-
filename TEXT NOT NULL,
|
|
21
|
-
filetype TEXT NOT NULL,
|
|
22
|
-
filesize INTEGER NOT NULL,
|
|
23
|
-
subdir TEXT,
|
|
24
|
-
url TEXT,
|
|
25
|
-
description TEXT,
|
|
26
|
-
alt text,
|
|
27
|
-
mime VARCHAR(100),
|
|
28
|
-
preview_url TEXT,
|
|
29
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
30
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
31
|
-
created_by text REFERENCES admin.users(uid),
|
|
32
|
-
updated_by text REFERENCES admin.users(uid)
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
COMMENT ON TABLE site.media IS 'Stores uploaded media files with metadata, URLs, and audit info.';
|
|
36
|
-
COMMENT ON COLUMN site.media.media_id IS 'Unique ID for the media item.';
|
|
37
|
-
COMMENT ON COLUMN site.media.filename IS 'Original name of the uploaded file.';
|
|
38
|
-
COMMENT ON COLUMN site.media.filetype IS 'Logical type of file (e.g., image, video, document).';
|
|
39
|
-
COMMENT ON COLUMN site.media.filesize IS 'Size of the file in bytes.';
|
|
40
|
-
-- COMMENT ON COLUMN site.media.subdir is 'Піддиректорія';
|
|
41
|
-
COMMENT ON COLUMN site.media.url IS 'URL where the file can be accessed.';
|
|
42
|
-
COMMENT ON COLUMN site.media.description IS 'Optional description or caption.';
|
|
43
|
-
COMMENT ON COLUMN site.media.alt IS 'Alternative text for screen readers or image fallbacks.';
|
|
44
|
-
COMMENT ON COLUMN site.media.mime IS 'MIME type indicating the file format (e.g., image/png).';
|
|
45
|
-
COMMENT ON COLUMN site.media.preview_url IS 'Optional preview or thumbnail URL.';
|
|
46
|
-
COMMENT ON COLUMN site.media.created_at IS 'Timestamp of when the media record was created.';
|
|
47
|
-
COMMENT ON COLUMN site.media.updated_at IS 'Timestamp of the last update to the media record.';
|
|
48
|
-
COMMENT ON COLUMN site.media.created_by IS 'User ID who uploaded the media.';
|
|
49
|
-
COMMENT ON COLUMN site.media.updated_by IS 'User ID who last updated the media.';
|
|
50
|
-
|
|
51
|
-
CREATE INDEX if not exists idx_media_filetype ON site.media(filetype);
|
|
52
|
-
CREATE INDEX if not exists idx_media_filesize ON site.media(filesize);
|
|
53
|
-
CREATE INDEX if not exists idx_media_mime ON site.media(mime);
|
|
54
|
-
CREATE INDEX if not exists idx_media_created_at ON site.media(created_at);
|
|
55
|
-
CREATE INDEX if not exists idx_media_created_by ON site.media(created_by);
|
|
56
|
-
CREATE INDEX if not exists idx_media_updated_at ON site.media(updated_at);
|
|
57
|
-
CREATE INDEX if not exists idx_media_updated_by ON site.media(updated_by);
|
|
58
|
-
|
|
59
|
-
-- drop table if exists site.content_types cascade;
|
|
60
|
-
CREATE TABLE if not exists site.content_types (
|
|
61
|
-
content_type_id text PRIMARY KEY default next_id(),
|
|
62
|
-
name VARCHAR (50) NOT NULL UNIQUE,
|
|
63
|
-
title VARCHAR (50) NOT NULL,
|
|
64
|
-
table_name VARCHAR(50),
|
|
65
|
-
columns json,
|
|
66
|
-
status VARCHAR (20) DEFAULT 'draft' CHECK (status::text = ANY (ARRAY['draft', 'published', 'archived']::text[])),
|
|
67
|
-
visible BOOLEAN DEFAULT TRUE,
|
|
68
|
-
localized BOOLEAN DEFAULT FALSE,
|
|
69
|
-
type VARCHAR(20) NOT NULL DEFAULT 'collection' CHECK (type::text = ANY (ARRAY['collection', 'single']::text[])),
|
|
70
|
-
schema JSONB,
|
|
71
|
-
description TEXT,
|
|
72
|
-
icon VARCHAR (50),
|
|
73
|
-
color VARCHAR (20),
|
|
74
|
-
preview_path text,
|
|
75
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
76
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
77
|
-
created_by text REFERENCES admin.users(uid),
|
|
78
|
-
updated_by text REFERENCES admin.users(uid)
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
ALTER TABLE site.content_types add COLUMN if not exists table_name text;
|
|
82
|
-
ALTER TABLE site.content_types add COLUMN if not exists title text;
|
|
83
|
-
ALTER TABLE site.content_types add COLUMN if not exists status text;
|
|
84
|
-
ALTER TABLE site.content_types add COLUMN if not exists visible boolean default true;
|
|
85
|
-
ALTER TABLE site.content_types add COLUMN if not exists localized boolean default false;
|
|
86
|
-
ALTER TABLE site.content_types add COLUMN if not exists schema jsonb;
|
|
87
|
-
ALTER TABLE site.content_types add COLUMN if not exists icon text;
|
|
88
|
-
ALTER TABLE site.content_types add COLUMN if not exists color text;
|
|
89
|
-
ALTER TABLE site.content_types add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
90
|
-
ALTER TABLE site.content_types add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
91
|
-
ALTER TABLE site.content_types add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
92
|
-
ALTER TABLE site.content_types add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
93
|
-
ALTER TABLE site.content_types add COLUMN if not exists preview_path text;
|
|
94
|
-
|
|
95
|
-
ALTER TABLE if exists site.content_types ALTER COLUMN table_name DROP NOT NULL;
|
|
96
|
-
ALTER TABLE if exists site.content_types ADD COLUMN if not exists columns json;
|
|
97
|
-
|
|
98
|
-
COMMENT ON TABLE site.content_types IS 'Defines reusable content structures for dynamic content management.';
|
|
99
|
-
COMMENT ON COLUMN site.content_types.content_type_id IS 'Unique identifier for the content type.';
|
|
100
|
-
COMMENT ON COLUMN site.content_types.name IS 'Internal name used in the system (must be unique).';
|
|
101
|
-
COMMENT ON COLUMN site.content_types.name IS 'Name / Alias / slug';
|
|
102
|
-
COMMENT ON COLUMN site.content_types.title IS 'Title';
|
|
103
|
-
COMMENT ON COLUMN site.content_types.table_name IS 'Physical table where entries of this type are stored.';
|
|
104
|
-
COMMENT ON COLUMN site.content_types.status IS 'Status of the content type (draft, published, archived).';
|
|
105
|
-
COMMENT ON COLUMN site.content_types.visible IS 'Controls whether this content type appears in admin UI.';
|
|
106
|
-
COMMENT ON COLUMN site.content_types.localized IS 'Indicates whether the content type supports localization.';
|
|
107
|
-
COMMENT ON COLUMN site.content_types.type IS 'Whether this content type is a collection or a single instance.';
|
|
108
|
-
COMMENT ON COLUMN site.content_types.schema IS 'JSON schema defining the structure and fields of this content type.';
|
|
109
|
-
COMMENT ON COLUMN site.content_types.description IS 'Optional description of the content type.';
|
|
110
|
-
COMMENT ON COLUMN site.content_types.icon IS 'UI icon identifier for this type.';
|
|
111
|
-
COMMENT ON COLUMN site.content_types.color IS 'UI color code or name for this type.';
|
|
112
|
-
COMMENT ON COLUMN site.content_types.created_at IS 'Timestamp when the content type was created.';
|
|
113
|
-
COMMENT ON COLUMN site.content_types.updated_at IS 'Timestamp when the content type was last modified.';
|
|
114
|
-
COMMENT ON COLUMN site.content_types.created_by IS 'Admin user who created the content type.';
|
|
115
|
-
COMMENT ON COLUMN site.content_types.updated_by IS 'Admin user who last updated the content type.';
|
|
116
|
-
COMMENT ON COLUMN site.content_types.preview_path IS 'Назва інтерфейсу на сайті';
|
|
117
|
-
|
|
118
|
-
ALTER TABLE if exists site.content_types ADD COLUMN if not exists include_search boolean;
|
|
119
|
-
|
|
120
|
-
CREATE INDEX if not exists idx_content_types_status ON site.content_types(status);
|
|
121
|
-
CREATE INDEX if not exists idx_content_types_visible ON site.content_types(visible);
|
|
122
|
-
CREATE INDEX if not exists idx_content_types_type ON site.content_types(type);
|
|
123
|
-
CREATE INDEX if not exists idx_content_types_table_name ON site.content_types(table_name);
|
|
124
|
-
|
|
125
|
-
-- drop table if exists site.settings cascade;
|
|
126
|
-
CREATE TABLE if not exists site.settings (
|
|
127
|
-
id serial PRIMARY KEY CHECK (id = 1),
|
|
128
|
-
key VARCHAR (50) NOT NULL UNIQUE,
|
|
129
|
-
value TEXT NOT NULL,
|
|
130
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
131
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
132
|
-
created_by text REFERENCES admin.users(uid),
|
|
133
|
-
updated_by text REFERENCES admin.users(uid)
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
COMMENT ON TABLE site.settings IS 'Stores global settings for the site, with only one record allowed.';
|
|
137
|
-
COMMENT ON COLUMN site.settings.id IS 'Unique ID for the settings table (always 1).';
|
|
138
|
-
COMMENT ON COLUMN site.settings.key IS 'Unique key for the setting (e.g., "site_title").';
|
|
139
|
-
COMMENT ON COLUMN site.settings.value IS 'The value associated with the key (e.g., "My Site Title").';
|
|
140
|
-
COMMENT ON COLUMN site.settings.created_at IS 'Timestamp when the setting was created.';
|
|
141
|
-
COMMENT ON COLUMN site.settings.updated_at IS 'Timestamp when the setting was last updated.';
|
|
142
|
-
COMMENT ON COLUMN site.settings.created_by IS 'User who created the setting record.';
|
|
143
|
-
COMMENT ON COLUMN site.settings.updated_by IS 'User who last updated the setting record.';
|
|
144
|
-
|
|
145
|
-
CREATE INDEX if not exists idx_settings_key ON site.settings(key);
|
|
146
|
-
|
|
147
|
-
-- drop table if exists site.menus cascade;
|
|
148
|
-
CREATE TABLE if not exists site.menus (
|
|
149
|
-
menu_id text PRIMARY KEY default next_id(),
|
|
150
|
-
name VARCHAR(100) NOT NULL,
|
|
151
|
-
locale VARCHAR(20) NOT NULL,
|
|
152
|
-
content TEXT,
|
|
153
|
-
items json,
|
|
154
|
-
description TEXT,
|
|
155
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
156
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
157
|
-
created_by text REFERENCES admin.users(uid),
|
|
158
|
-
updated_by text REFERENCES admin.users(uid)
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
alter table site.menus add column if not exists locale VARCHAR(20) not null default 'uk';
|
|
162
|
-
alter table site.menus add column if not exists content text;
|
|
163
|
-
alter table site.menus add column if not exists items json;
|
|
164
|
-
alter table site.menus add column if not exists description text;
|
|
165
|
-
ALTER TABLE site.menus add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
166
|
-
ALTER TABLE site.menus add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
167
|
-
ALTER TABLE site.menus add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
168
|
-
ALTER TABLE site.menus add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
169
|
-
|
|
170
|
-
ALTER TABLE site.menus DROP CONSTRAINT if exists menus_name_key;
|
|
171
|
-
ALTER TABLE site.menus DROP CONSTRAINT if exists menus_name_locale_unique;
|
|
172
|
-
alter table site.menus drop column if exists lang;
|
|
173
|
-
|
|
174
|
-
COMMENT ON TABLE site.menus IS 'Stores menu information with a name, slug, description, and audit fields.';
|
|
175
|
-
COMMENT ON COLUMN site.menus.menu_id IS 'Primary key for the menu (auto-generated).';
|
|
176
|
-
COMMENT ON COLUMN site.menus.name IS 'Unique name for the menu.';
|
|
177
|
-
COMMENT ON COLUMN site.menus.locale IS 'Localization';
|
|
178
|
-
COMMENT ON COLUMN site.menus.content IS 'Menu items in yml format.';
|
|
179
|
-
COMMENT ON COLUMN site.menus.items IS 'Menu items in json format.';
|
|
180
|
-
COMMENT ON COLUMN site.menus.description IS 'Optional description of the menu.';
|
|
181
|
-
COMMENT ON COLUMN site.menus.created_at IS 'Timestamp when the menu was created.';
|
|
182
|
-
COMMENT ON COLUMN site.menus.updated_at IS 'Timestamp when the menu was last updated.';
|
|
183
|
-
COMMENT ON COLUMN site.menus.created_by IS 'Admin user who created the menu.';
|
|
184
|
-
COMMENT ON COLUMN site.menus.updated_by IS 'Admin user who last updated the menu.';
|
|
185
|
-
|
|
186
|
-
CREATE INDEX if not exists idx_menus_name ON site.menus(name);
|
|
187
|
-
ALTER TABLE site.menus ADD CONSTRAINT menus_name_locale_unique UNIQUE (name, locale);
|
|
188
|
-
|
|
189
|
-
-- drop table if exists site.roles cascade;
|
|
190
|
-
CREATE TABLE if not exists site.roles (
|
|
191
|
-
role_id text PRIMARY KEY default next_id(),
|
|
192
|
-
name VARCHAR(100) UNIQUE NOT NULL,
|
|
193
|
-
description TEXT,
|
|
194
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
195
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
196
|
-
created_by text REFERENCES admin.users(uid),
|
|
197
|
-
updated_by text REFERENCES admin.users(uid)
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
COMMENT ON TABLE site.roles IS 'Stores information about user roles, which can be used for access control and permissions.';
|
|
201
|
-
COMMENT ON COLUMN site.roles.role_id IS 'Primary key for the role (auto-generated).';
|
|
202
|
-
COMMENT ON COLUMN site.roles.name IS 'Unique name of the role (e.g., "admin", "editor").';
|
|
203
|
-
COMMENT ON COLUMN site.roles.description IS 'Description of the role and its permissions.';
|
|
204
|
-
COMMENT ON COLUMN site.roles.created_at IS 'Timestamp when the role was created.';
|
|
205
|
-
COMMENT ON COLUMN site.roles.updated_at IS 'Timestamp when the role was last updated.';
|
|
206
|
-
COMMENT ON COLUMN site.roles.created_by IS 'User who created the role.';
|
|
207
|
-
COMMENT ON COLUMN site.roles.updated_by IS 'User who last updated the role.';
|
|
208
|
-
|
|
209
|
-
CREATE INDEX if not exists idx_roles_name ON site.roles(name);
|
|
210
|
-
|
|
211
|
-
-- drop table if exists site.permissions cascade;
|
|
212
|
-
CREATE TABLE if not exists site.permissions (
|
|
213
|
-
permission_id text PRIMARY KEY default next_id(),
|
|
214
|
-
role_id text references site.roles(role_id),
|
|
215
|
-
user_id text references admin.users(uid),
|
|
216
|
-
content_type_id text references site.content_types(content_type_id),
|
|
217
|
-
subject VARCHAR(100) NOT NULL,
|
|
218
|
-
actions TEXT[] NOT NULL check (actions && (ARRAY['read', 'create', 'delete', 'edit']::text[])),
|
|
219
|
-
description TEXT,
|
|
220
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
|
221
|
-
updated_at TIMESTAMP DEFAULT NOW(),
|
|
222
|
-
created_by text REFERENCES admin.users(uid),
|
|
223
|
-
updated_by text REFERENCES admin.users(uid)
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
COMMENT ON TABLE site.permissions IS 'Stores permissions assigned to roles or users, defining actions for specific subjects and content types.';
|
|
228
|
-
COMMENT ON COLUMN site.permissions.permission_id IS 'Primary key for the permission (auto-generated).';
|
|
229
|
-
COMMENT ON COLUMN site.permissions.role_id IS 'Foreign key linking to the role the permission is assigned to.';
|
|
230
|
-
COMMENT ON COLUMN site.permissions.user_id IS 'Foreign key linking to the user who has the permission.';
|
|
231
|
-
COMMENT ON COLUMN site.permissions.content_type_id IS 'Foreign key linking to the content type for which the permission applies.';
|
|
232
|
-
COMMENT ON COLUMN site.permissions.subject IS 'Subject (e.g., "post", "comment") of the permission.';
|
|
233
|
-
COMMENT ON COLUMN site.permissions.actions IS 'Array of actions allowed for the permission (e.g., ["create", "update"]).';
|
|
234
|
-
COMMENT ON COLUMN site.permissions.description IS 'Description of the permission.';
|
|
235
|
-
COMMENT ON COLUMN site.permissions.created_at IS 'Timestamp when the permission was created.';
|
|
236
|
-
COMMENT ON COLUMN site.permissions.updated_at IS 'Timestamp when the permission was last updated.';
|
|
237
|
-
COMMENT ON COLUMN site.permissions.created_by IS 'User who created the permission record.';
|
|
238
|
-
COMMENT ON COLUMN site.permissions.updated_by IS 'User who last updated the permission record.';
|
|
239
|
-
|
|
240
|
-
CREATE INDEX if not exists idx_permissions_role_id ON site.permissions(role_id);
|
|
241
|
-
CREATE INDEX if not exists idx_permissions_user_id ON site.permissions(user_id);
|
|
242
|
-
CREATE INDEX if not exists idx_permissions_content_type_id ON site.permissions(content_type_id);
|
|
243
|
-
CREATE INDEX if not exists idx_permissions_subject ON site.permissions(subject);
|
|
244
|
-
|
|
245
|
-
create schema if not exists site;
|
|
246
|
-
|
|
247
|
-
CREATE TABLE if not exists site.tokens (
|
|
248
|
-
id text PRIMARY KEY default next_id(), -- Auto-incremented primary key
|
|
249
|
-
token_name TEXT NOT NULL, -- Display name of the token (e.g., "Contentful CLI", "test")
|
|
250
|
-
token_value TEXT NOT NULL, -- Partially masked actual token string
|
|
251
|
-
last_used TIMESTAMP NULL, -- When the token was last used (nullable)
|
|
252
|
-
created_at TIMESTAMP NOT NULL default now(), -- When the token was created
|
|
253
|
-
updated_at TIMESTAMP NOT NULL default now(), -- When the token was updated
|
|
254
|
-
created_by TEXT, -- Who created the token
|
|
255
|
-
updated_by TEXT, -- When updated the token
|
|
256
|
-
expiration_date TIMESTAMP, -- (nullable) Expiration date of the token
|
|
257
|
-
token_type TEXT CHECK (token_type IN ('CMA', 'PAT')), -- Type of token
|
|
258
|
-
token_status TEXT CHECK (token_status IN ('Active')), -- Current status
|
|
259
|
-
space_id TEXT NOT NULL -- site / portal
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
COMMENT ON TABLE site.tokens IS 'Stores metadata for access tokens including their usage, status, and scope.';
|
|
263
|
-
|
|
264
|
-
COMMENT ON COLUMN site.tokens.id IS 'Unique identifier for each token record.';
|
|
265
|
-
COMMENT ON COLUMN site.tokens.token_name IS 'Display name of the token (e.g., "Contentful CLI", "test").';
|
|
266
|
-
COMMENT ON COLUMN site.tokens.token_value IS 'Partially masked actual token string.';
|
|
267
|
-
COMMENT ON COLUMN site.tokens.last_used IS 'Timestamp of the last time the token was used.';
|
|
268
|
-
COMMENT ON COLUMN site.tokens.created_at IS 'Timestamp when the token was created.';
|
|
269
|
-
COMMENT ON COLUMN site.tokens.expiration_date IS 'Expiration timestamp, if set.';
|
|
270
|
-
COMMENT ON COLUMN site.tokens.token_type IS 'Type of token, such as CMA or PAT.';
|
|
271
|
-
COMMENT ON COLUMN site.tokens.token_status IS 'Current status of the token (e.g., Active).';
|
|
272
|
-
COMMENT ON COLUMN site.tokens.space_id IS 'Identifier for the associated space.';
|
|
273
|
-
|
|
274
|
-
CREATE TABLE if not exists site.spaces (
|
|
275
|
-
space_id text PRIMARY KEY default next_id(), -- Unique identifier for the space
|
|
276
|
-
name TEXT NOT NULL, -- Human-readable name of the space
|
|
277
|
-
created_at TIMESTAMP NOT NULL default now(), -- When the space was created
|
|
278
|
-
updated_at TIMESTAMP NOT NULL default now(), -- Last modification timestamp
|
|
279
|
-
created_by TEXT, -- Author
|
|
280
|
-
updated_by TEXT, -- Editor
|
|
281
|
-
organization_id text, -- ID of the parent organization (if part of an org)
|
|
282
|
-
default_locale TEXT not null default 'uk', -- Default language/locale of the space (e.g., "en", "ua" etc.)
|
|
283
|
-
locales text[],
|
|
284
|
-
plan TEXT CHECK (plan IN ('Free', 'Premium')) default 'Free' -- Plan type (e.g., "Free", "Premium")
|
|
285
|
-
);
|
|
286
|
-
insert into site.spaces(space_id, name) values('default','default') on conflict(space_id) do nothing;
|
|
287
|
-
|
|
288
|
-
COMMENT ON TABLE site.spaces IS 'Represents content spaces / sites';
|
|
289
|
-
|
|
290
|
-
COMMENT ON COLUMN site.spaces.space_id IS 'Unique identifier for the space';
|
|
291
|
-
COMMENT ON COLUMN site.spaces.name IS 'Human-readable name of the space';
|
|
292
|
-
COMMENT ON COLUMN site.spaces.created_at IS 'When the space was created';
|
|
293
|
-
COMMENT ON COLUMN site.spaces.updated_at IS 'Last modification timestamp';
|
|
294
|
-
COMMENT ON COLUMN site.spaces.organization_id IS 'ID of the parent organization (if part of an org)';
|
|
295
|
-
COMMENT ON COLUMN site.spaces.default_locale IS 'Default language/locale of the space (e.g., "en", "uk" etc.)';
|
|
296
|
-
COMMENT ON COLUMN site.spaces.plan IS 'Plan type (e.g., "Free", "Premium")';
|
|
297
|
-
|
|
298
|
-
alter table site.spaces alter column default_locale set default 'uk';
|
|
299
|
-
|
|
300
|
-
CREATE TABLE if not exists site.organizations (
|
|
301
|
-
organization_id TEXT PRIMARY KEY DEFAULT next_id(), -- Unique identifier for the organization
|
|
302
|
-
name TEXT NOT NULL, -- Name of the organization
|
|
303
|
-
created_at TIMESTAMP NOT NULL default now(), -- When the space was created
|
|
304
|
-
updated_at TIMESTAMP NOT NULL default now(), -- Last modification timestamp
|
|
305
|
-
created_by TEXT, -- Author
|
|
306
|
-
updated_by TEXT, -- Editor
|
|
307
|
-
owner_id TEXT NOT NULL, -- User ID of the organization owner
|
|
308
|
-
billing_email TEXT, -- Email used for billing-related communication (nullable)
|
|
309
|
-
plan TEXT NOT NULL DEFAULT 'Free' CHECK (plan IN ('Free', 'Pro', 'Enterprise')), -- Subscription plan
|
|
310
|
-
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'deleted')) -- Organization status
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
COMMENT ON TABLE site.organizations IS 'Organizations';
|
|
314
|
-
|
|
315
|
-
COMMENT ON COLUMN site.organizations.organization_id IS 'Unique identifier for the organization';
|
|
316
|
-
COMMENT ON COLUMN site.organizations.name IS 'Name of the organization';
|
|
317
|
-
COMMENT ON COLUMN site.organizations.created_at IS 'Timestamp when the organization was created';
|
|
318
|
-
COMMENT ON COLUMN site.organizations.owner_id IS 'User ID of the organization owner';
|
|
319
|
-
COMMENT ON COLUMN site.organizations.billing_email IS 'Email used for billing-related communication (nullable)';
|
|
320
|
-
COMMENT ON COLUMN site.organizations.plan IS 'Subscription plan (Free, Pro, Enterprise)';
|
|
321
|
-
COMMENT ON COLUMN site.organizations.status IS 'Status of the organization (active, suspended, deleted)';
|
|
322
|
-
|
|
323
|
-
CREATE TABLE if not exists site.comments (
|
|
324
|
-
comment_id text PRIMARY KEY DEFAULT next_id(), -- Unique identifier for the comment
|
|
325
|
-
content_id text NOT NULL, -- ID of the content item the comment is attached to
|
|
326
|
-
content_type TEXT NOT NULL, -- Type of the content (e.g., entry, asset, field, content_type)
|
|
327
|
-
author_id text NOT NULL, -- ID of the user who posted the comment
|
|
328
|
-
body TEXT NOT NULL, -- Comment text body
|
|
329
|
-
created_at TIMESTAMP NOT NULL DEFAULT now(), -- Timestamp when the comment was created
|
|
330
|
-
updated_at TIMESTAMP NOT NULL DEFAULT now(), -- Timestamp of last edit (nullable if never edited)
|
|
331
|
-
created_by TEXT, -- Author
|
|
332
|
-
updated_by TEXT, -- Editor
|
|
333
|
-
resolved BOOLEAN NOT NULL DEFAULT false, -- Whether the comment thread is marked as resolved
|
|
334
|
-
parent_id text, -- (nullable) ID of the parent comment, if this is a reply
|
|
335
|
-
thread_id text NOT NULL -- ID of the top-level thread this comment belongs to
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
COMMENT ON COLUMN site.comments.comment_id IS 'Unique identifier for the comment';
|
|
339
|
-
COMMENT ON COLUMN site.comments.content_id IS 'ID of the content item the comment is attached to (entry, asset, etc.)';
|
|
340
|
-
COMMENT ON COLUMN site.comments.content_type IS 'Type of the content (e.g., entry, asset, field, content_type)';
|
|
341
|
-
COMMENT ON COLUMN site.comments.author_id IS 'ID of the user who posted the comment';
|
|
342
|
-
COMMENT ON COLUMN site.comments.body IS 'Comment text body';
|
|
343
|
-
COMMENT ON COLUMN site.comments.created_at IS 'Timestamp when the comment was created';
|
|
344
|
-
COMMENT ON COLUMN site.comments.updated_at IS 'Timestamp of last edit (nullable if never edited)';
|
|
345
|
-
COMMENT ON COLUMN site.comments.resolved IS 'Whether the comment thread is marked as resolved';
|
|
346
|
-
COMMENT ON COLUMN site.comments.parent_id IS 'ID of the parent comment if this is a reply';
|
|
347
|
-
COMMENT ON COLUMN site.comments.thread_id IS 'ID of the top-level thread this comment belongs to';
|
|
348
|
-
|
|
349
|
-
CREATE TABLE if not exists site.contents (
|
|
350
|
-
content_id text PRIMARY KEY default next_id(),
|
|
351
|
-
space_id text,
|
|
352
|
-
content_type_id text NOT NULL,
|
|
353
|
-
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
|
354
|
-
updated_at TIMESTAMP NOT NULL DEFAULT now(),
|
|
355
|
-
published_at TIMESTAMP,
|
|
356
|
-
revision INTEGER NOT NULL DEFAULT 1,
|
|
357
|
-
locale TEXT NOT NULL DEFAULT 'uk'::text,
|
|
358
|
-
status TEXT CHECK (status IN ('draft', 'published', 'archived')) NOT NULL default 'draft',
|
|
359
|
-
slug TEXT,
|
|
360
|
-
title TEXT,
|
|
361
|
-
created_by text,
|
|
362
|
-
published_by text,
|
|
363
|
-
updated_by text,
|
|
364
|
-
meta json,
|
|
365
|
-
main_image text,
|
|
366
|
-
FOREIGN KEY (space_id) REFERENCES site.spaces(space_id),
|
|
367
|
-
FOREIGN KEY (content_type_id) REFERENCES site.content_types(content_type_id),
|
|
368
|
-
FOREIGN KEY (created_by) REFERENCES admin.users(uid),
|
|
369
|
-
FOREIGN KEY (published_by) REFERENCES admin.users(uid),
|
|
370
|
-
FOREIGN KEY (updated_by) REFERENCES admin.users(uid)
|
|
371
|
-
);
|
|
372
|
-
|
|
373
|
-
alter table site.contents add column if not exists space_id text;
|
|
374
|
-
alter table site.contents add column if not exists content_type_id text;
|
|
375
|
-
ALTER TABLE site.contents add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
376
|
-
ALTER TABLE site.contents add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
377
|
-
ALTER TABLE site.contents add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
378
|
-
ALTER TABLE site.contents add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
379
|
-
ALTER TABLE site.contents add COLUMN if not exists published_at TIMESTAMP DEFAULT NOW();
|
|
380
|
-
ALTER TABLE site.contents add COLUMN if not exists revision INTEGER NOT NULL DEFAULT 1;
|
|
381
|
-
ALTER TABLE site.contents add COLUMN if not exists locale TEXT NOT NULL DEFAULT 'uk'::text;
|
|
382
|
-
ALTER TABLE site.contents add COLUMN if not exists published_by text;
|
|
383
|
-
ALTER TABLE site.contents add COLUMN if not exists slug text;
|
|
384
|
-
ALTER TABLE site.contents add COLUMN if not exists meta json;
|
|
385
|
-
|
|
386
|
-
COMMENT ON COLUMN site.contents.content_id IS 'Unique identifier for the content item (entry)';
|
|
387
|
-
COMMENT ON COLUMN site.contents.space_id IS 'FK to the space this content belongs to';
|
|
388
|
-
COMMENT ON COLUMN site.contents.content_type_id IS 'FK to the content type definition';
|
|
389
|
-
COMMENT ON COLUMN site.contents.created_at IS 'Timestamp when the content was created';
|
|
390
|
-
COMMENT ON COLUMN site.contents.updated_at IS 'Timestamp of last update';
|
|
391
|
-
COMMENT ON COLUMN site.contents.published_at IS 'Timestamp of publication (nullable if not published)';
|
|
392
|
-
COMMENT ON COLUMN site.contents.revision IS 'Revision/version number';
|
|
393
|
-
COMMENT ON COLUMN site.contents.locale IS 'Language/locale for this content entry (e.g., en)';
|
|
394
|
-
COMMENT ON COLUMN site.contents.status IS 'Status of the entry (e.g., draft, published, archived)';
|
|
395
|
-
COMMENT ON COLUMN site.contents.slug IS 'URL-friendly string identifier';
|
|
396
|
-
COMMENT ON COLUMN site.contents.title IS 'Title of the content entry';
|
|
397
|
-
COMMENT ON COLUMN site.contents.created_by IS 'User who created the entry';
|
|
398
|
-
COMMENT ON COLUMN site.contents.published_by IS 'User who published the entry';
|
|
399
|
-
COMMENT ON COLUMN site.contents.updated_by IS 'User who last updated the entry';
|
|
400
|
-
|
|
401
|
-
CREATE TABLE if not exists site.content_data (
|
|
402
|
-
field_id text PRIMARY KEY DEFAULT next_id(),
|
|
403
|
-
content_id text NOT NULL,
|
|
404
|
-
object_id text NOT NULL,
|
|
405
|
-
field_key TEXT NOT NULL,
|
|
406
|
-
field_type TEXT NOT NULL,
|
|
407
|
-
field_value TEXT,
|
|
408
|
-
field_value_object json,
|
|
409
|
-
locale TEXT NOT NULL DEFAULT 'uk'::text,
|
|
410
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
411
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
412
|
-
created_by text,
|
|
413
|
-
updated_by text,
|
|
414
|
-
|
|
415
|
-
constraint content_data_content_id_fkey FOREIGN KEY (content_id) REFERENCES site.contents(content_id) on delete cascade
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
alter table site.content_data add column if not exists field_key text not null;
|
|
420
|
-
alter table site.content_data add column if not exists field_type text;
|
|
421
|
-
alter table site.content_data add column if not exists field_value text;
|
|
422
|
-
alter table site.content_data add column if not exists field_value_object json;
|
|
423
|
-
alter table site.content_data add column if not exists locale text;
|
|
424
|
-
alter table site.content_data add column if not exists field_id text;
|
|
425
|
-
alter table site.content_data add column if not exists object_id text;
|
|
426
|
-
ALTER TABLE site.content_data add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
427
|
-
ALTER TABLE site.content_data add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
428
|
-
ALTER TABLE site.content_data add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
429
|
-
ALTER TABLE site.content_data add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
-- create unique index for slug
|
|
434
|
-
CREATE UNIQUE INDEX if not exists content_data_slug_unique ON site.content_data (field_value) WHERE field_key = 'slug';
|
|
435
|
-
|
|
436
|
-
COMMENT ON TABLE site.content_data IS 'Content fields';
|
|
437
|
-
|
|
438
|
-
COMMENT ON COLUMN site.content_data.field_id IS 'Unique identifier for the field entry';
|
|
439
|
-
COMMENT ON COLUMN site.content_data.content_id IS 'FK to Contents.content_id';
|
|
440
|
-
COMMENT ON COLUMN site.content_data.object_id IS 'Unique ID per content_id / field_key';
|
|
441
|
-
COMMENT ON COLUMN site.content_data.field_key IS 'Name of the field (e.g., title, description)';
|
|
442
|
-
COMMENT ON COLUMN site.content_data.field_type IS 'Field type (e.g., text, number, media, reference)';
|
|
443
|
-
COMMENT ON COLUMN site.content_data.field_value IS 'Data value stored as string';
|
|
444
|
-
COMMENT ON COLUMN site.content_data.field_value_object IS 'Data value stored as json';
|
|
445
|
-
COMMENT ON COLUMN site.content_data.locale IS 'Locale for this field (e.g., en-US, uk)';
|
|
446
|
-
COMMENT ON COLUMN site.content_data.created_at IS 'Field creation timestamp';
|
|
447
|
-
COMMENT ON COLUMN site.content_data.updated_at IS 'Last updated';
|
|
448
|
-
COMMENT ON COLUMN site.content_data.created_by IS 'Author';
|
|
449
|
-
COMMENT ON COLUMN site.content_data.updated_by IS 'Last editor';
|
|
450
|
-
|
|
451
|
-
alter table site.content_data alter column locale set default 'uk';
|
|
452
|
-
alter table site.contents alter column locale set default 'uk';
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
CREATE TABLE if not exists site.localization (
|
|
456
|
-
localization_id text PRIMARY KEY DEFAULT next_id(),
|
|
457
|
-
object_id text NOT NULL,
|
|
458
|
-
field_key TEXT NOT NULL,
|
|
459
|
-
field_value TEXT,
|
|
460
|
-
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
461
|
-
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
462
|
-
created_by text,
|
|
463
|
-
updated_by text,
|
|
464
|
-
constraint object_id_field_key_unique UNIQUE (object_id, field_key)
|
|
465
|
-
);
|
|
466
|
-
|
|
467
|
-
COMMENT ON TABLE site.localization IS 'Content localization';
|
|
468
|
-
|
|
469
|
-
COMMENT ON COLUMN site.localization.object_id IS 'Unique ID of content (content_data / custom data.table)';
|
|
470
|
-
COMMENT ON COLUMN site.localization.field_key IS 'Name of the field (e.g., title, description)';
|
|
471
|
-
COMMENT ON COLUMN site.localization.field_value IS 'Data value stored as string';
|
|
472
|
-
COMMENT ON COLUMN site.localization.created_at IS 'Field creation timestamp';
|
|
473
|
-
COMMENT ON COLUMN site.localization.updated_at IS 'Last updated';
|
|
474
|
-
COMMENT ON COLUMN site.localization.created_by IS 'Author';
|
|
475
|
-
COMMENT ON COLUMN site.localization.updated_by IS 'Last editor';
|
|
476
|
-
|
|
477
|
-
CREATE TABLE if not exists site.tags
|
|
478
|
-
(
|
|
479
|
-
tag_id text NOT NULL DEFAULT next_id(),
|
|
480
|
-
value text NOT NULL, -- Текстове значення тегу
|
|
481
|
-
slug text not null,
|
|
482
|
-
color text NOT NULL DEFAULT '#ababab'::text, -- Колір тегу
|
|
483
|
-
created_at timestamp without time zone DEFAULT now(),
|
|
484
|
-
updated_at timestamp without time zone,
|
|
485
|
-
created_by text,
|
|
486
|
-
updated_by text,
|
|
487
|
-
description text,
|
|
488
|
-
CONSTRAINT tags_pkey PRIMARY KEY (tag_id)
|
|
489
|
-
)
|
|
490
|
-
WITH (
|
|
491
|
-
OIDS=FALSE
|
|
492
|
-
);
|
|
493
|
-
ALTER TABLE site.tags
|
|
494
|
-
OWNER TO postgres;
|
|
495
|
-
COMMENT ON TABLE site.tags
|
|
496
|
-
IS 'Теги';
|
|
497
|
-
COMMENT ON COLUMN site.tags.value IS 'Текстове значення тегу';
|
|
498
|
-
COMMENT ON COLUMN site.tags.color IS 'Колір тегу';
|
|
499
|
-
|
|
500
|
-
alter table site.tags add column if not exists slug text;
|
|
501
|
-
COMMENT ON COLUMN site.tags.slug IS 'Alias тегу';
|
|
502
|
-
update site.tags set slug = tag_id where slug is null;
|
|
503
|
-
alter table site.tags alter column slug set not null;
|
|
504
|
-
|
|
505
|
-
CREATE TABLE if not exists site.tag_data
|
|
506
|
-
(
|
|
507
|
-
tag_content_id text NOT NULL DEFAULT next_id(),
|
|
508
|
-
tag_id text NOT NULL,
|
|
509
|
-
data_id text NOT NULL, -- Ідентифікатор будь якого контенту
|
|
510
|
-
created_at timestamp without time zone DEFAULT now(),
|
|
511
|
-
updated_at timestamp without time zone,
|
|
512
|
-
created_by text,
|
|
513
|
-
updated_by text,
|
|
514
|
-
CONSTRAINT tag_data_pkey PRIMARY KEY (tag_content_id),
|
|
515
|
-
CONSTRAINT tag_data_tag_id_fkey FOREIGN KEY (tag_id)
|
|
516
|
-
REFERENCES site.tags (tag_id) MATCH SIMPLE
|
|
517
|
-
ON UPDATE NO ACTION ON DELETE CASCADE,
|
|
518
|
-
CONSTRAINT tag_data_unique UNIQUE (tag_id, data_id)
|
|
519
|
-
);
|
|
520
|
-
|
|
521
|
-
ALTER TABLE site.tag_data drop constraint if exists tag_data_tag_id_fkey;
|
|
522
|
-
ALTER TABLE site.tag_data add CONSTRAINT tag_data_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES site.tags (tag_id) MATCH SIMPLE ON DELETE CASCADE;
|
|
523
|
-
COMMENT ON TABLE site.tag_data
|
|
524
|
-
IS 'Відношення тегів до контенту';
|
|
525
|
-
COMMENT ON COLUMN site.tag_data.data_id IS 'Ідентифікатор будь якого контенту';
|
|
526
|
-
|
|
527
|
-
CREATE TABLE if not exists site.feedback
|
|
528
|
-
(
|
|
529
|
-
message_id text NOT NULL DEFAULT next_id(), -- ID
|
|
530
|
-
title text, -- Заголовок
|
|
531
|
-
email text NOT NULL, -- Електронна пошта
|
|
532
|
-
user_name text, -- ПІБ Повністю
|
|
533
|
-
message_text text, -- Повідомлення
|
|
534
|
-
feedback_type text NOT NULL DEFAULT 'message'::text, -- Тип
|
|
535
|
-
status text NOT NULL DEFAULT 'new'::text, -- Статус
|
|
536
|
-
phone text, -- Телефон
|
|
537
|
-
headers json,
|
|
538
|
-
resume_link text, -- Посилання на резюме
|
|
539
|
-
linkedin_link text, -- Посилання на лінкедин
|
|
540
|
-
portfolio_link text, -- Посилання на портфоліо
|
|
541
|
-
telegram_link text, -- Посилання на телеграм
|
|
542
|
-
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
543
|
-
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
544
|
-
created_by text,
|
|
545
|
-
updated_by text,
|
|
546
|
-
CONSTRAINT feedback_pkey PRIMARY KEY (message_id)
|
|
547
|
-
);
|
|
548
|
-
|
|
549
|
-
alter table site.feedback add column if not exists message_id text not null default next_id();
|
|
550
|
-
alter table site.feedback add column if not exists title text;
|
|
551
|
-
alter table site.feedback add column if not exists user_name text;
|
|
552
|
-
alter table site.feedback add column if not exists message_text text;
|
|
553
|
-
alter table site.feedback add column if not exists feedback_type text NOT NULL DEFAULT 'message'::text;
|
|
554
|
-
alter table site.feedback add column if not exists resume_link text;
|
|
555
|
-
alter table site.feedback add column if not exists linkedin_link text;
|
|
556
|
-
alter table site.feedback add column if not exists portfolio_link text;
|
|
557
|
-
alter table site.feedback add column if not exists telegram_link text;
|
|
558
|
-
|
|
559
|
-
COMMENT ON COLUMN site.feedback.message_id IS 'ID';
|
|
560
|
-
COMMENT ON COLUMN site.feedback.title IS 'Заголовок';
|
|
561
|
-
COMMENT ON COLUMN site.feedback.email IS 'Електронна пошта';
|
|
562
|
-
COMMENT ON COLUMN site.feedback.user_name IS 'ПІБ Повністю';
|
|
563
|
-
COMMENT ON COLUMN site.feedback.message_text IS 'Повідомлення';
|
|
564
|
-
COMMENT ON COLUMN site.feedback.feedback_type IS 'Тип';
|
|
565
|
-
COMMENT ON COLUMN site.feedback.status IS 'Статус';
|
|
566
|
-
COMMENT ON COLUMN site.feedback.phone IS 'Телефон';
|
|
567
|
-
COMMENT ON COLUMN site.feedback.resume_link IS 'Посилання на резюме';
|
|
568
|
-
COMMENT ON COLUMN site.feedback.linkedin_link IS 'Посилання на лінкедин';
|
|
569
|
-
COMMENT ON COLUMN site.feedback.portfolio_link IS 'Посилання на портфоліо';
|
|
570
|
-
COMMENT ON COLUMN site.feedback.telegram_link IS 'Посилання на телеграм';
|
|
571
|
-
|
|
572
|
-
CREATE TABLE if not exists site.subscription
|
|
573
|
-
(
|
|
574
|
-
subscription_id text NOT NULL DEFAULT next_id(),
|
|
575
|
-
email text NOT NULL, -- Електронна пошта
|
|
576
|
-
enabled boolean DEFAULT true, -- Чи активна підписка
|
|
577
|
-
referer text, -- Звідки підписка
|
|
578
|
-
unsubscribed_at timestamp with time zone, -- Дата відписки
|
|
579
|
-
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
580
|
-
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
581
|
-
created_by text,
|
|
582
|
-
updated_by text,
|
|
583
|
-
CONSTRAINT subscription_pkey PRIMARY KEY (subscription_id),
|
|
584
|
-
CONSTRAINT subscription_email_unique UNIQUE (email)
|
|
585
|
-
);
|
|
586
|
-
COMMENT ON TABLE site.subscription
|
|
587
|
-
IS 'Підписки на новини';
|
|
588
|
-
|
|
589
|
-
alter table site.subscription add column if not exists referer text;
|
|
590
|
-
alter table site.subscription add column if not exists unsubscribed_at timestamp with time zone;
|
|
591
|
-
|
|
592
|
-
COMMENT ON COLUMN site.subscription.email IS 'Електронна пошта';
|
|
593
|
-
COMMENT ON COLUMN site.subscription.enabled IS 'Чи активна підписка';
|
|
594
|
-
COMMENT ON COLUMN site.subscription.referer IS 'Звідки підписка';
|
|
595
|
-
COMMENT ON COLUMN site.subscription.unsubscribed_at IS 'Дата відписки';
|
|
1
|
+
create schema if not exists admin;
|
|
2
|
+
create table if not exists admin.users (uid text primary key default next_id());
|
|
3
|
+
|
|
4
|
+
create schema if not exists site;
|
|
5
|
+
create schema if not exists data;
|
|
6
|
+
|
|
7
|
+
-- drop table if exists site.categories cascade;
|
|
8
|
+
create table if not exists site.categories (
|
|
9
|
+
category_id text primary key default next_id(),
|
|
10
|
+
name text not null,
|
|
11
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
12
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
13
|
+
created_by text REFERENCES admin.users(uid),
|
|
14
|
+
updated_by text REFERENCES admin.users(uid)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
-- drop table if exists site.media cascade;
|
|
18
|
+
CREATE TABLE if not exists site.media (
|
|
19
|
+
media_id text PRIMARY KEY default next_id(),
|
|
20
|
+
filename TEXT NOT NULL,
|
|
21
|
+
filetype TEXT NOT NULL,
|
|
22
|
+
filesize INTEGER NOT NULL,
|
|
23
|
+
subdir TEXT,
|
|
24
|
+
url TEXT,
|
|
25
|
+
description TEXT,
|
|
26
|
+
alt text,
|
|
27
|
+
mime VARCHAR(100),
|
|
28
|
+
preview_url TEXT,
|
|
29
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
30
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
31
|
+
created_by text REFERENCES admin.users(uid),
|
|
32
|
+
updated_by text REFERENCES admin.users(uid)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
COMMENT ON TABLE site.media IS 'Stores uploaded media files with metadata, URLs, and audit info.';
|
|
36
|
+
COMMENT ON COLUMN site.media.media_id IS 'Unique ID for the media item.';
|
|
37
|
+
COMMENT ON COLUMN site.media.filename IS 'Original name of the uploaded file.';
|
|
38
|
+
COMMENT ON COLUMN site.media.filetype IS 'Logical type of file (e.g., image, video, document).';
|
|
39
|
+
COMMENT ON COLUMN site.media.filesize IS 'Size of the file in bytes.';
|
|
40
|
+
-- COMMENT ON COLUMN site.media.subdir is 'Піддиректорія';
|
|
41
|
+
COMMENT ON COLUMN site.media.url IS 'URL where the file can be accessed.';
|
|
42
|
+
COMMENT ON COLUMN site.media.description IS 'Optional description or caption.';
|
|
43
|
+
COMMENT ON COLUMN site.media.alt IS 'Alternative text for screen readers or image fallbacks.';
|
|
44
|
+
COMMENT ON COLUMN site.media.mime IS 'MIME type indicating the file format (e.g., image/png).';
|
|
45
|
+
COMMENT ON COLUMN site.media.preview_url IS 'Optional preview or thumbnail URL.';
|
|
46
|
+
COMMENT ON COLUMN site.media.created_at IS 'Timestamp of when the media record was created.';
|
|
47
|
+
COMMENT ON COLUMN site.media.updated_at IS 'Timestamp of the last update to the media record.';
|
|
48
|
+
COMMENT ON COLUMN site.media.created_by IS 'User ID who uploaded the media.';
|
|
49
|
+
COMMENT ON COLUMN site.media.updated_by IS 'User ID who last updated the media.';
|
|
50
|
+
|
|
51
|
+
CREATE INDEX if not exists idx_media_filetype ON site.media(filetype);
|
|
52
|
+
CREATE INDEX if not exists idx_media_filesize ON site.media(filesize);
|
|
53
|
+
CREATE INDEX if not exists idx_media_mime ON site.media(mime);
|
|
54
|
+
CREATE INDEX if not exists idx_media_created_at ON site.media(created_at);
|
|
55
|
+
CREATE INDEX if not exists idx_media_created_by ON site.media(created_by);
|
|
56
|
+
CREATE INDEX if not exists idx_media_updated_at ON site.media(updated_at);
|
|
57
|
+
CREATE INDEX if not exists idx_media_updated_by ON site.media(updated_by);
|
|
58
|
+
|
|
59
|
+
-- drop table if exists site.content_types cascade;
|
|
60
|
+
CREATE TABLE if not exists site.content_types (
|
|
61
|
+
content_type_id text PRIMARY KEY default next_id(),
|
|
62
|
+
name VARCHAR (50) NOT NULL UNIQUE,
|
|
63
|
+
title VARCHAR (50) NOT NULL,
|
|
64
|
+
table_name VARCHAR(50),
|
|
65
|
+
columns json,
|
|
66
|
+
status VARCHAR (20) DEFAULT 'draft' CHECK (status::text = ANY (ARRAY['draft', 'published', 'archived']::text[])),
|
|
67
|
+
visible BOOLEAN DEFAULT TRUE,
|
|
68
|
+
localized BOOLEAN DEFAULT FALSE,
|
|
69
|
+
type VARCHAR(20) NOT NULL DEFAULT 'collection' CHECK (type::text = ANY (ARRAY['collection', 'single']::text[])),
|
|
70
|
+
schema JSONB,
|
|
71
|
+
description TEXT,
|
|
72
|
+
icon VARCHAR (50),
|
|
73
|
+
color VARCHAR (20),
|
|
74
|
+
preview_path text,
|
|
75
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
76
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
77
|
+
created_by text REFERENCES admin.users(uid),
|
|
78
|
+
updated_by text REFERENCES admin.users(uid)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
ALTER TABLE site.content_types add COLUMN if not exists table_name text;
|
|
82
|
+
ALTER TABLE site.content_types add COLUMN if not exists title text;
|
|
83
|
+
ALTER TABLE site.content_types add COLUMN if not exists status text;
|
|
84
|
+
ALTER TABLE site.content_types add COLUMN if not exists visible boolean default true;
|
|
85
|
+
ALTER TABLE site.content_types add COLUMN if not exists localized boolean default false;
|
|
86
|
+
ALTER TABLE site.content_types add COLUMN if not exists schema jsonb;
|
|
87
|
+
ALTER TABLE site.content_types add COLUMN if not exists icon text;
|
|
88
|
+
ALTER TABLE site.content_types add COLUMN if not exists color text;
|
|
89
|
+
ALTER TABLE site.content_types add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
90
|
+
ALTER TABLE site.content_types add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
91
|
+
ALTER TABLE site.content_types add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
92
|
+
ALTER TABLE site.content_types add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
93
|
+
ALTER TABLE site.content_types add COLUMN if not exists preview_path text;
|
|
94
|
+
|
|
95
|
+
ALTER TABLE if exists site.content_types ALTER COLUMN table_name DROP NOT NULL;
|
|
96
|
+
ALTER TABLE if exists site.content_types ADD COLUMN if not exists columns json;
|
|
97
|
+
|
|
98
|
+
COMMENT ON TABLE site.content_types IS 'Defines reusable content structures for dynamic content management.';
|
|
99
|
+
COMMENT ON COLUMN site.content_types.content_type_id IS 'Unique identifier for the content type.';
|
|
100
|
+
COMMENT ON COLUMN site.content_types.name IS 'Internal name used in the system (must be unique).';
|
|
101
|
+
COMMENT ON COLUMN site.content_types.name IS 'Name / Alias / slug';
|
|
102
|
+
COMMENT ON COLUMN site.content_types.title IS 'Title';
|
|
103
|
+
COMMENT ON COLUMN site.content_types.table_name IS 'Physical table where entries of this type are stored.';
|
|
104
|
+
COMMENT ON COLUMN site.content_types.status IS 'Status of the content type (draft, published, archived).';
|
|
105
|
+
COMMENT ON COLUMN site.content_types.visible IS 'Controls whether this content type appears in admin UI.';
|
|
106
|
+
COMMENT ON COLUMN site.content_types.localized IS 'Indicates whether the content type supports localization.';
|
|
107
|
+
COMMENT ON COLUMN site.content_types.type IS 'Whether this content type is a collection or a single instance.';
|
|
108
|
+
COMMENT ON COLUMN site.content_types.schema IS 'JSON schema defining the structure and fields of this content type.';
|
|
109
|
+
COMMENT ON COLUMN site.content_types.description IS 'Optional description of the content type.';
|
|
110
|
+
COMMENT ON COLUMN site.content_types.icon IS 'UI icon identifier for this type.';
|
|
111
|
+
COMMENT ON COLUMN site.content_types.color IS 'UI color code or name for this type.';
|
|
112
|
+
COMMENT ON COLUMN site.content_types.created_at IS 'Timestamp when the content type was created.';
|
|
113
|
+
COMMENT ON COLUMN site.content_types.updated_at IS 'Timestamp when the content type was last modified.';
|
|
114
|
+
COMMENT ON COLUMN site.content_types.created_by IS 'Admin user who created the content type.';
|
|
115
|
+
COMMENT ON COLUMN site.content_types.updated_by IS 'Admin user who last updated the content type.';
|
|
116
|
+
COMMENT ON COLUMN site.content_types.preview_path IS 'Назва інтерфейсу на сайті';
|
|
117
|
+
|
|
118
|
+
ALTER TABLE if exists site.content_types ADD COLUMN if not exists include_search boolean;
|
|
119
|
+
|
|
120
|
+
CREATE INDEX if not exists idx_content_types_status ON site.content_types(status);
|
|
121
|
+
CREATE INDEX if not exists idx_content_types_visible ON site.content_types(visible);
|
|
122
|
+
CREATE INDEX if not exists idx_content_types_type ON site.content_types(type);
|
|
123
|
+
CREATE INDEX if not exists idx_content_types_table_name ON site.content_types(table_name);
|
|
124
|
+
|
|
125
|
+
-- drop table if exists site.settings cascade;
|
|
126
|
+
CREATE TABLE if not exists site.settings (
|
|
127
|
+
id serial PRIMARY KEY CHECK (id = 1),
|
|
128
|
+
key VARCHAR (50) NOT NULL UNIQUE,
|
|
129
|
+
value TEXT NOT NULL,
|
|
130
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
131
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
132
|
+
created_by text REFERENCES admin.users(uid),
|
|
133
|
+
updated_by text REFERENCES admin.users(uid)
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
COMMENT ON TABLE site.settings IS 'Stores global settings for the site, with only one record allowed.';
|
|
137
|
+
COMMENT ON COLUMN site.settings.id IS 'Unique ID for the settings table (always 1).';
|
|
138
|
+
COMMENT ON COLUMN site.settings.key IS 'Unique key for the setting (e.g., "site_title").';
|
|
139
|
+
COMMENT ON COLUMN site.settings.value IS 'The value associated with the key (e.g., "My Site Title").';
|
|
140
|
+
COMMENT ON COLUMN site.settings.created_at IS 'Timestamp when the setting was created.';
|
|
141
|
+
COMMENT ON COLUMN site.settings.updated_at IS 'Timestamp when the setting was last updated.';
|
|
142
|
+
COMMENT ON COLUMN site.settings.created_by IS 'User who created the setting record.';
|
|
143
|
+
COMMENT ON COLUMN site.settings.updated_by IS 'User who last updated the setting record.';
|
|
144
|
+
|
|
145
|
+
CREATE INDEX if not exists idx_settings_key ON site.settings(key);
|
|
146
|
+
|
|
147
|
+
-- drop table if exists site.menus cascade;
|
|
148
|
+
CREATE TABLE if not exists site.menus (
|
|
149
|
+
menu_id text PRIMARY KEY default next_id(),
|
|
150
|
+
name VARCHAR(100) NOT NULL,
|
|
151
|
+
locale VARCHAR(20) NOT NULL,
|
|
152
|
+
content TEXT,
|
|
153
|
+
items json,
|
|
154
|
+
description TEXT,
|
|
155
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
156
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
157
|
+
created_by text REFERENCES admin.users(uid),
|
|
158
|
+
updated_by text REFERENCES admin.users(uid)
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
alter table site.menus add column if not exists locale VARCHAR(20) not null default 'uk';
|
|
162
|
+
alter table site.menus add column if not exists content text;
|
|
163
|
+
alter table site.menus add column if not exists items json;
|
|
164
|
+
alter table site.menus add column if not exists description text;
|
|
165
|
+
ALTER TABLE site.menus add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
166
|
+
ALTER TABLE site.menus add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
167
|
+
ALTER TABLE site.menus add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
168
|
+
ALTER TABLE site.menus add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
169
|
+
|
|
170
|
+
ALTER TABLE site.menus DROP CONSTRAINT if exists menus_name_key;
|
|
171
|
+
ALTER TABLE site.menus DROP CONSTRAINT if exists menus_name_locale_unique;
|
|
172
|
+
alter table site.menus drop column if exists lang;
|
|
173
|
+
|
|
174
|
+
COMMENT ON TABLE site.menus IS 'Stores menu information with a name, slug, description, and audit fields.';
|
|
175
|
+
COMMENT ON COLUMN site.menus.menu_id IS 'Primary key for the menu (auto-generated).';
|
|
176
|
+
COMMENT ON COLUMN site.menus.name IS 'Unique name for the menu.';
|
|
177
|
+
COMMENT ON COLUMN site.menus.locale IS 'Localization';
|
|
178
|
+
COMMENT ON COLUMN site.menus.content IS 'Menu items in yml format.';
|
|
179
|
+
COMMENT ON COLUMN site.menus.items IS 'Menu items in json format.';
|
|
180
|
+
COMMENT ON COLUMN site.menus.description IS 'Optional description of the menu.';
|
|
181
|
+
COMMENT ON COLUMN site.menus.created_at IS 'Timestamp when the menu was created.';
|
|
182
|
+
COMMENT ON COLUMN site.menus.updated_at IS 'Timestamp when the menu was last updated.';
|
|
183
|
+
COMMENT ON COLUMN site.menus.created_by IS 'Admin user who created the menu.';
|
|
184
|
+
COMMENT ON COLUMN site.menus.updated_by IS 'Admin user who last updated the menu.';
|
|
185
|
+
|
|
186
|
+
CREATE INDEX if not exists idx_menus_name ON site.menus(name);
|
|
187
|
+
ALTER TABLE site.menus ADD CONSTRAINT menus_name_locale_unique UNIQUE (name, locale);
|
|
188
|
+
|
|
189
|
+
-- drop table if exists site.roles cascade;
|
|
190
|
+
CREATE TABLE if not exists site.roles (
|
|
191
|
+
role_id text PRIMARY KEY default next_id(),
|
|
192
|
+
name VARCHAR(100) UNIQUE NOT NULL,
|
|
193
|
+
description TEXT,
|
|
194
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
195
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
196
|
+
created_by text REFERENCES admin.users(uid),
|
|
197
|
+
updated_by text REFERENCES admin.users(uid)
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
COMMENT ON TABLE site.roles IS 'Stores information about user roles, which can be used for access control and permissions.';
|
|
201
|
+
COMMENT ON COLUMN site.roles.role_id IS 'Primary key for the role (auto-generated).';
|
|
202
|
+
COMMENT ON COLUMN site.roles.name IS 'Unique name of the role (e.g., "admin", "editor").';
|
|
203
|
+
COMMENT ON COLUMN site.roles.description IS 'Description of the role and its permissions.';
|
|
204
|
+
COMMENT ON COLUMN site.roles.created_at IS 'Timestamp when the role was created.';
|
|
205
|
+
COMMENT ON COLUMN site.roles.updated_at IS 'Timestamp when the role was last updated.';
|
|
206
|
+
COMMENT ON COLUMN site.roles.created_by IS 'User who created the role.';
|
|
207
|
+
COMMENT ON COLUMN site.roles.updated_by IS 'User who last updated the role.';
|
|
208
|
+
|
|
209
|
+
CREATE INDEX if not exists idx_roles_name ON site.roles(name);
|
|
210
|
+
|
|
211
|
+
-- drop table if exists site.permissions cascade;
|
|
212
|
+
CREATE TABLE if not exists site.permissions (
|
|
213
|
+
permission_id text PRIMARY KEY default next_id(),
|
|
214
|
+
role_id text references site.roles(role_id),
|
|
215
|
+
user_id text references admin.users(uid),
|
|
216
|
+
content_type_id text references site.content_types(content_type_id),
|
|
217
|
+
subject VARCHAR(100) NOT NULL,
|
|
218
|
+
actions TEXT[] NOT NULL check (actions && (ARRAY['read', 'create', 'delete', 'edit']::text[])),
|
|
219
|
+
description TEXT,
|
|
220
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
221
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
222
|
+
created_by text REFERENCES admin.users(uid),
|
|
223
|
+
updated_by text REFERENCES admin.users(uid)
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
COMMENT ON TABLE site.permissions IS 'Stores permissions assigned to roles or users, defining actions for specific subjects and content types.';
|
|
228
|
+
COMMENT ON COLUMN site.permissions.permission_id IS 'Primary key for the permission (auto-generated).';
|
|
229
|
+
COMMENT ON COLUMN site.permissions.role_id IS 'Foreign key linking to the role the permission is assigned to.';
|
|
230
|
+
COMMENT ON COLUMN site.permissions.user_id IS 'Foreign key linking to the user who has the permission.';
|
|
231
|
+
COMMENT ON COLUMN site.permissions.content_type_id IS 'Foreign key linking to the content type for which the permission applies.';
|
|
232
|
+
COMMENT ON COLUMN site.permissions.subject IS 'Subject (e.g., "post", "comment") of the permission.';
|
|
233
|
+
COMMENT ON COLUMN site.permissions.actions IS 'Array of actions allowed for the permission (e.g., ["create", "update"]).';
|
|
234
|
+
COMMENT ON COLUMN site.permissions.description IS 'Description of the permission.';
|
|
235
|
+
COMMENT ON COLUMN site.permissions.created_at IS 'Timestamp when the permission was created.';
|
|
236
|
+
COMMENT ON COLUMN site.permissions.updated_at IS 'Timestamp when the permission was last updated.';
|
|
237
|
+
COMMENT ON COLUMN site.permissions.created_by IS 'User who created the permission record.';
|
|
238
|
+
COMMENT ON COLUMN site.permissions.updated_by IS 'User who last updated the permission record.';
|
|
239
|
+
|
|
240
|
+
CREATE INDEX if not exists idx_permissions_role_id ON site.permissions(role_id);
|
|
241
|
+
CREATE INDEX if not exists idx_permissions_user_id ON site.permissions(user_id);
|
|
242
|
+
CREATE INDEX if not exists idx_permissions_content_type_id ON site.permissions(content_type_id);
|
|
243
|
+
CREATE INDEX if not exists idx_permissions_subject ON site.permissions(subject);
|
|
244
|
+
|
|
245
|
+
create schema if not exists site;
|
|
246
|
+
|
|
247
|
+
CREATE TABLE if not exists site.tokens (
|
|
248
|
+
id text PRIMARY KEY default next_id(), -- Auto-incremented primary key
|
|
249
|
+
token_name TEXT NOT NULL, -- Display name of the token (e.g., "Contentful CLI", "test")
|
|
250
|
+
token_value TEXT NOT NULL, -- Partially masked actual token string
|
|
251
|
+
last_used TIMESTAMP NULL, -- When the token was last used (nullable)
|
|
252
|
+
created_at TIMESTAMP NOT NULL default now(), -- When the token was created
|
|
253
|
+
updated_at TIMESTAMP NOT NULL default now(), -- When the token was updated
|
|
254
|
+
created_by TEXT, -- Who created the token
|
|
255
|
+
updated_by TEXT, -- When updated the token
|
|
256
|
+
expiration_date TIMESTAMP, -- (nullable) Expiration date of the token
|
|
257
|
+
token_type TEXT CHECK (token_type IN ('CMA', 'PAT')), -- Type of token
|
|
258
|
+
token_status TEXT CHECK (token_status IN ('Active')), -- Current status
|
|
259
|
+
space_id TEXT NOT NULL -- site / portal
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
COMMENT ON TABLE site.tokens IS 'Stores metadata for access tokens including their usage, status, and scope.';
|
|
263
|
+
|
|
264
|
+
COMMENT ON COLUMN site.tokens.id IS 'Unique identifier for each token record.';
|
|
265
|
+
COMMENT ON COLUMN site.tokens.token_name IS 'Display name of the token (e.g., "Contentful CLI", "test").';
|
|
266
|
+
COMMENT ON COLUMN site.tokens.token_value IS 'Partially masked actual token string.';
|
|
267
|
+
COMMENT ON COLUMN site.tokens.last_used IS 'Timestamp of the last time the token was used.';
|
|
268
|
+
COMMENT ON COLUMN site.tokens.created_at IS 'Timestamp when the token was created.';
|
|
269
|
+
COMMENT ON COLUMN site.tokens.expiration_date IS 'Expiration timestamp, if set.';
|
|
270
|
+
COMMENT ON COLUMN site.tokens.token_type IS 'Type of token, such as CMA or PAT.';
|
|
271
|
+
COMMENT ON COLUMN site.tokens.token_status IS 'Current status of the token (e.g., Active).';
|
|
272
|
+
COMMENT ON COLUMN site.tokens.space_id IS 'Identifier for the associated space.';
|
|
273
|
+
|
|
274
|
+
CREATE TABLE if not exists site.spaces (
|
|
275
|
+
space_id text PRIMARY KEY default next_id(), -- Unique identifier for the space
|
|
276
|
+
name TEXT NOT NULL, -- Human-readable name of the space
|
|
277
|
+
created_at TIMESTAMP NOT NULL default now(), -- When the space was created
|
|
278
|
+
updated_at TIMESTAMP NOT NULL default now(), -- Last modification timestamp
|
|
279
|
+
created_by TEXT, -- Author
|
|
280
|
+
updated_by TEXT, -- Editor
|
|
281
|
+
organization_id text, -- ID of the parent organization (if part of an org)
|
|
282
|
+
default_locale TEXT not null default 'uk', -- Default language/locale of the space (e.g., "en", "ua" etc.)
|
|
283
|
+
locales text[],
|
|
284
|
+
plan TEXT CHECK (plan IN ('Free', 'Premium')) default 'Free' -- Plan type (e.g., "Free", "Premium")
|
|
285
|
+
);
|
|
286
|
+
insert into site.spaces(space_id, name) values('default','default') on conflict(space_id) do nothing;
|
|
287
|
+
|
|
288
|
+
COMMENT ON TABLE site.spaces IS 'Represents content spaces / sites';
|
|
289
|
+
|
|
290
|
+
COMMENT ON COLUMN site.spaces.space_id IS 'Unique identifier for the space';
|
|
291
|
+
COMMENT ON COLUMN site.spaces.name IS 'Human-readable name of the space';
|
|
292
|
+
COMMENT ON COLUMN site.spaces.created_at IS 'When the space was created';
|
|
293
|
+
COMMENT ON COLUMN site.spaces.updated_at IS 'Last modification timestamp';
|
|
294
|
+
COMMENT ON COLUMN site.spaces.organization_id IS 'ID of the parent organization (if part of an org)';
|
|
295
|
+
COMMENT ON COLUMN site.spaces.default_locale IS 'Default language/locale of the space (e.g., "en", "uk" etc.)';
|
|
296
|
+
COMMENT ON COLUMN site.spaces.plan IS 'Plan type (e.g., "Free", "Premium")';
|
|
297
|
+
|
|
298
|
+
alter table site.spaces alter column default_locale set default 'uk';
|
|
299
|
+
|
|
300
|
+
CREATE TABLE if not exists site.organizations (
|
|
301
|
+
organization_id TEXT PRIMARY KEY DEFAULT next_id(), -- Unique identifier for the organization
|
|
302
|
+
name TEXT NOT NULL, -- Name of the organization
|
|
303
|
+
created_at TIMESTAMP NOT NULL default now(), -- When the space was created
|
|
304
|
+
updated_at TIMESTAMP NOT NULL default now(), -- Last modification timestamp
|
|
305
|
+
created_by TEXT, -- Author
|
|
306
|
+
updated_by TEXT, -- Editor
|
|
307
|
+
owner_id TEXT NOT NULL, -- User ID of the organization owner
|
|
308
|
+
billing_email TEXT, -- Email used for billing-related communication (nullable)
|
|
309
|
+
plan TEXT NOT NULL DEFAULT 'Free' CHECK (plan IN ('Free', 'Pro', 'Enterprise')), -- Subscription plan
|
|
310
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'deleted')) -- Organization status
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
COMMENT ON TABLE site.organizations IS 'Organizations';
|
|
314
|
+
|
|
315
|
+
COMMENT ON COLUMN site.organizations.organization_id IS 'Unique identifier for the organization';
|
|
316
|
+
COMMENT ON COLUMN site.organizations.name IS 'Name of the organization';
|
|
317
|
+
COMMENT ON COLUMN site.organizations.created_at IS 'Timestamp when the organization was created';
|
|
318
|
+
COMMENT ON COLUMN site.organizations.owner_id IS 'User ID of the organization owner';
|
|
319
|
+
COMMENT ON COLUMN site.organizations.billing_email IS 'Email used for billing-related communication (nullable)';
|
|
320
|
+
COMMENT ON COLUMN site.organizations.plan IS 'Subscription plan (Free, Pro, Enterprise)';
|
|
321
|
+
COMMENT ON COLUMN site.organizations.status IS 'Status of the organization (active, suspended, deleted)';
|
|
322
|
+
|
|
323
|
+
CREATE TABLE if not exists site.comments (
|
|
324
|
+
comment_id text PRIMARY KEY DEFAULT next_id(), -- Unique identifier for the comment
|
|
325
|
+
content_id text NOT NULL, -- ID of the content item the comment is attached to
|
|
326
|
+
content_type TEXT NOT NULL, -- Type of the content (e.g., entry, asset, field, content_type)
|
|
327
|
+
author_id text NOT NULL, -- ID of the user who posted the comment
|
|
328
|
+
body TEXT NOT NULL, -- Comment text body
|
|
329
|
+
created_at TIMESTAMP NOT NULL DEFAULT now(), -- Timestamp when the comment was created
|
|
330
|
+
updated_at TIMESTAMP NOT NULL DEFAULT now(), -- Timestamp of last edit (nullable if never edited)
|
|
331
|
+
created_by TEXT, -- Author
|
|
332
|
+
updated_by TEXT, -- Editor
|
|
333
|
+
resolved BOOLEAN NOT NULL DEFAULT false, -- Whether the comment thread is marked as resolved
|
|
334
|
+
parent_id text, -- (nullable) ID of the parent comment, if this is a reply
|
|
335
|
+
thread_id text NOT NULL -- ID of the top-level thread this comment belongs to
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
COMMENT ON COLUMN site.comments.comment_id IS 'Unique identifier for the comment';
|
|
339
|
+
COMMENT ON COLUMN site.comments.content_id IS 'ID of the content item the comment is attached to (entry, asset, etc.)';
|
|
340
|
+
COMMENT ON COLUMN site.comments.content_type IS 'Type of the content (e.g., entry, asset, field, content_type)';
|
|
341
|
+
COMMENT ON COLUMN site.comments.author_id IS 'ID of the user who posted the comment';
|
|
342
|
+
COMMENT ON COLUMN site.comments.body IS 'Comment text body';
|
|
343
|
+
COMMENT ON COLUMN site.comments.created_at IS 'Timestamp when the comment was created';
|
|
344
|
+
COMMENT ON COLUMN site.comments.updated_at IS 'Timestamp of last edit (nullable if never edited)';
|
|
345
|
+
COMMENT ON COLUMN site.comments.resolved IS 'Whether the comment thread is marked as resolved';
|
|
346
|
+
COMMENT ON COLUMN site.comments.parent_id IS 'ID of the parent comment if this is a reply';
|
|
347
|
+
COMMENT ON COLUMN site.comments.thread_id IS 'ID of the top-level thread this comment belongs to';
|
|
348
|
+
|
|
349
|
+
CREATE TABLE if not exists site.contents (
|
|
350
|
+
content_id text PRIMARY KEY default next_id(),
|
|
351
|
+
space_id text,
|
|
352
|
+
content_type_id text NOT NULL,
|
|
353
|
+
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
|
354
|
+
updated_at TIMESTAMP NOT NULL DEFAULT now(),
|
|
355
|
+
published_at TIMESTAMP,
|
|
356
|
+
revision INTEGER NOT NULL DEFAULT 1,
|
|
357
|
+
locale TEXT NOT NULL DEFAULT 'uk'::text,
|
|
358
|
+
status TEXT CHECK (status IN ('draft', 'published', 'archived')) NOT NULL default 'draft',
|
|
359
|
+
slug TEXT,
|
|
360
|
+
title TEXT,
|
|
361
|
+
created_by text,
|
|
362
|
+
published_by text,
|
|
363
|
+
updated_by text,
|
|
364
|
+
meta json,
|
|
365
|
+
main_image text,
|
|
366
|
+
FOREIGN KEY (space_id) REFERENCES site.spaces(space_id),
|
|
367
|
+
FOREIGN KEY (content_type_id) REFERENCES site.content_types(content_type_id),
|
|
368
|
+
FOREIGN KEY (created_by) REFERENCES admin.users(uid),
|
|
369
|
+
FOREIGN KEY (published_by) REFERENCES admin.users(uid),
|
|
370
|
+
FOREIGN KEY (updated_by) REFERENCES admin.users(uid)
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
alter table site.contents add column if not exists space_id text;
|
|
374
|
+
alter table site.contents add column if not exists content_type_id text;
|
|
375
|
+
ALTER TABLE site.contents add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
376
|
+
ALTER TABLE site.contents add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
377
|
+
ALTER TABLE site.contents add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
378
|
+
ALTER TABLE site.contents add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
379
|
+
ALTER TABLE site.contents add COLUMN if not exists published_at TIMESTAMP DEFAULT NOW();
|
|
380
|
+
ALTER TABLE site.contents add COLUMN if not exists revision INTEGER NOT NULL DEFAULT 1;
|
|
381
|
+
ALTER TABLE site.contents add COLUMN if not exists locale TEXT NOT NULL DEFAULT 'uk'::text;
|
|
382
|
+
ALTER TABLE site.contents add COLUMN if not exists published_by text;
|
|
383
|
+
ALTER TABLE site.contents add COLUMN if not exists slug text;
|
|
384
|
+
ALTER TABLE site.contents add COLUMN if not exists meta json;
|
|
385
|
+
|
|
386
|
+
COMMENT ON COLUMN site.contents.content_id IS 'Unique identifier for the content item (entry)';
|
|
387
|
+
COMMENT ON COLUMN site.contents.space_id IS 'FK to the space this content belongs to';
|
|
388
|
+
COMMENT ON COLUMN site.contents.content_type_id IS 'FK to the content type definition';
|
|
389
|
+
COMMENT ON COLUMN site.contents.created_at IS 'Timestamp when the content was created';
|
|
390
|
+
COMMENT ON COLUMN site.contents.updated_at IS 'Timestamp of last update';
|
|
391
|
+
COMMENT ON COLUMN site.contents.published_at IS 'Timestamp of publication (nullable if not published)';
|
|
392
|
+
COMMENT ON COLUMN site.contents.revision IS 'Revision/version number';
|
|
393
|
+
COMMENT ON COLUMN site.contents.locale IS 'Language/locale for this content entry (e.g., en)';
|
|
394
|
+
COMMENT ON COLUMN site.contents.status IS 'Status of the entry (e.g., draft, published, archived)';
|
|
395
|
+
COMMENT ON COLUMN site.contents.slug IS 'URL-friendly string identifier';
|
|
396
|
+
COMMENT ON COLUMN site.contents.title IS 'Title of the content entry';
|
|
397
|
+
COMMENT ON COLUMN site.contents.created_by IS 'User who created the entry';
|
|
398
|
+
COMMENT ON COLUMN site.contents.published_by IS 'User who published the entry';
|
|
399
|
+
COMMENT ON COLUMN site.contents.updated_by IS 'User who last updated the entry';
|
|
400
|
+
|
|
401
|
+
CREATE TABLE if not exists site.content_data (
|
|
402
|
+
field_id text PRIMARY KEY DEFAULT next_id(),
|
|
403
|
+
content_id text NOT NULL,
|
|
404
|
+
object_id text NOT NULL,
|
|
405
|
+
field_key TEXT NOT NULL,
|
|
406
|
+
field_type TEXT NOT NULL,
|
|
407
|
+
field_value TEXT,
|
|
408
|
+
field_value_object json,
|
|
409
|
+
locale TEXT NOT NULL DEFAULT 'uk'::text,
|
|
410
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
411
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
412
|
+
created_by text,
|
|
413
|
+
updated_by text,
|
|
414
|
+
|
|
415
|
+
constraint content_data_content_id_fkey FOREIGN KEY (content_id) REFERENCES site.contents(content_id) on delete cascade
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
alter table site.content_data add column if not exists field_key text not null;
|
|
420
|
+
alter table site.content_data add column if not exists field_type text;
|
|
421
|
+
alter table site.content_data add column if not exists field_value text;
|
|
422
|
+
alter table site.content_data add column if not exists field_value_object json;
|
|
423
|
+
alter table site.content_data add column if not exists locale text;
|
|
424
|
+
alter table site.content_data add column if not exists field_id text;
|
|
425
|
+
alter table site.content_data add column if not exists object_id text;
|
|
426
|
+
ALTER TABLE site.content_data add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
|
|
427
|
+
ALTER TABLE site.content_data add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
|
|
428
|
+
ALTER TABLE site.content_data add COLUMN if not exists created_by text REFERENCES admin.users(uid);
|
|
429
|
+
ALTER TABLE site.content_data add COLUMN if not exists updated_by text REFERENCES admin.users(uid);
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
-- create unique index for slug
|
|
434
|
+
CREATE UNIQUE INDEX if not exists content_data_slug_unique ON site.content_data (field_value) WHERE field_key = 'slug';
|
|
435
|
+
|
|
436
|
+
COMMENT ON TABLE site.content_data IS 'Content fields';
|
|
437
|
+
|
|
438
|
+
COMMENT ON COLUMN site.content_data.field_id IS 'Unique identifier for the field entry';
|
|
439
|
+
COMMENT ON COLUMN site.content_data.content_id IS 'FK to Contents.content_id';
|
|
440
|
+
COMMENT ON COLUMN site.content_data.object_id IS 'Unique ID per content_id / field_key';
|
|
441
|
+
COMMENT ON COLUMN site.content_data.field_key IS 'Name of the field (e.g., title, description)';
|
|
442
|
+
COMMENT ON COLUMN site.content_data.field_type IS 'Field type (e.g., text, number, media, reference)';
|
|
443
|
+
COMMENT ON COLUMN site.content_data.field_value IS 'Data value stored as string';
|
|
444
|
+
COMMENT ON COLUMN site.content_data.field_value_object IS 'Data value stored as json';
|
|
445
|
+
COMMENT ON COLUMN site.content_data.locale IS 'Locale for this field (e.g., en-US, uk)';
|
|
446
|
+
COMMENT ON COLUMN site.content_data.created_at IS 'Field creation timestamp';
|
|
447
|
+
COMMENT ON COLUMN site.content_data.updated_at IS 'Last updated';
|
|
448
|
+
COMMENT ON COLUMN site.content_data.created_by IS 'Author';
|
|
449
|
+
COMMENT ON COLUMN site.content_data.updated_by IS 'Last editor';
|
|
450
|
+
|
|
451
|
+
alter table site.content_data alter column locale set default 'uk';
|
|
452
|
+
alter table site.contents alter column locale set default 'uk';
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
CREATE TABLE if not exists site.localization (
|
|
456
|
+
localization_id text PRIMARY KEY DEFAULT next_id(),
|
|
457
|
+
object_id text NOT NULL,
|
|
458
|
+
field_key TEXT NOT NULL,
|
|
459
|
+
field_value TEXT,
|
|
460
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
461
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
462
|
+
created_by text,
|
|
463
|
+
updated_by text,
|
|
464
|
+
constraint object_id_field_key_unique UNIQUE (object_id, field_key)
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
COMMENT ON TABLE site.localization IS 'Content localization';
|
|
468
|
+
|
|
469
|
+
COMMENT ON COLUMN site.localization.object_id IS 'Unique ID of content (content_data / custom data.table)';
|
|
470
|
+
COMMENT ON COLUMN site.localization.field_key IS 'Name of the field (e.g., title, description)';
|
|
471
|
+
COMMENT ON COLUMN site.localization.field_value IS 'Data value stored as string';
|
|
472
|
+
COMMENT ON COLUMN site.localization.created_at IS 'Field creation timestamp';
|
|
473
|
+
COMMENT ON COLUMN site.localization.updated_at IS 'Last updated';
|
|
474
|
+
COMMENT ON COLUMN site.localization.created_by IS 'Author';
|
|
475
|
+
COMMENT ON COLUMN site.localization.updated_by IS 'Last editor';
|
|
476
|
+
|
|
477
|
+
CREATE TABLE if not exists site.tags
|
|
478
|
+
(
|
|
479
|
+
tag_id text NOT NULL DEFAULT next_id(),
|
|
480
|
+
value text NOT NULL, -- Текстове значення тегу
|
|
481
|
+
slug text not null,
|
|
482
|
+
color text NOT NULL DEFAULT '#ababab'::text, -- Колір тегу
|
|
483
|
+
created_at timestamp without time zone DEFAULT now(),
|
|
484
|
+
updated_at timestamp without time zone,
|
|
485
|
+
created_by text,
|
|
486
|
+
updated_by text,
|
|
487
|
+
description text,
|
|
488
|
+
CONSTRAINT tags_pkey PRIMARY KEY (tag_id)
|
|
489
|
+
)
|
|
490
|
+
WITH (
|
|
491
|
+
OIDS=FALSE
|
|
492
|
+
);
|
|
493
|
+
ALTER TABLE site.tags
|
|
494
|
+
OWNER TO postgres;
|
|
495
|
+
COMMENT ON TABLE site.tags
|
|
496
|
+
IS 'Теги';
|
|
497
|
+
COMMENT ON COLUMN site.tags.value IS 'Текстове значення тегу';
|
|
498
|
+
COMMENT ON COLUMN site.tags.color IS 'Колір тегу';
|
|
499
|
+
|
|
500
|
+
alter table site.tags add column if not exists slug text;
|
|
501
|
+
COMMENT ON COLUMN site.tags.slug IS 'Alias тегу';
|
|
502
|
+
update site.tags set slug = tag_id where slug is null;
|
|
503
|
+
alter table site.tags alter column slug set not null;
|
|
504
|
+
|
|
505
|
+
CREATE TABLE if not exists site.tag_data
|
|
506
|
+
(
|
|
507
|
+
tag_content_id text NOT NULL DEFAULT next_id(),
|
|
508
|
+
tag_id text NOT NULL,
|
|
509
|
+
data_id text NOT NULL, -- Ідентифікатор будь якого контенту
|
|
510
|
+
created_at timestamp without time zone DEFAULT now(),
|
|
511
|
+
updated_at timestamp without time zone,
|
|
512
|
+
created_by text,
|
|
513
|
+
updated_by text,
|
|
514
|
+
CONSTRAINT tag_data_pkey PRIMARY KEY (tag_content_id),
|
|
515
|
+
CONSTRAINT tag_data_tag_id_fkey FOREIGN KEY (tag_id)
|
|
516
|
+
REFERENCES site.tags (tag_id) MATCH SIMPLE
|
|
517
|
+
ON UPDATE NO ACTION ON DELETE CASCADE,
|
|
518
|
+
CONSTRAINT tag_data_unique UNIQUE (tag_id, data_id)
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
ALTER TABLE site.tag_data drop constraint if exists tag_data_tag_id_fkey;
|
|
522
|
+
ALTER TABLE site.tag_data add CONSTRAINT tag_data_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES site.tags (tag_id) MATCH SIMPLE ON DELETE CASCADE;
|
|
523
|
+
COMMENT ON TABLE site.tag_data
|
|
524
|
+
IS 'Відношення тегів до контенту';
|
|
525
|
+
COMMENT ON COLUMN site.tag_data.data_id IS 'Ідентифікатор будь якого контенту';
|
|
526
|
+
|
|
527
|
+
CREATE TABLE if not exists site.feedback
|
|
528
|
+
(
|
|
529
|
+
message_id text NOT NULL DEFAULT next_id(), -- ID
|
|
530
|
+
title text, -- Заголовок
|
|
531
|
+
email text NOT NULL, -- Електронна пошта
|
|
532
|
+
user_name text, -- ПІБ Повністю
|
|
533
|
+
message_text text, -- Повідомлення
|
|
534
|
+
feedback_type text NOT NULL DEFAULT 'message'::text, -- Тип
|
|
535
|
+
status text NOT NULL DEFAULT 'new'::text, -- Статус
|
|
536
|
+
phone text, -- Телефон
|
|
537
|
+
headers json,
|
|
538
|
+
resume_link text, -- Посилання на резюме
|
|
539
|
+
linkedin_link text, -- Посилання на лінкедин
|
|
540
|
+
portfolio_link text, -- Посилання на портфоліо
|
|
541
|
+
telegram_link text, -- Посилання на телеграм
|
|
542
|
+
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
543
|
+
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
544
|
+
created_by text,
|
|
545
|
+
updated_by text,
|
|
546
|
+
CONSTRAINT feedback_pkey PRIMARY KEY (message_id)
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
alter table site.feedback add column if not exists message_id text not null default next_id();
|
|
550
|
+
alter table site.feedback add column if not exists title text;
|
|
551
|
+
alter table site.feedback add column if not exists user_name text;
|
|
552
|
+
alter table site.feedback add column if not exists message_text text;
|
|
553
|
+
alter table site.feedback add column if not exists feedback_type text NOT NULL DEFAULT 'message'::text;
|
|
554
|
+
alter table site.feedback add column if not exists resume_link text;
|
|
555
|
+
alter table site.feedback add column if not exists linkedin_link text;
|
|
556
|
+
alter table site.feedback add column if not exists portfolio_link text;
|
|
557
|
+
alter table site.feedback add column if not exists telegram_link text;
|
|
558
|
+
|
|
559
|
+
COMMENT ON COLUMN site.feedback.message_id IS 'ID';
|
|
560
|
+
COMMENT ON COLUMN site.feedback.title IS 'Заголовок';
|
|
561
|
+
COMMENT ON COLUMN site.feedback.email IS 'Електронна пошта';
|
|
562
|
+
COMMENT ON COLUMN site.feedback.user_name IS 'ПІБ Повністю';
|
|
563
|
+
COMMENT ON COLUMN site.feedback.message_text IS 'Повідомлення';
|
|
564
|
+
COMMENT ON COLUMN site.feedback.feedback_type IS 'Тип';
|
|
565
|
+
COMMENT ON COLUMN site.feedback.status IS 'Статус';
|
|
566
|
+
COMMENT ON COLUMN site.feedback.phone IS 'Телефон';
|
|
567
|
+
COMMENT ON COLUMN site.feedback.resume_link IS 'Посилання на резюме';
|
|
568
|
+
COMMENT ON COLUMN site.feedback.linkedin_link IS 'Посилання на лінкедин';
|
|
569
|
+
COMMENT ON COLUMN site.feedback.portfolio_link IS 'Посилання на портфоліо';
|
|
570
|
+
COMMENT ON COLUMN site.feedback.telegram_link IS 'Посилання на телеграм';
|
|
571
|
+
|
|
572
|
+
CREATE TABLE if not exists site.subscription
|
|
573
|
+
(
|
|
574
|
+
subscription_id text NOT NULL DEFAULT next_id(),
|
|
575
|
+
email text NOT NULL, -- Електронна пошта
|
|
576
|
+
enabled boolean DEFAULT true, -- Чи активна підписка
|
|
577
|
+
referer text, -- Звідки підписка
|
|
578
|
+
unsubscribed_at timestamp with time zone, -- Дата відписки
|
|
579
|
+
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
580
|
+
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
581
|
+
created_by text,
|
|
582
|
+
updated_by text,
|
|
583
|
+
CONSTRAINT subscription_pkey PRIMARY KEY (subscription_id),
|
|
584
|
+
CONSTRAINT subscription_email_unique UNIQUE (email)
|
|
585
|
+
);
|
|
586
|
+
COMMENT ON TABLE site.subscription
|
|
587
|
+
IS 'Підписки на новини';
|
|
588
|
+
|
|
589
|
+
alter table site.subscription add column if not exists referer text;
|
|
590
|
+
alter table site.subscription add column if not exists unsubscribed_at timestamp with time zone;
|
|
591
|
+
|
|
592
|
+
COMMENT ON COLUMN site.subscription.email IS 'Електронна пошта';
|
|
593
|
+
COMMENT ON COLUMN site.subscription.enabled IS 'Чи активна підписка';
|
|
594
|
+
COMMENT ON COLUMN site.subscription.referer IS 'Звідки підписка';
|
|
595
|
+
COMMENT ON COLUMN site.subscription.unsubscribed_at IS 'Дата відписки';
|