File size: 32,155 Bytes
e4a761a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
using System;
using System.Collections.Generic;
using FlowAPI.Application.DTOs.Graph;
using FlowAPI.Domain.Entities;
using FlowAPI.Domain.Enums;

namespace FlowAPI.Application.Services
{
    public static class TemplateLibrary
    {
        private class TemplateNodeDef
        {
            public string TempId { get; set; } = string.Empty;
            public string Label { get; set; } = string.Empty;
            public double PosX { get; set; }
            public double PosY { get; set; }
            public string Type { get; set; } = "sketch";
            public string Color { get; set; } = "white";
            public string Description { get; set; } = string.Empty;
            public string DecisionJson { get; set; } = string.Empty;
            public double? Width { get; set; }
            public double? Height { get; set; }
        }

        private class TemplateEdgeDef
        {
            public string FromTempId { get; set; } = string.Empty;
            public string ToTempId { get; set; } = string.Empty;
            public string Condition { get; set; } = "True";
        }

        private class TemplateDef
        {
            public string Key { get; set; } = string.Empty;
            public string Title { get; set; } = string.Empty;
            public string Description { get; set; } = string.Empty;
            public string Icon { get; set; } = string.Empty;
            public string Category { get; set; } = string.Empty;
            public List<TemplateNodeDef> Nodes { get; set; } = new();
            public List<TemplateEdgeDef> Edges { get; set; } = new();
        }

