letopis 0.16.0 → 0.18.1

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.
@@ -1,69 +1,111 @@
1
1
  -- =============================================================================
2
- -- Сид таблицы Schema из schema.booking.v2.json (источник правды — JSON).
3
- -- Файл сгенерирован: node lib/scripts/gen-seed.mjs — не редактировать вручную.
2
+ -- Сид таблицы Schema — ИСТОЧНИК ПРАВДЫ демо-домена booking (19 классов, 0.17).
3
+ -- Редактируется руками; накат: db/apply.mjs / up() (маркер <SCHEMA-NAME>).
4
4
  -- Идемпотентен (ON CONFLICT). Концы связей — Schema.links v2 (JSON-объекты в text[]).
5
5
  -- =============================================================================
6
+ --
7
+ -- FILE: lib/sql/seed.booking.sql
8
+ -- VERSION: 1.0.0
9
+ -- START_MODULE_CONTRACT
10
+ -- PURPOSE: Идемпотентный сид таблицы Schema — источник правды демо-домена booking (классы HUB + LINK).
11
+ -- SCOPE: 20 INSERT-ов классов (12 HUB: Entity/Org/Person/Staff/Customer/Location/Element/Service/Product/Complex/Schedule/Folder; 8 LINK: link/address/slot/booking/content/compo/skill/price).
12
+ -- DEPENDS: none
13
+ -- LINKS: M-SEED-BOOKING, V-M-SEED-BOOKING
14
+ -- ROLE: CONFIG
15
+ -- MAP_MODE: SUMMARY
16
+ -- END_MODULE_CONTRACT
17
+ --
18
+ -- START_MODULE_MAP
19
+ -- HUB-классы - сущности домена (наследование от Entity; id v5/v7)
20
+ -- LINK-классы - связи (концы Schema.links v2; id v5 из концов)
21
+ -- NB: фактически 20 классов (12 HUB + 8 LINK); заголовок файла говорит «19» — расхождение
22
+ -- END_MODULE_MAP
23
+ --
24
+ -- START_CHANGE_SUMMARY
25
+ -- LAST_CHANGE: [v1.0.0 - Documented existing module: reverse-engineered contract + markup]
26
+ -- END_CHANGE_SUMMARY
27
+ --
28
+ -- START_BLOCK_SEED_HUB_CLASSES
6
29
 
7
30
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
8
- ('entity', 'Entity', 'Сущность', 'HUB', NULL, '{"id":{"type":"uuid","generate":7}}'::jsonb, '{"abstract":true,"description":"Абстрактный корень всех сущностей"}'::jsonb, '[]'::jsonb, 100, ARRAY['Entity']::text[])
31
+ ('entity', 'Entity', 'Сущность', 'HUB', NULL, '{"id":{"type":"uuid","generate":7}}'::jsonb, '{"abstract":true,"appearance":{"icon":{"name":"mdi:atom","color":"text-violet-500"}},"description":"Абстрактный корень всех сущностей; дефолт id v7 наследуют все классы без своего правила"}'::jsonb, '[]'::jsonb, 100, ARRAY['Entity']::text[])
9
32
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
10
33
 
11
34
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
12
- ('entity', 'Org', 'Организация', 'HUB', 'Entity', '{"name":"string","timezone":{"type":"string","default":"Europe/Moscow"},"address":"string|optional","phone":"string|optional","active":{"type":"boolean","default":true},"settings":{"type":"object","optional":true,"strict":true,"props":{"booking":{"type":"object","optional":true,"strict":true,"props":{"deposit":{"type":"object","optional":true,"strict":true,"props":{"amount":"number|integer|min:0|default:0","currency":{"type":"enum","values":["RUB","USD","EUR","AED"],"default":"RUB"}}},"autoconfirm":"boolean|default:false"}}}}}'::jsonb, '{"abstract":false,"description":"Организация / точка / филиал — владелец каталога и расписаний; settings — вложенные настройки (пример структуры глубины 4)"}'::jsonb, '[]'::jsonb, 200, ARRAY['Org', 'Entity']::text[])
35
+ ('entity', 'Org', 'Организация', 'HUB', 'Entity', '{"name":"string","timezone":{"type":"string","default":"Europe/Moscow"},"address":"string|optional","phone":"string|optional","active":{"type":"boolean","default":true},"settings":{"type":"object","optional":true,"strict":true,"props":{"booking":{"type":"object","optional":true,"strict":true,"props":{"deposit":{"type":"object","optional":true,"strict":true,"props":{"amount":"number|integer|min:0|default:0","currency":{"type":"enum","values":["RUB","USD","EUR","AED"],"default":"RUB"}}},"autoconfirm":"boolean|default:false"}}}}}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:domain","color":"text-blue-600"}},"description":"Организация — арендатор (мультитенантность): владелец каталога, локаций и расписаний; settings — вложенные настройки (пример структуры глубины 4)"}'::jsonb, '[]'::jsonb, 200, ARRAY['Org', 'Entity']::text[])
13
36
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
14
37
 
15
38
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
16
- ('entity', 'Staff', 'Сотрудник', 'HUB', 'Entity', '{"name":"string","roles":{"type":"array","items":{"type":"enum","values":["owner","administrator","manager","master"]},"default":["master"]},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Человек: роли совмещаются (owner+master). Бронируемый ⇔ master ∈ roles. Владелец = первый сотрудник с owner."}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 300, ARRAY['Staff', 'Entity']::text[])
39
+ ('entity', 'Person', 'Контрагент', 'HUB', 'Entity', '{"name":"string","phone":"string"}'::jsonb, '{"abstract":true,"appearance":{"icon":{"name":"mdi:account-outline","color":"text-blue-500"}},"description":"Абстрактный контрагент: имя + телефон; наследуют Мастер и Клиент"}'::jsonb, '[]'::jsonb, 300, ARRAY['Person', 'Entity']::text[])
17
40
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
18
41
 
19
42
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
20
- ('entity', 'Folder', 'Папка', 'HUB', 'Entity', '{"name":"string","kind":{"type":"enum","values":["services","masters"],"default":"services"}}'::jsonb, '{"abstract":false,"description":"Папка-категория; вложенность — ссылкой на родительскую Папку в links"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 400, ARRAY['Folder', 'Entity']::text[])
43
+ ('entity', 'Staff', 'Мастер', 'HUB', 'Person', '{"photo":"string|optional","description":"string|optional","specialization":"string|optional"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:account-star","color":"text-indigo-500"}},"description":"Мастер — бронируемый исполнитель; name/phone наследует от Контрагента; локации — LINK адрес, доступность — LINK окно"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 400, ARRAY['Staff', 'Person', 'Entity']::text[])
21
44
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
22
45
 
23
46
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
24
- ('entity', 'Service', 'Услуга', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Org","name"]},"name":"string","description":"string|optional","duration":"number|integer|positive","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","default":{"RUB":0}},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Услуга: длительность (мин) + цена; занимает столько подряд окон, сколько покрывает duration"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 500, ARRAY['Service', 'Entity']::text[])
47
+ ('entity', 'Customer', 'Клиент', 'HUB', 'Person', '{"notes":"string|optional","preferred_contact":{"type":"enum","values":["phone","email","messenger"],"default":"phone"}}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:account","color":"text-green-500"}},"description":"Клиент — записывается на услуги; name/phone наследует от Контрагента"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 500, ARRAY['Customer', 'Person', 'Entity']::text[])
25
48
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
26
49
 
27
50
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
28
- ('entity', 'Complex', 'Комплекс', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Org","name"]},"name":"string","description":"string|optional","duration":"number|integer|positive","discount":"number|integer|default:0","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","optional":true}}'::jsonb, '{"abstract":false,"description":"Комплекс: собственный duration; состав — позиция(Комплекс→Услуга); свободный текст цены — в description"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 600, ARRAY['Complex', 'Entity']::text[])
51
+ ('entity', 'Location', 'Локация', 'HUB', 'Entity', '{"address":"string","coordinates":{"type":"object","optional":true,"props":{"lat":"number","lng":"number"}},"description":"string|optional"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:map-marker","color":"text-red-500"}},"description":"Локация — точка обслуживания организации"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 600, ARRAY['Location', 'Entity']::text[])
29
52
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
30
53
 
31
54
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
32
- ('entity', 'Customer', 'Клиент', 'HUB', 'Entity', '{"name":"string|optional","contact":"string|optional","language":{"type":"enum","values":["ru","en"],"default":"ru"},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Клиент — записывается на услуги"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 700, ARRAY['Customer', 'Entity']::text[])
55
+ ('entity', 'Element', 'Элемент', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Org","name"]},"name":"string","description":"string|optional"}'::jsonb, '{"abstract":true,"appearance":{"icon":{"name":"mdi:view-list","color":"text-teal-500"}},"description":"Абстрактная каталожная единица (Услуга/Товар/Комплекс). Правило id v5(Org, name) объявлено здесь один раз — наследуется потомками (имя уникально в организации, classId различает классы); links не наследуются — конец Org каждый потомок объявляет сам. Цена — отдельный LINK «цена» (варианты по пожеланиям, мультивалюта)"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 700, ARRAY['Element', 'Entity']::text[])
33
56
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
34
57
 
35
58
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
36
- ('entity', 'Schedule', 'Расписание', 'HUB', 'Entity', '{"start":{"type":"date","convert":true},"end":{"type":"date","convert":true},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Расписание — период организации, содержит непересекающиеся Окна (инвариант проверяет приложение)"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 800, ARRAY['Schedule', 'Entity']::text[])
59
+ ('entity', 'Service', 'Услуга', 'HUB', 'Element', '{"duration":"number|min:0|optional"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:spa","color":"text-purple-500"}},"description":"Услуга: длительность (мин); name/id-правило наследует от Элемента; цена — LINK «цена»"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 800, ARRAY['Service', 'Element', 'Entity']::text[])
37
60
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
38
61
 
39
62
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
40
- ('entity', 'Slot', 'Окно', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Schedule","start"]},"start":{"type":"date","convert":true},"end":{"type":"date","convert":true}}'::jsonb, '{"abstract":false,"description":"Окно — общий таймлайн произвольной длины внутри Расписания; статуса нет — занятость мастера хранит LINK занятость"}'::jsonb, '[{"class":"Schedule","cardinality":1}]'::jsonb, 900, ARRAY['Slot', 'Entity']::text[])
63
+ ('entity', 'Product', 'Товар', 'HUB', 'Element', '{"sku":"string|optional","unit":{"type":"string","default":"шт"}}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:package","color":"text-blue-400"}},"description":"Товар: артикул + единица измерения; name/id-правило наследует от Элемента; цена — LINK «цена»"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 900, ARRAY['Product', 'Element', 'Entity']::text[])
41
64
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
42
65
 
43
66
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
44
- ('entity', 'Booking', 'Запись', 'HUB', 'Entity', '{"status":{"type":"enum","values":["created","confirmed","completed","cancelled","no_show"],"default":"created"},"source":{"type":"enum","values":["online","web","admin","telegram"],"default":"online"},"comment":"string|optional","total":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","default":{"RUB":0}}}'::jsonb, '{"abstract":false,"description":"Запись клиента. Без мастера (мульти-мастер): мастера — на занятости/позиции. Ручная бронь по имени: без Customer, имя в comment. Дата приёма = start первого окна брони. history: полный аудит версиями"}'::jsonb, '[{"class":"Customer","optional":true,"cardinality":1}]'::jsonb, 1000, ARRAY['Booking', 'Entity']::text[])
67
+ ('entity', 'Complex', 'Комплекс', 'HUB', 'Element', '{"cost":"number|min:0","duration":"number|min:0"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:package-variant-closed","color":"text-orange-500"}},"description":"Комплекс: собственные cost/duration; состав — LINK состав (Комплекс ← Элемент); цена — LINK «цена»"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 1000, ARRAY['Complex', 'Element', 'Entity']::text[])
45
68
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
46
69
 
47
70
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
48
- ('entity', 'link', 'связь', 'LINK', NULL, '{"id":{"type":"uuid","generate":7}}'::jsonb, '{"abstract":true,"description":"Абстрактная связь; концы объявляются потомками в links (Schema.links v2: объекты-концы)"}'::jsonb, '[]'::jsonb, 100, ARRAY['link']::text[])
71
+ ('entity', 'Schedule', 'Расписание', 'HUB', 'Entity', '{"name":"string","year":"number|integer","month":"number|integer|min:1|max:12"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:calendar","color":"text-cyan-500"}},"description":"Месячное расписание организации; наполнение — LINK окно"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 1100, ARRAY['Schedule', 'Entity']::text[])
49
72
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
50
73
 
51
74
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
52
- ('entity', 'item', 'позиция', 'LINK', 'link', '{"qty":"number|integer|min:1|default:1","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","optional":true}}'::jsonb, '{"abstract":false,"description":"Позиция заказа: Запись × предмет [Услуга|Комплекс] × Сотрудник?. Снимок цены в price. Состав комплекса — отдельный LINK «состав» (compo)"}'::jsonb, '[{"classes":["Booking"],"cardinality":1},{"classes":["Service","Complex"],"cardinality":1},{"class":"Staff","optional":true,"cardinality":1}]'::jsonb, 200, ARRAY['item', 'link']::text[])
75
+ ('entity', 'Folder', 'Папка', 'HUB', 'Entity', '{"name":"string"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:folder","color":"text-yellow-500"}},"description":"Папка-категория; вложенность — HUB-конец на родительскую Папку; наполнение — LINK содержимое"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 1200, ARRAY['Folder', 'Entity']::text[])
53
76
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
54
77
 
78
+ -- END_BLOCK_SEED_HUB_CLASSES
79
+ -- START_BLOCK_SEED_LINK_CLASSES
55
80
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
56
- ('entity', 'compo', 'состав', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Complex","Service"]},"qty":"number|integer|min:1|default:1"}'::jsonb, '{"abstract":false,"description":"Состав комплекса: Комплекс ← Услуга (+qty). Раньше жил на позиции — вынесен отдельным классом"}'::jsonb, '[{"class":"Complex","cardinality":1},{"class":"Service","cardinality":1}]'::jsonb, 250, ARRAY['compo', 'link']::text[])
81
+ ('entity', 'link', 'связь', 'LINK', NULL, '{"id":{"type":"uuid","generate":7}}'::jsonb, '{"abstract":true,"appearance":{"icon":{"name":"mdi:link","color":"text-sky-500"}},"description":"Абстрактная связь; концы объявляются потомками в links (Schema.links v2: объекты-концы, только HUB-классы)"}'::jsonb, '[]'::jsonb, 100, ARRAY['link']::text[])
57
82
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
58
83
 
59
84
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
60
- ('entity', 'skill', 'навык', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Staff","Service|Complex"]}}'::jsonb, '{"abstract":false,"description":"Навык: Сотрудник умеет (Услуга|Комплекс); при записи проверяется"}'::jsonb, '[{"class":"Staff","cardinality":1},{"classes":["Service","Complex"],"cardinality":1}]'::jsonb, 300, ARRAY['skill', 'link']::text[])
85
+ ('entity', 'address', 'адрес', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Staff","Location"]},"default":"boolean|default:false","schedule_info":"string|optional"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:link","color":"text-sky-500"}},"description":"Адрес: Мастер работает в Локации; default — основная точка мастера"}'::jsonb, '[{"class":"Staff","cardinality":1},{"class":"Location","cardinality":1}]'::jsonb, 200, ARRAY['address', 'link']::text[])
61
86
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
62
87
 
63
88
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
64
- ('entity', 'shift', 'смена', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Schedule","Staff"]}}'::jsonb, '{"abstract":false,"description":"Ростер: сотрудник работает в расписании ⇒ по умолчанию доступен во всех его окнах"}'::jsonb, '[{"class":"Schedule","cardinality":1},{"class":"Staff","cardinality":1}]'::jsonb, 400, ARRAY['shift', 'link']::text[])
89
+ ('entity', 'slot', 'окно', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Staff","start_datetime"]},"start_datetime":{"type":"date","convert":true},"end_datetime":{"type":"date","convert":true}}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:clock-outline","color":"text-amber-500"}},"description":"Окно доступности: Мастер × Локация × Расписание + интервал. id = v5(Мастер, старт) — мастер не задваивает время ни в одной локации"}'::jsonb, '[{"class":"Staff","cardinality":1},{"class":"Location","cardinality":1},{"class":"Schedule","cardinality":1}]'::jsonb, 300, ARRAY['slot', 'link']::text[])
65
90
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
66
91
 
67
92
  INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
68
- ('entity', 'busy', 'занятость', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Slot","Staff"]},"kind":{"type":"enum","values":["off","hold","booking"],"default":"booking"},"reason":"string|optional"}'::jsonb, '{"abstract":false,"description":"Негативная доступность: свободно = НЕТ живой занятости. off — мастер убран из окна; hold — оформление; booking — бронь (+ключ Запись в links). id = uuidv5(Окно, Сотрудник) — считает схема (attributes.id) — детерминирован против двойной брони"}'::jsonb, '[{"class":"Staff","cardinality":1},{"class":"Slot","cardinality":1},{"class":"Booking","optional":true,"cardinality":1}]'::jsonb, 500, ARRAY['busy', 'link']::text[])
93
+ ('entity', 'booking', 'запись', 'LINK', 'slot', '{"notes":"string|optional"}'::jsonb, '{"abstract":false,"validation":"strict","appearance":{"icon":{"name":"mdi:calendar-check","color":"text-emerald-500"}},"description":"Запись — наследник окна (start/end_datetime и правило id v5(Мастер, старт) наследуются): бронь мастера на Элемент для Клиента. Ручная бронь — без Клиента, имя в notes. classId в v5-формуле различает окно и запись; двойная бронь того же времени мертва"}'::jsonb, '[{"class":"Staff","cardinality":1},{"class":"Location","cardinality":1},{"class":"Schedule","cardinality":1},{"classes":["Service","Product","Complex"],"cardinality":1},{"class":"Customer","optional":true,"cardinality":1}]'::jsonb, 400, ARRAY['booking', 'slot', 'link']::text[])
69
94
  ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
95
+
96
+ INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
97
+ ('entity', 'content', 'содержимое', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Folder","Service|Product|Complex"]},"order":"number|integer|default:0"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:link","color":"text-sky-500"}},"description":"Содержимое папки: Папка ← Элемент (+порядок); элемент может лежать в нескольких папках"}'::jsonb, '[{"class":"Folder","cardinality":1},{"classes":["Service","Product","Complex"],"cardinality":1}]'::jsonb, 500, ARRAY['content', 'link']::text[])
98
+ ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
99
+
100
+ INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
101
+ ('entity', 'compo', 'состав', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Complex","Service|Product"]},"order":"number|integer|default:0","quantity":"number|integer|min:1|default:1"}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:link","color":"text-sky-500"}},"description":"Состав комплекса: Комплекс ← Элемент (+порядок, +количество); в состав входят и услуги, и товары"}'::jsonb, '[{"class":"Complex","cardinality":1},{"classes":["Service","Product"],"cardinality":1}]'::jsonb, 600, ARRAY['compo', 'link']::text[])
102
+ ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
103
+
104
+ INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
105
+ ('entity', 'skill', 'навык', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Staff","Service"]},"level":{"type":"enum","values":["basic","intermediate","advanced","expert"],"default":"intermediate"}}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:link","color":"text-sky-500"}},"description":"Навык: Мастер умеет Услугу (+уровень); умение комплекса вычислимо по составу"}'::jsonb, '[{"class":"Staff","cardinality":1},{"class":"Service","cardinality":1}]'::jsonb, 700, ARRAY['skill', 'link']::text[])
106
+ ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
107
+
108
+ INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
109
+ ('entity', 'price', 'цена', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Service|Product|Complex","note"]},"note":{"type":"string","default":"базовая"},"amounts":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0"}}'::jsonb, '{"abstract":false,"appearance":{"icon":{"name":"mdi:cash-multiple","color":"text-green-600"}},"description":"Вариант цены каталожного элемента: мультивалютные суммы (amounts) + описание (note). У элемента несколько вариантов по пожеланиям клиента (note различает: базовая/с дизайном/…); id v5(элемент, note) — note не задан ⇒ дефолт «базовая»; правку одной валюты amounts мержит точечно"}'::jsonb, '[{"classes":["Service","Product","Complex"],"cardinality":1}]'::jsonb, 800, ARRAY['price', 'link']::text[])
110
+ ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
111
+ -- END_BLOCK_SEED_LINK_CLASSES