        private static readonly Dictionary<string, TemplateDef> Templates = new()
        {
            {
                "startup",
                new TemplateDef
                {
                    Key = "startup",
                    Title = "Запуск Стартапу",
                    Description = "Шлях від формулювання ціннісної пропозиції та CustDev до запуску MVP та перших 100 користувачів.",
                    Icon = "Rocket",
                    Category = "Business",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "vprop", Label = "Формулювання ціннісної пропозиції", PosX = 250, PosY = 50, Color = "purple", Description = "Чітко опишіть, яку проблему вирішує ваш продукт і для кого." },
                        new() { TempId = "custdev", Label = "CustDev: Інтерв'ю з клієнтами", PosX = 250, PosY = 170, Color = "blue", Description = "Проведіть принаймні 10 інтерв'ю з потенційними користувачами." },
                        new() { TempId = "fit", Label = "Чи підтверджено проблему?", PosX = 250, PosY = 290, Type = "condition", DecisionJson = "{\"options\":[{\"id\":\"opt-yes\",\"label\":\"Так (Є інтерес)\"},{\"id\":\"opt-no\",\"label\":\"Ні (Потрібен півот)\"}],\"selected\":[],\"multiSelect\":false}" },
                        new() { TempId = "mvp", Label = "Розробка MVP", PosX = 100, PosY = 420, Color = "green", Description = "Створіть мінімально життєздатний продукт з однією ключовою функцією." },
                        new() { TempId = "pivot", Label = "Півот ідеї", PosX = 400, PosY = 420, Color = "orange", Description = "Змініть напрямок або цільову аудиторію на основі фідбеку з інтерв'ю." },
                        new() { TempId = "landing", Label = "Лендинг та збір заявок", PosX = 100, PosY = 550, Color = "pink", Description = "Налаштуйте просту сторінку для збору контактів зацікавлених клієнтів." },
                        new() { TempId = "users", Label = "Залучення перших 100 користувачів", PosX = 100, PosY = 680, Color = "yellow", Description = "Використовуйте безкоштовні канали (соцмережі, профільні форуми, зв'язки)." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "vprop", ToTempId = "custdev" },
                        new() { FromTempId = "custdev", ToTempId = "fit" },
                        new() { FromTempId = "fit", ToTempId = "mvp", Condition = "True" },
                        new() { FromTempId = "fit", ToTempId = "pivot", Condition = "False" },
                        new() { FromTempId = "pivot", ToTempId = "vprop" },
                        new() { FromTempId = "mvp", ToTempId = "landing" },
                        new() { FromTempId = "landing", ToTempId = "users" }
                    }
                }
            },
            {
                "software",
                new TemplateDef
                {
                    Key = "software",
                    Title = "Розробка ПЗ (Web App)",
                    Description = "Стандартний життєвий цикл розробки веб-додатку: вимоги, дизайн, UI/UX, API, інтеграція та реліз.",
                    Icon = "Code",
                    Category = "Development",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "req", Label = "Збір та аналіз вимог", PosX = 250, PosY = 50, Color = "blue", Description = "Опишіть функціонал проекту та підготуйте ТЗ." },
                        new() { TempId = "arch", Label = "Архітектура та проектування БД", PosX = 250, PosY = 170, Color = "purple", Description = "Спроектуйте схему бази даних та виберіть стек технологій." },
                        new() { TempId = "uiux", Label = "UI/UX макети та дизайн", PosX = 100, PosY = 300, Color = "pink", Description = "Створіть клікабельний прототип у Figma." },
                        new() { TempId = "api", Label = "Розробка API та Бекенду", PosX = 400, PosY = 300, Color = "yellow", Description = "Реалізуйте серверу логіку, авторизацію та базу даних." },
                        new() { TempId = "integ", Label = "Інтеграція та тестування", PosX = 250, PosY = 440, Color = "green", Description = "З'єднайте фронтенд з бекендом та проведіть ручне тестування." },
                        new() { TempId = "staging", Label = "Деплой на Staging сервер", PosX = 250, PosY = 560, Color = "orange", Description = "Розгорніть тестову версію додатку для фінальної перевірки." },
                        new() { TempId = "prod", Label = "Реліз у Production та моніторинг", PosX = 250, PosY = 680, Color = "green", Description = "Запустіть додаток для реальних користувачів та підключіть аналітику." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "req", ToTempId = "arch" },
                        new() { FromTempId = "arch", ToTempId = "uiux" },
                        new() { FromTempId = "arch", ToTempId = "api" },
                        new() { FromTempId = "uiux", ToTempId = "integ" },
                        new() { FromTempId = "api", ToTempId = "integ" },
                        new() { FromTempId = "integ", ToTempId = "staging" },
                        new() { FromTempId = "staging", ToTempId = "prod" }
                    }
                }
            },
            {
                "language",
                new TemplateDef
                {
                    Key = "language",
                    Title = "Вивчення Іноземної Мови",
                    Description = "Методика освоєння мови через щоденні звички, проходження базового курсу та вихід у практику.",
                    Icon = "Languages",
                    Category = "Education",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "goal", Label = "Визначення цілей та ресурсів", PosX = 250, PosY = 50, Color = "purple", Description = "Оберіть додатки, підручники та поставте чітку ціль (наприклад, рівень B1)." },
                        new() { TempId = "words", Label = "Вчити 15 нових слів щодня", PosX = 100, PosY = 170, Type = "habit", Color = "blue", Description = "Використовуйте картки Anki або Quizlet для регулярного повторення.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Використовуйте картки Anki або Quizlet для регулярного повторення.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "listen", Label = "Слухати подкаст / дивитись відео", PosX = 400, PosY = 170, Type = "habit", Color = "pink", Description = "Принаймні 20 хвилин фонового або активного слухання щодня.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Принаймні 20 хвилин фонового або активного слухання щодня.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "course", Label = "Завершити курс для початківців", PosX = 250, PosY = 300, Color = "yellow", Description = "Пройти базову граматику та отримати розуміння структури мови." },
                        new() { TempId = "speak", Label = "Розмовна сесія (1 раз на тиждень)", PosX = 100, PosY = 430, Type = "habit", Color = "green", Description = "Знайдіть партнера для спілкування на Tandem або викладача.", DecisionJson = "{\"resetRule\":{\"type\":\"weekly\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Знайдіть партнера для спілкування на Tandem або викладача.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "read", Label = "Прочитати першу коротку розповідь", PosX = 400, PosY = 430, Color = "orange", Description = "Оберіть адаптовану книгу під ваш поточний рівень." },
                        new() { TempId = "exam", Label = "Скласти тестовий іспит", PosX = 250, PosY = 560, Color = "green", Description = "Перевірте свій прогрес за допомогою офіційного пробного тесту." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "goal", ToTempId = "words" },
                        new() { FromTempId = "goal", ToTempId = "listen" },
                        new() { FromTempId = "words", ToTempId = "course" },
                        new() { FromTempId = "listen", ToTempId = "course" },
                        new() { FromTempId = "course", ToTempId = "speak" },
                        new() { FromTempId = "course", ToTempId = "read" },
                        new() { FromTempId = "speak", ToTempId = "exam" },
                        new() { FromTempId = "read", ToTempId = "exam" }
                    }
                }
            },
            {
                "fitness",
                new TemplateDef
                {
                    Key = "fitness",
                    Title = "Фітнес та Здорове Тіло",
                    Description = "Збалансований план тренувань, контролю харчування та циклічного аналізу результатів.",
                    Icon = "Activity",
                    Category = "Health",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "setup", Label = "Поставити ціль та розрахувати КБЖВ", PosX = 250, PosY = 50, Color = "blue", Description = "Визначте добову норму калорій залежно від мети (схуднення чи набір маси)." },
                        new() { TempId = "plan", Label = "Скласти план тренувань та раціон", PosX = 250, PosY = 170, Color = "purple", Description = "Виберіть 3 дні для занять та підготуйте перелік здорових страв." },
                        new() { TempId = "diet", Label = "Трекати щоденне харчування та воду", PosX = 100, PosY = 300, Type = "habit", Color = "green", Description = "Записуйте все з'їдене в MyFitnessPal та пийте достатньо води.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Записуйте все з'їдене в MyFitnessPal та пийте достатньо води.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "workout", Label = "Силове або кардіо тренування", PosX = 400, PosY = 300, Type = "habit", Color = "orange", Description = "Виконуйте заплановане тренування 3 рази на тиждень.", DecisionJson = "{\"resetRule\":{\"type\":\"weekly\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Виконуйте заплановане тренування 3 рази на тиждень.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "check", Label = "Контрольне зважування та заміри (4 тижні)", PosX = 250, PosY = 430, Color = "yellow", Description = "Порівняйте поточну вагу та об'єми тіла з початковими показниками." },
                        new() { TempId = "satisfied", Label = "Чи є прогрес задовільним?", PosX = 250, PosY = 550, Type = "condition", DecisionJson = "{\"options\":[{\"id\":\"opt-yes\",\"label\":\"Так (Продовжуємо)\"},{\"id\":\"opt-no\",\"label\":\"Ні (Потрібні коригування)\"}],\"selected\":[],\"multiSelect\":false}" },
                        new() { TempId = "advance", Label = "Ускладнити програму тренувань", PosX = 100, PosY = 680, Color = "pink", Description = "Додайте вагу на снарядах або збільшіть інтенсивність." },
                        new() { TempId = "adjust", Label = "Скоригувати КБЖВ та план їжі", PosX = 400, PosY = 680, Color = "yellow", Description = "Зменшіть або збільшіть калорійність раціону на 10%." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "setup", ToTempId = "plan" },
                        new() { FromTempId = "plan", ToTempId = "diet" },
                        new() { FromTempId = "plan", ToTempId = "workout" },
                        new() { FromTempId = "diet", ToTempId = "check" },
                        new() { FromTempId = "workout", ToTempId = "check" },
                        new() { FromTempId = "check", ToTempId = "satisfied" },
                        new() { FromTempId = "satisfied", ToTempId = "advance", Condition = "True" },
                        new() { FromTempId = "satisfied", ToTempId = "adjust", Condition = "False" },
                        new() { FromTempId = "adjust", ToTempId = "plan" }
                    }
                }
            },
            {
                "gamedev",
                new TemplateDef
                {
                    Key = "gamedev",
                    Title = "Створення Інді-Гри",
                    Description = "Повний цикл геймдеву від ідеї та прототипу до створення сторінки в Steam та релізу.",
                    Icon = "Gamepad",
                    Category = "Creative",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "concept", Label = "Концепт та написання GDD", PosX = 250, PosY = 50, Color = "pink", Description = "Сформулюйте основну ідею гри та опишіть її механіки в дизайн-документі." },
                        new() { TempId = "proto", Label = "Прототип базового геймплею", PosX = 250, PosY = 170, Color = "purple", Description = "Створіть «сіру коробку» на рушії, щоб перевірити, чи весело грати." },
                        new() { TempId = "art", Label = "Стилістика та створення артів", PosX = 100, PosY = 300, Color = "orange", Description = "Визначте художній стиль та підготуйте перші 2D/3D моделі." },
                        new() { TempId = "level", Label = "Дизайн рівнів та звуковий супровід", PosX = 400, PosY = 300, Color = "blue", Description = "Створіть тестовий рівень та додайте базові звукові ефекти." },
                        new() { TempId = "playable", Label = "Перша грабельна демо-версія", PosX = 250, PosY = 430, Color = "yellow", Description = "Зберіть стабільний білд для тестування друзями." },
                        new() { TempId = "test", Label = "Плейтести та виправлення багів", PosX = 100, PosY = 560, Type = "habit", Color = "pink", Description = "Щодня грайте, збирайте фідбек та виправляйте помилки.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Щодня грайте, збирайте фідбек та виправляйте помилки.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "steam", Label = "Створення сторінки в Steam", PosX = 400, PosY = 560, Color = "yellow", Description = "Підготуйте красиві скріншоти, трейлер та запустіть сторінку для збору Wishlists." },
                        new() { TempId = "release", Label = "Реліз гри в Steam", PosX = 250, PosY = 690, Color = "green", Description = "Опублікуйте фінальний білд та підтримайте запуск маркетинговою кампанією." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "concept", ToTempId = "proto" },
                        new() { FromTempId = "proto", ToTempId = "art" },
                        new() { FromTempId = "proto", ToTempId = "level" },
                        new() { FromTempId = "art", ToTempId = "playable" },
                        new() { FromTempId = "level", ToTempId = "playable" },
                        new() { FromTempId = "playable", ToTempId = "test" },
                        new() { FromTempId = "playable", ToTempId = "steam" },
                        new() { FromTempId = "test", ToTempId = "release" },
                        new() { FromTempId = "steam", ToTempId = "release" }
                    }
                }
            },
            {
                "finance",
                new TemplateDef
                {
                    Key = "finance",
                    Title = "Фінансова Свобода",
                    Description = "Покроковий план досягнення фінансової незалежності: облік витрат, подушка безпеки та інвестиції.",
                    Icon = "DollarSign",
                    Category = "Finance",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "audit", Label = "Аудит активів та боргових зобов'язань", PosX = 250, PosY = 50, Color = "yellow", Description = "Запишіть усі свої збереження, майно та кредити." },
                        new() { TempId = "track", Label = "Щоденний облік усіх витрат", PosX = 100, PosY = 170, Type = "habit", Color = "blue", Description = "Записуйте кожну покупку в мобільний додаток або Excel таблицю.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Записуйте кожну покупку в мобільний додаток або Excel таблицю.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "emergency", Label = "Сформувати подушку на 3 місяці", PosX = 300, PosY = 170, Color = "orange", Description = "Розрахуйте мінімальний бюджет життя та накопичте цю суму на депозиті." },
                        new() { TempId = "debt", Label = "Виплатити всі споживчі кредити", PosX = 250, PosY = 290, Color = "pink", Description = "Спрямуйте вільні кошти на швидке закриття боргів з найвищими відсотками." },
                        new() { TempId = "invest", Label = "Інвестувати 20% від доходу", PosX = 100, PosY = 420, Type = "habit", Color = "green", Description = "Регулярно купуйте надійні індекси (ETF) або облігації.", DecisionJson = "{\"resetRule\":{\"type\":\"monthly\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Регулярно купуйте надійні індекси (ETF) або облігації.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "passive", Label = "Створити джерело пасивного доходу", PosX = 400, PosY = 420, Color = "purple", Description = "Створіть власний блог, курс, невеликий онлайн-сервіс чи придбайте дивідендні акції." },
                        new() { TempId = "freedom", Label = "Досягти фінансової незалежності", PosX = 250, PosY = 550, Color = "green", Description = "Коли пасивний дохід повністю перекриє ваші щомісячні витрати." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "audit", ToTempId = "track" },
                        new() { FromTempId = "audit", ToTempId = "emergency" },
                        new() { FromTempId = "track", ToTempId = "debt" },
                        new() { FromTempId = "emergency", ToTempId = "debt" },
                        new() { FromTempId = "debt", ToTempId = "invest" },
                        new() { FromTempId = "debt", ToTempId = "passive" },
                        new() { FromTempId = "invest", ToTempId = "freedom" },
                        new() { FromTempId = "passive", ToTempId = "freedom" }
                    }
                }
            },
            {
                "writing",
                new TemplateDef
                {
                    Key = "writing",
                    Title = "Написання та Публікація Книги",
                    Description = "Шлях автора: від розробки сюжету та персонажів до щоденного написання, редактури та релізу.",
                    Icon = "BookOpen",
                    Category = "Creative",
                    Nodes = new List<TemplateNodeDef>
                    {
                        new() { TempId = "outline", Label = "Побудова сюжету та анкет персонажів", PosX = 250, PosY = 50, Color = "pink", Description = "Напишіть синопсис та детально розпишіть структуру розділів книги." },
                        new() { TempId = "words", Label = "Писати по 1000 слів щодня", PosX = 100, PosY = 170, Type = "habit", Color = "purple", Description = "Формуйте звичку писати без критики та внутрішнього редактора.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Формуйте звичку писати без критики та внутрішнього редактора.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" },
                        new() { TempId = "draft", Label = "Завершити першу чернетку", PosX = 350, PosY = 170, Color = "yellow", Description = "Напишіть повну історію від початку до кінця (орієнтовно 50-80 тис. слів)." },
                        new() { TempId = "edit", Label = "Самостійна редактура та вичитка", PosX = 250, PosY = 300, Color = "orange", Description = "Виправте логічні помилки, покращіть діалоги та стиль оповідання." },
                        new() { TempId = "beta", Label = "Отримати фідбек від бета-рідерів", PosX = 250, PosY = 420, Color = "blue", Description = "Дайте почитати книгу кільком людям із вашої цільової аудиторії." },
                        new() { TempId = "professional", Label = "Професійна коректура та верстка", PosX = 250, PosY = 540, Color = "pink", Description = "Знайдіть професійного редактора для виправлення граматики та підготовки макету." },
                        new() { TempId = "cover", Label = "Створення обкладинки та форматування", PosX = 100, PosY = 660, Color = "purple", Description = "Замовте обкладинку в дизайнера та підготуйте формати ePub, PDF." },
                        new() { TempId = "publish", Label = "Публікація та запуск маркетингу", PosX = 350, PosY = 660, Color = "green", Description = "Опублікуйте книгу на Amazon / Litres та запустіть промо-акції." }
                    },
                    Edges = new List<TemplateEdgeDef>
                    {
                        new() { FromTempId = "outline", ToTempId = "words" },
                        new() { FromTempId = "words", ToTempId = "draft" },
                        new() { FromTempId = "draft", ToTempId = "edit" },
                        new() { FromTempId = "edit", ToTempId = "beta" },
                        new() { FromTempId = "beta", ToTempId = "professional" },
                        new() { FromTempId = "professional", ToTempId = "cover" },
                        new() { FromTempId = "professional", ToTempId = "publish" }
                    }
                }
            }
        };

        public static IEnumerable<TemplateInfoDto> GetTemplateInfos()
        {
            var list = new List<TemplateInfoDto>();
            foreach (var kv in Templates)
            {
                list.Add(new TemplateInfoDto
                {
                    Key = kv.Value.Key,
                    Title = kv.Value.Title,
                    Description = kv.Value.Description,
                    Icon = kv.Value.Icon,
                    Category = kv.Value.Category
                });
            }
            return list;
        }

        public static (List<TaskNode> Nodes, List<Edge> Edges) GetTemplateContent(string key, Guid graphId)
        {
            if (!Templates.TryGetValue(key.ToLower().Trim(), out var template))
            {
                return (new List<TaskNode>(), new List<Edge>());
            }

            var nodes = new List<TaskNode>();
            var edges = new List<Edge>();
            var idMapping = new Dictionary<string, Guid>();

            // 1. Instantiate nodes and map their IDs
            foreach (var nodeDef in template.Nodes)
            {
                var newId = Guid.NewGuid();
                idMapping[nodeDef.TempId] = newId;

                var taskNode = new TaskNode
                {
                    Id = newId,
                    GraphId = graphId,
                    Label = nodeDef.Label,
                    PosX = nodeDef.PosX,
                    PosY = nodeDef.PosY,
                    Type = nodeDef.Type,
                    State = NodeState.Pending,
                    CreatedAt = DateTime.UtcNow,
                    Description = nodeDef.Description,
                    Color = nodeDef.Color,
                    IsPinned = false,
                    Decision = string.IsNullOrEmpty(nodeDef.DecisionJson) ? null : nodeDef.DecisionJson
                };

                // For normal sketch nodes without custom Decision JSON, populate standard default JSON
                if (nodeDef.Type == "sketch" && string.IsNullOrEmpty(nodeDef.DecisionJson))
                {
                    taskNode.Decision = $"{{\"description\":\"{nodeDef.Description}\",\"progress\":0,\"showProgress\":false,\"decision\":\"bottom\",\"assignees\":[],\"color\":\"{nodeDef.Color}\",\"isPinned\":false,\"tags\":[],\"status\":\"Todo\"}}";
                }

                nodes.Add(taskNode);
            }

            // 2. Instantiate edges
            foreach (var edgeDef in template.Edges)
            {
                if (idMapping.TryGetValue(edgeDef.FromTempId, out var fromId) &&
                    idMapping.TryGetValue(edgeDef.ToTempId, out var toId))
                {
                    var edge = new Edge
                    {
                        Id = Guid.NewGuid(),
                        GraphId = graphId,
                        FromNodeId = fromId,
                        ToNodeId = toId,
                        Condition = edgeDef.Condition
                    };
                    edges.Add(edge);
                }
            }

            return (nodes, edges);
        }
    }
}