[{"data":1,"prerenderedAt":13884},["ShallowReactive",2],{"navigation_docs":3,"-csharp-aspnet-web-api-problemdetails-error-handling":2949,"-csharp-aspnet-web-api-problemdetails-error-handling-surround":13879},[4,1640,1765,2219,2352,2559,2641,2691,2748,2782,2908,2945],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","/csharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1346,1636],{"title":11,"path":7,"stem":12},"C# Roadmap","01.csharp/index",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","/csharp/fundamentals","01.csharp/01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","/csharp/fundamentals/introduction-to-ecosystem","01.csharp/01.fundamentals/01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","/csharp/fundamentals/program-structure","01.csharp/01.fundamentals/02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","/csharp/fundamentals/variables-data-types","01.csharp/01.fundamentals/03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","/csharp/fundamentals/arrays","01.csharp/01.fundamentals/04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","/csharp/fundamentals/strings-text-handling","01.csharp/01.fundamentals/05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","/csharp/fundamentals/dates-time-handling","01.csharp/01.fundamentals/06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","/csharp/fundamentals/control-flow","01.csharp/01.fundamentals/07.control-flow",{"title":48,"path":49,"stem":50},"Методи","/csharp/fundamentals/methods","01.csharp/01.fundamentals/08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","/csharp/fundamentals/debugging-basics","01.csharp/01.fundamentals/09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","/csharp/fundamentals/interactive-console","01.csharp/01.fundamentals/10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","/csharp/oop","01.csharp/02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","/csharp/oop/package-management","01.csharp/02.oop/01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","/csharp/oop/classes-objects","01.csharp/02.oop/02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","/csharp/oop/properties-fields","01.csharp/02.oop/03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","/csharp/oop/oop-pillars","01.csharp/02.oop/04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","/csharp/oop/advanced-types","01.csharp/02.oop/05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","/csharp/oop/namespaces","01.csharp/02.oop/06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","/csharp/advanced-core","01.csharp/03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","/csharp/advanced-core/generics","01.csharp/03.advanced-core/01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","/csharp/advanced-core/delegates-events-lambdas","01.csharp/03.advanced-core/02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","/csharp/advanced-core/interfaces-deep-dive","01.csharp/03.advanced-core/03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","/csharp/advanced-core/exception-handling","01.csharp/03.advanced-core/04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","/csharp/advanced-core/pattern-matching","01.csharp/03.advanced-core/05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","/csharp/advanced-core/additional-features","01.csharp/03.advanced-core/06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","/csharp/architecture-best-practices","01.csharp/04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","/csharp/architecture-best-practices/software-design-principles","01.csharp/04.architecture-best-practices/01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","/csharp/architecture-best-practices/design-patterns","01.csharp/04.architecture-best-practices/02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","/csharp/architecture-best-practices/design-patterns/creational","01.csharp/04.architecture-best-practices/02.design-patterns/creational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","/csharp/architecture-best-practices/design-patterns/creational/singleton","01.csharp/04.architecture-best-practices/02.design-patterns/creational/01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","/csharp/architecture-best-practices/design-patterns/creational/builder","01.csharp/04.architecture-best-practices/02.design-patterns/creational/02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","/csharp/architecture-best-practices/building-professional-clis","01.csharp/04.architecture-best-practices/03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","/csharp/architecture-best-practices/validation-flow-control","01.csharp/04.architecture-best-practices/04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","/csharp/architecture-best-practices/modern-dotnet-host","01.csharp/04.architecture-best-practices/05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","/csharp/architecture-best-practices/data-mapper-part1","01.csharp/04.architecture-best-practices/06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","/csharp/architecture-best-practices/data-mapper-part2","01.csharp/04.architecture-best-practices/07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","/csharp/architecture-best-practices/di-ioc","01.csharp/04.architecture-best-practices/08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","/csharp/architecture-best-practices/di-ioc/the-dependency-problem","01.csharp/04.architecture-best-practices/08.di-ioc/01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","/csharp/architecture-best-practices/di-ioc/build-your-own-container","01.csharp/04.architecture-best-practices/08.di-ioc/02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","/csharp/architecture-best-practices/di-ioc/service-locator-pattern","01.csharp/04.architecture-best-practices/08.di-ioc/03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","/csharp/architecture-best-practices/di-ioc/dependency-injection-patterns","01.csharp/04.architecture-best-practices/08.di-ioc/04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","/csharp/architecture-best-practices/di-ioc/microsoft-di-deep-dive","01.csharp/04.architecture-best-practices/08.di-ioc/05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","/csharp/architecture-best-practices/di-ioc/service-lifetimes-and-scopes","01.csharp/04.architecture-best-practices/08.di-ioc/06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","/csharp/architecture-best-practices/di-ioc/di-anti-patterns-and-best-practices","01.csharp/04.architecture-best-practices/08.di-ioc/07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","/csharp/standard-library","01.csharp/05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","/csharp/standard-library/collections","01.csharp/05.standard-library/01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","/csharp/standard-library/high-performance-types","01.csharp/05.standard-library/02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","/csharp/standard-library/linq","01.csharp/05.standard-library/03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","/csharp/system-internals-concurrency","01.csharp/06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","/csharp/system-internals-concurrency/memory-management","01.csharp/06.system-internals-concurrency/01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","/csharp/system-internals-concurrency/reflection-fundamentals","01.csharp/06.system-internals-concurrency/02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","/csharp/system-internals-concurrency/attributes-dynamic","01.csharp/06.system-internals-concurrency/03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","/csharp/system-internals-concurrency/expression-trees-compiled","01.csharp/06.system-internals-concurrency/04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","/csharp/system-internals-concurrency/source-generators","01.csharp/06.system-internals-concurrency/05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","/csharp/system-internals-concurrency/multithreading-fundamentals","01.csharp/06.system-internals-concurrency/06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","/csharp/system-internals-concurrency/synchronization-primitives","01.csharp/06.system-internals-concurrency/07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","/csharp/system-programming-windows","01.csharp/07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","/csharp/system-programming-windows/how-os-works","01.csharp/07.system-programming-windows/01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","/csharp/system-programming-windows/processes-in-dotnet","01.csharp/07.system-programming-windows/02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","/csharp/system-programming-windows/02a.processes-ipc","01.csharp/07.system-programming-windows/02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","/csharp/system-programming-windows/appdomains-assemblies","01.csharp/07.system-programming-windows/03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","/csharp/system-programming-windows/03a.appdomains-plugin-system","01.csharp/07.system-programming-windows/03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","/csharp/system-programming-windows/thread-fundamentals","01.csharp/07.system-programming-windows/04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","/csharp/system-programming-windows/04a.thread-lifecycle-priorities","01.csharp/07.system-programming-windows/04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","/csharp/system-programming-windows/shared-state-problems","01.csharp/07.system-programming-windows/05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","/csharp/system-programming-windows/05a.shared-state-memory-model","01.csharp/07.system-programming-windows/05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","/csharp/system-programming-windows/synchronization-fundamentals","01.csharp/07.system-programming-windows/06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","/csharp/system-programming-windows/06a.synchronization-walkthrough","01.csharp/07.system-programming-windows/06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","/csharp/system-programming-windows/synchronization-advanced","01.csharp/07.system-programming-windows/07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","/csharp/system-programming-windows/07a.synchronization-advanced-walkthrough","01.csharp/07.system-programming-windows/07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","/csharp/system-programming-windows/interlocked-cas-lockfree","01.csharp/07.system-programming-windows/08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","/csharp/system-programming-windows/08a.volatile-memory-model","01.csharp/07.system-programming-windows/08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","/csharp/system-programming-windows/thread-pool","01.csharp/07.system-programming-windows/09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","/csharp/system-programming-windows/09a.thread-pool-advanced","01.csharp/07.system-programming-windows/09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","/csharp/system-programming-windows/concurrent-collections","01.csharp/07.system-programming-windows/10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","/csharp/system-programming-windows/tpl-parallel-plinq","01.csharp/07.system-programming-windows/11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","/csharp/system-programming-windows/11a.tpl-parallel-plinq-advanced","01.csharp/07.system-programming-windows/11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async/Await — Фундамент Асинхронного Програмування","/csharp/system-programming-windows/async-fundamentals","01.csharp/07.system-programming-windows/12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","/csharp/system-programming-windows/async-context-configureawait","01.csharp/07.system-programming-windows/13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","/csharp/system-programming-windows/async-advanced","01.csharp/07.system-programming-windows/14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","/csharp/system-programming-windows/channels","01.csharp/07.system-programming-windows/15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","/csharp/system-programming-windows/async-synchronization","01.csharp/07.system-programming-windows/16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","/csharp/system-programming-windows/unsafe-code","01.csharp/07.system-programming-windows/17.unsafe-code",{"title":364,"path":365,"stem":366},"P/Invoke та Windows API — Міст між .NET та Native Code","/csharp/system-programming-windows/pinvoke-winapi","01.csharp/07.system-programming-windows/18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","/csharp/system-programming-windows/windows-registry","01.csharp/07.system-programming-windows/19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","/csharp/system-programming-windows/windows-hooks-services","01.csharp/07.system-programming-windows/20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","/csharp/system-programming-windows/implementation_plan","01.csharp/07.system-programming-windows/implementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","/csharp/io","01.csharp/08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","/csharp/io/file-system-basics","01.csharp/08.io/01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","/csharp/io/streams-serialization","01.csharp/08.io/02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","/csharp/io/json-serialization","01.csharp/08.io/03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","/csharp/io/xml-serialization","01.csharp/08.io/04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","/csharp/io/binary-serialization","01.csharp/08.io/05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","/csharp/ado-net","01.csharp/09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","/csharp/ado-net/introduction-to-adonet","01.csharp/09.ado-net/01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","/csharp/ado-net/connection","01.csharp/09.ado-net/02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","/csharp/ado-net/command-and-queries","01.csharp/09.ado-net/03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","/csharp/ado-net/datareader","01.csharp/09.ado-net/04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","/csharp/ado-net/parameters-and-sql-injection","01.csharp/09.ado-net/05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","/csharp/ado-net/transactions","01.csharp/09.ado-net/06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","/csharp/ado-net/provider-factory","01.csharp/09.ado-net/07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","/csharp/ado-net/async-data-access","01.csharp/09.ado-net/08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","/csharp/ado-net/disconnected-mode-dataset","01.csharp/09.ado-net/09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","/csharp/ado-net/data-adapter","01.csharp/09.ado-net/10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","/csharp/ado-net/data-mapper-repository","01.csharp/09.ado-net/11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","/csharp/ado-net/advanced-patterns","01.csharp/09.ado-net/12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","/csharp/ef-core","01.csharp/10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","/csharp/ef-core/what-is-orm","01.csharp/10.ef-core/01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","/csharp/ef-core/first-project","01.csharp/10.ef-core/02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","/csharp/ef-core/dbcontext-deep-dive","01.csharp/10.ef-core/03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","/csharp/ef-core/database-providers","01.csharp/10.ef-core/04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","/csharp/ef-core/conventions","01.csharp/10.ef-core/05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","/csharp/ef-core/fluent-api-vs-annotations","01.csharp/10.ef-core/06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","/csharp/ef-core/relationships-basics","01.csharp/10.ef-core/07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","/csharp/ef-core/relationships-advanced","01.csharp/10.ef-core/08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","/csharp/ef-core/property-configuration-part1","01.csharp/10.ef-core/09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","/csharp/ef-core/property-configuration-part2","01.csharp/10.ef-core/09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","/csharp/ef-core/complex-types-owned-part1","01.csharp/10.ef-core/10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","/csharp/ef-core/complex-types-owned-part2","01.csharp/10.ef-core/10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","/csharp/ef-core/json-columns-part1","01.csharp/10.ef-core/11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","/csharp/ef-core/json-columns-part2","01.csharp/10.ef-core/11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","/csharp/ef-core/inheritance-part1","01.csharp/10.ef-core/12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","/csharp/ef-core/inheritance-part2","01.csharp/10.ef-core/12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","/csharp/ef-core/indexes-constraints-part1","01.csharp/10.ef-core/13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","/csharp/ef-core/indexes-constraints-part2","01.csharp/10.ef-core/13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","/csharp/ef-core/seeding-part1","01.csharp/10.ef-core/14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","/csharp/ef-core/seeding-part2","01.csharp/10.ef-core/14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","/csharp/ef-core/global-query-filters-part1","01.csharp/10.ef-core/15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","/csharp/ef-core/global-query-filters-part2","01.csharp/10.ef-core/15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","/csharp/ef-core/linq-queries-part1","01.csharp/10.ef-core/16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","/csharp/ef-core/linq-queries-part2","01.csharp/10.ef-core/16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","/csharp/ef-core/loading-related-data-part1","01.csharp/10.ef-core/17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","/csharp/ef-core/loading-related-data-part2","01.csharp/10.ef-core/17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","/csharp/ef-core/raw-sql-part1","01.csharp/10.ef-core/18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","/csharp/ef-core/raw-sql-part2","01.csharp/10.ef-core/18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","/csharp/ef-core/advanced-queries-part1","01.csharp/10.ef-core/19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","/csharp/ef-core/advanced-queries-part2","01.csharp/10.ef-core/19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","/csharp/ef-core/change-tracking-part1","01.csharp/10.ef-core/20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","/csharp/ef-core/change-tracking-part2","01.csharp/10.ef-core/20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","/csharp/ef-core/saving-data-part1","01.csharp/10.ef-core/21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","/csharp/ef-core/saving-data-part2","01.csharp/10.ef-core/21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","/csharp/ef-core/concurrency-part1","01.csharp/10.ef-core/22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","/csharp/ef-core/concurrency-part2","01.csharp/10.ef-core/22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","/csharp/ef-core/migrations-basics-part1","01.csharp/10.ef-core/23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","/csharp/ef-core/migrations-basics-part2","01.csharp/10.ef-core/23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","/csharp/ef-core/migrations-advanced-part1","01.csharp/10.ef-core/24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","/csharp/ef-core/migrations-advanced-part2","01.csharp/10.ef-core/24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","/csharp/ef-core/schema-management-part1","01.csharp/10.ef-core/25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","/csharp/ef-core/schema-management-part2","01.csharp/10.ef-core/25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","/csharp/ef-core/performance-fundamentals-part1","01.csharp/10.ef-core/26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","/csharp/ef-core/interceptors-part1","01.csharp/10.ef-core/29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","/csharp/ef-core/interceptors-part2","01.csharp/10.ef-core/29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","/csharp/ef-core/implementation_plan","01.csharp/10.ef-core/implementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","/csharp/aspnet","01.csharp/11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","/csharp/aspnet/minimal-api","01.csharp/11.aspnet/01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","/csharp/aspnet/minimal-api/introduction","01.csharp/11.aspnet/01.minimal-api/01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","/csharp/aspnet/minimal-api/first-application","01.csharp/11.aspnet/01.minimal-api/02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","/csharp/aspnet/minimal-api/webapplication-builder","01.csharp/11.aspnet/01.minimal-api/03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","/csharp/aspnet/minimal-api/request-pipeline-middleware","01.csharp/11.aspnet/01.minimal-api/04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/routing-basics","01.csharp/11.aspnet/01.minimal-api/05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","/csharp/aspnet/minimal-api/routing-advanced","01.csharp/11.aspnet/01.minimal-api/06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","/csharp/aspnet/minimal-api/static-files","01.csharp/11.aspnet/01.minimal-api/07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","/csharp/aspnet/minimal-api/static-assets","01.csharp/11.aspnet/01.minimal-api/08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/configuration-fundamentals","01.csharp/11.aspnet/01.minimal-api/09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","/csharp/aspnet/minimal-api/configuration-options","01.csharp/11.aspnet/01.minimal-api/10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/logging-basics","01.csharp/11.aspnet/01.minimal-api/11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","/csharp/aspnet/minimal-api/logging-advanced","01.csharp/11.aspnet/01.minimal-api/12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","/csharp/aspnet/minimal-api/state-management","01.csharp/11.aspnet/01.minimal-api/13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","/csharp/aspnet/minimal-api/session-state","01.csharp/11.aspnet/01.minimal-api/14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","/csharp/aspnet/minimal-api/project-structure","01.csharp/11.aspnet/01.minimal-api/15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","/csharp/aspnet/minimal-api/scalar-openapi-fluent","01.csharp/11.aspnet/01.minimal-api/16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger / Swashbuckle у Minimal API: окремий класичний шлях","/csharp/aspnet/minimal-api/swagger-swashbuckle","01.csharp/11.aspnet/01.minimal-api/17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","/csharp/aspnet/api","01.csharp/11.aspnet/02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","/csharp/aspnet/api/what-is-api","01.csharp/11.aspnet/02.api/01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","/csharp/aspnet/api/data-formats","01.csharp/11.aspnet/02.api/02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","/csharp/aspnet/api/api-paradigms-rest","01.csharp/11.aspnet/02.api/03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","/csharp/aspnet/api/http-methods-status-codes","01.csharp/11.aspnet/02.api/04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","/csharp/aspnet/api/rest-organizing","01.csharp/11.aspnet/02.api/05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","/csharp/aspnet/api/url-nomenclature-crud","01.csharp/11.aspnet/02.api/06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","/csharp/aspnet/api/api-design-naming","01.csharp/11.aspnet/02.api/07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","/csharp/aspnet/api/api-design-validation","01.csharp/11.aspnet/02.api/08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","/csharp/aspnet/api/error-handling-http","01.csharp/11.aspnet/02.api/09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","/csharp/aspnet/api/idempotency-sync","01.csharp/11.aspnet/02.api/10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","/csharp/aspnet/api/pagination-lists","01.csharp/11.aspnet/02.api/11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","/csharp/aspnet/api/security-auth","01.csharp/11.aspnet/02.api/12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","/csharp/aspnet/api/api-design-process","01.csharp/11.aspnet/02.api/13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","/csharp/aspnet/api/openapi","01.csharp/11.aspnet/02.api/14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","/csharp/aspnet/auth","01.csharp/11.aspnet/03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","/csharp/aspnet/auth/auth-fundamentals","01.csharp/11.aspnet/03.auth/01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","/csharp/aspnet/auth/jwt-authentication","01.csharp/11.aspnet/03.auth/02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","/csharp/aspnet/auth/authorization-policies","01.csharp/11.aspnet/03.auth/03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","/csharp/aspnet/auth/cookie-auth-identity","01.csharp/11.aspnet/03.auth/04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","/csharp/aspnet/auth/04b.identity-auth-jwt","01.csharp/11.aspnet/03.auth/04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","/csharp/aspnet/auth/identity-email-confirmation","01.csharp/11.aspnet/03.auth/05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","/csharp/aspnet/auth/identity-two-factor","01.csharp/11.aspnet/03.auth/06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","/csharp/aspnet/auth/identity-internals","01.csharp/11.aspnet/03.auth/07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","/csharp/aspnet/auth/oauth-external-providers","01.csharp/11.aspnet/03.auth/08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","/csharp/aspnet/auth/security-hardening","01.csharp/11.aspnet/03.auth/09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","/csharp/aspnet/auth/oauth-theory","01.csharp/11.aspnet/03.auth/10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","/csharp/aspnet/auth/oidc-keycloak","01.csharp/11.aspnet/03.auth/10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","/csharp/aspnet/auth/api-keys","01.csharp/11.aspnet/03.auth/11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","/csharp/aspnet/auth/rate-limiting","01.csharp/11.aspnet/03.auth/12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","/csharp/aspnet/auth/refresh-token-rotation","01.csharp/11.aspnet/03.auth/13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","/csharp/aspnet/auth/certificate-auth","01.csharp/11.aspnet/03.auth/14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","/csharp/aspnet/auth/rbac-abac-rebac","01.csharp/11.aspnet/03.auth/15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","/csharp/aspnet/auth/multi-tenancy","01.csharp/11.aspnet/03.auth/16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","/csharp/aspnet/notifications","01.csharp/11.aspnet/04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","/csharp/aspnet/notifications/in-app-database-notifications","01.csharp/11.aspnet/04.notifications/01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","/csharp/aspnet/notifications/polling","01.csharp/11.aspnet/04.notifications/02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","/csharp/aspnet/notifications/server-sent-events","01.csharp/11.aspnet/04.notifications/03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","/csharp/aspnet/notifications/websockets","01.csharp/11.aspnet/04.notifications/04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","/csharp/aspnet/notifications/signalr","01.csharp/11.aspnet/04.notifications/05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","/csharp/aspnet/notifications/background-services","01.csharp/11.aspnet/04.notifications/06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","/csharp/aspnet/notifications/web-push","01.csharp/11.aspnet/04.notifications/07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","/csharp/aspnet/notifications/email-notifications","01.csharp/11.aspnet/04.notifications/08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","/csharp/aspnet/notifications/choosing-the-right-approach","01.csharp/11.aspnet/04.notifications/09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","/csharp/aspnet/notifications/hangfire","01.csharp/11.aspnet/04.notifications/10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","/csharp/aspnet/notifications/hangfire-image-webp","01.csharp/11.aspnet/04.notifications/11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","/csharp/aspnet/notifications/hangfire-video-hls","01.csharp/11.aspnet/04.notifications/12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","/csharp/aspnet/notifications/telegram-notifications","01.csharp/11.aspnet/04.notifications/13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","/csharp/aspnet/i18n","01.csharp/11.aspnet/05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","/csharp/aspnet/i18n/internationalization","01.csharp/11.aspnet/05.i18n/01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","/csharp/aspnet/i18n/humanizer","01.csharp/11.aspnet/05.i18n/02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","/csharp/aspnet/caching","01.csharp/11.aspnet/06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","/csharp/aspnet/caching/caching","01.csharp/11.aspnet/06.caching/01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","/csharp/aspnet/caching/memory-cache","01.csharp/11.aspnet/06.caching/02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","/csharp/aspnet/caching/distributed-cache","01.csharp/11.aspnet/06.caching/03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","/csharp/aspnet/caching/response-cache","01.csharp/11.aspnet/06.caching/04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","/csharp/aspnet/caching/output-cache","01.csharp/11.aspnet/06.caching/05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","/csharp/aspnet/testing","01.csharp/11.aspnet/07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","/csharp/aspnet/testing/what-is-testing","01.csharp/11.aspnet/07.testing/01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","/csharp/aspnet/testing/testing-pyramid","01.csharp/11.aspnet/07.testing/02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","/csharp/aspnet/testing/testing-schools","01.csharp/11.aspnet/07.testing/03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","/csharp/aspnet/testing/tdd-and-bdd","01.csharp/11.aspnet/07.testing/04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","/csharp/aspnet/testing/what-to-test","01.csharp/11.aspnet/07.testing/05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","/csharp/aspnet/testing/test-frameworks","01.csharp/11.aspnet/07.testing/06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","/csharp/aspnet/testing/xunit-basics","01.csharp/11.aspnet/07.testing/07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","/csharp/aspnet/testing/xunit-advanced","01.csharp/11.aspnet/07.testing/08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","/csharp/aspnet/testing/mocking-with-moq","01.csharp/11.aspnet/07.testing/09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","/csharp/aspnet/testing/database-testing","01.csharp/11.aspnet/07.testing/10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","/csharp/aspnet/testing/integration-testing","01.csharp/11.aspnet/07.testing/11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","/csharp/aspnet/testing/11a.integration-testing-practice","01.csharp/11.aspnet/07.testing/11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","/csharp/aspnet/testing/integration-testing-advanced","01.csharp/11.aspnet/07.testing/12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","/csharp/aspnet/testing/postman-professional","01.csharp/11.aspnet/07.testing/13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","/csharp/aspnet/testing/httpclient-testing","01.csharp/11.aspnet/07.testing/14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","/csharp/aspnet/testing/wiremock-net","01.csharp/11.aspnet/07.testing/15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","/csharp/aspnet/testing/testing-patterns","01.csharp/11.aspnet/07.testing/16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","/csharp/aspnet/testing/advanced-testing-tools","01.csharp/11.aspnet/07.testing/17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","/csharp/aspnet/testing/architecture-testing","01.csharp/11.aspnet/07.testing/18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","/csharp/aspnet/testing/performance-testing","01.csharp/11.aspnet/07.testing/19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","/csharp/aspnet/testing/remaining_plan","01.csharp/11.aspnet/07.testing/remaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","/csharp/aspnet/payments","01.csharp/11.aspnet/08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","/csharp/aspnet/payments/payment-fundamentals","01.csharp/11.aspnet/08.payments/01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","/csharp/aspnet/payments/payment-methods-ukraine","01.csharp/11.aspnet/08.payments/02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","/csharp/aspnet/payments/pci-dss-security","01.csharp/11.aspnet/08.payments/03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","/csharp/aspnet/payments/payment-architecture","01.csharp/11.aspnet/08.payments/04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","/csharp/aspnet/payments/liqpay-integration","01.csharp/11.aspnet/08.payments/05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","/csharp/aspnet/payments/monobank-acquiring","01.csharp/11.aspnet/08.payments/06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","/csharp/aspnet/payments/stripe-integration","01.csharp/11.aspnet/08.payments/07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","/csharp/aspnet/payments/webhooks-deep-dive","01.csharp/11.aspnet/08.payments/08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","/csharp/aspnet/payments/subscriptions-recurring","01.csharp/11.aspnet/08.payments/09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","/csharp/aspnet/payments/refunds-disputes","01.csharp/11.aspnet/08.payments/10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","/csharp/aspnet/payments/testing-payments","01.csharp/11.aspnet/08.payments/11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","/csharp/aspnet/payments/production-checklist","01.csharp/11.aspnet/08.payments/12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","/csharp/aspnet/libraries","01.csharp/11.aspnet/09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","/csharp/aspnet/libraries/fluent-validation","01.csharp/11.aspnet/09.libraries/01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","/csharp/aspnet/libraries/mapster","01.csharp/11.aspnet/09.libraries/02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","/csharp/aspnet/libraries/erroror-result-pattern","01.csharp/11.aspnet/09.libraries/03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","/csharp/aspnet/libraries/serilog","01.csharp/11.aspnet/09.libraries/04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","/csharp/aspnet/libraries/mediatr","01.csharp/11.aspnet/09.libraries/05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","/csharp/aspnet/libraries/polly","01.csharp/11.aspnet/09.libraries/06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","/csharp/aspnet/libraries/health-checks","01.csharp/11.aspnet/09.libraries/07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","/csharp/aspnet/libraries/feature-management","01.csharp/11.aspnet/09.libraries/08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","/csharp/aspnet/libraries/fluent-email","01.csharp/11.aspnet/09.libraries/09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","/csharp/aspnet/libraries/quest-pdf","01.csharp/11.aspnet/09.libraries/10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","/csharp/aspnet/libraries/bogus","01.csharp/11.aspnet/09.libraries/11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","/csharp/aspnet/libraries/humanizer-guard","01.csharp/11.aspnet/09.libraries/12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","/csharp/aspnet/libraries/plan","01.csharp/11.aspnet/09.libraries/plan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","/csharp/aspnet/razor-pages","01.csharp/11.aspnet/10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","/csharp/aspnet/razor-pages/from-minimal-api","01.csharp/11.aspnet/10.razor-pages/01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","/csharp/aspnet/razor-pages/page-model","01.csharp/11.aspnet/10.razor-pages/02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","/csharp/aspnet/razor-pages/razor-syntax","01.csharp/11.aspnet/10.razor-pages/03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","/csharp/aspnet/razor-pages/tag-helpers","01.csharp/11.aspnet/10.razor-pages/04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","/csharp/aspnet/razor-pages/forms-validation","01.csharp/11.aspnet/10.razor-pages/05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","/csharp/aspnet/razor-pages/project-task-manager","01.csharp/11.aspnet/10.razor-pages/06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","/csharp/aspnet/mvc","01.csharp/11.aspnet/11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","/csharp/aspnet/mvc/mvc-pattern","01.csharp/11.aspnet/11.mvc/01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","/csharp/aspnet/mvc/from-razor-pages","01.csharp/11.aspnet/11.mvc/02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","/csharp/aspnet/mvc/controllers-actions","01.csharp/11.aspnet/11.mvc/03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","/csharp/aspnet/mvc/routing-mvc","01.csharp/11.aspnet/11.mvc/04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","/csharp/aspnet/mvc/model-binding","01.csharp/11.aspnet/11.mvc/05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","/csharp/aspnet/mvc/views-viewdata-tempdata","01.csharp/11.aspnet/11.mvc/06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","/csharp/aspnet/mvc/filters","01.csharp/11.aspnet/11.mvc/07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","/csharp/aspnet/mvc/areas","01.csharp/11.aspnet/11.mvc/08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","/csharp/aspnet/mvc/view-components","01.csharp/11.aspnet/11.mvc/09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","/csharp/aspnet/mvc/display-editor-templates","01.csharp/11.aspnet/11.mvc/10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","/csharp/aspnet/mvc/validation-advanced","01.csharp/11.aspnet/11.mvc/11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","/csharp/aspnet/mvc/htmx","01.csharp/11.aspnet/11.mvc/12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","/csharp/aspnet/mvc/ajax-htmx-mvc","01.csharp/11.aspnet/11.mvc/13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","/csharp/aspnet/mvc/htmx-project","01.csharp/11.aspnet/11.mvc/14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","/csharp/aspnet/mvc/file-upload","01.csharp/11.aspnet/11.mvc/15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","/csharp/aspnet/mvc/globalization-localization","01.csharp/11.aspnet/11.mvc/16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","/csharp/aspnet/mvc/mvc-project","01.csharp/11.aspnet/11.mvc/17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","/csharp/aspnet/mvc/plan","01.csharp/11.aspnet/11.mvc/plan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","/csharp/aspnet/web-api","01.csharp/11.aspnet/12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","/csharp/aspnet/web-api/from-minimal-api-to-controllers","01.csharp/11.aspnet/12.web-api/01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","/csharp/aspnet/web-api/controller-base-actionresult","01.csharp/11.aspnet/12.web-api/02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","/csharp/aspnet/web-api/content-negotiation","01.csharp/11.aspnet/12.web-api/03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","/csharp/aspnet/web-api/api-versioning","01.csharp/11.aspnet/12.web-api/04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","/csharp/aspnet/web-api/problemdetails-error-handling","01.csharp/11.aspnet/12.web-api/05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","/csharp/aspnet/web-api/filters-for-api","01.csharp/11.aspnet/12.web-api/06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","/csharp/aspnet/web-api/pagination-filtering-sorting","01.csharp/11.aspnet/12.web-api/07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","/csharp/aspnet/web-api/hateoas-resource-expansion","01.csharp/11.aspnet/12.web-api/08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","/csharp/aspnet/web-api/minimal-api-vs-controllers-hybrid","01.csharp/11.aspnet/12.web-api/09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","/csharp/aspnet/web-api/api-documentation-generation","01.csharp/11.aspnet/12.web-api/10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","/csharp/aspnet/web-api/health-checks-monitoring","01.csharp/11.aspnet/12.web-api/11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","/csharp/aspnet/web-api/web-api-project","01.csharp/11.aspnet/12.web-api/12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","/csharp/aspnet/web-api/plan","01.csharp/11.aspnet/12.web-api/plan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Desktop UI","i-lucide-app-window","/csharp/desktop-ui","01.csharp/12.desktop-ui",[1352,1356,1360,1364,1368,1372,1376,1380,1384,1388,1392,1396,1400,1404,1408,1412,1416,1420,1424,1428,1432,1436,1440,1444,1448,1452,1456,1460,1464,1468,1472,1476,1480,1484,1488,1492,1496,1500,1504,1508,1512,1516,1520,1524,1528,1532,1536,1540,1544,1548,1552,1556,1560,1564,1568,1572,1576,1580,1584,1588,1592,1596,1600,1604,1608,1612,1616,1620,1624,1628,1632],{"title":1353,"path":1354,"stem":1355},"Що таке десктопна розробка?","/csharp/desktop-ui/what-is-desktop-dev","01.csharp/12.desktop-ui/01.what-is-desktop-dev",{"title":1357,"path":1358,"stem":1359},"Архітектура WPF — як влаштований графічний інтерфейс","/csharp/desktop-ui/wpf-architecture","01.csharp/12.desktop-ui/02.wpf-architecture",{"title":1361,"path":1362,"stem":1363},"Перший WPF-проєкт — від нуля до вікна","/csharp/desktop-ui/first-wpf-app","01.csharp/12.desktop-ui/03.first-wpf-app",{"title":1365,"path":1366,"stem":1367},"Перший Avalonia-проєкт: WPF для всіх платформ","/csharp/desktop-ui/03a.first-avalonia-app","01.csharp/12.desktop-ui/03a.first-avalonia-app",{"title":1369,"path":1370,"stem":1371},"XAML: декларативний інтерфейс","/csharp/desktop-ui/xaml-basics","01.csharp/12.desktop-ui/04.xaml-basics",{"title":1373,"path":1374,"stem":1375},"Fluent UI у WPF — сучасний дизайн Windows 11","/csharp/desktop-ui/04a.wpf-fluent-ui","01.csharp/12.desktop-ui/04a.wpf-fluent-ui",{"title":1377,"path":1378,"stem":1379},"WPF UI — сучасна бібліотека Fluent контролів","/csharp/desktop-ui/04b.wpf-ui-library","01.csharp/12.desktop-ui/04b.wpf-ui-library",{"title":1381,"path":1382,"stem":1383},"HandyControl — велика бібліотека UI контролів для WPF","/csharp/desktop-ui/04c.handycontrol-library","01.csharp/12.desktop-ui/04c.handycontrol-library",{"title":1385,"path":1386,"stem":1387},"Простори імен та ресурси XAML","/csharp/desktop-ui/xaml-namespaces-resources","01.csharp/12.desktop-ui/05.xaml-namespaces-resources",{"title":1389,"path":1390,"stem":1391},"XAML в Avalonia: ключові відмінності від WPF","/csharp/desktop-ui/05a.avalonia-xaml-differences","01.csharp/12.desktop-ui/05a.avalonia-xaml-differences",{"title":1393,"path":1394,"stem":1395},"Розширення розмітки XAML (Markup Extensions)","/csharp/desktop-ui/xaml-markup-extensions","01.csharp/12.desktop-ui/06.xaml-markup-extensions",{"title":1397,"path":1398,"stem":1399},"Панелі Layout: StackPanel, WrapPanel, DockPanel","/csharp/desktop-ui/layout-panels-part1","01.csharp/12.desktop-ui/07.layout-panels-part1",{"title":1401,"path":1402,"stem":1403},"Grid, Canvas, UniformGrid","/csharp/desktop-ui/layout-panels-part2","01.csharp/12.desktop-ui/07.layout-panels-part2",{"title":1405,"path":1406,"stem":1407},"Просунуті техніки Layout","/csharp/desktop-ui/layout-advanced","01.csharp/12.desktop-ui/08.layout-advanced",{"title":1409,"path":1410,"stem":1411},"Адаптивний Layout та найкращі практики","/csharp/desktop-ui/layout-responsive","01.csharp/12.desktop-ui/09.layout-responsive",{"title":1413,"path":1414,"stem":1415},"Layout в Avalonia: відмінності та нові можливості","/csharp/desktop-ui/09a.layout-avalonia","01.csharp/12.desktop-ui/09a.layout-avalonia",{"title":1417,"path":1418,"stem":1419},"Button, Image, ProgressBar та інші базові контроли","/csharp/desktop-ui/basic-controls","01.csharp/12.desktop-ui/10.basic-controls",{"title":1421,"path":1422,"stem":1423},"Контроли в Avalonia: відмінності від WPF","/csharp/desktop-ui/10a.controls-avalonia","01.csharp/12.desktop-ui/10a.controls-avalonia",{"title":1425,"path":1426,"stem":1427},"Текстові контроли — TextBlock, TextBox, RichTextBox","/csharp/desktop-ui/text-controls","01.csharp/12.desktop-ui/11.text-controls",{"title":1429,"path":1430,"stem":1431},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","/csharp/desktop-ui/selection-controls","01.csharp/12.desktop-ui/12.selection-controls",{"title":1433,"path":1434,"stem":1435},"Content Model — GroupBox, Expander, TabControl, StatusBar","/csharp/desktop-ui/content-controls","01.csharp/12.desktop-ui/13.content-controls",{"title":1437,"path":1438,"stem":1439},"UI/UX принципи десктопних застосунків","/csharp/desktop-ui/13a.ui-ux-principles","01.csharp/12.desktop-ui/13a.ui-ux-principles",{"title":1441,"path":1442,"stem":1443},"Dependency Properties — Концепція та Value Resolution","/csharp/desktop-ui/dependency-properties-part1","01.csharp/12.desktop-ui/14.dependency-properties-part1",{"title":1445,"path":1446,"stem":1447},"Avalonia Property System — StyledProperty та DirectProperty","/csharp/desktop-ui/14a.avalonia-property-system","01.csharp/12.desktop-ui/14a.avalonia-property-system",{"title":1449,"path":1450,"stem":1451},"Attached Properties — Властивості без меж","/csharp/desktop-ui/attached-properties","01.csharp/12.desktop-ui/15.attached-properties",{"title":1453,"path":1454,"stem":1455},"Routed Events — Маршрутизація подій у WPF","/csharp/desktop-ui/routed-events","01.csharp/12.desktop-ui/16.routed-events",{"title":1457,"path":1458,"stem":1459},"Data Binding — Від Code-Behind до Декларативності","/csharp/desktop-ui/data-binding-basics-part1","01.csharp/12.desktop-ui/17.data-binding-basics-part1",{"title":1461,"path":1462,"stem":1463},"INotifyPropertyChanged — Живе оновлення UI","/csharp/desktop-ui/data-binding-basics-part2","01.csharp/12.desktop-ui/17.data-binding-basics-part2",{"title":1465,"path":1466,"stem":1467},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","/csharp/desktop-ui/17a.avalonia-compiled-bindings","01.csharp/12.desktop-ui/17a.avalonia-compiled-bindings",{"title":1469,"path":1470,"stem":1471},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","/csharp/desktop-ui/data-binding-advanced","01.csharp/12.desktop-ui/18.data-binding-advanced",{"title":1473,"path":1474,"stem":1475},"Value Converters — Перетворення типів даних у Data Binding","/csharp/desktop-ui/value-converters","01.csharp/12.desktop-ui/19.value-converters",{"title":1477,"path":1478,"stem":1479},"Data Templates — Візуалізація об'єктів у WPF","/csharp/desktop-ui/data-templates","01.csharp/12.desktop-ui/20.data-templates",{"title":1481,"path":1482,"stem":1483},"Collections Binding Part 1 — ObservableCollection та ItemsControl","/csharp/desktop-ui/collections-binding-part1","01.csharp/12.desktop-ui/21.collections-binding-part1",{"title":1485,"path":1486,"stem":1487},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","/csharp/desktop-ui/collections-binding-part2","01.csharp/12.desktop-ui/21.collections-binding-part2",{"title":1489,"path":1490,"stem":1491},"MVVM Pattern — Від Spaghetti Code до архітектури","/csharp/desktop-ui/mvvm-pattern","01.csharp/12.desktop-ui/22.mvvm-pattern",{"title":1493,"path":1494,"stem":1495},"ViewModel Implementation — Від BaseViewModel до валідації","/csharp/desktop-ui/viewmodel-implementation","01.csharp/12.desktop-ui/23.viewmodel-implementation",{"title":1497,"path":1498,"stem":1499},"Commands — Від event handlers до декларативних команд","/csharp/desktop-ui/commands","01.csharp/12.desktop-ui/24.commands",{"title":1501,"path":1502,"stem":1503},"MVVM Toolkit — MVVM без boilerplate через Source Generators","/csharp/desktop-ui/mvvm-toolkit","01.csharp/12.desktop-ui/25.mvvm-toolkit",{"title":1505,"path":1506,"stem":1507},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","/csharp/desktop-ui/messenger-pattern","01.csharp/12.desktop-ui/26.messenger-pattern",{"title":1509,"path":1510,"stem":1511},"Стилі WPF — CSS для десктопу","/csharp/desktop-ui/styles-basics","01.csharp/12.desktop-ui/27.styles-basics",{"title":1513,"path":1514,"stem":1515},"CSS-like стилі Avalonia","/csharp/desktop-ui/27a.avalonia-css-styling","01.csharp/12.desktop-ui/27a.avalonia-css-styling",{"title":1517,"path":1518,"stem":1519},"Control Templates — Частина 1. Концепція та TemplateBinding","/csharp/desktop-ui/control-templates-part1","01.csharp/12.desktop-ui/28.control-templates-part1",{"title":1521,"path":1522,"stem":1523},"Control Templates — Частина 2. Named Parts та ContentPresenter","/csharp/desktop-ui/control-templates-part2","01.csharp/12.desktop-ui/28.control-templates-part2",{"title":1525,"path":1526,"stem":1527},"Control Themes в Avalonia — нова ера стилізації","/csharp/desktop-ui/28a.avalonia-control-themes","01.csharp/12.desktop-ui/28a.avalonia-control-themes",{"title":1529,"path":1530,"stem":1531},"Triggers та Visual State Manager у WPF","/csharp/desktop-ui/triggers-visual-states","01.csharp/12.desktop-ui/29.triggers-visual-states",{"title":1533,"path":1534,"stem":1535},"Pseudo-classes в Avalonia — замість WPF Triggers","/csharp/desktop-ui/29a.avalonia-pseudo-classes","01.csharp/12.desktop-ui/29a.avalonia-pseudo-classes",{"title":1537,"path":1538,"stem":1539},"Теми та ресурсні словники у WPF","/csharp/desktop-ui/resources-themes","01.csharp/12.desktop-ui/30.resources-themes",{"title":1541,"path":1542,"stem":1543},"Avalonia Themes — Fluent Design та система тематизації","/csharp/desktop-ui/30a.avalonia-themes-fluent","01.csharp/12.desktop-ui/30a.avalonia-themes-fluent",{"title":1545,"path":1546,"stem":1547},"Контроли колекцій — глибоке занурення","/csharp/desktop-ui/collection-controls","01.csharp/12.desktop-ui/31.collection-controls",{"title":1549,"path":1550,"stem":1551},"DataGrid — колонки та базове відображення","/csharp/desktop-ui/datagrid-part1","01.csharp/12.desktop-ui/32.datagrid-part1",{"title":1553,"path":1554,"stem":1555},"DataGrid — сортування, фільтрація, редагування","/csharp/desktop-ui/datagrid-part2","01.csharp/12.desktop-ui/32.datagrid-part2",{"title":1557,"path":1558,"stem":1559},"TreeView та GridView","/csharp/desktop-ui/treeview-listview","01.csharp/12.desktop-ui/33.treeview-listview",{"title":1561,"path":1562,"stem":1563},"Меню, Toolbar, ContextMenu, StatusBar","/csharp/desktop-ui/menus-toolbars","01.csharp/12.desktop-ui/34.menus-toolbars",{"title":1565,"path":1566,"stem":1567},"Навігація та керування вікнами. Частина 1: вікна та сторінки","/csharp/desktop-ui/navigation-windows-part1","01.csharp/12.desktop-ui/35.navigation-windows-part1",{"title":1569,"path":1570,"stem":1571},"Навігація та керування вікнами. Частина 2: MVVM-навігація","/csharp/desktop-ui/navigation-windows-part2","01.csharp/12.desktop-ui/35.navigation-windows-part2",{"title":1573,"path":1574,"stem":1575},"Avalonia — Навігація та діалоги","/csharp/desktop-ui/35a.avalonia-navigation-dialogs","01.csharp/12.desktop-ui/35a.avalonia-navigation-dialogs",{"title":1577,"path":1578,"stem":1579},"Діалоги та File Pickers у WPF","/csharp/desktop-ui/dialogs-file-pickers","01.csharp/12.desktop-ui/36.dialogs-file-pickers",{"title":1581,"path":1582,"stem":1583},"UserControl: компонентний підхід у WPF","/csharp/desktop-ui/user-controls","01.csharp/12.desktop-ui/37.user-controls",{"title":1585,"path":1586,"stem":1587},"Custom Controls: Lookless Controls у WPF","/csharp/desktop-ui/custom-controls","01.csharp/12.desktop-ui/38.custom-controls",{"title":1589,"path":1590,"stem":1591},"Avalonia TemplatedControl — Lookless Controls","/csharp/desktop-ui/38a.avalonia-templated-controls","01.csharp/12.desktop-ui/38a.avalonia-templated-controls",{"title":1593,"path":1594,"stem":1595},"Анімації у WPF: Storyboard та Easing Functions","/csharp/desktop-ui/animations-transitions","01.csharp/12.desktop-ui/39.animations-transitions",{"title":1597,"path":1598,"stem":1599},"Анімації в Avalonia","/csharp/desktop-ui/39a.avalonia-animations","01.csharp/12.desktop-ui/39a.avalonia-animations",{"title":1601,"path":1602,"stem":1603},"2D Графіка та Мультимедіа у WPF","/csharp/desktop-ui/media-graphics","01.csharp/12.desktop-ui/40.media-graphics",{"title":1605,"path":1606,"stem":1607},"Dependency Injection у WPF та Avalonia","/csharp/desktop-ui/di-integration","01.csharp/12.desktop-ui/41.di-integration",{"title":1609,"path":1610,"stem":1611},"SQLite та EF Core у десктопних додатках","/csharp/desktop-ui/data-persistence-part1","01.csharp/12.desktop-ui/42.data-persistence-part1",{"title":1613,"path":1614,"stem":1615},"Repository Pattern та Unit of Work","/csharp/desktop-ui/data-persistence-part2","01.csharp/12.desktop-ui/43.data-persistence-part2",{"title":1617,"path":1618,"stem":1619},"Тестування ViewModels","/csharp/desktop-ui/viewmodel-testing","01.csharp/12.desktop-ui/44.viewmodel-testing",{"title":1621,"path":1622,"stem":1623},"Avalonia Headless Testing — тестування UI без вікон","/csharp/desktop-ui/44a.avalonia-headless-testing","01.csharp/12.desktop-ui/44a.avalonia-headless-testing",{"title":1625,"path":1626,"stem":1627},"Кросплатформна розробка з Avalonia","/csharp/desktop-ui/avalonia-cross-platform","01.csharp/12.desktop-ui/45.avalonia-cross-platform",{"title":1629,"path":1630,"stem":1631},"Пакування та розгортання Avalonia додатків","/csharp/desktop-ui/avalonia-packaging-deployment","01.csharp/12.desktop-ui/46.avalonia-packaging-deployment",{"title":1633,"path":1634,"stem":1635},"Розгортання WPF застосунків","/csharp/desktop-ui/wpf-packaging-deployment","01.csharp/12.desktop-ui/47.wpf-packaging-deployment",{"title":1637,"path":1638,"stem":1639},"C# & .NET: The Ultimate Roadmap","/csharp/roadmap","01.csharp/roadmap",{"title":1641,"icon":1642,"path":1643,"stem":1644,"children":1645,"page":59},"C++","i-devicon-cplusplus","/cpp","02.cpp",[1646,1650,1654,1658,1662,1666,1670,1674,1678,1681,1685,1689,1693,1697,1701,1705,1709,1713,1717,1721,1725,1729,1733,1737,1741,1745,1749,1753,1757,1761],{"title":1647,"path":1648,"stem":1649},"Вступ у програмування та алгоритми","/cpp/intro-algorithms","02.cpp/01.intro-algorithms",{"title":1651,"path":1652,"stem":1653},"Code Style: угоди про оформлення коду","/cpp/code-style","02.cpp/02.code-style",{"title":1655,"path":1656,"stem":1657},"Середовище розробки та перший проєкт","/cpp/ide-setup","02.cpp/03.ide-setup",{"title":1659,"path":1660,"stem":1661},"Вивід даних на екран","/cpp/data-output","02.cpp/04.data-output",{"title":1663,"path":1664,"stem":1665},"Типи даних, змінні та константи","/cpp/data-types-variables","02.cpp/05.data-types-variables",{"title":1667,"path":1668,"stem":1669},"Ввід даних з клавіатури","/cpp/data-input","02.cpp/06.data-input",{"title":1671,"path":1672,"stem":1673},"Оператори, перетворення типів та логічні операції","/cpp/operators-type-conversion","02.cpp/07.operators-type-conversion",{"title":1675,"path":1676,"stem":1677},"Цикли","/cpp/loops","02.cpp/08.loops",{"title":32,"path":1679,"stem":1680},"/cpp/arrays","02.cpp/09.arrays",{"title":1682,"path":1683,"stem":1684},"Алгоритми сортування та аналіз складності","/cpp/sorting","02.cpp/10.sorting",{"title":1686,"path":1687,"stem":1688},"Алгоритми пошуку","/cpp/searching","02.cpp/11.searching",{"title":1690,"path":1691,"stem":1692},"Функції: основи","/cpp/functions-basics","02.cpp/12.functions-basics",{"title":1694,"path":1695,"stem":1696},"Функції: прототипи, область видимості та додаткові можливості","/cpp/functions-scope","02.cpp/13.functions-scope",{"title":1698,"path":1699,"stem":1700},"Функції: перевантаження та шаблони","/cpp/functions-overloading-templates","02.cpp/14.functions-overloading-templates",{"title":1702,"path":1703,"stem":1704},"Вказівники: основи","/cpp/pointers-basics","02.cpp/15.pointers-basics",{"title":1706,"path":1707,"stem":1708},"Посилання (References)","/cpp/references","02.cpp/16.references",{"title":1710,"path":1711,"stem":1712},"Вказівники, const і масиви","/cpp/pointers-const-arrays","02.cpp/17.pointers-const-arrays",{"title":1714,"path":1715,"stem":1716},"Адресна арифметика","/cpp/pointer-arithmetic","02.cpp/18.pointer-arithmetic",{"title":1718,"path":1719,"stem":1720},"Динамічна пам'ять","/cpp/dynamic-memory","02.cpp/19.dynamic-memory",{"title":1722,"path":1723,"stem":1724},"Вказівники типу void","/cpp/void-pointers","02.cpp/20.void-pointers",{"title":1726,"path":1727,"stem":1728},"Вказівники на вказівники","/cpp/pointers-to-pointers","02.cpp/21.pointers-to-pointers",{"title":1730,"path":1731,"stem":1732},"Оператор доступу до членів через вказівник (->)","/cpp/member-access-operator","02.cpp/22.member-access-operator",{"title":1734,"path":1735,"stem":1736},"Цикл for-each (Range-based for)","/cpp/foreach-loop","02.cpp/23.foreach-loop",{"title":1738,"path":1739,"stem":1740},"Вказівники на функції","/cpp/function-pointers","02.cpp/24.function-pointers",{"title":1742,"path":1743,"stem":1744},"Лямбда-вирази","/cpp/lambdas","02.cpp/25.lambdas",{"title":1746,"path":1747,"stem":1748},"Лямбда-захоплення","/cpp/lambda-captures","02.cpp/26.lambda-captures",{"title":1750,"path":1751,"stem":1752},"Еліпсис","/cpp/ellipsis","02.cpp/27.ellipsis",{"title":1754,"path":1755,"stem":1756},"Аргументи командного рядка","/cpp/command-line-arguments","02.cpp/28.command-line-arguments",{"title":1758,"path":1759,"stem":1760},"Перерахування (enum)","/cpp/enum","02.cpp/29.enum",{"title":1762,"path":1763,"stem":1764},"План навчання: Курс C++ — Продовження (Статті 29–60+)","/cpp/curriculum-plan","02.cpp/curriculum-plan",{"title":1766,"icon":1767,"path":1768,"stem":1769,"children":1770,"page":59},"JavaScript","i-devicon-javascript","/javascript","03.javascript",[1771,1797,1851,1873,2177,2215],{"title":1772,"icon":1773,"path":1774,"stem":1775,"children":1776,"page":59},"Events","i-lucide-mouse-pointer-click","/javascript/events","03.javascript/01.events",[1777,1781,1785,1789,1793],{"title":1778,"path":1779,"stem":1780},"Вступ до подій браузера","/javascript/events/intro","03.javascript/01.events/01.intro",{"title":1782,"path":1783,"stem":1784},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","/javascript/events/bubbling-capturing","03.javascript/01.events/02.bubbling-capturing",{"title":1786,"path":1787,"stem":1788},"Делегування подій (Event Delegation)","/javascript/events/delegate-events","03.javascript/01.events/03.delegate-events",{"title":1790,"path":1791,"stem":1792},"Типові дії браузера та preventDefault()","/javascript/events/prevent-default","03.javascript/01.events/04.prevent-default",{"title":1794,"path":1795,"stem":1796},"Запуск користувацьких подій (Custom Events)","/javascript/events/custom-events","03.javascript/01.events/05.custom-events",{"title":1798,"icon":1799,"path":1800,"stem":1801,"children":1802,"page":59},"Network","i-lucide-globe","/javascript/network","03.javascript/02.network",[1803,1807,1811,1815,1819,1823,1827,1831,1835,1839,1843,1847],{"title":1804,"path":1805,"stem":1806},"Fetch API - Сучасний підхід до HTTP-запитів","/javascript/network/01-fetch-api","03.javascript/02.network/01-fetch-api",{"title":1808,"path":1809,"stem":1810},"FormData - Робота з формами та файлами","/javascript/network/02-formdata","03.javascript/02.network/02-formdata",{"title":1812,"path":1813,"stem":1814},"Відстеження прогресу завантаження","/javascript/network/03-download-progress","03.javascript/02.network/03-download-progress",{"title":1816,"path":1817,"stem":1818},"Переривання fetch-запитів","/javascript/network/04-abort-requests","03.javascript/02.network/04-abort-requests",{"title":1820,"path":1821,"stem":1822},"CORS - Запити між різними джерелами","/javascript/network/05-cors","03.javascript/02.network/05-cors",{"title":1824,"path":1825,"stem":1826},"Fetch API - Повний довідник опцій","/javascript/network/06-fetch-options","03.javascript/02.network/06-fetch-options",{"title":1828,"path":1829,"stem":1830},"URL Objects - Робота з посиланнями","/javascript/network/07-url-objects","03.javascript/02.network/07-url-objects",{"title":1832,"path":1833,"stem":1834},"XMLHttpRequest - AJAX та низькорівневі запити","/javascript/network/08-xmlhttprequest","03.javascript/02.network/08-xmlhttprequest",{"title":1836,"path":1837,"stem":1838},"Відновлюване завантаження файлів","/javascript/network/09-resumable-upload","03.javascript/02.network/09-resumable-upload",{"title":1840,"path":1841,"stem":1842},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","/javascript/network/10-cookies","03.javascript/02.network/10-cookies",{"title":1844,"path":1845,"stem":1846},"js-cookie: Керування Cookies без Болю","/javascript/network/11-js-cookie","03.javascript/02.network/11-js-cookie",{"title":1848,"path":1849,"stem":1850},"Axios: Потужний HTTP-клієнт для JavaScript","/javascript/network/12-axios","03.javascript/02.network/12-axios",{"title":1852,"icon":1853,"path":1854,"stem":1855,"children":1856,"page":59},"Bom","i-lucide-monitor","/javascript/bom","03.javascript/03.bom",[1857,1861,1865,1869],{"title":1858,"path":1859,"stem":1860},"LocalStorage, SessionStorage та patterns збереження даних","/javascript/bom/01-localstorage","03.javascript/03.bom/01-localstorage",{"title":1862,"path":1863,"stem":1864},"Location Object - Керування адресою сторінки","/javascript/bom/02-location-object","03.javascript/03.bom/02-location-object",{"title":1866,"path":1867,"stem":1868},"History API - Керування історією браузера","/javascript/bom/03-history-api","03.javascript/03.bom/03-history-api",{"title":1870,"path":1871,"stem":1872},"Navigator Object - Ідентифікація та Можливості Пристрою","/javascript/bom/04-navigator-object","03.javascript/03.bom/04-navigator-object",{"title":1874,"icon":1875,"path":1876,"stem":1877,"children":1878},"React","i-devicon-react","/javascript/react","03.javascript/04.react/index",[1879,1880,1884,1888,1892,1896,1959,1994,2146],{"title":1874,"path":1876,"stem":1877},{"title":1881,"path":1882,"stem":1883},"Робота з Формами в React","/javascript/react/react-forms","03.javascript/04.react/01.react-forms",{"title":1885,"path":1886,"stem":1887},"React Hook Form: Професійна Робота з Формами","/javascript/react/react-hook-form","03.javascript/04.react/02.react-hook-form",{"title":1889,"path":1890,"stem":1891},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","/javascript/react/react-hook-form-new","03.javascript/04.react/02.react-hook-form-new",{"title":1893,"path":1894,"stem":1895},"Axios та React: Професійна Архітектура Запитів","/javascript/react/data-fetching-axios","03.javascript/04.react/03.data-fetching-axios",{"title":1897,"icon":132,"path":1898,"stem":1899,"children":1900},"Tanstack Query","/javascript/react/tanstack-query","03.javascript/04.react/04.tanstack-query/index",[1901,1903,1907,1911,1915,1919,1923,1927,1931,1935,1939,1943,1947,1951,1955],{"title":1902,"path":1898,"stem":1899},"TanStack Query: Майстерність Керування Станом Сервера",{"title":1904,"path":1905,"stem":1906},"Парадигма Server State: Чому useEffect недостатньо","/javascript/react/tanstack-query/server-state-paradigm","03.javascript/04.react/04.tanstack-query/01.server-state-paradigm",{"title":1908,"path":1909,"stem":1910},"Встановлення та Налаштування: Фундамент","/javascript/react/tanstack-query/installation-and-devtools","03.javascript/04.react/04.tanstack-query/02.installation-and-devtools",{"title":1912,"path":1913,"stem":1914},"Основи Запитів та Магія Ключів","/javascript/react/tanstack-query/query-basics-and-keys","03.javascript/04.react/04.tanstack-query/03.query-basics-and-keys",{"title":1916,"path":1917,"stem":1918},"Синхронізація Даних: Життєвий Цикл Запиту","/javascript/react/tanstack-query/data-synchronization","03.javascript/04.react/04.tanstack-query/04.data-synchronization",{"title":1920,"path":1921,"stem":1922},"Мутації та Інвалідація: Зміна Даних","/javascript/react/tanstack-query/mutations-and-invalidation","03.javascript/04.react/04.tanstack-query/05.mutations-and-invalidation",{"title":1924,"path":1925,"stem":1926},"Оптимістичні Оновлення: Швидше за Світло","/javascript/react/tanstack-query/optimistic-updates","03.javascript/04.react/04.tanstack-query/06.optimistic-updates",{"title":1928,"path":1929,"stem":1930},"Пагінація та Infinite Scroll","/javascript/react/tanstack-query/pagination-and-load-more","03.javascript/04.react/04.tanstack-query/07.pagination-and-load-more",{"title":1932,"path":1933,"stem":1934},"Просунуті Патерни та Оптимізація","/javascript/react/tanstack-query/advanced-patterns","03.javascript/04.react/04.tanstack-query/08.advanced-patterns",{"title":1936,"path":1937,"stem":1938},"Архітектура та Best Practices","/javascript/react/tanstack-query/architecture-and-best-practices","03.javascript/04.react/04.tanstack-query/09.architecture-and-best-practices",{"title":1940,"path":1941,"stem":1942},"Server-Side Rendering (SSR) та Гідратація","/javascript/react/tanstack-query/server-side-rendering","03.javascript/04.react/04.tanstack-query/10.server-side-rendering",{"title":1944,"path":1945,"stem":1946},"Стратегії Тестування","/javascript/react/tanstack-query/testing-strategies","03.javascript/04.react/04.tanstack-query/11.testing-strategies",{"title":1948,"path":1949,"stem":1950},"Аутентифікація та Обробка Помилок","/javascript/react/tanstack-query/authentication-and-errors","03.javascript/04.react/04.tanstack-query/12.authentication-and-errors",{"title":1952,"path":1953,"stem":1954},"React Suspense та Майбутнє","/javascript/react/tanstack-query/react-suspense","03.javascript/04.react/04.tanstack-query/13.react-suspense",{"title":1956,"path":1957,"stem":1958},"Глибоке Занурення в Продуктивність","/javascript/react/tanstack-query/performance-deep-dive","03.javascript/04.react/04.tanstack-query/14.performance-deep-dive",{"title":1960,"icon":1875,"path":1961,"stem":1962,"children":1963},"React Router","/javascript/react/react-router","03.javascript/04.react/05.react-router/index",[1964,1966,1970,1974,1978,1982,1986,1990],{"title":1965,"path":1961,"stem":1962},"React Router: Навігаційна система сучасного вебу",{"title":1967,"path":1968,"stem":1969},"Налаштування та Базовий Роутинг","/javascript/react/react-router/setup-and-basic-routing","03.javascript/04.react/05.react-router/01.setup-and-basic-routing",{"title":1971,"path":1972,"stem":1973},"Динамічна Навігація","/javascript/react/react-router/navigation-and-links","03.javascript/04.react/05.react-router/02.navigation-and-links",{"title":1975,"path":1976,"stem":1977},"Вкладені Маршрути та Макети","/javascript/react/react-router/nested-routes-and-layouts","03.javascript/04.react/05.react-router/03.nested-routes-and-layouts",{"title":1979,"path":1980,"stem":1981},"Динамічні Маршрути та Параметри","/javascript/react/react-router/dynamic-routing","03.javascript/04.react/05.react-router/04.dynamic-routing",{"title":1983,"path":1984,"stem":1985},"Data APIs: Loaders та Actions","/javascript/react/react-router/data-loading","03.javascript/04.react/05.react-router/05.data-loading",{"title":1987,"path":1988,"stem":1989},"Просунуті Патерни","/javascript/react/react-router/advanced-patterns","03.javascript/04.react/05.react-router/06.advanced-patterns",{"title":1991,"path":1992,"stem":1993},"Legacy Routing: Компонентний підхід","/javascript/react/react-router/legacy-routing","03.javascript/04.react/05.react-router/07.legacy-routing",{"title":1995,"icon":132,"path":1996,"stem":1997,"children":1998},"Redux","/javascript/react/redux","03.javascript/04.react/06.redux/index",[1999,2001,2017,2046,2055,2076,2092,2121],{"title":2000,"path":1996,"stem":1997},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2002,"stem":2003,"children":2004,"page":59},"/javascript/react/redux/fundamentals","03.javascript/04.react/06.redux/01.fundamentals",[2005,2009,2013],{"title":2006,"path":2007,"stem":2008},"Вступ до State Management","/javascript/react/redux/fundamentals/intro-state-management","03.javascript/04.react/06.redux/01.fundamentals/01.intro-state-management",{"title":2010,"path":2011,"stem":2012},"Філософія Redux та Три Принципи","/javascript/react/redux/fundamentals/redux-philosophy","03.javascript/04.react/06.redux/01.fundamentals/02.redux-philosophy",{"title":2014,"path":2015,"stem":2016},"Чисті функції та Іммутабельність","/javascript/react/redux/fundamentals/pure-functions-immutability","03.javascript/04.react/06.redux/01.fundamentals/03.pure-functions-immutability",{"title":2018,"icon":132,"path":2019,"stem":2020,"children":2021,"page":59},"Classic Redux","/javascript/react/redux/classic-redux","03.javascript/04.react/06.redux/02.classic-redux",[2022,2026,2030,2034,2038,2042],{"title":2023,"path":2024,"stem":2025},"Створення Store (Classic Redux)","/javascript/react/redux/classic-redux/store-setup","03.javascript/04.react/06.redux/02.classic-redux/01.store-setup",{"title":2027,"path":2028,"stem":2029},"Actions, Constants та Action Creators","/javascript/react/redux/classic-redux/actions-constants","03.javascript/04.react/06.redux/02.classic-redux/02.actions-constants",{"title":2031,"path":2032,"stem":2033},"Логіка Reducers","/javascript/react/redux/classic-redux/reducers","03.javascript/04.react/06.redux/02.classic-redux/03.reducers",{"title":2035,"path":2036,"stem":2037},"Комбінування Reducers (Root Reducer)","/javascript/react/redux/classic-redux/data-flow","03.javascript/04.react/06.redux/02.classic-redux/04.data-flow",{"title":2039,"path":2040,"stem":2041},"Підключення до React (React-Redux)","/javascript/react/redux/classic-redux/react-redux-connection","03.javascript/04.react/06.redux/02.classic-redux/05.react-redux-connection",{"title":2043,"path":2044,"stem":2045},"Middleware та Асинхронність (Redux Thunk)","/javascript/react/redux/classic-redux/middleware-thunk","03.javascript/04.react/06.redux/02.classic-redux/06.middleware-thunk",{"title":2047,"icon":132,"path":2048,"stem":2049,"children":2050,"page":59},"Transition To Rtk","/javascript/react/redux/transition-to-rtk","03.javascript/04.react/06.redux/03.transition-to-rtk",[2051],{"title":2052,"path":2053,"stem":2054},"Проблеми класичного Redux","/javascript/react/redux/transition-to-rtk/problems-with-classic","03.javascript/04.react/06.redux/03.transition-to-rtk/01.problems-with-classic",{"title":2056,"icon":132,"path":2057,"stem":2058,"children":2059,"page":59},"Redux Toolkit","/javascript/react/redux/redux-toolkit","03.javascript/04.react/06.redux/04.redux-toolkit",[2060,2064,2068,2072],{"title":2061,"path":2062,"stem":2063},"Налаштування Store з configureStore","/javascript/react/redux/redux-toolkit/configure-store","03.javascript/04.react/06.redux/04.redux-toolkit/01.configure-store",{"title":2065,"path":2066,"stem":2067},"createSlice: Революція в Redux","/javascript/react/redux/redux-toolkit/create-slice","03.javascript/04.react/06.redux/04.redux-toolkit/02.create-slice",{"title":2069,"path":2070,"stem":2071},"Асинхронність з createAsyncThunk","/javascript/react/redux/redux-toolkit/async-thunks","03.javascript/04.react/06.redux/04.redux-toolkit/03.async-thunks",{"title":2073,"path":2074,"stem":2075},"04. Entity Adapter: Керування нормалізованим станом","/javascript/react/redux/redux-toolkit/entity-adapter","03.javascript/04.react/06.redux/04.redux-toolkit/04.entity-adapter",{"title":2077,"icon":92,"path":2078,"stem":2079,"children":2080,"page":59},"Advanced","/javascript/react/redux/advanced","03.javascript/04.react/06.redux/05.advanced",[2081,2085,2089],{"title":2082,"path":2083,"stem":2084},"Мемоізація та Селектори: Повний Гайд по Reselect","/javascript/react/redux/advanced/selectors-reselect","03.javascript/04.react/06.redux/05.advanced/01.selectors-reselect",{"title":2086,"path":2087,"stem":2088},"RTK Query: Архітектура Серверного Кешу","/javascript/react/redux/advanced/rtk-query-intro","03.javascript/04.react/06.redux/05.advanced/02.rtk-query-intro",{"title":1936,"path":2090,"stem":2091},"/javascript/react/redux/advanced/architecture-best-practices","03.javascript/04.react/06.redux/05.advanced/03.architecture-best-practices",{"title":2093,"icon":132,"path":2094,"stem":2095,"children":2096,"page":59},"Project Kanban","/javascript/react/redux/project-kanban","03.javascript/04.react/06.redux/06.project-kanban",[2097,2101,2105,2109,2113,2117],{"title":2098,"path":2099,"stem":2100},"Проєкт: Kanban Board (Trello Clone)","/javascript/react/redux/project-kanban/project-overview","03.javascript/04.react/06.redux/06.project-kanban/01.project-overview",{"title":2102,"path":2103,"stem":2104},"Налаштування та Типізація","/javascript/react/redux/project-kanban/setup-and-types","03.javascript/04.react/06.redux/06.project-kanban/02.setup-and-types",{"title":2106,"path":2107,"stem":2108},"Board Slice: Серце Дошки","/javascript/react/redux/project-kanban/board-slice","03.javascript/04.react/06.redux/06.project-kanban/03.board-slice",{"title":2110,"path":2111,"stem":2112},"Логіка Drag & Drop","/javascript/react/redux/project-kanban/drag-and-drop-logic","03.javascript/04.react/06.redux/06.project-kanban/04.drag-and-drop-logic",{"title":2114,"path":2115,"stem":2116},"Інтеграція з RTK Query","/javascript/react/redux/project-kanban/rtk-query-integration","03.javascript/04.react/06.redux/06.project-kanban/05.rtk-query-integration",{"title":2118,"path":2119,"stem":2120},"Optimistic Updates","/javascript/react/redux/project-kanban/optimistic-updates","03.javascript/04.react/06.redux/06.project-kanban/06.optimistic-updates",{"title":2122,"icon":132,"path":2123,"stem":2124,"children":2125,"page":59},"Testing","/javascript/react/redux/testing","03.javascript/04.react/06.redux/07.testing",[2126,2130,2134,2138,2142],{"title":2127,"path":2128,"stem":2129},"Тестування Redux","/javascript/react/redux/testing/intro-testing","03.javascript/04.react/06.redux/07.testing/01.intro-testing",{"title":2131,"path":2132,"stem":2133},"Тестування Reducers","/javascript/react/redux/testing/testing-reducers","03.javascript/04.react/06.redux/07.testing/02.testing-reducers",{"title":2135,"path":2136,"stem":2137},"Тестування Селекторів","/javascript/react/redux/testing/testing-selectors","03.javascript/04.react/06.redux/07.testing/03.testing-selectors",{"title":2139,"path":2140,"stem":2141},"Тестування Компонентів (Integration)","/javascript/react/redux/testing/testing-components","03.javascript/04.react/06.redux/07.testing/04.testing-components",{"title":2143,"path":2144,"stem":2145},"Тестування Async Thunks","/javascript/react/redux/testing/testing-thunks","03.javascript/04.react/06.redux/07.testing/05.testing-thunks",{"title":2147,"icon":132,"path":2148,"stem":2149,"children":2150},"Ui Libraries","/javascript/react/ui-libraries","03.javascript/04.react/07.ui-libraries/index",[2151,2153,2157,2161,2165,2169,2173],{"title":2152,"path":2148,"stem":2149},"UI Бібліотеки в React",{"title":2154,"path":2155,"stem":2156},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","/javascript/react/ui-libraries/introduction-to-ui-libraries","03.javascript/04.react/07.ui-libraries/01.introduction-to-ui-libraries",{"title":2158,"path":2159,"stem":2160},"Філософія shadcn/ui: \"Not a Component Library\"","/javascript/react/ui-libraries/shadcn-philosophy","03.javascript/04.react/07.ui-libraries/02.shadcn-philosophy",{"title":2162,"path":2163,"stem":2164},"Установка та Налаштування shadcn/ui","/javascript/react/ui-libraries/shadcn-installation","03.javascript/04.react/07.ui-libraries/03.shadcn-installation",{"title":2166,"path":2167,"stem":2168},"Базові Компоненти shadcn/ui: Фундамент Інтерфейсу","/javascript/react/ui-libraries/shadcn-components-basics","03.javascript/04.react/07.ui-libraries/04.shadcn-components-basics",{"title":2170,"path":2171,"stem":2172},"Компоненти Форм: Побудова Інтерактивних Form","/javascript/react/ui-libraries/shadcn-components-forms","03.javascript/04.react/07.ui-libraries/05.shadcn-components-forms",{"title":2174,"path":2175,"stem":2176},"Складні Компоненти: Dialog, Dropdown, Table та Command","/javascript/react/ui-libraries/shadcn-components-advanced","03.javascript/04.react/07.ui-libraries/06.shadcn-components-advanced",{"title":2178,"icon":2179,"path":2180,"stem":2181,"children":2182,"page":59},"TypeScript","i-devicon-typescript","/javascript/typescript","03.javascript/05.typescript",[2183,2187,2191,2195,2199,2203,2207,2211],{"title":2184,"path":2185,"stem":2186},"TypeScript: Броня для вашого коду","/javascript/typescript/intro-and-basic-types","03.javascript/05.typescript/01.intro-and-basic-types",{"title":2188,"path":2189,"stem":2190},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","/javascript/typescript/interfaces-and-advanced-types","03.javascript/05.typescript/02.interfaces-and-advanced-types",{"title":2192,"path":2193,"stem":2194},"Алхімія Типів: Generics та Utility Types","/javascript/typescript/generics-and-utilities","03.javascript/05.typescript/03.generics-and-utilities",{"title":2196,"path":2197,"stem":2198},"Архітектура та Шаблони: Класи в TypeScript","/javascript/typescript/classes-and-oop","03.javascript/05.typescript/04.classes-and-oop",{"title":2200,"path":2201,"stem":2202},"Продакшн та Екосистема: Advanced Config & Workflow","/javascript/typescript/advanced-patterns-and-config","03.javascript/05.typescript/05.advanced-patterns-and-config",{"title":2204,"path":2205,"stem":2206},"TypeScript у світі React","/javascript/typescript/react-basics","03.javascript/05.typescript/06.react-basics",{"title":2208,"path":2209,"stem":2210},"React + TypeScript: Продвинуті патерни","/javascript/typescript/react-advanced","03.javascript/05.typescript/07.react-advanced",{"title":2212,"path":2213,"stem":2214},"React + TypeScript: Екосистема та бібліотеки","/javascript/typescript/react-ecosystem","03.javascript/05.typescript/08.react-ecosystem",{"title":2216,"path":2217,"stem":2218},"Atomic Design","/javascript/atomic-design","03.javascript/2.atomic-design",{"title":2220,"icon":2221,"path":2222,"stem":2223,"children":2224,"page":59},"Java","i-devicon-java","/java","04.java",[2225,2228,2231,2235,2239,2243,2247],{"title":162,"path":2226,"stem":2227},"/java/data-mapper-part1","04.java/01.data-mapper-part1",{"title":166,"path":2229,"stem":2230},"/java/data-mapper-part2","04.java/02.data-mapper-part2",{"title":2232,"path":2233,"stem":2234},"Service Layer: Організація бізнес-логіки","/java/service-layer","04.java/03.service-layer",{"title":2236,"path":2237,"stem":2238},"Rich Domain Model та State Pattern","/java/rich-domain-model","04.java/04.rich-domain-model",{"title":2240,"path":2241,"stem":2242},"Патерни для складної бізнес-логіки","/java/business-logic-patterns","04.java/05.business-logic-patterns",{"title":2244,"path":2245,"stem":2246},"Обробка помилок та валідація","/java/error-handling-validation","04.java/06.error-handling-validation",{"title":2248,"path":2249,"stem":2250,"children":2251,"page":59},"Проектування баз даних","/java/pr2","04.java/pr2",[2252,2256,2260,2264,2268,2272,2276,2280,2284,2288,2292,2296,2300,2304,2308,2312,2316,2320,2324,2328,2332,2336,2340,2344,2348],{"title":2253,"path":2254,"stem":2255},"Концептуальне моделювання: Мистецтво розуміння предметної області","/java/pr2/conceptual-modeling","04.java/pr2/01.conceptual-modeling",{"title":2257,"path":2258,"stem":2259},"Логічне моделювання: Від бізнес-ідей до структур даних","/java/pr2/logical-modeling","04.java/pr2/02.logical-modeling",{"title":2261,"path":2262,"stem":2263},"Нормалізація: Гігієна даних та боротьба з аномаліями","/java/pr2/normalization","04.java/pr2/03.normalization",{"title":2265,"path":2266,"stem":2267},"Фізична схема: Від абстракції до DDL","/java/pr2/physical-schema","04.java/pr2/04.physical-schema",{"title":2269,"path":2270,"stem":2271},"Архітектурна класифікація таблиць","/java/pr2/table-classification","04.java/pr2/05.table-classification",{"title":2273,"path":2274,"stem":2275},"Database Migrations: Версіонування схеми з Flyway","/java/pr2/database-migrations","04.java/pr2/06.database-migrations",{"title":2277,"path":2278,"stem":2279},"А що, якби це була не реляційна БД?","/java/pr2/beyond-relational","04.java/pr2/07.beyond-relational",{"title":2281,"path":2282,"stem":2283},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","/java/pr2/impedance-mismatch","04.java/pr2/09.impedance-mismatch",{"title":2285,"path":2286,"stem":2287},"JDBC: Перший контакт із базою даних","/java/pr2/jdbc-fundamentals","04.java/pr2/10.jdbc-fundamentals",{"title":2289,"path":2290,"stem":2291},"Якість коду: Spotless, SpotBugs та SonarQube","/java/pr2/10a.code-quality","04.java/pr2/10a.code-quality",{"title":2293,"path":2294,"stem":2295},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","/java/pr2/connection-pool","04.java/pr2/11.connection-pool",{"title":2297,"path":2298,"stem":2299},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","/java/pr2/row-data-gateway","04.java/pr2/12.row-data-gateway",{"title":2301,"path":2302,"stem":2303},"Table Data Gateway: Фасад таблиці як архітектурний відступ","/java/pr2/table-data-gateway","04.java/pr2/13.table-data-gateway",{"title":2305,"path":2306,"stem":2307},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","/java/pr2/repository-data-mapper","04.java/pr2/14.repository-data-mapper",{"title":2309,"path":2310,"stem":2311},"Identity Map: Кешування сутностей у рамках сесії","/java/pr2/identity-map","04.java/pr2/15.identity-map",{"title":2313,"path":2314,"stem":2315},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","/java/pr2/unit-of-work","04.java/pr2/16.unit-of-work",{"title":2317,"path":2318,"stem":2319},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","/java/pr2/strategy-sql","04.java/pr2/17.strategy-sql",{"title":2321,"path":2322,"stem":2323},"Proxy: Lazy Loading для One-To-Many колекцій","/java/pr2/proxy-lazy-loading","04.java/pr2/18.proxy-lazy-loading",{"title":2325,"path":2326,"stem":2327},"Generic Repository через Java Reflection: анотації та динамічний SQL","/java/pr2/generic-repository-reflection","04.java/pr2/19.generic-repository-reflection",{"title":2329,"path":2330,"stem":2331},"Specification Pattern: Композиція бізнес-правил для складних запитів","/java/pr2/specification-pattern","04.java/pr2/20.specification-pattern",{"title":2333,"path":2334,"stem":2335},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","/java/pr2/20a.advanced-specifications","04.java/pr2/20a.advanced-specifications",{"title":2337,"path":2338,"stem":2339},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","/java/pr2/asynchronous-jdbc","04.java/pr2/21.asynchronous-jdbc",{"title":2341,"path":2342,"stem":2343},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","/java/pr2/integration-testing-h2","04.java/pr2/22.integration-testing-h2",{"title":2345,"path":2346,"stem":2347},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","/java/pr2/integration-testing-testcontainers","04.java/pr2/23.integration-testing-testcontainers",{"title":2349,"path":2350,"stem":2351},"Модуль \"Проектування реляційних баз даних\" для 04.java/pr2","/java/pr2/implementation_plan","04.java/pr2/implementation_plan",{"title":2353,"icon":2354,"path":2355,"stem":2356,"children":2357,"page":59},"Бази даних","i-lucide-database","/databases","06.databases",[2358,2388,2411,2448,2477,2495,2529,2541,2550],{"title":2359,"icon":2360,"path":2361,"stem":2362,"children":2363,"page":59},"Intro","i-lucide-play","/databases/intro","06.databases/01.intro",[2364,2368,2372,2376,2380,2384],{"title":2365,"path":2366,"stem":2367},"Введення в теорію баз даних","/databases/intro/introduction-to-databases","06.databases/01.intro/01.introduction-to-databases",{"title":2369,"path":2370,"stem":2371},"Реляційна модель даних","/databases/intro/relational-model-theory","06.databases/01.intro/02.relational-model-theory",{"title":2373,"path":2374,"stem":2375},"ER-моделювання","/databases/intro/er-modeling","06.databases/01.intro/03.er-modeling",{"title":2377,"path":2378,"stem":2379},"Логічне проектування БД","/databases/intro/logical-schema","06.databases/01.intro/04.logical-schema",{"title":2381,"path":2382,"stem":2383},"Класифікація таблиць","/databases/intro/table-classification","06.databases/01.intro/05.table-classification",{"title":2385,"path":2386,"stem":2387},"PlantUML для баз даних","/databases/intro/plantuml-diagrams","06.databases/01.intro/06.plantuml-diagrams",{"title":2389,"icon":2354,"path":2390,"stem":2391,"children":2392,"page":59},"MS SQL Server Start","/databases/ms-sql-server-start","06.databases/02.ms-sql-server-start",[2393,2397,2403,2407],{"title":2394,"path":2395,"stem":2396},"Типи даних у MS SQL Server","/databases/ms-sql-server-start/data-types","06.databases/02.ms-sql-server-start/01.data-types",{"title":2398,"path":2399,"stem":2400,"children":2401},"Індекси у MS SQL Server","/databases/ms-sql-server-start/sql-indexes","06.databases/02.ms-sql-server-start/02.sql-indexes",[2402],{"title":2398,"path":2399,"stem":2400},{"title":2404,"path":2405,"stem":2406},"Системні бази даних MS SQL Server","/databases/ms-sql-server-start/system-databases","06.databases/02.ms-sql-server-start/03.system-databases",{"title":2408,"path":2409,"stem":2410},"Огляд мови SQL та запитів","/databases/ms-sql-server-start/sql-queries-overview","06.databases/02.ms-sql-server-start/04.sql-queries-overview",{"title":2412,"icon":2354,"path":2413,"stem":2414,"children":2415,"page":59},"SQL","/databases/sql","06.databases/03.sql",[2416,2420,2424,2428,2432,2436,2440,2444],{"title":2417,"path":2418,"stem":2419},"Налаштування демонстраційної бази даних","/databases/sql/sample-database-setup","06.databases/03.sql/00.sample-database-setup",{"title":2421,"path":2422,"stem":2423},"DDL - Створення таблиць (CREATE TABLE)","/databases/sql/ddl-create-table","06.databases/03.sql/01.ddl-create-table",{"title":2425,"path":2426,"stem":2427},"DDL - Зміна та видалення таблиць (ALTER, DROP)","/databases/sql/ddl-alter-drop-table","06.databases/03.sql/02.ddl-alter-drop-table",{"title":2429,"path":2430,"stem":2431},"SELECT запити - Основи","/databases/sql/select-queries-fundamentals","06.databases/03.sql/03.select-queries-fundamentals",{"title":2433,"path":2434,"stem":2435},"SELECT запити - Розширені можливості","/databases/sql/select-queries-advanced","06.databases/03.sql/04.select-queries-advanced",{"title":2437,"path":2438,"stem":2439},"INSERT запити - Додавання даних","/databases/sql/insert-queries","06.databases/03.sql/05.insert-queries",{"title":2441,"path":2442,"stem":2443},"UPDATE та DELETE запити","/databases/sql/update-delete-queries","06.databases/03.sql/06.update-delete-queries",{"title":2445,"path":2446,"stem":2447},"Транзакції в SQL","/databases/sql/transactions","06.databases/03.sql/07.transactions",{"title":2449,"icon":2354,"path":2450,"stem":2451,"children":2452,"page":59},"Multi Table Databases","/databases/multi-table-databases","06.databases/04.multi-table-databases",[2453,2457,2461,2465,2469,2473],{"title":2454,"path":2455,"stem":2456},"Зв'язки та нормалізація БД","/databases/multi-table-databases/relationships-and-normalization","06.databases/04.multi-table-databases/00.relationships-and-normalization",{"title":2458,"path":2459,"stem":2460},"INNER JOIN - З'єднання таблиць","/databases/multi-table-databases/inner-join","06.databases/04.multi-table-databases/01.inner-join",{"title":2462,"path":2463,"stem":2464},"OUTER JOINs - LEFT, RIGHT, FULL","/databases/multi-table-databases/outer-joins","06.databases/04.multi-table-databases/02.outer-joins",{"title":2466,"path":2467,"stem":2468},"CROSS та SELF JOINs","/databases/multi-table-databases/cross-self-joins","06.databases/04.multi-table-databases/03.cross-self-joins",{"title":2470,"path":2471,"stem":2472},"Підзапити (Subqueries)","/databases/multi-table-databases/subqueries","06.databases/04.multi-table-databases/04.subqueries",{"title":2474,"path":2475,"stem":2476},"Агрегації з JOIN","/databases/multi-table-databases/aggregations-with-joins","06.databases/04.multi-table-databases/05.aggregations-with-joins",{"title":2478,"icon":2479,"path":2480,"stem":2481,"children":2482,"page":59},"Aggregate Functions","i-lucide-calculator","/databases/aggregate-functions","06.databases/05.aggregate-functions",[2483,2487,2491],{"title":2484,"path":2485,"stem":2486},"Функції агрегування в MS SQL Server","/databases/aggregate-functions/introduction-aggregate-functions","06.databases/05.aggregate-functions/01.introduction-aggregate-functions",{"title":2488,"path":2489,"stem":2490},"Групування даних в MS SQL Server","/databases/aggregate-functions/grouping-data","06.databases/05.aggregate-functions/02.grouping-data",{"title":2492,"path":2493,"stem":2494},"Підзапити з агрегатними функціями","/databases/aggregate-functions/subqueries-aggregates","06.databases/05.aggregate-functions/03.subqueries-aggregates",{"title":2496,"icon":2497,"path":2498,"stem":2499,"children":2500,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","/databases/triggers-stored-procedures","06.databases/07.triggers-stored-procedures",[2501,2505,2509,2513,2517,2521,2525],{"title":2502,"path":2503,"stem":2504},"DML-тригери","/databases/triggers-stored-procedures/dml-triggers","06.databases/07.triggers-stored-procedures/01.dml-triggers",{"title":2506,"path":2507,"stem":2508},"DDL-тригери","/databases/triggers-stored-procedures/ddl-triggers","06.databases/07.triggers-stored-procedures/02.ddl-triggers",{"title":2510,"path":2511,"stem":2512},"Transact-SQL розширення","/databases/triggers-stored-procedures/transact-sql-extensions","06.databases/07.triggers-stored-procedures/03.transact-sql-extensions",{"title":2514,"path":2515,"stem":2516},"Транзакції","/databases/triggers-stored-procedures/transactions","06.databases/07.triggers-stored-procedures/04.transactions",{"title":2518,"path":2519,"stem":2520},"Зберігаємі процедури","/databases/triggers-stored-procedures/stored-procedures","06.databases/07.triggers-stored-procedures/05.stored-procedures",{"title":2522,"path":2523,"stem":2524},"Користувацькі функції","/databases/triggers-stored-procedures/user-defined-functions","06.databases/07.triggers-stored-procedures/06.user-defined-functions",{"title":2526,"path":2527,"stem":2528},"Безпека баз даних","/databases/triggers-stored-procedures/security","06.databases/07.triggers-stored-procedures/08.security",{"title":2526,"icon":793,"path":2530,"stem":2531,"children":2532,"page":59},"/databases/security","06.databases/08.security",[2533,2537],{"title":2534,"path":2535,"stem":2536},"Вступ до безпеки баз даних","/databases/security/introduction","06.databases/08.security/01.introduction",{"title":2538,"path":2539,"stem":2540},"Системні представлення та метадані","/databases/security/system-views","06.databases/08.security/02.system-views",{"title":2542,"icon":2543,"path":2544,"stem":2545,"children":2546,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","/databases/backup-recovery","06.databases/09.backup-recovery",[2547],{"title":2542,"path":2548,"stem":2549},"/databases/backup-recovery/backup-restore","06.databases/09.backup-recovery/01.backup-restore",{"title":2551,"icon":2552,"path":2553,"stem":2554,"children":2555,"page":59},"Повнотекстовий пошук","i-lucide-search","/databases/full-text-search","06.databases/10.full-text-search",[2556],{"title":2551,"path":2557,"stem":2558},"/databases/full-text-search/full-text-search","06.databases/10.full-text-search/01.full-text-search",{"title":2560,"icon":2561,"path":2562,"stem":2563,"children":2564,"page":59},"Tools","i-lucide-wrench","/tools","07.tools",[2565],{"title":2566,"icon":2567,"path":2568,"stem":2569,"children":2570},"Docker","i-simple-icons-docker","/tools/docker","07.tools/01.docker/index",[2571,2573,2577,2581,2585,2589,2593,2597,2601,2605,2609,2613,2617,2621,2625,2629,2633,2637],{"title":2572,"path":2568,"stem":2569},"Docker: від нуля до production",{"title":2574,"path":2575,"stem":2576},"Контейнеризація — від проблеми до рішення","/tools/docker/containerization-concept","07.tools/01.docker/01.containerization-concept",{"title":2578,"path":2579,"stem":2580},"Docker — що це і навіщо?","/tools/docker/docker-what-and-why","07.tools/01.docker/02.docker-what-and-why",{"title":2582,"path":2583,"stem":2584},"Архітектура Docker Engine","/tools/docker/docker-architecture","07.tools/01.docker/03.docker-architecture",{"title":2586,"path":2587,"stem":2588},"Встановлення Docker","/tools/docker/installation","07.tools/01.docker/04.installation",{"title":2590,"path":2591,"stem":2592},"Перший контейнер — docker run","/tools/docker/first-container","07.tools/01.docker/05.first-container",{"title":2594,"path":2595,"stem":2596},"Життєвий цикл контейнера","/tools/docker/container-lifecycle","07.tools/01.docker/06.container-lifecycle",{"title":2598,"path":2599,"stem":2600},"Docker Images — фундаментальні концепції","/tools/docker/docker-images-fundamentals","07.tools/01.docker/07.docker-images-fundamentals",{"title":2602,"path":2603,"stem":2604},"Dockerfile — основи","/tools/docker/dockerfile-basics","07.tools/01.docker/08.dockerfile-basics",{"title":2606,"path":2607,"stem":2608},"Dockerfile — просунуті техніки","/tools/docker/dockerfile-advanced","07.tools/01.docker/09.dockerfile-advanced",{"title":2610,"path":2611,"stem":2612},"Build Context та кешування шарів","/tools/docker/build-context-and-cache","07.tools/01.docker/10.build-context-and-cache",{"title":2614,"path":2615,"stem":2616},"Реєстри Docker-образів","/tools/docker/image-registries","07.tools/01.docker/11.image-registries",{"title":2618,"path":2619,"stem":2620},"Контейнеризація .NET додатків","/tools/docker/dotnet-containerization","07.tools/01.docker/12.dotnet-containerization",{"title":2622,"path":2623,"stem":2624},"Томи та збереження даних","/tools/docker/volumes-and-data","07.tools/01.docker/13.volumes-and-data",{"title":2626,"path":2627,"stem":2628},"Основи мережі в Docker","/tools/docker/networking-basics","07.tools/01.docker/14.networking-basics",{"title":2630,"path":2631,"stem":2632},"Змінні оточення та конфігурація","/tools/docker/environment-and-configuration","07.tools/01.docker/15.environment-and-configuration",{"title":2634,"path":2635,"stem":2636},"Docker Compose — оркестрація контейнерів","/tools/docker/docker-compose-basics","07.tools/01.docker/16.docker-compose-basics",{"title":2638,"path":2639,"stem":2640},"Docker Compose — Multi-Service застосунки","/tools/docker/compose-multi-service","07.tools/01.docker/17.compose-multi-service",{"title":2642,"icon":2643,"path":2644,"stem":2645,"children":2646,"page":59},"Software Engineering","i-lucide-code-2","/software-engineering","09.software-engineering",[2647,2651,2655,2659,2663,2667,2671,2675,2679,2683,2687],{"title":2648,"path":2649,"stem":2650},"1. Аналіз предметної області. Експертні знання та складність","/software-engineering/intro.subdomains","09.software-engineering/01.intro.subdomains",{"title":2652,"path":2653,"stem":2654},"2. Обмежені контексти. Інтеграція обмежених контекстів","/software-engineering/integrating-limited-contexts","09.software-engineering/02.integrating-limited-contexts",{"title":2656,"path":2657,"stem":2658},"3. Реалізація простої бізнес-логіки","/software-engineering/simple","09.software-engineering/03.simple",{"title":2660,"path":2661,"stem":2662},"4. Опрацювання складної бізнес-логіки","/software-engineering/complex-business-logic","09.software-engineering/04.complex-business-logic",{"title":2664,"path":2665,"stem":2666},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","/software-engineering/modelling-the-time-factor","09.software-engineering/05.modelling-the-time-factor",{"title":2668,"path":2669,"stem":2670},"6. Архітектурні патерни","/software-engineering/architectural-patterns","09.software-engineering/06.architectural-patterns",{"title":2672,"path":2673,"stem":2674},"Паттерни взаємодії","/software-engineering/patterns-of-interaction","09.software-engineering/07.patterns-of-interaction",{"title":2676,"path":2677,"stem":2678},"Евристика проєктування","/software-engineering/design-heuristics","09.software-engineering/08.design-heuristics",{"title":2680,"path":2681,"stem":2682},"Еволюція проєктних рішень","/software-engineering/evolution-of-design-solutions","09.software-engineering/09.evolution-of-design-solutions",{"title":2684,"path":2685,"stem":2686},"EventStorming","/software-engineering/eventstorming","09.software-engineering/10.eventstorming",{"title":2688,"path":2689,"stem":2690},"DDD на практиці","/software-engineering/ddd-in-practice","09.software-engineering/11.ddd-in-practice",{"title":2692,"icon":943,"path":2693,"stem":2694,"children":2695,"page":59},"DDD","/ddd","10.ddd",[2696,2700,2704,2708,2712,2716,2720,2724,2728,2732,2736,2740,2744],{"title":2697,"path":2698,"stem":2699},"Аналіз предметної області","/ddd/domain-analysis","10.ddd/01.domain-analysis",{"title":2701,"path":2702,"stem":2703},"Експертні знання про предметну область","/ddd/domain-expert-knowledge","10.ddd/02.domain-expert-knowledge",{"title":2705,"path":2706,"stem":2707},"Як осмислити складність предметної області","/ddd/managing-domain-complexity","10.ddd/03.managing-domain-complexity",{"title":2709,"path":2710,"stem":2711},"Інтеграція обмежених контекстів","/ddd/bounded-context-integration","10.ddd/04.bounded-context-integration",{"title":2713,"path":2714,"stem":2715},"Реалізація простої бізнес-логіки","/ddd/simple-business-logic","10.ddd/05.simple-business-logic",{"title":2717,"path":2718,"stem":2719},"Обробка складної бізнес-логіки","/ddd/complex-business-logic","10.ddd/06.complex-business-logic",{"title":2721,"path":2722,"stem":2723},"Моделювання фактора часу","/ddd/time-modeling","10.ddd/07.time-modeling",{"title":2725,"path":2726,"stem":2727},"Глава 8. Архітектурні Патерни","/ddd/architectural-patterns","10.ddd/08.architectural-patterns",{"title":2729,"path":2730,"stem":2731},"Глава 9. Патерни Взаємодії","/ddd/interaction-patterns","10.ddd/09.interaction-patterns",{"title":2733,"path":2734,"stem":2735},"Глава 10. Проектні Евристики","/ddd/design-heuristics","10.ddd/10.design-heuristics",{"title":2737,"path":2738,"stem":2739},"Глава 11. Еволюція Проектних Рішень","/ddd/evolution-of-design-decisions","10.ddd/11.evolution-of-design-decisions",{"title":2741,"path":2742,"stem":2743},"Глава 12. EventStorming","/ddd/event-storming","10.ddd/12.event-storming",{"title":2745,"path":2746,"stem":2747},"Глава 13. DDD на Практиці","/ddd/ddd-in-practice","10.ddd/13.ddd-in-practice",{"title":2749,"icon":2750,"path":2751,"stem":2752,"children":2753,"page":59},"Media Streaming","i-lucide-video","/media-streaming","11.media-streaming",[2754,2758,2762,2766,2770,2774,2778],{"title":2755,"path":2756,"stem":2757},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","/media-streaming/introduction","11.media-streaming/01.introduction",{"title":2759,"path":2760,"stem":2761},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","/media-streaming/audio-video-anatomy","11.media-streaming/02.audio-video-anatomy",{"title":2763,"path":2764,"stem":2765},"03. The Gym: FFmpeg Deep Dive","/media-streaming/ffmpeg-gym","11.media-streaming/03.ffmpeg-gym",{"title":2767,"path":2768,"stem":2769},"04. HLS Protocol: HTTP Live Streaming у Деталях","/media-streaming/hls-protocol","11.media-streaming/04.hls-protocol",{"title":2771,"path":2772,"stem":2773},"05. DASH Protocol: Відкритий Стандарт","/media-streaming/dash-protocol","11.media-streaming/05.dash-protocol",{"title":2775,"path":2776,"stem":2777},"06. Масштабування: CDN та Adaptive Bitrate","/media-streaming/cdn-and-adaptive-bitrate","11.media-streaming/06.cdn-and-adaptive-bitrate",{"title":2779,"path":2780,"stem":2781},"07. Війна із Затримкою (Latency)","/media-streaming/realtime-latency","11.media-streaming/07.realtime-latency",{"title":2783,"icon":2784,"path":2785,"stem":2786,"children":2787,"page":59},"HTML & CSS","i-devicon-html5","/html-css","12.html-css",[2788,2792,2796,2800,2804,2808,2812,2816,2820,2824,2828,2832,2836,2840,2844,2848,2852,2856,2860,2864,2868,2872,2876,2880,2884,2888,2892,2896,2900,2904],{"title":2789,"path":2790,"stem":2791},"Вступ до HTML. Структура документа","/html-css/intro-html-structure","12.html-css/01.intro-html-structure",{"title":2793,"path":2794,"stem":2795},"Форматування тексту в HTML","/html-css/html-text-formatting","12.html-css/02.html-text-formatting",{"title":2797,"path":2798,"stem":2799},"Посилання та зображення в HTML","/html-css/html-links-images","12.html-css/03.html-links-images",{"title":2801,"path":2802,"stem":2803},"Списки та таблиці в HTML","/html-css/html-lists-tables","12.html-css/04.html-lists-tables",{"title":2805,"path":2806,"stem":2807},"Форми в HTML","/html-css/html-forms","12.html-css/05.html-forms",{"title":2809,"path":2810,"stem":2811},"Семантичні елементи HTML5","/html-css/html-semantic-elements","12.html-css/06.html-semantic-elements",{"title":2813,"path":2814,"stem":2815},"Мультимедіа та розширені елементи HTML","/html-css/html-multimedia-advanced","12.html-css/07.html-multimedia-advanced",{"title":2817,"path":2818,"stem":2819},"Мікророзмітка та SEO в HTML","/html-css/html-microdata-seo","12.html-css/08.html-microdata-seo",{"title":2821,"path":2822,"stem":2823},"Вступ до CSS. Селектори та специфічність","/html-css/css-intro-selectors","12.html-css/09.css-intro-selectors",{"title":2825,"path":2826,"stem":2827},"Блокова модель CSS. Відступи. Box Sizing","/html-css/css-box-model","12.html-css/10.css-box-model",{"title":2829,"path":2830,"stem":2831},"Розміри у CSS: повний довідник одиниць і ключових слів","/html-css/10a.css-sizing","12.html-css/10a.css-sizing",{"title":2833,"path":2834,"stem":2835},"Типографіка в CSS. Шрифти та текст","/html-css/css-typography","12.html-css/11.css-typography",{"title":2837,"path":2838,"stem":2839},"Кольори та фони в CSS","/html-css/css-colors-backgrounds","12.html-css/12.css-colors-backgrounds",{"title":2841,"path":2842,"stem":2843},"Тіні та фільтри в CSS","/html-css/12b.css-shadows-filters","12.html-css/12b.css-shadows-filters",{"title":2845,"path":2846,"stem":2847},"CSS Flexbox: Фундамент гнучких макетів","/html-css/css-flexbox-fundamentals","12.html-css/13.css-flexbox-fundamentals",{"title":2849,"path":2850,"stem":2851},"CSS Flexbox: Вирівнювання та Позиціонування","/html-css/css-flexbox-alignment-sizing-and-patterns","12.html-css/14.css-flexbox-alignment-sizing-and-patterns",{"title":2853,"path":2854,"stem":2855},"CSS Grid. Двовимірний макет. Частина 1","/html-css/css-layout-grid","12.html-css/15.css-layout-grid",{"title":2857,"path":2858,"stem":2859},"CSS Grid. Двовимірний макет. Частина 2","/html-css/css-layout-grid-advanced","12.html-css/16.css-layout-grid-advanced",{"title":2861,"path":2862,"stem":2863},"Позиціонування в CSS. Z-index. Stacking Context","/html-css/css-positioning","12.html-css/17.css-positioning",{"title":2865,"path":2866,"stem":2867},"CSS Анімації та Переходи","/html-css/css-animations-transitions","12.html-css/18.css-animations-transitions",{"title":2869,"path":2870,"stem":2871},"Адаптивний дизайн. Media Queries. Частина 1","/html-css/css-responsive-media-queries","12.html-css/19.css-responsive-media-queries",{"title":2873,"path":2874,"stem":2875},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","/html-css/css-responsive-advanced","12.html-css/20.css-responsive-advanced",{"title":2877,"path":2878,"stem":2879},"CSS Custom Properties. Методології. Сучасний CSS","/html-css/css-variables-methodologies","12.html-css/21.css-variables-methodologies",{"title":2881,"path":2882,"stem":2883},"Сучасний CSS 2023–2025: Нові можливості","/html-css/css-modern-features","12.html-css/22.css-modern-features",{"title":2885,"path":2886,"stem":2887},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","/html-css/22a.css-nesting-modern-syntax","12.html-css/22a.css-nesting-modern-syntax",{"title":2889,"path":2890,"stem":2891},"CSS для форм та інтерактивних станів","/html-css/css-forms-interactive-states","12.html-css/23.css-forms-interactive-states",{"title":2893,"path":2894,"stem":2895},"Доступність у CSS (CSS Accessibility)","/html-css/css-accessibility","12.html-css/24.css-accessibility",{"title":2897,"path":2898,"stem":2899},"CSS-функції та сучасні sizing primitives","/html-css/css-functions-sizing","12.html-css/25.css-functions-sizing",{"title":2901,"path":2902,"stem":2903},"Rendering Pipeline і CSS Performance","/html-css/css-rendering-performance","12.html-css/26.css-rendering-performance",{"title":2905,"path":2906,"stem":2907},"CSS Best Practices: типові ситуації та правильні рішення","/html-css/css-best-practices","12.html-css/27.css-best-practices",{"title":2909,"path":2910,"stem":2911,"children":2912,"page":59},"Tailwind","/tailwind","21.tailwind",[2913,2917,2921,2925,2929,2933,2937,2941],{"title":2914,"path":2915,"stem":2916},"Що таке Tailwind CSS і навіщо він потрібен","/tailwind/tailwind-intro-philosophy","21.tailwind/01.tailwind-intro-philosophy",{"title":2918,"path":2919,"stem":2920},"Встановлення та налаштування Tailwind CSS v4","/tailwind/tailwind-installation-setup","21.tailwind/02.tailwind-installation-setup",{"title":2922,"path":2923,"stem":2924},"Utility-класи: основи та система Tailwind","/tailwind/tailwind-utility-classes-core","21.tailwind/03.tailwind-utility-classes-core",{"title":2926,"path":2927,"stem":2928},"Layout: Flexbox та Grid через Tailwind","/tailwind/tailwind-flexbox-grid","21.tailwind/04.tailwind-flexbox-grid",{"title":2930,"path":2931,"stem":2932},"Кастомізація теми через @theme у Tailwind v4","/tailwind/tailwind-theme-customization","21.tailwind/05.tailwind-theme-customization",{"title":2934,"path":2935,"stem":2936},"Варіанти: hover, focus, responsive, dark mode та нові v4","/tailwind/tailwind-variants-states","21.tailwind/06.tailwind-variants-states",{"title":2938,"path":2939,"stem":2940},"Типографіка та система кольорів у Tailwind v4","/tailwind/tailwind-typography-colors","21.tailwind/07.tailwind-typography-colors",{"title":2942,"path":2943,"stem":2944},"Компоненти та повторюваність: @apply, @utility та патерни","/tailwind/tailwind-components-patterns","21.tailwind/08.tailwind-components-patterns",{"title":2946,"path":2947,"stem":2948},"Showcase Компонентів kostyl.dev","/test-new-components","98.test-new-components",{"id":2950,"title":1311,"body":2951,"description":13873,"extension":13874,"links":13875,"meta":13876,"navigation":4534,"path":1312,"seo":13877,"stem":1313,"__hash__":13878},"docs/01.csharp/11.aspnet/12.web-api/05.problemdetails-error-handling.md",{"type":2952,"value":2953,"toc":13831},"minimark",[2954,2958,2963,2967,2975,3243,3254,3261,3266,3277,3282,3372,3377,3472,3477,3567,3570,3596,3599,3603,3607,3614,3680,3685,3750,3755,3793,3798,3805,3912,3916,3971,3975,3982,3989,4164,4175,4233,4238,4320,4417,4419,4423,4429,4433,6011,6013,6017,6023,6028,7643,7648,7697,7701,8310,8315,8348,8350,8354,8359,9921,9925,9952,9954,9958,10275,10277,10281,10285,10291,10704,10709,10722,10726,10729,10961,10965,10976,10980,10987,11437,11442,11453,11457,11468,11478,11480,11484,11488,11491,11885,11889,11892,12224,12228,12231,12456,12459,12524,12526,12530,12534,12655,12657,12661,13256,13258,13262,13708,13710,13714,13721,13726,13780,13786,13788,13792,13817,13819,13827],[2955,2956,1311],"h1",{"id":2957},"problemdetails-та-структурована-обробка-помилок",[2959,2960,2962],"h2",{"id":2961},"вступ-мова-помилок","Вступ: Мова помилок",[2964,2965,2966],"p",{},"Уявіть, що ви розробляєте мобільний додаток, який інтегрується з вашим API. Все працює чудово, поки користувач не вводить невалідні дані або не намагається отримати доступ до неіснуючого ресурсу. API повертає помилку, але що саме пішло не так? Як показати користувачу зрозуміле повідомлення? Як залогувати помилку для debugging?",[2964,2968,2969,2970,2974],{},"Якщо ваш API повертає помилки у ",[2971,2972,2973],"strong",{},"різних форматах",", клієнтський код перетворюється на кошмар:",[2976,2977,2982],"pre",{"className":2978,"code":2979,"language":2980,"meta":2981,"style":2981},"language-typescript shiki shiki-themes light-plus dark-plus dark-plus","// Кошмар клієнтського коду\ntry {\n  const response = await api.getProduct(id);\n} catch (error) {\n  // Що тут? Рядок? Об'єкт? Масив?\n  if (typeof error === 'string') {\n    showError(error);\n  } else if (error.message) {\n    showError(error.message);\n  } else if (error.errors) {\n    showValidationErrors(error.errors);\n  } else if (error.error_description) {\n    showError(error.error_description);\n  } else {\n    showError('Unknown error');\n  }\n}\n","typescript","",[2983,2984,2985,2994,3005,3042,3060,3066,3089,3101,3124,3139,3159,3175,3195,3210,3219,3231,3237],"code",{"__ignoreMap":2981},[2986,2987,2990],"span",{"class":2988,"line":2989},"line",1,[2986,2991,2993],{"class":2992},"spJ8K","// Кошмар клієнтського коду\n",[2986,2995,2997,3001],{"class":2988,"line":2996},2,[2986,2998,3000],{"class":2999},"sCDza","try",[2986,3002,3004],{"class":3003},"sHH4Y"," {\n",[2986,3006,3008,3012,3016,3019,3022,3026,3029,3033,3036,3039],{"class":2988,"line":3007},3,[2986,3009,3011],{"class":3010},"su1O8","  const",[2986,3013,3015],{"class":3014},"s-QsJ"," response",[2986,3017,3018],{"class":3003}," = ",[2986,3020,3021],{"class":2999},"await",[2986,3023,3025],{"class":3024},"siwwj"," api",[2986,3027,3028],{"class":3003},".",[2986,3030,3032],{"class":3031},"s8Opu","getProduct",[2986,3034,3035],{"class":3003},"(",[2986,3037,3038],{"class":3024},"id",[2986,3040,3041],{"class":3003},");\n",[2986,3043,3045,3048,3051,3054,3057],{"class":2988,"line":3044},4,[2986,3046,3047],{"class":3003},"} ",[2986,3049,3050],{"class":2999},"catch",[2986,3052,3053],{"class":3003}," (",[2986,3055,3056],{"class":3024},"error",[2986,3058,3059],{"class":3003},") {\n",[2986,3061,3063],{"class":2988,"line":3062},5,[2986,3064,3065],{"class":2992},"  // Що тут? Рядок? Об'єкт? Масив?\n",[2986,3067,3069,3072,3074,3077,3080,3083,3087],{"class":2988,"line":3068},6,[2986,3070,3071],{"class":2999},"  if",[2986,3073,3053],{"class":3003},[2986,3075,3076],{"class":3010},"typeof",[2986,3078,3079],{"class":3024}," error",[2986,3081,3082],{"class":3003}," === ",[2986,3084,3086],{"class":3085},"sbdoH","'string'",[2986,3088,3059],{"class":3003},[2986,3090,3092,3095,3097,3099],{"class":2988,"line":3091},7,[2986,3093,3094],{"class":3031},"    showError",[2986,3096,3035],{"class":3003},[2986,3098,3056],{"class":3024},[2986,3100,3041],{"class":3003},[2986,3102,3104,3107,3110,3113,3115,3117,3119,3122],{"class":2988,"line":3103},8,[2986,3105,3106],{"class":3003},"  } ",[2986,3108,3109],{"class":2999},"else",[2986,3111,3112],{"class":2999}," if",[2986,3114,3053],{"class":3003},[2986,3116,3056],{"class":3024},[2986,3118,3028],{"class":3003},[2986,3120,3121],{"class":3024},"message",[2986,3123,3059],{"class":3003},[2986,3125,3127,3129,3131,3133,3135,3137],{"class":2988,"line":3126},9,[2986,3128,3094],{"class":3031},[2986,3130,3035],{"class":3003},[2986,3132,3056],{"class":3024},[2986,3134,3028],{"class":3003},[2986,3136,3121],{"class":3024},[2986,3138,3041],{"class":3003},[2986,3140,3142,3144,3146,3148,3150,3152,3154,3157],{"class":2988,"line":3141},10,[2986,3143,3106],{"class":3003},[2986,3145,3109],{"class":2999},[2986,3147,3112],{"class":2999},[2986,3149,3053],{"class":3003},[2986,3151,3056],{"class":3024},[2986,3153,3028],{"class":3003},[2986,3155,3156],{"class":3024},"errors",[2986,3158,3059],{"class":3003},[2986,3160,3162,3165,3167,3169,3171,3173],{"class":2988,"line":3161},11,[2986,3163,3164],{"class":3031},"    showValidationErrors",[2986,3166,3035],{"class":3003},[2986,3168,3056],{"class":3024},[2986,3170,3028],{"class":3003},[2986,3172,3156],{"class":3024},[2986,3174,3041],{"class":3003},[2986,3176,3178,3180,3182,3184,3186,3188,3190,3193],{"class":2988,"line":3177},12,[2986,3179,3106],{"class":3003},[2986,3181,3109],{"class":2999},[2986,3183,3112],{"class":2999},[2986,3185,3053],{"class":3003},[2986,3187,3056],{"class":3024},[2986,3189,3028],{"class":3003},[2986,3191,3192],{"class":3024},"error_description",[2986,3194,3059],{"class":3003},[2986,3196,3198,3200,3202,3204,3206,3208],{"class":2988,"line":3197},13,[2986,3199,3094],{"class":3031},[2986,3201,3035],{"class":3003},[2986,3203,3056],{"class":3024},[2986,3205,3028],{"class":3003},[2986,3207,3192],{"class":3024},[2986,3209,3041],{"class":3003},[2986,3211,3213,3215,3217],{"class":2988,"line":3212},14,[2986,3214,3106],{"class":3003},[2986,3216,3109],{"class":2999},[2986,3218,3004],{"class":3003},[2986,3220,3222,3224,3226,3229],{"class":2988,"line":3221},15,[2986,3223,3094],{"class":3031},[2986,3225,3035],{"class":3003},[2986,3227,3228],{"class":3085},"'Unknown error'",[2986,3230,3041],{"class":3003},[2986,3232,3234],{"class":2988,"line":3233},16,[2986,3235,3236],{"class":3003},"  }\n",[2986,3238,3240],{"class":2988,"line":3239},17,[2986,3241,3242],{"class":3003},"}\n",[2964,3244,3245,3246,3249,3250,3253],{},"Рішення цієї проблеми — ",[2971,3247,3248],{},"ProblemDetails"," (RFC 9457) — стандартизований формат для представлення помилок у HTTP API. Це не просто технічна специфікація, а ",[2971,3251,3252],{},"мова спілкування"," між сервером та клієнтом про те, що пішло не так.",[3255,3256,3257,3260],"note",{},[2971,3258,3259],{},"Передумови:"," Ця стаття базується на знаннях з попередніх статей (01-04 Web API Controllers), а також на розумінні HTTP-кодів з курсу API Design (стаття 05).",[3262,3263,3265],"h3",{"id":3264},"що-ви-створите-в-цій-статті","Що ви створите в цій статті",[2964,3267,3268,3269,3272,3273,3276],{},"Ми побудуємо ",[2971,3270,3271],{},"Banking API"," з ",[2971,3274,3275],{},"професійною системою обробки помилок",":",[2964,3278,3279],{},[2971,3280,3281],{},"Стандартна помилка (404):",[2976,3283,3287],{"className":3284,"code":3285,"language":3286,"meta":2981,"style":2981},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n  \"type\": \"https://api.bank.com/errors/account-not-found\",\n  \"title\": \"Account Not Found\",\n  \"status\": 404,\n  \"detail\": \"Account with ID 12345 does not exist\",\n  \"instance\": \"/api/accounts/12345\",\n  \"traceId\": \"00-a1b2c3d4e5f6-7890abcdef-00\"\n}\n","json",[2983,3288,3289,3294,3309,3321,3334,3346,3358,3368],{"__ignoreMap":2981},[2986,3290,3291],{"class":2988,"line":2989},[2986,3292,3293],{"class":3003},"{\n",[2986,3295,3296,3300,3303,3306],{"class":2988,"line":2996},[2986,3297,3299],{"class":3298},"sLwNe","  \"type\"",[2986,3301,3302],{"class":3003},": ",[2986,3304,3305],{"class":3085},"\"https://api.bank.com/errors/account-not-found\"",[2986,3307,3308],{"class":3003},",\n",[2986,3310,3311,3314,3316,3319],{"class":2988,"line":3007},[2986,3312,3313],{"class":3298},"  \"title\"",[2986,3315,3302],{"class":3003},[2986,3317,3318],{"class":3085},"\"Account Not Found\"",[2986,3320,3308],{"class":3003},[2986,3322,3323,3326,3328,3332],{"class":2988,"line":3044},[2986,3324,3325],{"class":3298},"  \"status\"",[2986,3327,3302],{"class":3003},[2986,3329,3331],{"class":3330},"sJj4R","404",[2986,3333,3308],{"class":3003},[2986,3335,3336,3339,3341,3344],{"class":2988,"line":3062},[2986,3337,3338],{"class":3298},"  \"detail\"",[2986,3340,3302],{"class":3003},[2986,3342,3343],{"class":3085},"\"Account with ID 12345 does not exist\"",[2986,3345,3308],{"class":3003},[2986,3347,3348,3351,3353,3356],{"class":2988,"line":3068},[2986,3349,3350],{"class":3298},"  \"instance\"",[2986,3352,3302],{"class":3003},[2986,3354,3355],{"class":3085},"\"/api/accounts/12345\"",[2986,3357,3308],{"class":3003},[2986,3359,3360,3363,3365],{"class":2988,"line":3091},[2986,3361,3362],{"class":3298},"  \"traceId\"",[2986,3364,3302],{"class":3003},[2986,3366,3367],{"class":3085},"\"00-a1b2c3d4e5f6-7890abcdef-00\"\n",[2986,3369,3370],{"class":2988,"line":3103},[2986,3371,3242],{"class":3003},[2964,3373,3374],{},[2971,3375,3376],{},"Валідаційна помилка (400):",[2976,3378,3380],{"className":3284,"code":3379,"language":3286,"meta":2981,"style":2981},"{\n  \"type\": \"https://tools.ietf.org/html/rfc9457#section-3.1\",\n  \"title\": \"One or more validation errors occurred\",\n  \"status\": 400,\n  \"errors\": {\n    \"amount\": [\"Amount must be greater than 0\"],\n    \"accountNumber\": [\"Invalid account number format\"]\n  },\n  \"traceId\": \"00-xyz123-456-00\"\n}\n",[2983,3381,3382,3386,3397,3408,3419,3427,3441,3454,3459,3468],{"__ignoreMap":2981},[2986,3383,3384],{"class":2988,"line":2989},[2986,3385,3293],{"class":3003},[2986,3387,3388,3390,3392,3395],{"class":2988,"line":2996},[2986,3389,3299],{"class":3298},[2986,3391,3302],{"class":3003},[2986,3393,3394],{"class":3085},"\"https://tools.ietf.org/html/rfc9457#section-3.1\"",[2986,3396,3308],{"class":3003},[2986,3398,3399,3401,3403,3406],{"class":2988,"line":3007},[2986,3400,3313],{"class":3298},[2986,3402,3302],{"class":3003},[2986,3404,3405],{"class":3085},"\"One or more validation errors occurred\"",[2986,3407,3308],{"class":3003},[2986,3409,3410,3412,3414,3417],{"class":2988,"line":3044},[2986,3411,3325],{"class":3298},[2986,3413,3302],{"class":3003},[2986,3415,3416],{"class":3330},"400",[2986,3418,3308],{"class":3003},[2986,3420,3421,3424],{"class":2988,"line":3062},[2986,3422,3423],{"class":3298},"  \"errors\"",[2986,3425,3426],{"class":3003},": {\n",[2986,3428,3429,3432,3435,3438],{"class":2988,"line":3068},[2986,3430,3431],{"class":3298},"    \"amount\"",[2986,3433,3434],{"class":3003},": [",[2986,3436,3437],{"class":3085},"\"Amount must be greater than 0\"",[2986,3439,3440],{"class":3003},"],\n",[2986,3442,3443,3446,3448,3451],{"class":2988,"line":3091},[2986,3444,3445],{"class":3298},"    \"accountNumber\"",[2986,3447,3434],{"class":3003},[2986,3449,3450],{"class":3085},"\"Invalid account number format\"",[2986,3452,3453],{"class":3003},"]\n",[2986,3455,3456],{"class":2988,"line":3103},[2986,3457,3458],{"class":3003},"  },\n",[2986,3460,3461,3463,3465],{"class":2988,"line":3126},[2986,3462,3362],{"class":3298},[2986,3464,3302],{"class":3003},[2986,3466,3467],{"class":3085},"\"00-xyz123-456-00\"\n",[2986,3469,3470],{"class":2988,"line":3141},[2986,3471,3242],{"class":3003},[2964,3473,3474],{},[2971,3475,3476],{},"Бізнес-помилка (409):",[2976,3478,3480],{"className":3284,"code":3479,"language":3286,"meta":2981,"style":2981},"{\n  \"type\": \"https://api.bank.com/errors/insufficient-funds\",\n  \"title\": \"Insufficient Funds\",\n  \"status\": 409,\n  \"detail\": \"Account balance (100.00 USD) is insufficient for transaction (150.00 USD)\",\n  \"balance\": 100.00,\n  \"requiredAmount\": 150.00,\n  \"traceId\": \"00-abc789-def-00\"\n}\n",[2983,3481,3482,3486,3497,3508,3519,3530,3542,3554,3563],{"__ignoreMap":2981},[2986,3483,3484],{"class":2988,"line":2989},[2986,3485,3293],{"class":3003},[2986,3487,3488,3490,3492,3495],{"class":2988,"line":2996},[2986,3489,3299],{"class":3298},[2986,3491,3302],{"class":3003},[2986,3493,3494],{"class":3085},"\"https://api.bank.com/errors/insufficient-funds\"",[2986,3496,3308],{"class":3003},[2986,3498,3499,3501,3503,3506],{"class":2988,"line":3007},[2986,3500,3313],{"class":3298},[2986,3502,3302],{"class":3003},[2986,3504,3505],{"class":3085},"\"Insufficient Funds\"",[2986,3507,3308],{"class":3003},[2986,3509,3510,3512,3514,3517],{"class":2988,"line":3044},[2986,3511,3325],{"class":3298},[2986,3513,3302],{"class":3003},[2986,3515,3516],{"class":3330},"409",[2986,3518,3308],{"class":3003},[2986,3520,3521,3523,3525,3528],{"class":2988,"line":3062},[2986,3522,3338],{"class":3298},[2986,3524,3302],{"class":3003},[2986,3526,3527],{"class":3085},"\"Account balance (100.00 USD) is insufficient for transaction (150.00 USD)\"",[2986,3529,3308],{"class":3003},[2986,3531,3532,3535,3537,3540],{"class":2988,"line":3068},[2986,3533,3534],{"class":3298},"  \"balance\"",[2986,3536,3302],{"class":3003},[2986,3538,3539],{"class":3330},"100.00",[2986,3541,3308],{"class":3003},[2986,3543,3544,3547,3549,3552],{"class":2988,"line":3091},[2986,3545,3546],{"class":3298},"  \"requiredAmount\"",[2986,3548,3302],{"class":3003},[2986,3550,3551],{"class":3330},"150.00",[2986,3553,3308],{"class":3003},[2986,3555,3556,3558,3560],{"class":2988,"line":3103},[2986,3557,3362],{"class":3298},[2986,3559,3302],{"class":3003},[2986,3561,3562],{"class":3085},"\"00-abc789-def-00\"\n",[2986,3564,3565],{"class":2988,"line":3126},[2986,3566,3242],{"class":3003},[2964,3568,3569],{},"До кінця статті ви зможете:",[3571,3572,3573,3577,3580,3587,3590,3593],"ul",{},[3574,3575,3576],"li",{},"Реалізовувати RFC 9457 у ASP.NET Core",[3574,3578,3579],{},"Створювати глобальні exception handlers",[3574,3581,3582,3583,3586],{},"Використовувати ",[2983,3584,3585],{},"IExceptionHandler"," (.NET 8+)",[3574,3588,3589],{},"Додавати кастомні поля до ProblemDetails",[3574,3591,3592],{},"Реалізовувати traceability через correlation IDs",[3574,3594,3595],{},"Обробляти різні типи помилок консистентно",[3597,3598],"hr",{},[2959,3600,3602],{"id":3601},"фундаментальні-концепції-rfc-9457-problemdetails","Фундаментальні концепції: RFC 9457 ProblemDetails",[3262,3604,3606],{"id":3605},"структура-problemdetails","Структура ProblemDetails",[2964,3608,3609,3610,3613],{},"RFC 9457 визначає ",[2971,3611,3612],{},"стандартний формат"," для представлення помилок у JSON:",[2976,3615,3617],{"className":3284,"code":3616,"language":3286,"meta":2981,"style":2981},"{\n  \"type\": \"https://example.com/errors/out-of-credit\",\n  \"title\": \"You do not have enough credit\",\n  \"status\": 403,\n  \"detail\": \"Your current balance is 30, but that costs 50\",\n  \"instance\": \"/account/12345/transactions/abc\"\n}\n",[2983,3618,3619,3623,3634,3645,3656,3667,3676],{"__ignoreMap":2981},[2986,3620,3621],{"class":2988,"line":2989},[2986,3622,3293],{"class":3003},[2986,3624,3625,3627,3629,3632],{"class":2988,"line":2996},[2986,3626,3299],{"class":3298},[2986,3628,3302],{"class":3003},[2986,3630,3631],{"class":3085},"\"https://example.com/errors/out-of-credit\"",[2986,3633,3308],{"class":3003},[2986,3635,3636,3638,3640,3643],{"class":2988,"line":3007},[2986,3637,3313],{"class":3298},[2986,3639,3302],{"class":3003},[2986,3641,3642],{"class":3085},"\"You do not have enough credit\"",[2986,3644,3308],{"class":3003},[2986,3646,3647,3649,3651,3654],{"class":2988,"line":3044},[2986,3648,3325],{"class":3298},[2986,3650,3302],{"class":3003},[2986,3652,3653],{"class":3330},"403",[2986,3655,3308],{"class":3003},[2986,3657,3658,3660,3662,3665],{"class":2988,"line":3062},[2986,3659,3338],{"class":3298},[2986,3661,3302],{"class":3003},[2986,3663,3664],{"class":3085},"\"Your current balance is 30, but that costs 50\"",[2986,3666,3308],{"class":3003},[2986,3668,3669,3671,3673],{"class":2988,"line":3068},[2986,3670,3350],{"class":3298},[2986,3672,3302],{"class":3003},[2986,3674,3675],{"class":3085},"\"/account/12345/transactions/abc\"\n",[2986,3677,3678],{"class":2988,"line":3091},[2986,3679,3242],{"class":3003},[2964,3681,3682],{},[2971,3683,3684],{},"Обов'язкові поля:",[3686,3687,3688,3704],"table",{},[3689,3690,3691],"thead",{},[3692,3693,3694,3698,3701],"tr",{},[3695,3696,3697],"th",{},"Поле",[3695,3699,3700],{},"Тип",[3695,3702,3703],{},"Опис",[3705,3706,3707,3724,3737],"tbody",{},[3692,3708,3709,3715,3718],{},[3710,3711,3712],"td",{},[2983,3713,3714],{},"type",[3710,3716,3717],{},"string (URI)",[3710,3719,3720,3721],{},"Унікальний ідентифікатор типу помилки. За замовчуванням: ",[2983,3722,3723],{},"about:blank",[3692,3725,3726,3731,3734],{},[3710,3727,3728],{},[2983,3729,3730],{},"title",[3710,3732,3733],{},"string",[3710,3735,3736],{},"Коротке, зрозуміле людині резюме проблеми",[3692,3738,3739,3744,3747],{},[3710,3740,3741],{},[2983,3742,3743],{},"status",[3710,3745,3746],{},"number",[3710,3748,3749],{},"HTTP-код статусу (дублює код відповіді)",[2964,3751,3752],{},[2971,3753,3754],{},"Опціональні поля:",[3686,3756,3757,3767],{},[3689,3758,3759],{},[3692,3760,3761,3763,3765],{},[3695,3762,3697],{},[3695,3764,3700],{},[3695,3766,3703],{},[3705,3768,3769,3781],{},[3692,3770,3771,3776,3778],{},[3710,3772,3773],{},[2983,3774,3775],{},"detail",[3710,3777,3733],{},[3710,3779,3780],{},"Детальне пояснення конкретного випадку помилки",[3692,3782,3783,3788,3790],{},[3710,3784,3785],{},[2983,3786,3787],{},"instance",[3710,3789,3717],{},[3710,3791,3792],{},"URI, що ідентифікує конкретний випадок проблеми",[2964,3794,3795],{},[2971,3796,3797],{},"Кастомні поля:",[2964,3799,3800,3801,3804],{},"RFC дозволяє додавати ",[2971,3802,3803],{},"будь-які додаткові поля"," для специфічного контексту:",[2976,3806,3808],{"className":3284,"code":3807,"language":3286,"meta":2981,"style":2981},"{\n  \"type\": \"https://api.bank.com/errors/insufficient-funds\",\n  \"title\": \"Insufficient Funds\",\n  \"status\": 409,\n  \"detail\": \"Account balance is insufficient\",\n  \"balance\": 100.00,           // Кастомне поле\n  \"requiredAmount\": 150.00,    // Кастомне поле\n  \"currency\": \"USD\",           // Кастомне поле\n  \"traceId\": \"00-abc123-def\"   // Кастомне поле\n}\n",[2983,3809,3810,3814,3824,3834,3844,3855,3869,3882,3896,3908],{"__ignoreMap":2981},[2986,3811,3812],{"class":2988,"line":2989},[2986,3813,3293],{"class":3003},[2986,3815,3816,3818,3820,3822],{"class":2988,"line":2996},[2986,3817,3299],{"class":3298},[2986,3819,3302],{"class":3003},[2986,3821,3494],{"class":3085},[2986,3823,3308],{"class":3003},[2986,3825,3826,3828,3830,3832],{"class":2988,"line":3007},[2986,3827,3313],{"class":3298},[2986,3829,3302],{"class":3003},[2986,3831,3505],{"class":3085},[2986,3833,3308],{"class":3003},[2986,3835,3836,3838,3840,3842],{"class":2988,"line":3044},[2986,3837,3325],{"class":3298},[2986,3839,3302],{"class":3003},[2986,3841,3516],{"class":3330},[2986,3843,3308],{"class":3003},[2986,3845,3846,3848,3850,3853],{"class":2988,"line":3062},[2986,3847,3338],{"class":3298},[2986,3849,3302],{"class":3003},[2986,3851,3852],{"class":3085},"\"Account balance is insufficient\"",[2986,3854,3308],{"class":3003},[2986,3856,3857,3859,3861,3863,3866],{"class":2988,"line":3068},[2986,3858,3534],{"class":3298},[2986,3860,3302],{"class":3003},[2986,3862,3539],{"class":3330},[2986,3864,3865],{"class":3003},",           ",[2986,3867,3868],{"class":2992},"// Кастомне поле\n",[2986,3870,3871,3873,3875,3877,3880],{"class":2988,"line":3091},[2986,3872,3546],{"class":3298},[2986,3874,3302],{"class":3003},[2986,3876,3551],{"class":3330},[2986,3878,3879],{"class":3003},",    ",[2986,3881,3868],{"class":2992},[2986,3883,3884,3887,3889,3892,3894],{"class":2988,"line":3103},[2986,3885,3886],{"class":3298},"  \"currency\"",[2986,3888,3302],{"class":3003},[2986,3890,3891],{"class":3085},"\"USD\"",[2986,3893,3865],{"class":3003},[2986,3895,3868],{"class":2992},[2986,3897,3898,3900,3902,3905],{"class":2988,"line":3126},[2986,3899,3362],{"class":3298},[2986,3901,3302],{"class":3003},[2986,3903,3904],{"class":3085},"\"00-abc123-def\"",[2986,3906,3907],{"class":2992},"   // Кастомне поле\n",[2986,3909,3910],{"class":2988,"line":3141},[2986,3911,3242],{"class":3003},[3262,3913,3915],{"id":3914},"чому-problemdetails-важливий","Чому ProblemDetails важливий?",[3917,3918,3919,3929,3940,3951,3956,3964],"card-group",{},[3920,3921,3924,3925,3928],"card",{"icon":3922,"title":3923},"i-lucide-check-circle","✅ Консистентність","Всі помилки мають однакову структуру. Клієнт пише обробку помилок ",[2971,3926,3927],{},"один раз"," для всього API.",[3920,3930,3932,3933,3935,3936,3939],{"icon":255,"title":3931},"✅ Машиночитаність","Поле ",[2983,3934,3714],{}," дозволяє клієнту ",[2971,3937,3938],{},"програмно"," визначити тип помилки та відреагувати відповідно.",[3920,3941,3944,3945,3947,3948,3950],{"icon":3942,"title":3943},"i-lucide-user","✅ Людиночитаність","Поля ",[2983,3946,3730],{}," та ",[2983,3949,3775],{}," надають зрозумілі повідомлення для розробників та користувачів.",[3920,3952,3955],{"icon":3953,"title":3954},"i-lucide-puzzle","✅ Розширюваність","Можна додавати кастомні поля для специфічного контексту без порушення стандарту.",[3920,3957,3959,3960,3963],{"icon":1799,"title":3958},"✅ Стандартизація","RFC 9457 — це ",[2971,3961,3962],{},"міжнародний стандарт",", підтримуваний багатьма фреймворками та бібліотеками.",[3920,3965,3932,3968,3970],{"icon":3966,"title":3967},"i-lucide-bug","✅ Debugging",[2983,3969,3787],{}," та кастомні поля (traceId) полегшують відстеження помилок у логах.",[3262,3972,3974],{"id":3973},"problemdetails-vs-validationproblemdetails","ProblemDetails vs ValidationProblemDetails",[2964,3976,3977,3978,3981],{},"ASP.NET Core надає ",[2971,3979,3980],{},"два типи"," ProblemDetails:",[2964,3983,3984,3988],{},[2971,3985,3986],{},[2983,3987,3248],{}," — для загальних помилок:",[2976,3990,3994],{"className":3991,"code":3992,"language":3993,"meta":2981,"style":2981},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","public class ProblemDetails\n{\n    public string? Type { get; set; }\n    public string? Title { get; set; }\n    public int? Status { get; set; }\n    public string? Detail { get; set; }\n    public string? Instance { get; set; }\n    public IDictionary\u003Cstring, object?> Extensions { get; set; }\n}\n","csharp",[2983,3995,3996,4008,4012,4041,4062,4084,4105,4126,4160],{"__ignoreMap":2981},[2986,3997,3998,4001,4004],{"class":2988,"line":2989},[2986,3999,4000],{"class":3010},"public",[2986,4002,4003],{"class":3010}," class",[2986,4005,4007],{"class":4006},"sN1BT"," ProblemDetails\n",[2986,4009,4010],{"class":2988,"line":2996},[2986,4011,3293],{"class":3003},[2986,4013,4014,4017,4020,4023,4026,4029,4032,4035,4038],{"class":2988,"line":3007},[2986,4015,4016],{"class":3010},"    public",[2986,4018,4019],{"class":3010}," string",[2986,4021,4022],{"class":3003},"? ",[2986,4024,4025],{"class":3024},"Type",[2986,4027,4028],{"class":3003}," { ",[2986,4030,4031],{"class":3010},"get",[2986,4033,4034],{"class":3003},"; ",[2986,4036,4037],{"class":3010},"set",[2986,4039,4040],{"class":3003},"; }\n",[2986,4042,4043,4045,4047,4049,4052,4054,4056,4058,4060],{"class":2988,"line":3044},[2986,4044,4016],{"class":3010},[2986,4046,4019],{"class":3010},[2986,4048,4022],{"class":3003},[2986,4050,4051],{"class":3024},"Title",[2986,4053,4028],{"class":3003},[2986,4055,4031],{"class":3010},[2986,4057,4034],{"class":3003},[2986,4059,4037],{"class":3010},[2986,4061,4040],{"class":3003},[2986,4063,4064,4066,4069,4071,4074,4076,4078,4080,4082],{"class":2988,"line":3062},[2986,4065,4016],{"class":3010},[2986,4067,4068],{"class":3010}," int",[2986,4070,4022],{"class":3003},[2986,4072,4073],{"class":3024},"Status",[2986,4075,4028],{"class":3003},[2986,4077,4031],{"class":3010},[2986,4079,4034],{"class":3003},[2986,4081,4037],{"class":3010},[2986,4083,4040],{"class":3003},[2986,4085,4086,4088,4090,4092,4095,4097,4099,4101,4103],{"class":2988,"line":3068},[2986,4087,4016],{"class":3010},[2986,4089,4019],{"class":3010},[2986,4091,4022],{"class":3003},[2986,4093,4094],{"class":3024},"Detail",[2986,4096,4028],{"class":3003},[2986,4098,4031],{"class":3010},[2986,4100,4034],{"class":3003},[2986,4102,4037],{"class":3010},[2986,4104,4040],{"class":3003},[2986,4106,4107,4109,4111,4113,4116,4118,4120,4122,4124],{"class":2988,"line":3091},[2986,4108,4016],{"class":3010},[2986,4110,4019],{"class":3010},[2986,4112,4022],{"class":3003},[2986,4114,4115],{"class":3024},"Instance",[2986,4117,4028],{"class":3003},[2986,4119,4031],{"class":3010},[2986,4121,4034],{"class":3003},[2986,4123,4037],{"class":3010},[2986,4125,4040],{"class":3003},[2986,4127,4128,4130,4133,4136,4138,4141,4144,4147,4150,4152,4154,4156,4158],{"class":2988,"line":3103},[2986,4129,4016],{"class":3010},[2986,4131,4132],{"class":4006}," IDictionary",[2986,4134,4135],{"class":3003},"\u003C",[2986,4137,3733],{"class":3010},[2986,4139,4140],{"class":3003},", ",[2986,4142,4143],{"class":3010},"object",[2986,4145,4146],{"class":3003},"?> ",[2986,4148,4149],{"class":3024},"Extensions",[2986,4151,4028],{"class":3003},[2986,4153,4031],{"class":3010},[2986,4155,4034],{"class":3003},[2986,4157,4037],{"class":3010},[2986,4159,4040],{"class":3003},[2986,4161,4162],{"class":2988,"line":3126},[2986,4163,3242],{"class":3003},[2964,4165,4166,4171,4172,4174],{},[2971,4167,4168],{},[2983,4169,4170],{},"ValidationProblemDetails"," — для валідаційних помилок (успадковується від ",[2983,4173,3248],{},"):",[2976,4176,4178],{"className":3991,"code":4177,"language":3993,"meta":2981,"style":2981},"public class ValidationProblemDetails : ProblemDetails\n{\n    public IDictionary\u003Cstring, string[]> Errors { get; set; }\n}\n",[2983,4179,4180,4195,4199,4229],{"__ignoreMap":2981},[2986,4181,4182,4184,4186,4189,4192],{"class":2988,"line":2989},[2986,4183,4000],{"class":3010},[2986,4185,4003],{"class":3010},[2986,4187,4188],{"class":4006}," ValidationProblemDetails",[2986,4190,4191],{"class":3003}," : ",[2986,4193,4194],{"class":4006},"ProblemDetails\n",[2986,4196,4197],{"class":2988,"line":2996},[2986,4198,3293],{"class":3003},[2986,4200,4201,4203,4205,4207,4209,4211,4213,4216,4219,4221,4223,4225,4227],{"class":2988,"line":3007},[2986,4202,4016],{"class":3010},[2986,4204,4132],{"class":4006},[2986,4206,4135],{"class":3003},[2986,4208,3733],{"class":3010},[2986,4210,4140],{"class":3003},[2986,4212,3733],{"class":3010},[2986,4214,4215],{"class":3003},"[]> ",[2986,4217,4218],{"class":3024},"Errors",[2986,4220,4028],{"class":3003},[2986,4222,4031],{"class":3010},[2986,4224,4034],{"class":3003},[2986,4226,4037],{"class":3010},[2986,4228,4040],{"class":3003},[2986,4230,4231],{"class":2988,"line":3044},[2986,4232,3242],{"class":3003},[2964,4234,4235,4236,3276],{},"Приклад ",[2983,4237,4170],{},[2976,4239,4241],{"className":3284,"code":4240,"language":3286,"meta":2981,"style":2981},"{\n  \"type\": \"https://tools.ietf.org/html/rfc9457#section-3.1\",\n  \"title\": \"One or more validation errors occurred\",\n  \"status\": 400,\n  \"errors\": {\n    \"email\": [\"Email is required\", \"Email format is invalid\"],\n    \"age\": [\"Age must be between 18 and 120\"]\n  }\n}\n",[2983,4242,4243,4247,4257,4267,4277,4283,4300,4312,4316],{"__ignoreMap":2981},[2986,4244,4245],{"class":2988,"line":2989},[2986,4246,3293],{"class":3003},[2986,4248,4249,4251,4253,4255],{"class":2988,"line":2996},[2986,4250,3299],{"class":3298},[2986,4252,3302],{"class":3003},[2986,4254,3394],{"class":3085},[2986,4256,3308],{"class":3003},[2986,4258,4259,4261,4263,4265],{"class":2988,"line":3007},[2986,4260,3313],{"class":3298},[2986,4262,3302],{"class":3003},[2986,4264,3405],{"class":3085},[2986,4266,3308],{"class":3003},[2986,4268,4269,4271,4273,4275],{"class":2988,"line":3044},[2986,4270,3325],{"class":3298},[2986,4272,3302],{"class":3003},[2986,4274,3416],{"class":3330},[2986,4276,3308],{"class":3003},[2986,4278,4279,4281],{"class":2988,"line":3062},[2986,4280,3423],{"class":3298},[2986,4282,3426],{"class":3003},[2986,4284,4285,4288,4290,4293,4295,4298],{"class":2988,"line":3068},[2986,4286,4287],{"class":3298},"    \"email\"",[2986,4289,3434],{"class":3003},[2986,4291,4292],{"class":3085},"\"Email is required\"",[2986,4294,4140],{"class":3003},[2986,4296,4297],{"class":3085},"\"Email format is invalid\"",[2986,4299,3440],{"class":3003},[2986,4301,4302,4305,4307,4310],{"class":2988,"line":3091},[2986,4303,4304],{"class":3298},"    \"age\"",[2986,4306,3434],{"class":3003},[2986,4308,4309],{"class":3085},"\"Age must be between 18 and 120\"",[2986,4311,3453],{"class":3003},[2986,4313,4314],{"class":2988,"line":3103},[2986,4315,3236],{"class":3003},[2986,4317,4318],{"class":2988,"line":3126},[2986,4319,3242],{"class":3003},[4321,4322,4323],"mermaid",{},[2976,4324,4327],{"className":4325,"code":4326,"language":4321,"meta":2981,"style":2981},"language-mermaid shiki shiki-themes light-plus dark-plus dark-plus","classDiagram\n    class ProblemDetails {\n        +string Type\n        +string Title\n        +int Status\n        +string Detail\n        +string Instance\n        +IDictionary Extensions\n    }\n    \n    class ValidationProblemDetails {\n        +IDictionary~string,string[]~ Errors\n    }\n    \n    ProblemDetails \u003C|-- ValidationProblemDetails\n    \n    style ProblemDetails fill:#3b82f6,stroke:#1d4ed8,color:#ffffff\n    style ValidationProblemDetails fill:#10b981,stroke:#059669,color:#ffffff\n",[2983,4328,4329,4334,4339,4344,4349,4354,4359,4364,4369,4374,4379,4384,4389,4393,4397,4402,4406,4411],{"__ignoreMap":2981},[2986,4330,4331],{"class":2988,"line":2989},[2986,4332,4333],{},"classDiagram\n",[2986,4335,4336],{"class":2988,"line":2996},[2986,4337,4338],{},"    class ProblemDetails {\n",[2986,4340,4341],{"class":2988,"line":3007},[2986,4342,4343],{},"        +string Type\n",[2986,4345,4346],{"class":2988,"line":3044},[2986,4347,4348],{},"        +string Title\n",[2986,4350,4351],{"class":2988,"line":3062},[2986,4352,4353],{},"        +int Status\n",[2986,4355,4356],{"class":2988,"line":3068},[2986,4357,4358],{},"        +string Detail\n",[2986,4360,4361],{"class":2988,"line":3091},[2986,4362,4363],{},"        +string Instance\n",[2986,4365,4366],{"class":2988,"line":3103},[2986,4367,4368],{},"        +IDictionary Extensions\n",[2986,4370,4371],{"class":2988,"line":3126},[2986,4372,4373],{},"    }\n",[2986,4375,4376],{"class":2988,"line":3141},[2986,4377,4378],{},"    \n",[2986,4380,4381],{"class":2988,"line":3161},[2986,4382,4383],{},"    class ValidationProblemDetails {\n",[2986,4385,4386],{"class":2988,"line":3177},[2986,4387,4388],{},"        +IDictionary~string,string[]~ Errors\n",[2986,4390,4391],{"class":2988,"line":3197},[2986,4392,4373],{},[2986,4394,4395],{"class":2988,"line":3212},[2986,4396,4378],{},[2986,4398,4399],{"class":2988,"line":3221},[2986,4400,4401],{},"    ProblemDetails \u003C|-- ValidationProblemDetails\n",[2986,4403,4404],{"class":2988,"line":3233},[2986,4405,4378],{},[2986,4407,4408],{"class":2988,"line":3239},[2986,4409,4410],{},"    style ProblemDetails fill:#3b82f6,stroke:#1d4ed8,color:#ffffff\n",[2986,4412,4414],{"class":2988,"line":4413},18,[2986,4415,4416],{},"    style ValidationProblemDetails fill:#10b981,stroke:#059669,color:#ffffff\n",[3597,4418],{},[2959,4420,4422],{"id":4421},"практична-реалізація-banking-api-з-професійною-обробкою-помилок","Практична реалізація: Banking API з професійною обробкою помилок",[2964,4424,4425,4426,3028],{},"Створимо реальний API з ",[2971,4427,4428],{},"глобальною системою обробки помилок",[3262,4430,4432],{"id":4431},"крок-1-налаштування-проєкту","Крок 1: Налаштування проєкту",[4434,4435,4436,4440,4499,4503,4509,5420,5425,5464,5468,5473],"steps",{},[3262,4437,4439],{"id":4438},"створення-проєкту","Створення проєкту",[4441,4442,4444,4459,4467,4470,4480,4490],"terminal-preview",{"title":4443},"bash",[4445,4446,4448,4453,4454],"div",{"className":4447},[2988],[2986,4449,4452],{"className":4450},[4451],"opacity-40","$"," ",[2971,4455,4458],{"className":4456},[4457],"font-bold","dotnet new webapi -n BankingApi",[4445,4460,4462],{"className":4461},[2988],[2986,4463,4466],{"className":4464},[4465,4457],"text-green-400","The template \"ASP.NET Core Web API\" was created successfully.",[4445,4468],{"className":4469},[2988],[4445,4471,4473,4453,4476],{"className":4472},[2988],[2986,4474,4452],{"className":4475},[4451],[2971,4477,4479],{"className":4478},[4457],"cd BankingApi",[4445,4481,4483,4453,4486],{"className":4482},[2988],[2986,4484,4452],{"className":4485},[4451],[2971,4487,4489],{"className":4488},[4457],"dotnet add package Microsoft.EntityFrameworkCore.InMemory",[4445,4491,4493,4498],{"className":4492},[2988],[2986,4494,4497],{"className":4495},[4496],"text-blue-400","info"," : PackageReference added successfully",[3262,4500,4502],{"id":4501},"створення-кастомних-винятків","Створення кастомних винятків",[2964,4504,4505,4506,3276],{},"Створіть файл ",[2983,4507,4508],{},"Exceptions/BankingExceptions.cs",[2976,4510,4512],{"className":3991,"code":4511,"language":3993,"meta":2981,"style":2981},"namespace BankingApi.Exceptions;\n\n// Базовий клас для бізнес-винятків\npublic abstract class BusinessException : Exception\n{\n    public int StatusCode { get; }\n    public string ErrorType { get; }\n\n    protected BusinessException(\n        string message, \n        int statusCode, \n        string errorType) \n        : base(message)\n    {\n        StatusCode = statusCode;\n        ErrorType = errorType;\n    }\n}\n\n// 404 Not Found\npublic class AccountNotFoundException : BusinessException\n{\n    public string AccountId { get; }\n\n    public AccountNotFoundException(string accountId)\n        : base(\n            $\"Account with ID '{accountId}' does not exist\",\n            StatusCodes.Status404NotFound,\n            \"account-not-found\")\n    {\n        AccountId = accountId;\n    }\n}\n\n// 409 Conflict - Insufficient Funds\npublic class InsufficientFundsException : BusinessException\n{\n    public decimal Balance { get; }\n    public decimal RequiredAmount { get; }\n    public string Currency { get; }\n\n    public InsufficientFundsException(\n        decimal balance, \n        decimal requiredAmount, \n        string currency = \"USD\")\n        : base(\n            $\"Account balance ({balance:F2} {currency}) is insufficient for transaction ({requiredAmount:F2} {currency})\",\n            StatusCodes.Status409Conflict,\n            \"insufficient-funds\")\n    {\n        Balance = balance;\n        RequiredAmount = requiredAmount;\n        Currency = currency;\n    }\n}\n\n// 409 Conflict - Account Locked\npublic class AccountLockedException : BusinessException\n{\n    public string Reason { get; }\n    public DateTime? UnlockedAt { get; }\n\n    public AccountLockedException(string reason, DateTime? unlockedAt = null)\n        : base(\n            $\"Account is locked: {reason}\",\n            StatusCodes.Status409Conflict,\n            \"account-locked\")\n    {\n        Reason = reason;\n        UnlockedAt = unlockedAt;\n    }\n}\n\n// 400 Bad Request - Invalid Transaction\npublic class InvalidTransactionException : BusinessException\n{\n    public string ValidationError { get; }\n\n    public InvalidTransactionException(string validationError)\n        : base(\n            $\"Transaction is invalid: {validationError}\",\n            StatusCodes.Status400BadRequest,\n            \"invalid-transaction\")\n    {\n        ValidationError = validationError;\n    }\n}\n",[2983,4513,4514,4530,4536,4541,4558,4562,4577,4592,4596,4606,4617,4627,4637,4652,4657,4669,4681,4685,4689,4694,4700,4715,4720,4736,4741,4757,4766,4787,4800,4808,4813,4825,4830,4835,4840,4846,4860,4865,4882,4898,4914,4919,4928,4939,4949,4963,4972,5023,5035,5043,5048,5060,5072,5084,5089,5094,5099,5105,5119,5124,5140,5159,5164,5195,5204,5222,5233,5241,5246,5258,5270,5275,5280,5285,5291,5305,5310,5326,5331,5347,5356,5373,5385,5393,5398,5410,5415],{"__ignoreMap":2981},[2986,4515,4516,4519,4522,4524,4527],{"class":2988,"line":2989},[2986,4517,4518],{"class":3010},"namespace",[2986,4520,4521],{"class":4006}," BankingApi",[2986,4523,3028],{"class":3003},[2986,4525,4526],{"class":4006},"Exceptions",[2986,4528,4529],{"class":3003},";\n",[2986,4531,4532],{"class":2988,"line":2996},[2986,4533,4535],{"emptyLinePlaceholder":4534},true,"\n",[2986,4537,4538],{"class":2988,"line":3007},[2986,4539,4540],{"class":2992},"// Базовий клас для бізнес-винятків\n",[2986,4542,4543,4545,4548,4550,4553,4555],{"class":2988,"line":3044},[2986,4544,4000],{"class":3010},[2986,4546,4547],{"class":3010}," abstract",[2986,4549,4003],{"class":3010},[2986,4551,4552],{"class":4006}," BusinessException",[2986,4554,4191],{"class":3003},[2986,4556,4557],{"class":4006},"Exception\n",[2986,4559,4560],{"class":2988,"line":3062},[2986,4561,3293],{"class":3003},[2986,4563,4564,4566,4568,4571,4573,4575],{"class":2988,"line":3068},[2986,4565,4016],{"class":3010},[2986,4567,4068],{"class":3010},[2986,4569,4570],{"class":3024}," StatusCode",[2986,4572,4028],{"class":3003},[2986,4574,4031],{"class":3010},[2986,4576,4040],{"class":3003},[2986,4578,4579,4581,4583,4586,4588,4590],{"class":2988,"line":3091},[2986,4580,4016],{"class":3010},[2986,4582,4019],{"class":3010},[2986,4584,4585],{"class":3024}," ErrorType",[2986,4587,4028],{"class":3003},[2986,4589,4031],{"class":3010},[2986,4591,4040],{"class":3003},[2986,4593,4594],{"class":2988,"line":3103},[2986,4595,4535],{"emptyLinePlaceholder":4534},[2986,4597,4598,4601,4603],{"class":2988,"line":3126},[2986,4599,4600],{"class":3010},"    protected",[2986,4602,4552],{"class":3031},[2986,4604,4605],{"class":3003},"(\n",[2986,4607,4608,4611,4614],{"class":2988,"line":3141},[2986,4609,4610],{"class":3010},"        string",[2986,4612,4613],{"class":3024}," message",[2986,4615,4616],{"class":3003},", \n",[2986,4618,4619,4622,4625],{"class":2988,"line":3161},[2986,4620,4621],{"class":3010},"        int",[2986,4623,4624],{"class":3024}," statusCode",[2986,4626,4616],{"class":3003},[2986,4628,4629,4631,4634],{"class":2988,"line":3177},[2986,4630,4610],{"class":3010},[2986,4632,4633],{"class":3024}," errorType",[2986,4635,4636],{"class":3003},") \n",[2986,4638,4639,4642,4645,4647,4649],{"class":2988,"line":3197},[2986,4640,4641],{"class":3003},"        : ",[2986,4643,4644],{"class":3010},"base",[2986,4646,3035],{"class":3003},[2986,4648,3121],{"class":3024},[2986,4650,4651],{"class":3003},")\n",[2986,4653,4654],{"class":2988,"line":3212},[2986,4655,4656],{"class":3003},"    {\n",[2986,4658,4659,4662,4664,4667],{"class":2988,"line":3221},[2986,4660,4661],{"class":3024},"        StatusCode",[2986,4663,3018],{"class":3003},[2986,4665,4666],{"class":3024},"statusCode",[2986,4668,4529],{"class":3003},[2986,4670,4671,4674,4676,4679],{"class":2988,"line":3233},[2986,4672,4673],{"class":3024},"        ErrorType",[2986,4675,3018],{"class":3003},[2986,4677,4678],{"class":3024},"errorType",[2986,4680,4529],{"class":3003},[2986,4682,4683],{"class":2988,"line":3239},[2986,4684,4373],{"class":3003},[2986,4686,4687],{"class":2988,"line":4413},[2986,4688,3242],{"class":3003},[2986,4690,4692],{"class":2988,"line":4691},19,[2986,4693,4535],{"emptyLinePlaceholder":4534},[2986,4695,4697],{"class":2988,"line":4696},20,[2986,4698,4699],{"class":2992},"// 404 Not Found\n",[2986,4701,4703,4705,4707,4710,4712],{"class":2988,"line":4702},21,[2986,4704,4000],{"class":3010},[2986,4706,4003],{"class":3010},[2986,4708,4709],{"class":4006}," AccountNotFoundException",[2986,4711,4191],{"class":3003},[2986,4713,4714],{"class":4006},"BusinessException\n",[2986,4716,4718],{"class":2988,"line":4717},22,[2986,4719,3293],{"class":3003},[2986,4721,4723,4725,4727,4730,4732,4734],{"class":2988,"line":4722},23,[2986,4724,4016],{"class":3010},[2986,4726,4019],{"class":3010},[2986,4728,4729],{"class":3024}," AccountId",[2986,4731,4028],{"class":3003},[2986,4733,4031],{"class":3010},[2986,4735,4040],{"class":3003},[2986,4737,4739],{"class":2988,"line":4738},24,[2986,4740,4535],{"emptyLinePlaceholder":4534},[2986,4742,4744,4746,4748,4750,4752,4755],{"class":2988,"line":4743},25,[2986,4745,4016],{"class":3010},[2986,4747,4709],{"class":3031},[2986,4749,3035],{"class":3003},[2986,4751,3733],{"class":3010},[2986,4753,4754],{"class":3024}," accountId",[2986,4756,4651],{"class":3003},[2986,4758,4760,4762,4764],{"class":2988,"line":4759},26,[2986,4761,4641],{"class":3003},[2986,4763,4644],{"class":3010},[2986,4765,4605],{"class":3003},[2986,4767,4769,4772,4776,4779,4782,4785],{"class":2988,"line":4768},27,[2986,4770,4771],{"class":3085},"            $\"Account with ID '",[2986,4773,4775],{"class":4774},"sD7JJ","{",[2986,4777,4778],{"class":3024},"accountId",[2986,4780,4781],{"class":4774},"}",[2986,4783,4784],{"class":3085},"' does not exist\"",[2986,4786,3308],{"class":3003},[2986,4788,4790,4793,4795,4798],{"class":2988,"line":4789},28,[2986,4791,4792],{"class":3024},"            StatusCodes",[2986,4794,3028],{"class":3003},[2986,4796,4797],{"class":3024},"Status404NotFound",[2986,4799,3308],{"class":3003},[2986,4801,4803,4806],{"class":2988,"line":4802},29,[2986,4804,4805],{"class":3085},"            \"account-not-found\"",[2986,4807,4651],{"class":3003},[2986,4809,4811],{"class":2988,"line":4810},30,[2986,4812,4656],{"class":3003},[2986,4814,4816,4819,4821,4823],{"class":2988,"line":4815},31,[2986,4817,4818],{"class":3024},"        AccountId",[2986,4820,3018],{"class":3003},[2986,4822,4778],{"class":3024},[2986,4824,4529],{"class":3003},[2986,4826,4828],{"class":2988,"line":4827},32,[2986,4829,4373],{"class":3003},[2986,4831,4833],{"class":2988,"line":4832},33,[2986,4834,3242],{"class":3003},[2986,4836,4838],{"class":2988,"line":4837},34,[2986,4839,4535],{"emptyLinePlaceholder":4534},[2986,4841,4843],{"class":2988,"line":4842},35,[2986,4844,4845],{"class":2992},"// 409 Conflict - Insufficient Funds\n",[2986,4847,4849,4851,4853,4856,4858],{"class":2988,"line":4848},36,[2986,4850,4000],{"class":3010},[2986,4852,4003],{"class":3010},[2986,4854,4855],{"class":4006}," InsufficientFundsException",[2986,4857,4191],{"class":3003},[2986,4859,4714],{"class":4006},[2986,4861,4863],{"class":2988,"line":4862},37,[2986,4864,3293],{"class":3003},[2986,4866,4868,4870,4873,4876,4878,4880],{"class":2988,"line":4867},38,[2986,4869,4016],{"class":3010},[2986,4871,4872],{"class":3010}," decimal",[2986,4874,4875],{"class":3024}," Balance",[2986,4877,4028],{"class":3003},[2986,4879,4031],{"class":3010},[2986,4881,4040],{"class":3003},[2986,4883,4885,4887,4889,4892,4894,4896],{"class":2988,"line":4884},39,[2986,4886,4016],{"class":3010},[2986,4888,4872],{"class":3010},[2986,4890,4891],{"class":3024}," RequiredAmount",[2986,4893,4028],{"class":3003},[2986,4895,4031],{"class":3010},[2986,4897,4040],{"class":3003},[2986,4899,4901,4903,4905,4908,4910,4912],{"class":2988,"line":4900},40,[2986,4902,4016],{"class":3010},[2986,4904,4019],{"class":3010},[2986,4906,4907],{"class":3024}," Currency",[2986,4909,4028],{"class":3003},[2986,4911,4031],{"class":3010},[2986,4913,4040],{"class":3003},[2986,4915,4917],{"class":2988,"line":4916},41,[2986,4918,4535],{"emptyLinePlaceholder":4534},[2986,4920,4922,4924,4926],{"class":2988,"line":4921},42,[2986,4923,4016],{"class":3010},[2986,4925,4855],{"class":3031},[2986,4927,4605],{"class":3003},[2986,4929,4931,4934,4937],{"class":2988,"line":4930},43,[2986,4932,4933],{"class":3010},"        decimal",[2986,4935,4936],{"class":3024}," balance",[2986,4938,4616],{"class":3003},[2986,4940,4942,4944,4947],{"class":2988,"line":4941},44,[2986,4943,4933],{"class":3010},[2986,4945,4946],{"class":3024}," requiredAmount",[2986,4948,4616],{"class":3003},[2986,4950,4952,4954,4957,4959,4961],{"class":2988,"line":4951},45,[2986,4953,4610],{"class":3010},[2986,4955,4956],{"class":3024}," currency",[2986,4958,3018],{"class":3003},[2986,4960,3891],{"class":3085},[2986,4962,4651],{"class":3003},[2986,4964,4966,4968,4970],{"class":2988,"line":4965},46,[2986,4967,4641],{"class":3003},[2986,4969,4644],{"class":3010},[2986,4971,4605],{"class":3003},[2986,4973,4975,4978,4980,4983,4985,4988,4990,4993,4996,4998,5001,5003,5006,5008,5010,5012,5014,5016,5018,5021],{"class":2988,"line":4974},47,[2986,4976,4977],{"class":3085},"            $\"Account balance (",[2986,4979,4775],{"class":4774},[2986,4981,4982],{"class":3024},"balance",[2986,4984,3276],{"class":3003},[2986,4986,4987],{"class":3024},"F2",[2986,4989,4781],{"class":4774},[2986,4991,4992],{"class":4774}," {",[2986,4994,4995],{"class":3024},"currency",[2986,4997,4781],{"class":4774},[2986,4999,5000],{"class":3085},") is insufficient for transaction (",[2986,5002,4775],{"class":4774},[2986,5004,5005],{"class":3024},"requiredAmount",[2986,5007,3276],{"class":3003},[2986,5009,4987],{"class":3024},[2986,5011,4781],{"class":4774},[2986,5013,4992],{"class":4774},[2986,5015,4995],{"class":3024},[2986,5017,4781],{"class":4774},[2986,5019,5020],{"class":3085},")\"",[2986,5022,3308],{"class":3003},[2986,5024,5026,5028,5030,5033],{"class":2988,"line":5025},48,[2986,5027,4792],{"class":3024},[2986,5029,3028],{"class":3003},[2986,5031,5032],{"class":3024},"Status409Conflict",[2986,5034,3308],{"class":3003},[2986,5036,5038,5041],{"class":2988,"line":5037},49,[2986,5039,5040],{"class":3085},"            \"insufficient-funds\"",[2986,5042,4651],{"class":3003},[2986,5044,5046],{"class":2988,"line":5045},50,[2986,5047,4656],{"class":3003},[2986,5049,5051,5054,5056,5058],{"class":2988,"line":5050},51,[2986,5052,5053],{"class":3024},"        Balance",[2986,5055,3018],{"class":3003},[2986,5057,4982],{"class":3024},[2986,5059,4529],{"class":3003},[2986,5061,5063,5066,5068,5070],{"class":2988,"line":5062},52,[2986,5064,5065],{"class":3024},"        RequiredAmount",[2986,5067,3018],{"class":3003},[2986,5069,5005],{"class":3024},[2986,5071,4529],{"class":3003},[2986,5073,5075,5078,5080,5082],{"class":2988,"line":5074},53,[2986,5076,5077],{"class":3024},"        Currency",[2986,5079,3018],{"class":3003},[2986,5081,4995],{"class":3024},[2986,5083,4529],{"class":3003},[2986,5085,5087],{"class":2988,"line":5086},54,[2986,5088,4373],{"class":3003},[2986,5090,5092],{"class":2988,"line":5091},55,[2986,5093,3242],{"class":3003},[2986,5095,5097],{"class":2988,"line":5096},56,[2986,5098,4535],{"emptyLinePlaceholder":4534},[2986,5100,5102],{"class":2988,"line":5101},57,[2986,5103,5104],{"class":2992},"// 409 Conflict - Account Locked\n",[2986,5106,5108,5110,5112,5115,5117],{"class":2988,"line":5107},58,[2986,5109,4000],{"class":3010},[2986,5111,4003],{"class":3010},[2986,5113,5114],{"class":4006}," AccountLockedException",[2986,5116,4191],{"class":3003},[2986,5118,4714],{"class":4006},[2986,5120,5122],{"class":2988,"line":5121},59,[2986,5123,3293],{"class":3003},[2986,5125,5127,5129,5131,5134,5136,5138],{"class":2988,"line":5126},60,[2986,5128,4016],{"class":3010},[2986,5130,4019],{"class":3010},[2986,5132,5133],{"class":3024}," Reason",[2986,5135,4028],{"class":3003},[2986,5137,4031],{"class":3010},[2986,5139,4040],{"class":3003},[2986,5141,5143,5145,5148,5150,5153,5155,5157],{"class":2988,"line":5142},61,[2986,5144,4016],{"class":3010},[2986,5146,5147],{"class":4006}," DateTime",[2986,5149,4022],{"class":3003},[2986,5151,5152],{"class":3024},"UnlockedAt",[2986,5154,4028],{"class":3003},[2986,5156,4031],{"class":3010},[2986,5158,4040],{"class":3003},[2986,5160,5162],{"class":2988,"line":5161},62,[2986,5163,4535],{"emptyLinePlaceholder":4534},[2986,5165,5167,5169,5171,5173,5175,5178,5180,5183,5185,5188,5190,5193],{"class":2988,"line":5166},63,[2986,5168,4016],{"class":3010},[2986,5170,5114],{"class":3031},[2986,5172,3035],{"class":3003},[2986,5174,3733],{"class":3010},[2986,5176,5177],{"class":3024}," reason",[2986,5179,4140],{"class":3003},[2986,5181,5182],{"class":4006},"DateTime",[2986,5184,4022],{"class":3003},[2986,5186,5187],{"class":3024},"unlockedAt",[2986,5189,3018],{"class":3003},[2986,5191,5192],{"class":3010},"null",[2986,5194,4651],{"class":3003},[2986,5196,5198,5200,5202],{"class":2988,"line":5197},64,[2986,5199,4641],{"class":3003},[2986,5201,4644],{"class":3010},[2986,5203,4605],{"class":3003},[2986,5205,5207,5210,5212,5215,5217,5220],{"class":2988,"line":5206},65,[2986,5208,5209],{"class":3085},"            $\"Account is locked: ",[2986,5211,4775],{"class":4774},[2986,5213,5214],{"class":3024},"reason",[2986,5216,4781],{"class":4774},[2986,5218,5219],{"class":3085},"\"",[2986,5221,3308],{"class":3003},[2986,5223,5225,5227,5229,5231],{"class":2988,"line":5224},66,[2986,5226,4792],{"class":3024},[2986,5228,3028],{"class":3003},[2986,5230,5032],{"class":3024},[2986,5232,3308],{"class":3003},[2986,5234,5236,5239],{"class":2988,"line":5235},67,[2986,5237,5238],{"class":3085},"            \"account-locked\"",[2986,5240,4651],{"class":3003},[2986,5242,5244],{"class":2988,"line":5243},68,[2986,5245,4656],{"class":3003},[2986,5247,5249,5252,5254,5256],{"class":2988,"line":5248},69,[2986,5250,5251],{"class":3024},"        Reason",[2986,5253,3018],{"class":3003},[2986,5255,5214],{"class":3024},[2986,5257,4529],{"class":3003},[2986,5259,5261,5264,5266,5268],{"class":2988,"line":5260},70,[2986,5262,5263],{"class":3024},"        UnlockedAt",[2986,5265,3018],{"class":3003},[2986,5267,5187],{"class":3024},[2986,5269,4529],{"class":3003},[2986,5271,5273],{"class":2988,"line":5272},71,[2986,5274,4373],{"class":3003},[2986,5276,5278],{"class":2988,"line":5277},72,[2986,5279,3242],{"class":3003},[2986,5281,5283],{"class":2988,"line":5282},73,[2986,5284,4535],{"emptyLinePlaceholder":4534},[2986,5286,5288],{"class":2988,"line":5287},74,[2986,5289,5290],{"class":2992},"// 400 Bad Request - Invalid Transaction\n",[2986,5292,5294,5296,5298,5301,5303],{"class":2988,"line":5293},75,[2986,5295,4000],{"class":3010},[2986,5297,4003],{"class":3010},[2986,5299,5300],{"class":4006}," InvalidTransactionException",[2986,5302,4191],{"class":3003},[2986,5304,4714],{"class":4006},[2986,5306,5308],{"class":2988,"line":5307},76,[2986,5309,3293],{"class":3003},[2986,5311,5313,5315,5317,5320,5322,5324],{"class":2988,"line":5312},77,[2986,5314,4016],{"class":3010},[2986,5316,4019],{"class":3010},[2986,5318,5319],{"class":3024}," ValidationError",[2986,5321,4028],{"class":3003},[2986,5323,4031],{"class":3010},[2986,5325,4040],{"class":3003},[2986,5327,5329],{"class":2988,"line":5328},78,[2986,5330,4535],{"emptyLinePlaceholder":4534},[2986,5332,5334,5336,5338,5340,5342,5345],{"class":2988,"line":5333},79,[2986,5335,4016],{"class":3010},[2986,5337,5300],{"class":3031},[2986,5339,3035],{"class":3003},[2986,5341,3733],{"class":3010},[2986,5343,5344],{"class":3024}," validationError",[2986,5346,4651],{"class":3003},[2986,5348,5350,5352,5354],{"class":2988,"line":5349},80,[2986,5351,4641],{"class":3003},[2986,5353,4644],{"class":3010},[2986,5355,4605],{"class":3003},[2986,5357,5359,5362,5364,5367,5369,5371],{"class":2988,"line":5358},81,[2986,5360,5361],{"class":3085},"            $\"Transaction is invalid: ",[2986,5363,4775],{"class":4774},[2986,5365,5366],{"class":3024},"validationError",[2986,5368,4781],{"class":4774},[2986,5370,5219],{"class":3085},[2986,5372,3308],{"class":3003},[2986,5374,5376,5378,5380,5383],{"class":2988,"line":5375},82,[2986,5377,4792],{"class":3024},[2986,5379,3028],{"class":3003},[2986,5381,5382],{"class":3024},"Status400BadRequest",[2986,5384,3308],{"class":3003},[2986,5386,5388,5391],{"class":2988,"line":5387},83,[2986,5389,5390],{"class":3085},"            \"invalid-transaction\"",[2986,5392,4651],{"class":3003},[2986,5394,5396],{"class":2988,"line":5395},84,[2986,5397,4656],{"class":3003},[2986,5399,5401,5404,5406,5408],{"class":2988,"line":5400},85,[2986,5402,5403],{"class":3024},"        ValidationError",[2986,5405,3018],{"class":3003},[2986,5407,5366],{"class":3024},[2986,5409,4529],{"class":3003},[2986,5411,5413],{"class":2988,"line":5412},86,[2986,5414,4373],{"class":3003},[2986,5416,5418],{"class":2988,"line":5417},87,[2986,5419,3242],{"class":3003},[2964,5421,5422],{},[2971,5423,5424],{},"Декомпозиція:",[5426,5427,5428,5442,5448],"ol",{},[3574,5429,5430,5435,5436,3947,5439],{},[2971,5431,5432],{},[2983,5433,5434],{},"BusinessException"," — базовий клас для всіх бізнес-винятків з ",[2983,5437,5438],{},"StatusCode",[2983,5440,5441],{},"ErrorType",[3574,5443,5444,5447],{},[2971,5445,5446],{},"Спеціалізовані винятки"," — кожен тип помилки має свій клас з релевантними властивостями",[3574,5449,5450,5453,5454,4140,5457,4140,5460,5463],{},[2971,5451,5452],{},"Кастомні властивості"," — ",[2983,5455,5456],{},"Balance",[2983,5458,5459],{},"RequiredAmount",[2983,5461,5462],{},"Reason"," тощо для додаткового контексту",[3262,5465,5467],{"id":5466},"створення-моделей","Створення моделей",[2964,5469,4505,5470,3276],{},[2983,5471,5472],{},"Models/Account.cs",[2976,5474,5476],{"className":3991,"code":5475,"language":3993,"meta":2981,"style":2981},"using System.ComponentModel.DataAnnotations;\n\nnamespace BankingApi.Models;\n\npublic class Account\n{\n    public int Id { get; set; }\n    \n    [Required]\n    [MaxLength(20)]\n    public required string AccountNumber { get; set; }\n    \n    [Required]\n    [MaxLength(100)]\n    public required string OwnerName { get; set; }\n    \n    [Range(0, double.MaxValue)]\n    public decimal Balance { get; set; }\n    \n    [MaxLength(3)]\n    public string Currency { get; set; } = \"USD\";\n    \n    public bool IsLocked { get; set; }\n    \n    public string? LockReason { get; set; }\n    \n    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;\n}\n\npublic record TransferRequest\n{\n    [Required(ErrorMessage = \"Source account is required\")]\n    public required string FromAccountNumber { get; init; }\n    \n    [Required(ErrorMessage = \"Destination account is required\")]\n    public required string ToAccountNumber { get; init; }\n    \n    [Range(0.01, 1_000_000, ErrorMessage = \"Amount must be between 0.01 and 1,000,000\")]\n    public decimal Amount { get; init; }\n    \n    [MaxLength(200)]\n    public string? Description { get; init; }\n}\n",[2983,5477,5478,5498,5502,5515,5519,5528,5532,5551,5555,5565,5580,5602,5606,5614,5627,5648,5652,5676,5694,5698,5711,5734,5738,5758,5762,5783,5787,5815,5819,5823,5833,5837,5855,5877,5881,5898,5919,5923,5950,5969,5973,5986,6007],{"__ignoreMap":2981},[2986,5479,5480,5483,5486,5488,5491,5493,5496],{"class":2988,"line":2989},[2986,5481,5482],{"class":2999},"using",[2986,5484,5485],{"class":4006}," System",[2986,5487,3028],{"class":3003},[2986,5489,5490],{"class":4006},"ComponentModel",[2986,5492,3028],{"class":3003},[2986,5494,5495],{"class":4006},"DataAnnotations",[2986,5497,4529],{"class":3003},[2986,5499,5500],{"class":2988,"line":2996},[2986,5501,4535],{"emptyLinePlaceholder":4534},[2986,5503,5504,5506,5508,5510,5513],{"class":2988,"line":3007},[2986,5505,4518],{"class":3010},[2986,5507,4521],{"class":4006},[2986,5509,3028],{"class":3003},[2986,5511,5512],{"class":4006},"Models",[2986,5514,4529],{"class":3003},[2986,5516,5517],{"class":2988,"line":3044},[2986,5518,4535],{"emptyLinePlaceholder":4534},[2986,5520,5521,5523,5525],{"class":2988,"line":3062},[2986,5522,4000],{"class":3010},[2986,5524,4003],{"class":3010},[2986,5526,5527],{"class":4006}," Account\n",[2986,5529,5530],{"class":2988,"line":3068},[2986,5531,3293],{"class":3003},[2986,5533,5534,5536,5538,5541,5543,5545,5547,5549],{"class":2988,"line":3091},[2986,5535,4016],{"class":3010},[2986,5537,4068],{"class":3010},[2986,5539,5540],{"class":3024}," Id",[2986,5542,4028],{"class":3003},[2986,5544,4031],{"class":3010},[2986,5546,4034],{"class":3003},[2986,5548,4037],{"class":3010},[2986,5550,4040],{"class":3003},[2986,5552,5553],{"class":2988,"line":3103},[2986,5554,4378],{"class":3003},[2986,5556,5557,5560,5563],{"class":2988,"line":3126},[2986,5558,5559],{"class":3003},"    [",[2986,5561,5562],{"class":4006},"Required",[2986,5564,3453],{"class":3003},[2986,5566,5567,5569,5572,5574,5577],{"class":2988,"line":3141},[2986,5568,5559],{"class":3003},[2986,5570,5571],{"class":4006},"MaxLength",[2986,5573,3035],{"class":3003},[2986,5575,5576],{"class":3330},"20",[2986,5578,5579],{"class":3003},")]\n",[2986,5581,5582,5584,5587,5589,5592,5594,5596,5598,5600],{"class":2988,"line":3161},[2986,5583,4016],{"class":3010},[2986,5585,5586],{"class":3010}," required",[2986,5588,4019],{"class":3010},[2986,5590,5591],{"class":3024}," AccountNumber",[2986,5593,4028],{"class":3003},[2986,5595,4031],{"class":3010},[2986,5597,4034],{"class":3003},[2986,5599,4037],{"class":3010},[2986,5601,4040],{"class":3003},[2986,5603,5604],{"class":2988,"line":3177},[2986,5605,4378],{"class":3003},[2986,5607,5608,5610,5612],{"class":2988,"line":3197},[2986,5609,5559],{"class":3003},[2986,5611,5562],{"class":4006},[2986,5613,3453],{"class":3003},[2986,5615,5616,5618,5620,5622,5625],{"class":2988,"line":3212},[2986,5617,5559],{"class":3003},[2986,5619,5571],{"class":4006},[2986,5621,3035],{"class":3003},[2986,5623,5624],{"class":3330},"100",[2986,5626,5579],{"class":3003},[2986,5628,5629,5631,5633,5635,5638,5640,5642,5644,5646],{"class":2988,"line":3221},[2986,5630,4016],{"class":3010},[2986,5632,5586],{"class":3010},[2986,5634,4019],{"class":3010},[2986,5636,5637],{"class":3024}," OwnerName",[2986,5639,4028],{"class":3003},[2986,5641,4031],{"class":3010},[2986,5643,4034],{"class":3003},[2986,5645,4037],{"class":3010},[2986,5647,4040],{"class":3003},[2986,5649,5650],{"class":2988,"line":3233},[2986,5651,4378],{"class":3003},[2986,5653,5654,5656,5659,5661,5664,5666,5669,5671,5674],{"class":2988,"line":3239},[2986,5655,5559],{"class":3003},[2986,5657,5658],{"class":4006},"Range",[2986,5660,3035],{"class":3003},[2986,5662,5663],{"class":3330},"0",[2986,5665,4140],{"class":3003},[2986,5667,5668],{"class":3010},"double",[2986,5670,3028],{"class":3003},[2986,5672,5673],{"class":3024},"MaxValue",[2986,5675,5579],{"class":3003},[2986,5677,5678,5680,5682,5684,5686,5688,5690,5692],{"class":2988,"line":4413},[2986,5679,4016],{"class":3010},[2986,5681,4872],{"class":3010},[2986,5683,4875],{"class":3024},[2986,5685,4028],{"class":3003},[2986,5687,4031],{"class":3010},[2986,5689,4034],{"class":3003},[2986,5691,4037],{"class":3010},[2986,5693,4040],{"class":3003},[2986,5695,5696],{"class":2988,"line":4691},[2986,5697,4378],{"class":3003},[2986,5699,5700,5702,5704,5706,5709],{"class":2988,"line":4696},[2986,5701,5559],{"class":3003},[2986,5703,5571],{"class":4006},[2986,5705,3035],{"class":3003},[2986,5707,5708],{"class":3330},"3",[2986,5710,5579],{"class":3003},[2986,5712,5713,5715,5717,5719,5721,5723,5725,5727,5730,5732],{"class":2988,"line":4702},[2986,5714,4016],{"class":3010},[2986,5716,4019],{"class":3010},[2986,5718,4907],{"class":3024},[2986,5720,4028],{"class":3003},[2986,5722,4031],{"class":3010},[2986,5724,4034],{"class":3003},[2986,5726,4037],{"class":3010},[2986,5728,5729],{"class":3003},"; } = ",[2986,5731,3891],{"class":3085},[2986,5733,4529],{"class":3003},[2986,5735,5736],{"class":2988,"line":4717},[2986,5737,4378],{"class":3003},[2986,5739,5740,5742,5745,5748,5750,5752,5754,5756],{"class":2988,"line":4722},[2986,5741,4016],{"class":3010},[2986,5743,5744],{"class":3010}," bool",[2986,5746,5747],{"class":3024}," IsLocked",[2986,5749,4028],{"class":3003},[2986,5751,4031],{"class":3010},[2986,5753,4034],{"class":3003},[2986,5755,4037],{"class":3010},[2986,5757,4040],{"class":3003},[2986,5759,5760],{"class":2988,"line":4738},[2986,5761,4378],{"class":3003},[2986,5763,5764,5766,5768,5770,5773,5775,5777,5779,5781],{"class":2988,"line":4743},[2986,5765,4016],{"class":3010},[2986,5767,4019],{"class":3010},[2986,5769,4022],{"class":3003},[2986,5771,5772],{"class":3024},"LockReason",[2986,5774,4028],{"class":3003},[2986,5776,4031],{"class":3010},[2986,5778,4034],{"class":3003},[2986,5780,4037],{"class":3010},[2986,5782,4040],{"class":3003},[2986,5784,5785],{"class":2988,"line":4759},[2986,5786,4378],{"class":3003},[2986,5788,5789,5791,5793,5796,5798,5800,5802,5804,5806,5808,5810,5813],{"class":2988,"line":4768},[2986,5790,4016],{"class":3010},[2986,5792,5147],{"class":4006},[2986,5794,5795],{"class":3024}," CreatedAt",[2986,5797,4028],{"class":3003},[2986,5799,4031],{"class":3010},[2986,5801,4034],{"class":3003},[2986,5803,4037],{"class":3010},[2986,5805,5729],{"class":3003},[2986,5807,5182],{"class":3024},[2986,5809,3028],{"class":3003},[2986,5811,5812],{"class":3024},"UtcNow",[2986,5814,4529],{"class":3003},[2986,5816,5817],{"class":2988,"line":4789},[2986,5818,3242],{"class":3003},[2986,5820,5821],{"class":2988,"line":4802},[2986,5822,4535],{"emptyLinePlaceholder":4534},[2986,5824,5825,5827,5830],{"class":2988,"line":4810},[2986,5826,4000],{"class":3010},[2986,5828,5829],{"class":3010}," record",[2986,5831,5832],{"class":4006}," TransferRequest\n",[2986,5834,5835],{"class":2988,"line":4815},[2986,5836,3293],{"class":3003},[2986,5838,5839,5841,5843,5845,5848,5850,5853],{"class":2988,"line":4827},[2986,5840,5559],{"class":3003},[2986,5842,5562],{"class":4006},[2986,5844,3035],{"class":3003},[2986,5846,5847],{"class":3024},"ErrorMessage",[2986,5849,3018],{"class":3003},[2986,5851,5852],{"class":3085},"\"Source account is required\"",[2986,5854,5579],{"class":3003},[2986,5856,5857,5859,5861,5863,5866,5868,5870,5872,5875],{"class":2988,"line":4832},[2986,5858,4016],{"class":3010},[2986,5860,5586],{"class":3010},[2986,5862,4019],{"class":3010},[2986,5864,5865],{"class":3024}," FromAccountNumber",[2986,5867,4028],{"class":3003},[2986,5869,4031],{"class":3010},[2986,5871,4034],{"class":3003},[2986,5873,5874],{"class":3010},"init",[2986,5876,4040],{"class":3003},[2986,5878,5879],{"class":2988,"line":4837},[2986,5880,4378],{"class":3003},[2986,5882,5883,5885,5887,5889,5891,5893,5896],{"class":2988,"line":4842},[2986,5884,5559],{"class":3003},[2986,5886,5562],{"class":4006},[2986,5888,3035],{"class":3003},[2986,5890,5847],{"class":3024},[2986,5892,3018],{"class":3003},[2986,5894,5895],{"class":3085},"\"Destination account is required\"",[2986,5897,5579],{"class":3003},[2986,5899,5900,5902,5904,5906,5909,5911,5913,5915,5917],{"class":2988,"line":4848},[2986,5901,4016],{"class":3010},[2986,5903,5586],{"class":3010},[2986,5905,4019],{"class":3010},[2986,5907,5908],{"class":3024}," ToAccountNumber",[2986,5910,4028],{"class":3003},[2986,5912,4031],{"class":3010},[2986,5914,4034],{"class":3003},[2986,5916,5874],{"class":3010},[2986,5918,4040],{"class":3003},[2986,5920,5921],{"class":2988,"line":4862},[2986,5922,4378],{"class":3003},[2986,5924,5925,5927,5929,5931,5934,5936,5939,5941,5943,5945,5948],{"class":2988,"line":4867},[2986,5926,5559],{"class":3003},[2986,5928,5658],{"class":4006},[2986,5930,3035],{"class":3003},[2986,5932,5933],{"class":3330},"0.01",[2986,5935,4140],{"class":3003},[2986,5937,5938],{"class":3330},"1_000_000",[2986,5940,4140],{"class":3003},[2986,5942,5847],{"class":3024},[2986,5944,3018],{"class":3003},[2986,5946,5947],{"class":3085},"\"Amount must be between 0.01 and 1,000,000\"",[2986,5949,5579],{"class":3003},[2986,5951,5952,5954,5956,5959,5961,5963,5965,5967],{"class":2988,"line":4884},[2986,5953,4016],{"class":3010},[2986,5955,4872],{"class":3010},[2986,5957,5958],{"class":3024}," Amount",[2986,5960,4028],{"class":3003},[2986,5962,4031],{"class":3010},[2986,5964,4034],{"class":3003},[2986,5966,5874],{"class":3010},[2986,5968,4040],{"class":3003},[2986,5970,5971],{"class":2988,"line":4900},[2986,5972,4378],{"class":3003},[2986,5974,5975,5977,5979,5981,5984],{"class":2988,"line":4916},[2986,5976,5559],{"class":3003},[2986,5978,5571],{"class":4006},[2986,5980,3035],{"class":3003},[2986,5982,5983],{"class":3330},"200",[2986,5985,5579],{"class":3003},[2986,5987,5988,5990,5992,5994,5997,5999,6001,6003,6005],{"class":2988,"line":4921},[2986,5989,4016],{"class":3010},[2986,5991,4019],{"class":3010},[2986,5993,4022],{"class":3003},[2986,5995,5996],{"class":3024},"Description",[2986,5998,4028],{"class":3003},[2986,6000,4031],{"class":3010},[2986,6002,4034],{"class":3003},[2986,6004,5874],{"class":3010},[2986,6006,4040],{"class":3003},[2986,6008,6009],{"class":2988,"line":4930},[2986,6010,3242],{"class":3003},[3597,6012],{},[3262,6014,6016],{"id":6015},"крок-2-створення-global-exception-handler-net-8","Крок 2: Створення Global Exception Handler (.NET 8+)",[2964,6018,6019,6020,6022],{},".NET 8 представив новий інтерфейс ",[2983,6021,3585],{}," для централізованої обробки помилок.",[2964,6024,4505,6025,3276],{},[2983,6026,6027],{},"Handlers/GlobalExceptionHandler.cs",[2976,6029,6031],{"className":3991,"code":6030,"language":3993,"meta":2981,"style":2981},"using Microsoft.AspNetCore.Diagnostics;\nusing Microsoft.AspNetCore.Mvc;\nusing BankingApi.Exceptions;\nusing System.Diagnostics;\n\nnamespace BankingApi.Handlers;\n\npublic class GlobalExceptionHandler : IExceptionHandler\n{\n    private readonly ILogger\u003CGlobalExceptionHandler> _logger;\n    private readonly IHostEnvironment _environment;\n\n    public GlobalExceptionHandler(\n        ILogger\u003CGlobalExceptionHandler> logger,\n        IHostEnvironment environment)\n    {\n        _logger = logger;\n        _environment = environment;\n    }\n\n    public async ValueTask\u003Cbool> TryHandleAsync(\n        HttpContext httpContext,\n        Exception exception,\n        CancellationToken cancellationToken)\n    {\n        var traceId = Activity.Current?.Id ?? httpContext.TraceIdentifier;\n\n        _logger.LogError(\n            exception,\n            \"Exception occurred: {Message}. TraceId: {TraceId}\",\n            exception.Message,\n            traceId);\n\n        var problemDetails = exception switch\n        {\n            // Бізнес-винятки\n            BusinessException businessEx => CreateBusinessProblemDetails(\n                businessEx, \n                httpContext, \n                traceId),\n\n            // Валідаційні помилки (не повинні потрапляти сюди через [ApiController])\n            ValidationException validationEx => CreateValidationProblemDetails(\n                validationEx, \n                httpContext, \n                traceId),\n\n            // Необроблені винятки\n            _ => CreateGenericProblemDetails(\n                exception, \n                httpContext, \n                traceId)\n        };\n\n        httpContext.Response.StatusCode = problemDetails.Status ?? 500;\n        httpContext.Response.ContentType = \"application/problem+json\";\n\n        await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken);\n\n        return true; // Exception handled\n    }\n\n    private ProblemDetails CreateBusinessProblemDetails(\n        BusinessException exception,\n        HttpContext context,\n        string traceId)\n    {\n        var problemDetails = new ProblemDetails\n        {\n            Type = $\"https://api.bank.com/errors/{exception.ErrorType}\",\n            Title = exception.GetType().Name.Replace(\"Exception\", \"\"),\n            Status = exception.StatusCode,\n            Detail = exception.Message,\n            Instance = context.Request.Path\n        };\n\n        // Додаємо traceId для debugging\n        problemDetails.Extensions[\"traceId\"] = traceId;\n\n        // Додаємо кастомні властивості залежно від типу винятку\n        switch (exception)\n        {\n            case InsufficientFundsException insufficientFunds:\n                problemDetails.Extensions[\"balance\"] = insufficientFunds.Balance;\n                problemDetails.Extensions[\"requiredAmount\"] = insufficientFunds.RequiredAmount;\n                problemDetails.Extensions[\"currency\"] = insufficientFunds.Currency;\n                break;\n\n            case AccountLockedException accountLocked:\n                problemDetails.Extensions[\"reason\"] = accountLocked.Reason;\n                if (accountLocked.UnlockedAt.HasValue)\n                {\n                    problemDetails.Extensions[\"unlockedAt\"] = accountLocked.UnlockedAt.Value;\n                }\n                break;\n\n            case AccountNotFoundException accountNotFound:\n                problemDetails.Extensions[\"accountId\"] = accountNotFound.AccountId;\n                break;\n        }\n\n        return problemDetails;\n    }\n\n    private ValidationProblemDetails CreateValidationProblemDetails(\n        ValidationException exception,\n        HttpContext context,\n        string traceId)\n    {\n        var problemDetails = new ValidationProblemDetails\n        {\n            Type = \"https://tools.ietf.org/html/rfc9457#section-3.1\",\n            Title = \"One or more validation errors occurred\",\n            Status = StatusCodes.Status400BadRequest,\n            Detail = exception.Message,\n            Instance = context.Request.Path\n        };\n\n        problemDetails.Extensions[\"traceId\"] = traceId;\n\n        return problemDetails;\n    }\n\n    private ProblemDetails CreateGenericProblemDetails(\n        Exception exception,\n        HttpContext context,\n        string traceId)\n    {\n        var problemDetails = new ProblemDetails\n        {\n            Type = \"https://tools.ietf.org/html/rfc9457#section-3.1\",\n            Title = \"An error occurred while processing your request\",\n            Status = StatusCodes.Status500InternalServerError,\n            Instance = context.Request.Path\n        };\n\n        // У development показуємо деталі помилки\n        if (_environment.IsDevelopment())\n        {\n            problemDetails.Detail = exception.Message;\n            problemDetails.Extensions[\"stackTrace\"] = exception.StackTrace;\n        }\n        else\n        {\n            // У production приховуємо деталі\n            problemDetails.Detail = \"An unexpected error occurred. Please contact support.\";\n        }\n\n        problemDetails.Extensions[\"traceId\"] = traceId;\n\n        return problemDetails;\n    }\n}\n",[2983,6032,6033,6052,6069,6081,6093,6097,6110,6114,6128,6132,6156,6170,6174,6182,6198,6208,6212,6223,6235,6239,6243,6265,6275,6285,6295,6299,6336,6340,6351,6358,6365,6376,6383,6387,6402,6407,6412,6428,6435,6442,6450,6454,6459,6474,6481,6487,6493,6497,6502,6514,6521,6527,6533,6538,6542,6572,6592,6596,6623,6627,6640,6644,6648,6660,6669,6678,6686,6690,6703,6707,6731,6768,6783,6798,6818,6822,6826,6831,6854,6858,6863,6874,6878,6891,6916,6939,6963,6970,6975,6987,7012,7033,7039,7069,7075,7082,7087,7099,7125,7132,7138,7143,7152,7157,7162,7174,7184,7193,7202,7207,7221,7226,7237,7248,7264,7279,7296,7301,7306,7325,7330,7339,7344,7349,7361,7370,7379,7388,7393,7406,7411,7422,7434,7450,7467,7472,7477,7483,7502,7507,7527,7552,7557,7563,7568,7574,7590,7595,7600,7619,7624,7633,7638],{"__ignoreMap":2981},[2986,6034,6035,6037,6040,6042,6045,6047,6050],{"class":2988,"line":2989},[2986,6036,5482],{"class":2999},[2986,6038,6039],{"class":4006}," Microsoft",[2986,6041,3028],{"class":3003},[2986,6043,6044],{"class":4006},"AspNetCore",[2986,6046,3028],{"class":3003},[2986,6048,6049],{"class":4006},"Diagnostics",[2986,6051,4529],{"class":3003},[2986,6053,6054,6056,6058,6060,6062,6064,6067],{"class":2988,"line":2996},[2986,6055,5482],{"class":2999},[2986,6057,6039],{"class":4006},[2986,6059,3028],{"class":3003},[2986,6061,6044],{"class":4006},[2986,6063,3028],{"class":3003},[2986,6065,6066],{"class":4006},"Mvc",[2986,6068,4529],{"class":3003},[2986,6070,6071,6073,6075,6077,6079],{"class":2988,"line":3007},[2986,6072,5482],{"class":2999},[2986,6074,4521],{"class":4006},[2986,6076,3028],{"class":3003},[2986,6078,4526],{"class":4006},[2986,6080,4529],{"class":3003},[2986,6082,6083,6085,6087,6089,6091],{"class":2988,"line":3044},[2986,6084,5482],{"class":2999},[2986,6086,5485],{"class":4006},[2986,6088,3028],{"class":3003},[2986,6090,6049],{"class":4006},[2986,6092,4529],{"class":3003},[2986,6094,6095],{"class":2988,"line":3062},[2986,6096,4535],{"emptyLinePlaceholder":4534},[2986,6098,6099,6101,6103,6105,6108],{"class":2988,"line":3068},[2986,6100,4518],{"class":3010},[2986,6102,4521],{"class":4006},[2986,6104,3028],{"class":3003},[2986,6106,6107],{"class":4006},"Handlers",[2986,6109,4529],{"class":3003},[2986,6111,6112],{"class":2988,"line":3091},[2986,6113,4535],{"emptyLinePlaceholder":4534},[2986,6115,6116,6118,6120,6123,6125],{"class":2988,"line":3103},[2986,6117,4000],{"class":3010},[2986,6119,4003],{"class":3010},[2986,6121,6122],{"class":4006}," GlobalExceptionHandler",[2986,6124,4191],{"class":3003},[2986,6126,6127],{"class":4006},"IExceptionHandler\n",[2986,6129,6130],{"class":2988,"line":3126},[2986,6131,3293],{"class":3003},[2986,6133,6134,6137,6140,6143,6145,6148,6151,6154],{"class":2988,"line":3141},[2986,6135,6136],{"class":3010},"    private",[2986,6138,6139],{"class":3010}," readonly",[2986,6141,6142],{"class":4006}," ILogger",[2986,6144,4135],{"class":3003},[2986,6146,6147],{"class":4006},"GlobalExceptionHandler",[2986,6149,6150],{"class":3003},"> ",[2986,6152,6153],{"class":3024},"_logger",[2986,6155,4529],{"class":3003},[2986,6157,6158,6160,6162,6165,6168],{"class":2988,"line":3161},[2986,6159,6136],{"class":3010},[2986,6161,6139],{"class":3010},[2986,6163,6164],{"class":4006}," IHostEnvironment",[2986,6166,6167],{"class":3024}," _environment",[2986,6169,4529],{"class":3003},[2986,6171,6172],{"class":2988,"line":3177},[2986,6173,4535],{"emptyLinePlaceholder":4534},[2986,6175,6176,6178,6180],{"class":2988,"line":3197},[2986,6177,4016],{"class":3010},[2986,6179,6122],{"class":3031},[2986,6181,4605],{"class":3003},[2986,6183,6184,6187,6189,6191,6193,6196],{"class":2988,"line":3212},[2986,6185,6186],{"class":4006},"        ILogger",[2986,6188,4135],{"class":3003},[2986,6190,6147],{"class":4006},[2986,6192,6150],{"class":3003},[2986,6194,6195],{"class":3024},"logger",[2986,6197,3308],{"class":3003},[2986,6199,6200,6203,6206],{"class":2988,"line":3221},[2986,6201,6202],{"class":4006},"        IHostEnvironment",[2986,6204,6205],{"class":3024}," environment",[2986,6207,4651],{"class":3003},[2986,6209,6210],{"class":2988,"line":3233},[2986,6211,4656],{"class":3003},[2986,6213,6214,6217,6219,6221],{"class":2988,"line":3239},[2986,6215,6216],{"class":3024},"        _logger",[2986,6218,3018],{"class":3003},[2986,6220,6195],{"class":3024},[2986,6222,4529],{"class":3003},[2986,6224,6225,6228,6230,6233],{"class":2988,"line":4413},[2986,6226,6227],{"class":3024},"        _environment",[2986,6229,3018],{"class":3003},[2986,6231,6232],{"class":3024},"environment",[2986,6234,4529],{"class":3003},[2986,6236,6237],{"class":2988,"line":4691},[2986,6238,4373],{"class":3003},[2986,6240,6241],{"class":2988,"line":4696},[2986,6242,4535],{"emptyLinePlaceholder":4534},[2986,6244,6245,6247,6250,6253,6255,6258,6260,6263],{"class":2988,"line":4702},[2986,6246,4016],{"class":3010},[2986,6248,6249],{"class":3010}," async",[2986,6251,6252],{"class":4006}," ValueTask",[2986,6254,4135],{"class":3003},[2986,6256,6257],{"class":3010},"bool",[2986,6259,6150],{"class":3003},[2986,6261,6262],{"class":3031},"TryHandleAsync",[2986,6264,4605],{"class":3003},[2986,6266,6267,6270,6273],{"class":2988,"line":4717},[2986,6268,6269],{"class":4006},"        HttpContext",[2986,6271,6272],{"class":3024}," httpContext",[2986,6274,3308],{"class":3003},[2986,6276,6277,6280,6283],{"class":2988,"line":4722},[2986,6278,6279],{"class":4006},"        Exception",[2986,6281,6282],{"class":3024}," exception",[2986,6284,3308],{"class":3003},[2986,6286,6287,6290,6293],{"class":2988,"line":4738},[2986,6288,6289],{"class":4006},"        CancellationToken",[2986,6291,6292],{"class":3024}," cancellationToken",[2986,6294,4651],{"class":3003},[2986,6296,6297],{"class":2988,"line":4743},[2986,6298,4656],{"class":3003},[2986,6300,6301,6304,6307,6309,6312,6314,6317,6320,6323,6326,6329,6331,6334],{"class":2988,"line":4759},[2986,6302,6303],{"class":3010},"        var",[2986,6305,6306],{"class":3024}," traceId",[2986,6308,3018],{"class":3003},[2986,6310,6311],{"class":3024},"Activity",[2986,6313,3028],{"class":3003},[2986,6315,6316],{"class":3024},"Current",[2986,6318,6319],{"class":3003},"?.",[2986,6321,6322],{"class":3024},"Id",[2986,6324,6325],{"class":3003}," ?? ",[2986,6327,6328],{"class":3024},"httpContext",[2986,6330,3028],{"class":3003},[2986,6332,6333],{"class":3024},"TraceIdentifier",[2986,6335,4529],{"class":3003},[2986,6337,6338],{"class":2988,"line":4768},[2986,6339,4535],{"emptyLinePlaceholder":4534},[2986,6341,6342,6344,6346,6349],{"class":2988,"line":4789},[2986,6343,6216],{"class":3024},[2986,6345,3028],{"class":3003},[2986,6347,6348],{"class":3031},"LogError",[2986,6350,4605],{"class":3003},[2986,6352,6353,6356],{"class":2988,"line":4802},[2986,6354,6355],{"class":3024},"            exception",[2986,6357,3308],{"class":3003},[2986,6359,6360,6363],{"class":2988,"line":4810},[2986,6361,6362],{"class":3085},"            \"Exception occurred: {Message}. TraceId: {TraceId}\"",[2986,6364,3308],{"class":3003},[2986,6366,6367,6369,6371,6374],{"class":2988,"line":4815},[2986,6368,6355],{"class":3024},[2986,6370,3028],{"class":3003},[2986,6372,6373],{"class":3024},"Message",[2986,6375,3308],{"class":3003},[2986,6377,6378,6381],{"class":2988,"line":4827},[2986,6379,6380],{"class":3024},"            traceId",[2986,6382,3041],{"class":3003},[2986,6384,6385],{"class":2988,"line":4832},[2986,6386,4535],{"emptyLinePlaceholder":4534},[2986,6388,6389,6391,6394,6396,6399],{"class":2988,"line":4837},[2986,6390,6303],{"class":3010},[2986,6392,6393],{"class":3024}," problemDetails",[2986,6395,3018],{"class":3003},[2986,6397,6398],{"class":3024},"exception",[2986,6400,6401],{"class":2999}," switch\n",[2986,6403,6404],{"class":2988,"line":4842},[2986,6405,6406],{"class":3003},"        {\n",[2986,6408,6409],{"class":2988,"line":4848},[2986,6410,6411],{"class":2992},"            // Бізнес-винятки\n",[2986,6413,6414,6417,6420,6423,6426],{"class":2988,"line":4862},[2986,6415,6416],{"class":4006},"            BusinessException",[2986,6418,6419],{"class":3024}," businessEx",[2986,6421,6422],{"class":3003}," => ",[2986,6424,6425],{"class":3031},"CreateBusinessProblemDetails",[2986,6427,4605],{"class":3003},[2986,6429,6430,6433],{"class":2988,"line":4867},[2986,6431,6432],{"class":3024},"                businessEx",[2986,6434,4616],{"class":3003},[2986,6436,6437,6440],{"class":2988,"line":4884},[2986,6438,6439],{"class":3024},"                httpContext",[2986,6441,4616],{"class":3003},[2986,6443,6444,6447],{"class":2988,"line":4900},[2986,6445,6446],{"class":3024},"                traceId",[2986,6448,6449],{"class":3003},"),\n",[2986,6451,6452],{"class":2988,"line":4916},[2986,6453,4535],{"emptyLinePlaceholder":4534},[2986,6455,6456],{"class":2988,"line":4921},[2986,6457,6458],{"class":2992},"            // Валідаційні помилки (не повинні потрапляти сюди через [ApiController])\n",[2986,6460,6461,6464,6467,6469,6472],{"class":2988,"line":4930},[2986,6462,6463],{"class":4006},"            ValidationException",[2986,6465,6466],{"class":3024}," validationEx",[2986,6468,6422],{"class":3003},[2986,6470,6471],{"class":3031},"CreateValidationProblemDetails",[2986,6473,4605],{"class":3003},[2986,6475,6476,6479],{"class":2988,"line":4941},[2986,6477,6478],{"class":3024},"                validationEx",[2986,6480,4616],{"class":3003},[2986,6482,6483,6485],{"class":2988,"line":4951},[2986,6484,6439],{"class":3024},[2986,6486,4616],{"class":3003},[2986,6488,6489,6491],{"class":2988,"line":4965},[2986,6490,6446],{"class":3024},[2986,6492,6449],{"class":3003},[2986,6494,6495],{"class":2988,"line":4974},[2986,6496,4535],{"emptyLinePlaceholder":4534},[2986,6498,6499],{"class":2988,"line":5025},[2986,6500,6501],{"class":2992},"            // Необроблені винятки\n",[2986,6503,6504,6507,6509,6512],{"class":2988,"line":5037},[2986,6505,6506],{"class":3010},"            _",[2986,6508,6422],{"class":3003},[2986,6510,6511],{"class":3031},"CreateGenericProblemDetails",[2986,6513,4605],{"class":3003},[2986,6515,6516,6519],{"class":2988,"line":5045},[2986,6517,6518],{"class":3024},"                exception",[2986,6520,4616],{"class":3003},[2986,6522,6523,6525],{"class":2988,"line":5050},[2986,6524,6439],{"class":3024},[2986,6526,4616],{"class":3003},[2986,6528,6529,6531],{"class":2988,"line":5062},[2986,6530,6446],{"class":3024},[2986,6532,4651],{"class":3003},[2986,6534,6535],{"class":2988,"line":5074},[2986,6536,6537],{"class":3003},"        };\n",[2986,6539,6540],{"class":2988,"line":5086},[2986,6541,4535],{"emptyLinePlaceholder":4534},[2986,6543,6544,6547,6549,6552,6554,6556,6558,6561,6563,6565,6567,6570],{"class":2988,"line":5091},[2986,6545,6546],{"class":3024},"        httpContext",[2986,6548,3028],{"class":3003},[2986,6550,6551],{"class":3024},"Response",[2986,6553,3028],{"class":3003},[2986,6555,5438],{"class":3024},[2986,6557,3018],{"class":3003},[2986,6559,6560],{"class":3024},"problemDetails",[2986,6562,3028],{"class":3003},[2986,6564,4073],{"class":3024},[2986,6566,6325],{"class":3003},[2986,6568,6569],{"class":3330},"500",[2986,6571,4529],{"class":3003},[2986,6573,6574,6576,6578,6580,6582,6585,6587,6590],{"class":2988,"line":5096},[2986,6575,6546],{"class":3024},[2986,6577,3028],{"class":3003},[2986,6579,6551],{"class":3024},[2986,6581,3028],{"class":3003},[2986,6583,6584],{"class":3024},"ContentType",[2986,6586,3018],{"class":3003},[2986,6588,6589],{"class":3085},"\"application/problem+json\"",[2986,6591,4529],{"class":3003},[2986,6593,6594],{"class":2988,"line":5101},[2986,6595,4535],{"emptyLinePlaceholder":4534},[2986,6597,6598,6601,6603,6605,6607,6609,6612,6614,6616,6618,6621],{"class":2988,"line":5107},[2986,6599,6600],{"class":3010},"        await",[2986,6602,6272],{"class":3024},[2986,6604,3028],{"class":3003},[2986,6606,6551],{"class":3024},[2986,6608,3028],{"class":3003},[2986,6610,6611],{"class":3031},"WriteAsJsonAsync",[2986,6613,3035],{"class":3003},[2986,6615,6560],{"class":3024},[2986,6617,4140],{"class":3003},[2986,6619,6620],{"class":3024},"cancellationToken",[2986,6622,3041],{"class":3003},[2986,6624,6625],{"class":2988,"line":5121},[2986,6626,4535],{"emptyLinePlaceholder":4534},[2986,6628,6629,6632,6635,6637],{"class":2988,"line":5126},[2986,6630,6631],{"class":2999},"        return",[2986,6633,6634],{"class":3010}," true",[2986,6636,4034],{"class":3003},[2986,6638,6639],{"class":2992},"// Exception handled\n",[2986,6641,6642],{"class":2988,"line":5142},[2986,6643,4373],{"class":3003},[2986,6645,6646],{"class":2988,"line":5161},[2986,6647,4535],{"emptyLinePlaceholder":4534},[2986,6649,6650,6652,6655,6658],{"class":2988,"line":5166},[2986,6651,6136],{"class":3010},[2986,6653,6654],{"class":4006}," ProblemDetails",[2986,6656,6657],{"class":3031}," CreateBusinessProblemDetails",[2986,6659,4605],{"class":3003},[2986,6661,6662,6665,6667],{"class":2988,"line":5197},[2986,6663,6664],{"class":4006},"        BusinessException",[2986,6666,6282],{"class":3024},[2986,6668,3308],{"class":3003},[2986,6670,6671,6673,6676],{"class":2988,"line":5206},[2986,6672,6269],{"class":4006},[2986,6674,6675],{"class":3024}," context",[2986,6677,3308],{"class":3003},[2986,6679,6680,6682,6684],{"class":2988,"line":5224},[2986,6681,4610],{"class":3010},[2986,6683,6306],{"class":3024},[2986,6685,4651],{"class":3003},[2986,6687,6688],{"class":2988,"line":5235},[2986,6689,4656],{"class":3003},[2986,6691,6692,6694,6696,6698,6701],{"class":2988,"line":5243},[2986,6693,6303],{"class":3010},[2986,6695,6393],{"class":3024},[2986,6697,3018],{"class":3003},[2986,6699,6700],{"class":3010},"new",[2986,6702,4007],{"class":4006},[2986,6704,6705],{"class":2988,"line":5248},[2986,6706,6406],{"class":3003},[2986,6708,6709,6712,6714,6717,6719,6721,6723,6725,6727,6729],{"class":2988,"line":5260},[2986,6710,6711],{"class":3024},"            Type",[2986,6713,3018],{"class":3003},[2986,6715,6716],{"class":3085},"$\"https://api.bank.com/errors/",[2986,6718,4775],{"class":4774},[2986,6720,6398],{"class":3024},[2986,6722,3028],{"class":4774},[2986,6724,5441],{"class":3024},[2986,6726,4781],{"class":4774},[2986,6728,5219],{"class":3085},[2986,6730,3308],{"class":3003},[2986,6732,6733,6736,6738,6740,6742,6745,6748,6751,6753,6756,6758,6761,6763,6766],{"class":2988,"line":5272},[2986,6734,6735],{"class":3024},"            Title",[2986,6737,3018],{"class":3003},[2986,6739,6398],{"class":3024},[2986,6741,3028],{"class":3003},[2986,6743,6744],{"class":3031},"GetType",[2986,6746,6747],{"class":3003},"().",[2986,6749,6750],{"class":3024},"Name",[2986,6752,3028],{"class":3003},[2986,6754,6755],{"class":3031},"Replace",[2986,6757,3035],{"class":3003},[2986,6759,6760],{"class":3085},"\"Exception\"",[2986,6762,4140],{"class":3003},[2986,6764,6765],{"class":3085},"\"\"",[2986,6767,6449],{"class":3003},[2986,6769,6770,6773,6775,6777,6779,6781],{"class":2988,"line":5277},[2986,6771,6772],{"class":3024},"            Status",[2986,6774,3018],{"class":3003},[2986,6776,6398],{"class":3024},[2986,6778,3028],{"class":3003},[2986,6780,5438],{"class":3024},[2986,6782,3308],{"class":3003},[2986,6784,6785,6788,6790,6792,6794,6796],{"class":2988,"line":5282},[2986,6786,6787],{"class":3024},"            Detail",[2986,6789,3018],{"class":3003},[2986,6791,6398],{"class":3024},[2986,6793,3028],{"class":3003},[2986,6795,6373],{"class":3024},[2986,6797,3308],{"class":3003},[2986,6799,6800,6803,6805,6808,6810,6813,6815],{"class":2988,"line":5287},[2986,6801,6802],{"class":3024},"            Instance",[2986,6804,3018],{"class":3003},[2986,6806,6807],{"class":3024},"context",[2986,6809,3028],{"class":3003},[2986,6811,6812],{"class":3024},"Request",[2986,6814,3028],{"class":3003},[2986,6816,6817],{"class":3024},"Path\n",[2986,6819,6820],{"class":2988,"line":5293},[2986,6821,6537],{"class":3003},[2986,6823,6824],{"class":2988,"line":5307},[2986,6825,4535],{"emptyLinePlaceholder":4534},[2986,6827,6828],{"class":2988,"line":5312},[2986,6829,6830],{"class":2992},"        // Додаємо traceId для debugging\n",[2986,6832,6833,6836,6838,6840,6843,6846,6849,6852],{"class":2988,"line":5328},[2986,6834,6835],{"class":3024},"        problemDetails",[2986,6837,3028],{"class":3003},[2986,6839,4149],{"class":3024},[2986,6841,6842],{"class":3003},"[",[2986,6844,6845],{"class":3085},"\"traceId\"",[2986,6847,6848],{"class":3003},"] = ",[2986,6850,6851],{"class":3024},"traceId",[2986,6853,4529],{"class":3003},[2986,6855,6856],{"class":2988,"line":5333},[2986,6857,4535],{"emptyLinePlaceholder":4534},[2986,6859,6860],{"class":2988,"line":5349},[2986,6861,6862],{"class":2992},"        // Додаємо кастомні властивості залежно від типу винятку\n",[2986,6864,6865,6868,6870,6872],{"class":2988,"line":5358},[2986,6866,6867],{"class":2999},"        switch",[2986,6869,3053],{"class":3003},[2986,6871,6398],{"class":3024},[2986,6873,4651],{"class":3003},[2986,6875,6876],{"class":2988,"line":5375},[2986,6877,6406],{"class":3003},[2986,6879,6880,6883,6885,6888],{"class":2988,"line":5387},[2986,6881,6882],{"class":2999},"            case",[2986,6884,4855],{"class":4006},[2986,6886,6887],{"class":3024}," insufficientFunds",[2986,6889,6890],{"class":3003},":\n",[2986,6892,6893,6896,6898,6900,6902,6905,6907,6910,6912,6914],{"class":2988,"line":5395},[2986,6894,6895],{"class":3024},"                problemDetails",[2986,6897,3028],{"class":3003},[2986,6899,4149],{"class":3024},[2986,6901,6842],{"class":3003},[2986,6903,6904],{"class":3085},"\"balance\"",[2986,6906,6848],{"class":3003},[2986,6908,6909],{"class":3024},"insufficientFunds",[2986,6911,3028],{"class":3003},[2986,6913,5456],{"class":3024},[2986,6915,4529],{"class":3003},[2986,6917,6918,6920,6922,6924,6926,6929,6931,6933,6935,6937],{"class":2988,"line":5400},[2986,6919,6895],{"class":3024},[2986,6921,3028],{"class":3003},[2986,6923,4149],{"class":3024},[2986,6925,6842],{"class":3003},[2986,6927,6928],{"class":3085},"\"requiredAmount\"",[2986,6930,6848],{"class":3003},[2986,6932,6909],{"class":3024},[2986,6934,3028],{"class":3003},[2986,6936,5459],{"class":3024},[2986,6938,4529],{"class":3003},[2986,6940,6941,6943,6945,6947,6949,6952,6954,6956,6958,6961],{"class":2988,"line":5412},[2986,6942,6895],{"class":3024},[2986,6944,3028],{"class":3003},[2986,6946,4149],{"class":3024},[2986,6948,6842],{"class":3003},[2986,6950,6951],{"class":3085},"\"currency\"",[2986,6953,6848],{"class":3003},[2986,6955,6909],{"class":3024},[2986,6957,3028],{"class":3003},[2986,6959,6960],{"class":3024},"Currency",[2986,6962,4529],{"class":3003},[2986,6964,6965,6968],{"class":2988,"line":5417},[2986,6966,6967],{"class":2999},"                break",[2986,6969,4529],{"class":3003},[2986,6971,6973],{"class":2988,"line":6972},88,[2986,6974,4535],{"emptyLinePlaceholder":4534},[2986,6976,6978,6980,6982,6985],{"class":2988,"line":6977},89,[2986,6979,6882],{"class":2999},[2986,6981,5114],{"class":4006},[2986,6983,6984],{"class":3024}," accountLocked",[2986,6986,6890],{"class":3003},[2986,6988,6990,6992,6994,6996,6998,7001,7003,7006,7008,7010],{"class":2988,"line":6989},90,[2986,6991,6895],{"class":3024},[2986,6993,3028],{"class":3003},[2986,6995,4149],{"class":3024},[2986,6997,6842],{"class":3003},[2986,6999,7000],{"class":3085},"\"reason\"",[2986,7002,6848],{"class":3003},[2986,7004,7005],{"class":3024},"accountLocked",[2986,7007,3028],{"class":3003},[2986,7009,5462],{"class":3024},[2986,7011,4529],{"class":3003},[2986,7013,7015,7018,7020,7022,7024,7026,7028,7031],{"class":2988,"line":7014},91,[2986,7016,7017],{"class":2999},"                if",[2986,7019,3053],{"class":3003},[2986,7021,7005],{"class":3024},[2986,7023,3028],{"class":3003},[2986,7025,5152],{"class":3024},[2986,7027,3028],{"class":3003},[2986,7029,7030],{"class":3024},"HasValue",[2986,7032,4651],{"class":3003},[2986,7034,7036],{"class":2988,"line":7035},92,[2986,7037,7038],{"class":3003},"                {\n",[2986,7040,7042,7045,7047,7049,7051,7054,7056,7058,7060,7062,7064,7067],{"class":2988,"line":7041},93,[2986,7043,7044],{"class":3024},"                    problemDetails",[2986,7046,3028],{"class":3003},[2986,7048,4149],{"class":3024},[2986,7050,6842],{"class":3003},[2986,7052,7053],{"class":3085},"\"unlockedAt\"",[2986,7055,6848],{"class":3003},[2986,7057,7005],{"class":3024},[2986,7059,3028],{"class":3003},[2986,7061,5152],{"class":3024},[2986,7063,3028],{"class":3003},[2986,7065,7066],{"class":3024},"Value",[2986,7068,4529],{"class":3003},[2986,7070,7072],{"class":2988,"line":7071},94,[2986,7073,7074],{"class":3003},"                }\n",[2986,7076,7078,7080],{"class":2988,"line":7077},95,[2986,7079,6967],{"class":2999},[2986,7081,4529],{"class":3003},[2986,7083,7085],{"class":2988,"line":7084},96,[2986,7086,4535],{"emptyLinePlaceholder":4534},[2986,7088,7090,7092,7094,7097],{"class":2988,"line":7089},97,[2986,7091,6882],{"class":2999},[2986,7093,4709],{"class":4006},[2986,7095,7096],{"class":3024}," accountNotFound",[2986,7098,6890],{"class":3003},[2986,7100,7102,7104,7106,7108,7110,7113,7115,7118,7120,7123],{"class":2988,"line":7101},98,[2986,7103,6895],{"class":3024},[2986,7105,3028],{"class":3003},[2986,7107,4149],{"class":3024},[2986,7109,6842],{"class":3003},[2986,7111,7112],{"class":3085},"\"accountId\"",[2986,7114,6848],{"class":3003},[2986,7116,7117],{"class":3024},"accountNotFound",[2986,7119,3028],{"class":3003},[2986,7121,7122],{"class":3024},"AccountId",[2986,7124,4529],{"class":3003},[2986,7126,7128,7130],{"class":2988,"line":7127},99,[2986,7129,6967],{"class":2999},[2986,7131,4529],{"class":3003},[2986,7133,7135],{"class":2988,"line":7134},100,[2986,7136,7137],{"class":3003},"        }\n",[2986,7139,7141],{"class":2988,"line":7140},101,[2986,7142,4535],{"emptyLinePlaceholder":4534},[2986,7144,7146,7148,7150],{"class":2988,"line":7145},102,[2986,7147,6631],{"class":2999},[2986,7149,6393],{"class":3024},[2986,7151,4529],{"class":3003},[2986,7153,7155],{"class":2988,"line":7154},103,[2986,7156,4373],{"class":3003},[2986,7158,7160],{"class":2988,"line":7159},104,[2986,7161,4535],{"emptyLinePlaceholder":4534},[2986,7163,7165,7167,7169,7172],{"class":2988,"line":7164},105,[2986,7166,6136],{"class":3010},[2986,7168,4188],{"class":4006},[2986,7170,7171],{"class":3031}," CreateValidationProblemDetails",[2986,7173,4605],{"class":3003},[2986,7175,7177,7180,7182],{"class":2988,"line":7176},106,[2986,7178,7179],{"class":4006},"        ValidationException",[2986,7181,6282],{"class":3024},[2986,7183,3308],{"class":3003},[2986,7185,7187,7189,7191],{"class":2988,"line":7186},107,[2986,7188,6269],{"class":4006},[2986,7190,6675],{"class":3024},[2986,7192,3308],{"class":3003},[2986,7194,7196,7198,7200],{"class":2988,"line":7195},108,[2986,7197,4610],{"class":3010},[2986,7199,6306],{"class":3024},[2986,7201,4651],{"class":3003},[2986,7203,7205],{"class":2988,"line":7204},109,[2986,7206,4656],{"class":3003},[2986,7208,7210,7212,7214,7216,7218],{"class":2988,"line":7209},110,[2986,7211,6303],{"class":3010},[2986,7213,6393],{"class":3024},[2986,7215,3018],{"class":3003},[2986,7217,6700],{"class":3010},[2986,7219,7220],{"class":4006}," ValidationProblemDetails\n",[2986,7222,7224],{"class":2988,"line":7223},111,[2986,7225,6406],{"class":3003},[2986,7227,7229,7231,7233,7235],{"class":2988,"line":7228},112,[2986,7230,6711],{"class":3024},[2986,7232,3018],{"class":3003},[2986,7234,3394],{"class":3085},[2986,7236,3308],{"class":3003},[2986,7238,7240,7242,7244,7246],{"class":2988,"line":7239},113,[2986,7241,6735],{"class":3024},[2986,7243,3018],{"class":3003},[2986,7245,3405],{"class":3085},[2986,7247,3308],{"class":3003},[2986,7249,7251,7253,7255,7258,7260,7262],{"class":2988,"line":7250},114,[2986,7252,6772],{"class":3024},[2986,7254,3018],{"class":3003},[2986,7256,7257],{"class":3024},"StatusCodes",[2986,7259,3028],{"class":3003},[2986,7261,5382],{"class":3024},[2986,7263,3308],{"class":3003},[2986,7265,7267,7269,7271,7273,7275,7277],{"class":2988,"line":7266},115,[2986,7268,6787],{"class":3024},[2986,7270,3018],{"class":3003},[2986,7272,6398],{"class":3024},[2986,7274,3028],{"class":3003},[2986,7276,6373],{"class":3024},[2986,7278,3308],{"class":3003},[2986,7280,7282,7284,7286,7288,7290,7292,7294],{"class":2988,"line":7281},116,[2986,7283,6802],{"class":3024},[2986,7285,3018],{"class":3003},[2986,7287,6807],{"class":3024},[2986,7289,3028],{"class":3003},[2986,7291,6812],{"class":3024},[2986,7293,3028],{"class":3003},[2986,7295,6817],{"class":3024},[2986,7297,7299],{"class":2988,"line":7298},117,[2986,7300,6537],{"class":3003},[2986,7302,7304],{"class":2988,"line":7303},118,[2986,7305,4535],{"emptyLinePlaceholder":4534},[2986,7307,7309,7311,7313,7315,7317,7319,7321,7323],{"class":2988,"line":7308},119,[2986,7310,6835],{"class":3024},[2986,7312,3028],{"class":3003},[2986,7314,4149],{"class":3024},[2986,7316,6842],{"class":3003},[2986,7318,6845],{"class":3085},[2986,7320,6848],{"class":3003},[2986,7322,6851],{"class":3024},[2986,7324,4529],{"class":3003},[2986,7326,7328],{"class":2988,"line":7327},120,[2986,7329,4535],{"emptyLinePlaceholder":4534},[2986,7331,7333,7335,7337],{"class":2988,"line":7332},121,[2986,7334,6631],{"class":2999},[2986,7336,6393],{"class":3024},[2986,7338,4529],{"class":3003},[2986,7340,7342],{"class":2988,"line":7341},122,[2986,7343,4373],{"class":3003},[2986,7345,7347],{"class":2988,"line":7346},123,[2986,7348,4535],{"emptyLinePlaceholder":4534},[2986,7350,7352,7354,7356,7359],{"class":2988,"line":7351},124,[2986,7353,6136],{"class":3010},[2986,7355,6654],{"class":4006},[2986,7357,7358],{"class":3031}," CreateGenericProblemDetails",[2986,7360,4605],{"class":3003},[2986,7362,7364,7366,7368],{"class":2988,"line":7363},125,[2986,7365,6279],{"class":4006},[2986,7367,6282],{"class":3024},[2986,7369,3308],{"class":3003},[2986,7371,7373,7375,7377],{"class":2988,"line":7372},126,[2986,7374,6269],{"class":4006},[2986,7376,6675],{"class":3024},[2986,7378,3308],{"class":3003},[2986,7380,7382,7384,7386],{"class":2988,"line":7381},127,[2986,7383,4610],{"class":3010},[2986,7385,6306],{"class":3024},[2986,7387,4651],{"class":3003},[2986,7389,7391],{"class":2988,"line":7390},128,[2986,7392,4656],{"class":3003},[2986,7394,7396,7398,7400,7402,7404],{"class":2988,"line":7395},129,[2986,7397,6303],{"class":3010},[2986,7399,6393],{"class":3024},[2986,7401,3018],{"class":3003},[2986,7403,6700],{"class":3010},[2986,7405,4007],{"class":4006},[2986,7407,7409],{"class":2988,"line":7408},130,[2986,7410,6406],{"class":3003},[2986,7412,7414,7416,7418,7420],{"class":2988,"line":7413},131,[2986,7415,6711],{"class":3024},[2986,7417,3018],{"class":3003},[2986,7419,3394],{"class":3085},[2986,7421,3308],{"class":3003},[2986,7423,7425,7427,7429,7432],{"class":2988,"line":7424},132,[2986,7426,6735],{"class":3024},[2986,7428,3018],{"class":3003},[2986,7430,7431],{"class":3085},"\"An error occurred while processing your request\"",[2986,7433,3308],{"class":3003},[2986,7435,7437,7439,7441,7443,7445,7448],{"class":2988,"line":7436},133,[2986,7438,6772],{"class":3024},[2986,7440,3018],{"class":3003},[2986,7442,7257],{"class":3024},[2986,7444,3028],{"class":3003},[2986,7446,7447],{"class":3024},"Status500InternalServerError",[2986,7449,3308],{"class":3003},[2986,7451,7453,7455,7457,7459,7461,7463,7465],{"class":2988,"line":7452},134,[2986,7454,6802],{"class":3024},[2986,7456,3018],{"class":3003},[2986,7458,6807],{"class":3024},[2986,7460,3028],{"class":3003},[2986,7462,6812],{"class":3024},[2986,7464,3028],{"class":3003},[2986,7466,6817],{"class":3024},[2986,7468,7470],{"class":2988,"line":7469},135,[2986,7471,6537],{"class":3003},[2986,7473,7475],{"class":2988,"line":7474},136,[2986,7476,4535],{"emptyLinePlaceholder":4534},[2986,7478,7480],{"class":2988,"line":7479},137,[2986,7481,7482],{"class":2992},"        // У development показуємо деталі помилки\n",[2986,7484,7486,7489,7491,7494,7496,7499],{"class":2988,"line":7485},138,[2986,7487,7488],{"class":2999},"        if",[2986,7490,3053],{"class":3003},[2986,7492,7493],{"class":3024},"_environment",[2986,7495,3028],{"class":3003},[2986,7497,7498],{"class":3031},"IsDevelopment",[2986,7500,7501],{"class":3003},"())\n",[2986,7503,7505],{"class":2988,"line":7504},139,[2986,7506,6406],{"class":3003},[2986,7508,7510,7513,7515,7517,7519,7521,7523,7525],{"class":2988,"line":7509},140,[2986,7511,7512],{"class":3024},"            problemDetails",[2986,7514,3028],{"class":3003},[2986,7516,4094],{"class":3024},[2986,7518,3018],{"class":3003},[2986,7520,6398],{"class":3024},[2986,7522,3028],{"class":3003},[2986,7524,6373],{"class":3024},[2986,7526,4529],{"class":3003},[2986,7528,7530,7532,7534,7536,7538,7541,7543,7545,7547,7550],{"class":2988,"line":7529},141,[2986,7531,7512],{"class":3024},[2986,7533,3028],{"class":3003},[2986,7535,4149],{"class":3024},[2986,7537,6842],{"class":3003},[2986,7539,7540],{"class":3085},"\"stackTrace\"",[2986,7542,6848],{"class":3003},[2986,7544,6398],{"class":3024},[2986,7546,3028],{"class":3003},[2986,7548,7549],{"class":3024},"StackTrace",[2986,7551,4529],{"class":3003},[2986,7553,7555],{"class":2988,"line":7554},142,[2986,7556,7137],{"class":3003},[2986,7558,7560],{"class":2988,"line":7559},143,[2986,7561,7562],{"class":2999},"        else\n",[2986,7564,7566],{"class":2988,"line":7565},144,[2986,7567,6406],{"class":3003},[2986,7569,7571],{"class":2988,"line":7570},145,[2986,7572,7573],{"class":2992},"            // У production приховуємо деталі\n",[2986,7575,7577,7579,7581,7583,7585,7588],{"class":2988,"line":7576},146,[2986,7578,7512],{"class":3024},[2986,7580,3028],{"class":3003},[2986,7582,4094],{"class":3024},[2986,7584,3018],{"class":3003},[2986,7586,7587],{"class":3085},"\"An unexpected error occurred. Please contact support.\"",[2986,7589,4529],{"class":3003},[2986,7591,7593],{"class":2988,"line":7592},147,[2986,7594,7137],{"class":3003},[2986,7596,7598],{"class":2988,"line":7597},148,[2986,7599,4535],{"emptyLinePlaceholder":4534},[2986,7601,7603,7605,7607,7609,7611,7613,7615,7617],{"class":2988,"line":7602},149,[2986,7604,6835],{"class":3024},[2986,7606,3028],{"class":3003},[2986,7608,4149],{"class":3024},[2986,7610,6842],{"class":3003},[2986,7612,6845],{"class":3085},[2986,7614,6848],{"class":3003},[2986,7616,6851],{"class":3024},[2986,7618,4529],{"class":3003},[2986,7620,7622],{"class":2988,"line":7621},150,[2986,7623,4535],{"emptyLinePlaceholder":4534},[2986,7625,7627,7629,7631],{"class":2988,"line":7626},151,[2986,7628,6631],{"class":2999},[2986,7630,6393],{"class":3024},[2986,7632,4529],{"class":3003},[2986,7634,7636],{"class":2988,"line":7635},152,[2986,7637,4373],{"class":3003},[2986,7639,7641],{"class":2988,"line":7640},153,[2986,7642,3242],{"class":3003},[2964,7644,7645],{},[2971,7646,7647],{},"Декомпозиція коду:",[5426,7649,7650,7658,7667,7673,7681,7687],{},[3574,7651,7652,7657],{},[2971,7653,7654],{},[2983,7655,7656],{},"TryHandleAsync()"," — головний метод обробки винятків",[3574,7659,7660,7663,7664],{},[2971,7661,7662],{},"Pattern matching"," — визначаємо тип винятку через ",[2983,7665,7666],{},"switch",[3574,7668,7669,7672],{},[2971,7670,7671],{},"Логування"," — всі винятки логуються з traceId",[3574,7674,7675,7678,7679],{},[2971,7676,7677],{},"Кастомні поля"," — додаємо релевантні дані через ",[2983,7680,4149],{},[3574,7682,7683,7686],{},[2971,7684,7685],{},"Environment-aware"," — у development показуємо stack trace, у production — приховуємо",[3574,7688,7689,7692,7693,7696],{},[2971,7690,7691],{},"TraceId"," — використовуємо ",[2983,7694,7695],{},"Activity.Current?.Id"," для distributed tracing",[3262,7698,7700],{"id":7699},"налаштування-в-programcs","Налаштування в Program.cs",[2976,7702,7704],{"className":3991,"code":7703,"language":3993,"meta":2981,"style":2981},"using Microsoft.EntityFrameworkCore;\nusing BankingApi.Data;\nusing BankingApi.Handlers;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Реєстрація DbContext\nbuilder.Services.AddDbContext\u003CBankingDbContext>(options =>\n    options.UseInMemoryDatabase(\"BankingDb\"));\n\n// Реєстрація Global Exception Handler\nbuilder.Services.AddExceptionHandler\u003CGlobalExceptionHandler>();\n\n// Налаштування ProblemDetails\nbuilder.Services.AddProblemDetails(options =>\n{\n    // Кастомізація ProblemDetails для всіх помилок\n    options.CustomizeProblemDetails = context =>\n    {\n        // Додаємо machine name для debugging у development\n        if (builder.Environment.IsDevelopment())\n        {\n            context.ProblemDetails.Extensions[\"machine\"] = Environment.MachineName;\n        }\n\n        // Додаємо timestamp\n        context.ProblemDetails.Extensions[\"timestamp\"] = DateTime.UtcNow;\n    };\n});\n\nbuilder.Services.AddControllers();\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n// Ініціалізація бази даних\nusing (var scope = app.Services.CreateScope())\n{\n    var db = scope.ServiceProvider.GetRequiredService\u003CBankingDbContext>();\n    db.Database.EnsureCreated();\n}\n\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\n// ВАЖЛИВО: Exception handler має бути перед іншими middleware\napp.UseExceptionHandler();\n\napp.UseHttpsRedirection();\napp.UseAuthorization();\napp.MapControllers();\n\napp.Run();\n",[2983,7705,7706,7719,7732,7744,7748,7773,7777,7782,7811,7829,7833,7838,7858,7862,7867,7886,7890,7895,7910,7914,7919,7938,7942,7971,7975,7979,7984,8012,8017,8022,8026,8042,8057,8072,8076,8094,8098,8103,8130,8134,8163,8180,8184,8188,8207,8211,8223,8234,8238,8242,8247,8258,8262,8273,8284,8295,8299],{"__ignoreMap":2981},[2986,7707,7708,7710,7712,7714,7717],{"class":2988,"line":2989},[2986,7709,5482],{"class":2999},[2986,7711,6039],{"class":4006},[2986,7713,3028],{"class":3003},[2986,7715,7716],{"class":4006},"EntityFrameworkCore",[2986,7718,4529],{"class":3003},[2986,7720,7721,7723,7725,7727,7730],{"class":2988,"line":2996},[2986,7722,5482],{"class":2999},[2986,7724,4521],{"class":4006},[2986,7726,3028],{"class":3003},[2986,7728,7729],{"class":4006},"Data",[2986,7731,4529],{"class":3003},[2986,7733,7734,7736,7738,7740,7742],{"class":2988,"line":3007},[2986,7735,5482],{"class":2999},[2986,7737,4521],{"class":4006},[2986,7739,3028],{"class":3003},[2986,7741,6107],{"class":4006},[2986,7743,4529],{"class":3003},[2986,7745,7746],{"class":2988,"line":3044},[2986,7747,4535],{"emptyLinePlaceholder":4534},[2986,7749,7750,7753,7756,7758,7761,7763,7766,7768,7771],{"class":2988,"line":3062},[2986,7751,7752],{"class":3010},"var",[2986,7754,7755],{"class":3024}," builder",[2986,7757,3018],{"class":3003},[2986,7759,7760],{"class":3024},"WebApplication",[2986,7762,3028],{"class":3003},[2986,7764,7765],{"class":3031},"CreateBuilder",[2986,7767,3035],{"class":3003},[2986,7769,7770],{"class":3024},"args",[2986,7772,3041],{"class":3003},[2986,7774,7775],{"class":2988,"line":3068},[2986,7776,4535],{"emptyLinePlaceholder":4534},[2986,7778,7779],{"class":2988,"line":3091},[2986,7780,7781],{"class":2992},"// Реєстрація DbContext\n",[2986,7783,7784,7787,7789,7792,7794,7797,7799,7802,7805,7808],{"class":2988,"line":3103},[2986,7785,7786],{"class":3024},"builder",[2986,7788,3028],{"class":3003},[2986,7790,7791],{"class":3024},"Services",[2986,7793,3028],{"class":3003},[2986,7795,7796],{"class":3031},"AddDbContext",[2986,7798,4135],{"class":3003},[2986,7800,7801],{"class":4006},"BankingDbContext",[2986,7803,7804],{"class":3003},">(",[2986,7806,7807],{"class":3024},"options",[2986,7809,7810],{"class":3003}," =>\n",[2986,7812,7813,7816,7818,7821,7823,7826],{"class":2988,"line":3126},[2986,7814,7815],{"class":3024},"    options",[2986,7817,3028],{"class":3003},[2986,7819,7820],{"class":3031},"UseInMemoryDatabase",[2986,7822,3035],{"class":3003},[2986,7824,7825],{"class":3085},"\"BankingDb\"",[2986,7827,7828],{"class":3003},"));\n",[2986,7830,7831],{"class":2988,"line":3141},[2986,7832,4535],{"emptyLinePlaceholder":4534},[2986,7834,7835],{"class":2988,"line":3161},[2986,7836,7837],{"class":2992},"// Реєстрація Global Exception Handler\n",[2986,7839,7840,7842,7844,7846,7848,7851,7853,7855],{"class":2988,"line":3177},[2986,7841,7786],{"class":3024},[2986,7843,3028],{"class":3003},[2986,7845,7791],{"class":3024},[2986,7847,3028],{"class":3003},[2986,7849,7850],{"class":3031},"AddExceptionHandler",[2986,7852,4135],{"class":3003},[2986,7854,6147],{"class":4006},[2986,7856,7857],{"class":3003},">();\n",[2986,7859,7860],{"class":2988,"line":3197},[2986,7861,4535],{"emptyLinePlaceholder":4534},[2986,7863,7864],{"class":2988,"line":3212},[2986,7865,7866],{"class":2992},"// Налаштування ProblemDetails\n",[2986,7868,7869,7871,7873,7875,7877,7880,7882,7884],{"class":2988,"line":3221},[2986,7870,7786],{"class":3024},[2986,7872,3028],{"class":3003},[2986,7874,7791],{"class":3024},[2986,7876,3028],{"class":3003},[2986,7878,7879],{"class":3031},"AddProblemDetails",[2986,7881,3035],{"class":3003},[2986,7883,7807],{"class":3024},[2986,7885,7810],{"class":3003},[2986,7887,7888],{"class":2988,"line":3233},[2986,7889,3293],{"class":3003},[2986,7891,7892],{"class":2988,"line":3239},[2986,7893,7894],{"class":2992},"    // Кастомізація ProblemDetails для всіх помилок\n",[2986,7896,7897,7899,7901,7904,7906,7908],{"class":2988,"line":4413},[2986,7898,7815],{"class":3024},[2986,7900,3028],{"class":3003},[2986,7902,7903],{"class":3024},"CustomizeProblemDetails",[2986,7905,3018],{"class":3003},[2986,7907,6807],{"class":3024},[2986,7909,7810],{"class":3003},[2986,7911,7912],{"class":2988,"line":4691},[2986,7913,4656],{"class":3003},[2986,7915,7916],{"class":2988,"line":4696},[2986,7917,7918],{"class":2992},"        // Додаємо machine name для debugging у development\n",[2986,7920,7921,7923,7925,7927,7929,7932,7934,7936],{"class":2988,"line":4702},[2986,7922,7488],{"class":2999},[2986,7924,3053],{"class":3003},[2986,7926,7786],{"class":3024},[2986,7928,3028],{"class":3003},[2986,7930,7931],{"class":3024},"Environment",[2986,7933,3028],{"class":3003},[2986,7935,7498],{"class":3031},[2986,7937,7501],{"class":3003},[2986,7939,7940],{"class":2988,"line":4717},[2986,7941,6406],{"class":3003},[2986,7943,7944,7947,7949,7951,7953,7955,7957,7960,7962,7964,7966,7969],{"class":2988,"line":4722},[2986,7945,7946],{"class":3024},"            context",[2986,7948,3028],{"class":3003},[2986,7950,3248],{"class":3024},[2986,7952,3028],{"class":3003},[2986,7954,4149],{"class":3024},[2986,7956,6842],{"class":3003},[2986,7958,7959],{"class":3085},"\"machine\"",[2986,7961,6848],{"class":3003},[2986,7963,7931],{"class":3024},[2986,7965,3028],{"class":3003},[2986,7967,7968],{"class":3024},"MachineName",[2986,7970,4529],{"class":3003},[2986,7972,7973],{"class":2988,"line":4738},[2986,7974,7137],{"class":3003},[2986,7976,7977],{"class":2988,"line":4743},[2986,7978,4535],{"emptyLinePlaceholder":4534},[2986,7980,7981],{"class":2988,"line":4759},[2986,7982,7983],{"class":2992},"        // Додаємо timestamp\n",[2986,7985,7986,7989,7991,7993,7995,7997,7999,8002,8004,8006,8008,8010],{"class":2988,"line":4768},[2986,7987,7988],{"class":3024},"        context",[2986,7990,3028],{"class":3003},[2986,7992,3248],{"class":3024},[2986,7994,3028],{"class":3003},[2986,7996,4149],{"class":3024},[2986,7998,6842],{"class":3003},[2986,8000,8001],{"class":3085},"\"timestamp\"",[2986,8003,6848],{"class":3003},[2986,8005,5182],{"class":3024},[2986,8007,3028],{"class":3003},[2986,8009,5812],{"class":3024},[2986,8011,4529],{"class":3003},[2986,8013,8014],{"class":2988,"line":4789},[2986,8015,8016],{"class":3003},"    };\n",[2986,8018,8019],{"class":2988,"line":4802},[2986,8020,8021],{"class":3003},"});\n",[2986,8023,8024],{"class":2988,"line":4810},[2986,8025,4535],{"emptyLinePlaceholder":4534},[2986,8027,8028,8030,8032,8034,8036,8039],{"class":2988,"line":4815},[2986,8029,7786],{"class":3024},[2986,8031,3028],{"class":3003},[2986,8033,7791],{"class":3024},[2986,8035,3028],{"class":3003},[2986,8037,8038],{"class":3031},"AddControllers",[2986,8040,8041],{"class":3003},"();\n",[2986,8043,8044,8046,8048,8050,8052,8055],{"class":2988,"line":4827},[2986,8045,7786],{"class":3024},[2986,8047,3028],{"class":3003},[2986,8049,7791],{"class":3024},[2986,8051,3028],{"class":3003},[2986,8053,8054],{"class":3031},"AddEndpointsApiExplorer",[2986,8056,8041],{"class":3003},[2986,8058,8059,8061,8063,8065,8067,8070],{"class":2988,"line":4832},[2986,8060,7786],{"class":3024},[2986,8062,3028],{"class":3003},[2986,8064,7791],{"class":3024},[2986,8066,3028],{"class":3003},[2986,8068,8069],{"class":3031},"AddSwaggerGen",[2986,8071,8041],{"class":3003},[2986,8073,8074],{"class":2988,"line":4837},[2986,8075,4535],{"emptyLinePlaceholder":4534},[2986,8077,8078,8080,8083,8085,8087,8089,8092],{"class":2988,"line":4842},[2986,8079,7752],{"class":3010},[2986,8081,8082],{"class":3024}," app",[2986,8084,3018],{"class":3003},[2986,8086,7786],{"class":3024},[2986,8088,3028],{"class":3003},[2986,8090,8091],{"class":3031},"Build",[2986,8093,8041],{"class":3003},[2986,8095,8096],{"class":2988,"line":4848},[2986,8097,4535],{"emptyLinePlaceholder":4534},[2986,8099,8100],{"class":2988,"line":4862},[2986,8101,8102],{"class":2992},"// Ініціалізація бази даних\n",[2986,8104,8105,8107,8109,8111,8114,8116,8119,8121,8123,8125,8128],{"class":2988,"line":4867},[2986,8106,5482],{"class":2999},[2986,8108,3053],{"class":3003},[2986,8110,7752],{"class":3010},[2986,8112,8113],{"class":3024}," scope",[2986,8115,3018],{"class":3003},[2986,8117,8118],{"class":3024},"app",[2986,8120,3028],{"class":3003},[2986,8122,7791],{"class":3024},[2986,8124,3028],{"class":3003},[2986,8126,8127],{"class":3031},"CreateScope",[2986,8129,7501],{"class":3003},[2986,8131,8132],{"class":2988,"line":4884},[2986,8133,3293],{"class":3003},[2986,8135,8136,8139,8142,8144,8147,8149,8152,8154,8157,8159,8161],{"class":2988,"line":4900},[2986,8137,8138],{"class":3010},"    var",[2986,8140,8141],{"class":3024}," db",[2986,8143,3018],{"class":3003},[2986,8145,8146],{"class":3024},"scope",[2986,8148,3028],{"class":3003},[2986,8150,8151],{"class":3024},"ServiceProvider",[2986,8153,3028],{"class":3003},[2986,8155,8156],{"class":3031},"GetRequiredService",[2986,8158,4135],{"class":3003},[2986,8160,7801],{"class":4006},[2986,8162,7857],{"class":3003},[2986,8164,8165,8168,8170,8173,8175,8178],{"class":2988,"line":4916},[2986,8166,8167],{"class":3024},"    db",[2986,8169,3028],{"class":3003},[2986,8171,8172],{"class":3024},"Database",[2986,8174,3028],{"class":3003},[2986,8176,8177],{"class":3031},"EnsureCreated",[2986,8179,8041],{"class":3003},[2986,8181,8182],{"class":2988,"line":4921},[2986,8183,3242],{"class":3003},[2986,8185,8186],{"class":2988,"line":4930},[2986,8187,4535],{"emptyLinePlaceholder":4534},[2986,8189,8190,8193,8195,8197,8199,8201,8203,8205],{"class":2988,"line":4941},[2986,8191,8192],{"class":2999},"if",[2986,8194,3053],{"class":3003},[2986,8196,8118],{"class":3024},[2986,8198,3028],{"class":3003},[2986,8200,7931],{"class":3024},[2986,8202,3028],{"class":3003},[2986,8204,7498],{"class":3031},[2986,8206,7501],{"class":3003},[2986,8208,8209],{"class":2988,"line":4951},[2986,8210,3293],{"class":3003},[2986,8212,8213,8216,8218,8221],{"class":2988,"line":4965},[2986,8214,8215],{"class":3024},"    app",[2986,8217,3028],{"class":3003},[2986,8219,8220],{"class":3031},"UseSwagger",[2986,8222,8041],{"class":3003},[2986,8224,8225,8227,8229,8232],{"class":2988,"line":4974},[2986,8226,8215],{"class":3024},[2986,8228,3028],{"class":3003},[2986,8230,8231],{"class":3031},"UseSwaggerUI",[2986,8233,8041],{"class":3003},[2986,8235,8236],{"class":2988,"line":5025},[2986,8237,3242],{"class":3003},[2986,8239,8240],{"class":2988,"line":5037},[2986,8241,4535],{"emptyLinePlaceholder":4534},[2986,8243,8244],{"class":2988,"line":5045},[2986,8245,8246],{"class":2992},"// ВАЖЛИВО: Exception handler має бути перед іншими middleware\n",[2986,8248,8249,8251,8253,8256],{"class":2988,"line":5050},[2986,8250,8118],{"class":3024},[2986,8252,3028],{"class":3003},[2986,8254,8255],{"class":3031},"UseExceptionHandler",[2986,8257,8041],{"class":3003},[2986,8259,8260],{"class":2988,"line":5062},[2986,8261,4535],{"emptyLinePlaceholder":4534},[2986,8263,8264,8266,8268,8271],{"class":2988,"line":5074},[2986,8265,8118],{"class":3024},[2986,8267,3028],{"class":3003},[2986,8269,8270],{"class":3031},"UseHttpsRedirection",[2986,8272,8041],{"class":3003},[2986,8274,8275,8277,8279,8282],{"class":2988,"line":5086},[2986,8276,8118],{"class":3024},[2986,8278,3028],{"class":3003},[2986,8280,8281],{"class":3031},"UseAuthorization",[2986,8283,8041],{"class":3003},[2986,8285,8286,8288,8290,8293],{"class":2988,"line":5091},[2986,8287,8118],{"class":3024},[2986,8289,3028],{"class":3003},[2986,8291,8292],{"class":3031},"MapControllers",[2986,8294,8041],{"class":3003},[2986,8296,8297],{"class":2988,"line":5096},[2986,8298,4535],{"emptyLinePlaceholder":4534},[2986,8300,8301,8303,8305,8308],{"class":2988,"line":5101},[2986,8302,8118],{"class":3024},[2986,8304,3028],{"class":3003},[2986,8306,8307],{"class":3031},"Run",[2986,8309,8041],{"class":3003},[2964,8311,8312],{},[2971,8313,8314],{},"Ключові моменти:",[5426,8316,8317,8325,8333,8340],{},[3574,8318,8319,8324],{},[2971,8320,8321],{},[2983,8322,8323],{},"AddExceptionHandler\u003CGlobalExceptionHandler>()"," — реєструє наш handler",[3574,8326,8327,8332],{},[2971,8328,8329],{},[2983,8330,8331],{},"AddProblemDetails()"," — налаштовує генерацію ProblemDetails",[3574,8334,8335,8339],{},[2971,8336,8337],{},[2983,8338,7903],{}," — дозволяє додавати глобальні поля до всіх помилок",[3574,8341,8342,8347],{},[2971,8343,8344],{},[2983,8345,8346],{},"UseExceptionHandler()"," — активує middleware (має бути на початку pipeline)",[3597,8349],{},[3262,8351,8353],{"id":8352},"крок-3-створення-контролера-з-бізнес-логікою","Крок 3: Створення контролера з бізнес-логікою",[2964,8355,4505,8356,3276],{},[2983,8357,8358],{},"Controllers/AccountsController.cs",[2976,8360,8362],{"className":3991,"code":8361,"language":3993,"meta":2981,"style":2981},"using Microsoft.AspNetCore.Mvc;\nusing Microsoft.EntityFrameworkCore;\nusing BankingApi.Data;\nusing BankingApi.Models;\nusing BankingApi.Exceptions;\n\nnamespace BankingApi.Controllers;\n\n[ApiController]\n[Route(\"api/[controller]\")]\npublic class AccountsController : ControllerBase\n{\n    private readonly BankingDbContext _db;\n    private readonly ILogger\u003CAccountsController> _logger;\n\n    public AccountsController(BankingDbContext db, ILogger\u003CAccountsController> logger)\n    {\n        _db = db;\n        _logger = logger;\n    }\n\n    /// \u003Csummary>\n    /// Отримати рахунок за номером\n    /// \u003C/summary>\n    [HttpGet(\"{accountNumber}\")]\n    [ProducesResponseType(typeof(Account), StatusCodes.Status200OK)]\n    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]\n    public async Task\u003CActionResult\u003CAccount>> GetByAccountNumber(string accountNumber)\n    {\n        var account = await _db.Accounts\n            .FirstOrDefaultAsync(a => a.AccountNumber == accountNumber);\n\n        if (account is null)\n        {\n            // Кидаємо кастомний виняток - GlobalExceptionHandler обробить\n            throw new AccountNotFoundException(accountNumber);\n        }\n\n        return account;\n    }\n\n    /// \u003Csummary>\n    /// Переказ коштів між рахунками\n    /// \u003C/summary>\n    [HttpPost(\"transfer\")]\n    [ProducesResponseType(StatusCodes.Status200OK)]\n    [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]\n    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]\n    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)]\n    public async Task\u003CIActionResult> Transfer(TransferRequest request)\n    {\n        _logger.LogInformation(\n            \"Transfer request: {From} -> {To}, Amount: {Amount}\",\n            request.FromAccountNumber,\n            request.ToAccountNumber,\n            request.Amount);\n\n        // Валідація: не можна переказувати на той самий рахунок\n        if (request.FromAccountNumber == request.ToAccountNumber)\n        {\n            throw new InvalidTransactionException(\n                \"Cannot transfer to the same account\");\n        }\n\n        // Знаходимо рахунки\n        var fromAccount = await _db.Accounts\n            .FirstOrDefaultAsync(a => a.AccountNumber == request.FromAccountNumber);\n\n        if (fromAccount is null)\n        {\n            throw new AccountNotFoundException(request.FromAccountNumber);\n        }\n\n        var toAccount = await _db.Accounts\n            .FirstOrDefaultAsync(a => a.AccountNumber == request.ToAccountNumber);\n\n        if (toAccount is null)\n        {\n            throw new AccountNotFoundException(request.ToAccountNumber);\n        }\n\n        // Перевірка: чи не заблокований рахунок\n        if (fromAccount.IsLocked)\n        {\n            throw new AccountLockedException(\n                fromAccount.LockReason ?? \"Account is locked\");\n        }\n\n        // Перевірка: чи достатньо коштів\n        if (fromAccount.Balance \u003C request.Amount)\n        {\n            throw new InsufficientFundsException(\n                fromAccount.Balance,\n                request.Amount,\n                fromAccount.Currency);\n        }\n\n        // Виконуємо переказ\n        fromAccount.Balance -= request.Amount;\n        toAccount.Balance += request.Amount;\n\n        await _db.SaveChangesAsync();\n\n        _logger.LogInformation(\n            \"Transfer completed: {From} -> {To}, Amount: {Amount}\",\n            request.FromAccountNumber,\n            request.ToAccountNumber,\n            request.Amount);\n\n        return Ok(new\n        {\n            message = \"Transfer completed successfully\",\n            fromBalance = fromAccount.Balance,\n            toBalance = toAccount.Balance\n        });\n    }\n\n    /// \u003Csummary>\n    /// Заблокувати рахунок\n    /// \u003C/summary>\n    [HttpPost(\"{accountNumber}/lock\")]\n    [ProducesResponseType(StatusCodes.Status200OK)]\n    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]\n    public async Task\u003CIActionResult> LockAccount(\n        string accountNumber,\n        [FromBody] string reason)\n    {\n        var account = await _db.Accounts\n            .FirstOrDefaultAsync(a => a.AccountNumber == accountNumber);\n\n        if (account is null)\n        {\n            throw new AccountNotFoundException(accountNumber);\n        }\n\n        account.IsLocked = true;\n        account.LockReason = reason;\n\n        await _db.SaveChangesAsync();\n\n        return Ok(new { message = \"Account locked successfully\" });\n    }\n}\n",[2983,8363,8364,8380,8392,8404,8416,8428,8432,8445,8449,8458,8472,8486,8490,8504,8523,8527,8554,8558,8570,8580,8584,8588,8603,8608,8619,8633,8661,8685,8718,8722,8740,8770,8774,8791,8795,8800,8816,8820,8824,8832,8836,8840,8850,8855,8865,8879,8895,8919,8943,8967,8995,8999,9010,9017,9029,9040,9051,9055,9060,9083,9087,9097,9104,9108,9112,9117,9134,9162,9166,9181,9185,9203,9207,9211,9228,9256,9260,9275,9279,9297,9301,9305,9310,9325,9329,9339,9355,9359,9363,9368,9391,9395,9405,9415,9426,9436,9440,9444,9449,9469,9489,9493,9506,9510,9520,9527,9537,9547,9557,9561,9573,9577,9589,9604,9618,9623,9627,9631,9641,9646,9656,9669,9685,9709,9728,9736,9753,9757,9773,9797,9801,9815,9819,9833,9837,9841,9857,9871,9875,9887,9891,9913,9917],{"__ignoreMap":2981},[2986,8365,8366,8368,8370,8372,8374,8376,8378],{"class":2988,"line":2989},[2986,8367,5482],{"class":2999},[2986,8369,6039],{"class":4006},[2986,8371,3028],{"class":3003},[2986,8373,6044],{"class":4006},[2986,8375,3028],{"class":3003},[2986,8377,6066],{"class":4006},[2986,8379,4529],{"class":3003},[2986,8381,8382,8384,8386,8388,8390],{"class":2988,"line":2996},[2986,8383,5482],{"class":2999},[2986,8385,6039],{"class":4006},[2986,8387,3028],{"class":3003},[2986,8389,7716],{"class":4006},[2986,8391,4529],{"class":3003},[2986,8393,8394,8396,8398,8400,8402],{"class":2988,"line":3007},[2986,8395,5482],{"class":2999},[2986,8397,4521],{"class":4006},[2986,8399,3028],{"class":3003},[2986,8401,7729],{"class":4006},[2986,8403,4529],{"class":3003},[2986,8405,8406,8408,8410,8412,8414],{"class":2988,"line":3044},[2986,8407,5482],{"class":2999},[2986,8409,4521],{"class":4006},[2986,8411,3028],{"class":3003},[2986,8413,5512],{"class":4006},[2986,8415,4529],{"class":3003},[2986,8417,8418,8420,8422,8424,8426],{"class":2988,"line":3062},[2986,8419,5482],{"class":2999},[2986,8421,4521],{"class":4006},[2986,8423,3028],{"class":3003},[2986,8425,4526],{"class":4006},[2986,8427,4529],{"class":3003},[2986,8429,8430],{"class":2988,"line":3068},[2986,8431,4535],{"emptyLinePlaceholder":4534},[2986,8433,8434,8436,8438,8440,8443],{"class":2988,"line":3091},[2986,8435,4518],{"class":3010},[2986,8437,4521],{"class":4006},[2986,8439,3028],{"class":3003},[2986,8441,8442],{"class":4006},"Controllers",[2986,8444,4529],{"class":3003},[2986,8446,8447],{"class":2988,"line":3103},[2986,8448,4535],{"emptyLinePlaceholder":4534},[2986,8450,8451,8453,8456],{"class":2988,"line":3126},[2986,8452,6842],{"class":3003},[2986,8454,8455],{"class":4006},"ApiController",[2986,8457,3453],{"class":3003},[2986,8459,8460,8462,8465,8467,8470],{"class":2988,"line":3141},[2986,8461,6842],{"class":3003},[2986,8463,8464],{"class":4006},"Route",[2986,8466,3035],{"class":3003},[2986,8468,8469],{"class":3085},"\"api/[controller]\"",[2986,8471,5579],{"class":3003},[2986,8473,8474,8476,8478,8481,8483],{"class":2988,"line":3161},[2986,8475,4000],{"class":3010},[2986,8477,4003],{"class":3010},[2986,8479,8480],{"class":4006}," AccountsController",[2986,8482,4191],{"class":3003},[2986,8484,8485],{"class":4006},"ControllerBase\n",[2986,8487,8488],{"class":2988,"line":3177},[2986,8489,3293],{"class":3003},[2986,8491,8492,8494,8496,8499,8502],{"class":2988,"line":3197},[2986,8493,6136],{"class":3010},[2986,8495,6139],{"class":3010},[2986,8497,8498],{"class":4006}," BankingDbContext",[2986,8500,8501],{"class":3024}," _db",[2986,8503,4529],{"class":3003},[2986,8505,8506,8508,8510,8512,8514,8517,8519,8521],{"class":2988,"line":3212},[2986,8507,6136],{"class":3010},[2986,8509,6139],{"class":3010},[2986,8511,6142],{"class":4006},[2986,8513,4135],{"class":3003},[2986,8515,8516],{"class":4006},"AccountsController",[2986,8518,6150],{"class":3003},[2986,8520,6153],{"class":3024},[2986,8522,4529],{"class":3003},[2986,8524,8525],{"class":2988,"line":3221},[2986,8526,4535],{"emptyLinePlaceholder":4534},[2986,8528,8529,8531,8533,8535,8537,8539,8541,8544,8546,8548,8550,8552],{"class":2988,"line":3233},[2986,8530,4016],{"class":3010},[2986,8532,8480],{"class":3031},[2986,8534,3035],{"class":3003},[2986,8536,7801],{"class":4006},[2986,8538,8141],{"class":3024},[2986,8540,4140],{"class":3003},[2986,8542,8543],{"class":4006},"ILogger",[2986,8545,4135],{"class":3003},[2986,8547,8516],{"class":4006},[2986,8549,6150],{"class":3003},[2986,8551,6195],{"class":3024},[2986,8553,4651],{"class":3003},[2986,8555,8556],{"class":2988,"line":3239},[2986,8557,4656],{"class":3003},[2986,8559,8560,8563,8565,8568],{"class":2988,"line":4413},[2986,8561,8562],{"class":3024},"        _db",[2986,8564,3018],{"class":3003},[2986,8566,8567],{"class":3024},"db",[2986,8569,4529],{"class":3003},[2986,8571,8572,8574,8576,8578],{"class":2988,"line":4691},[2986,8573,6216],{"class":3024},[2986,8575,3018],{"class":3003},[2986,8577,6195],{"class":3024},[2986,8579,4529],{"class":3003},[2986,8581,8582],{"class":2988,"line":4696},[2986,8583,4373],{"class":3003},[2986,8585,8586],{"class":2988,"line":4702},[2986,8587,4535],{"emptyLinePlaceholder":4534},[2986,8589,8590,8593,8596,8600],{"class":2988,"line":4717},[2986,8591,8592],{"class":2992},"    /// ",[2986,8594,4135],{"class":8595},"s0P7L",[2986,8597,8599],{"class":8598},"sKtos","summary",[2986,8601,8602],{"class":8595},">\n",[2986,8604,8605],{"class":2988,"line":4722},[2986,8606,8607],{"class":2992},"    /// Отримати рахунок за номером\n",[2986,8609,8610,8612,8615,8617],{"class":2988,"line":4738},[2986,8611,8592],{"class":2992},[2986,8613,8614],{"class":8595},"\u003C/",[2986,8616,8599],{"class":8598},[2986,8618,8602],{"class":8595},[2986,8620,8621,8623,8626,8628,8631],{"class":2988,"line":4743},[2986,8622,5559],{"class":3003},[2986,8624,8625],{"class":4006},"HttpGet",[2986,8627,3035],{"class":3003},[2986,8629,8630],{"class":3085},"\"{accountNumber}\"",[2986,8632,5579],{"class":3003},[2986,8634,8635,8637,8640,8642,8644,8646,8649,8652,8654,8656,8659],{"class":2988,"line":4759},[2986,8636,5559],{"class":3003},[2986,8638,8639],{"class":4006},"ProducesResponseType",[2986,8641,3035],{"class":3003},[2986,8643,3076],{"class":3010},[2986,8645,3035],{"class":3003},[2986,8647,8648],{"class":4006},"Account",[2986,8650,8651],{"class":3003},"), ",[2986,8653,7257],{"class":3024},[2986,8655,3028],{"class":3003},[2986,8657,8658],{"class":3024},"Status200OK",[2986,8660,5579],{"class":3003},[2986,8662,8663,8665,8667,8669,8671,8673,8675,8677,8679,8681,8683],{"class":2988,"line":4768},[2986,8664,5559],{"class":3003},[2986,8666,8639],{"class":4006},[2986,8668,3035],{"class":3003},[2986,8670,3076],{"class":3010},[2986,8672,3035],{"class":3003},[2986,8674,3248],{"class":4006},[2986,8676,8651],{"class":3003},[2986,8678,7257],{"class":3024},[2986,8680,3028],{"class":3003},[2986,8682,4797],{"class":3024},[2986,8684,5579],{"class":3003},[2986,8686,8687,8689,8691,8694,8696,8699,8701,8703,8706,8709,8711,8713,8716],{"class":2988,"line":4789},[2986,8688,4016],{"class":3010},[2986,8690,6249],{"class":3010},[2986,8692,8693],{"class":4006}," Task",[2986,8695,4135],{"class":3003},[2986,8697,8698],{"class":4006},"ActionResult",[2986,8700,4135],{"class":3003},[2986,8702,8648],{"class":4006},[2986,8704,8705],{"class":3003},">> ",[2986,8707,8708],{"class":3031},"GetByAccountNumber",[2986,8710,3035],{"class":3003},[2986,8712,3733],{"class":3010},[2986,8714,8715],{"class":3024}," accountNumber",[2986,8717,4651],{"class":3003},[2986,8719,8720],{"class":2988,"line":4802},[2986,8721,4656],{"class":3003},[2986,8723,8724,8726,8729,8731,8733,8735,8737],{"class":2988,"line":4810},[2986,8725,6303],{"class":3010},[2986,8727,8728],{"class":3024}," account",[2986,8730,3018],{"class":3003},[2986,8732,3021],{"class":3010},[2986,8734,8501],{"class":3024},[2986,8736,3028],{"class":3003},[2986,8738,8739],{"class":3024},"Accounts\n",[2986,8741,8742,8745,8748,8750,8753,8755,8757,8759,8762,8765,8768],{"class":2988,"line":4815},[2986,8743,8744],{"class":3003},"            .",[2986,8746,8747],{"class":3031},"FirstOrDefaultAsync",[2986,8749,3035],{"class":3003},[2986,8751,8752],{"class":3024},"a",[2986,8754,6422],{"class":3003},[2986,8756,8752],{"class":3024},[2986,8758,3028],{"class":3003},[2986,8760,8761],{"class":3024},"AccountNumber",[2986,8763,8764],{"class":3003}," == ",[2986,8766,8767],{"class":3024},"accountNumber",[2986,8769,3041],{"class":3003},[2986,8771,8772],{"class":2988,"line":4827},[2986,8773,4535],{"emptyLinePlaceholder":4534},[2986,8775,8776,8778,8780,8783,8786,8789],{"class":2988,"line":4832},[2986,8777,7488],{"class":2999},[2986,8779,3053],{"class":3003},[2986,8781,8782],{"class":3024},"account",[2986,8784,8785],{"class":3010}," is",[2986,8787,8788],{"class":3010}," null",[2986,8790,4651],{"class":3003},[2986,8792,8793],{"class":2988,"line":4837},[2986,8794,6406],{"class":3003},[2986,8796,8797],{"class":2988,"line":4842},[2986,8798,8799],{"class":2992},"            // Кидаємо кастомний виняток - GlobalExceptionHandler обробить\n",[2986,8801,8802,8805,8808,8810,8812,8814],{"class":2988,"line":4848},[2986,8803,8804],{"class":2999},"            throw",[2986,8806,8807],{"class":3010}," new",[2986,8809,4709],{"class":4006},[2986,8811,3035],{"class":3003},[2986,8813,8767],{"class":3024},[2986,8815,3041],{"class":3003},[2986,8817,8818],{"class":2988,"line":4862},[2986,8819,7137],{"class":3003},[2986,8821,8822],{"class":2988,"line":4867},[2986,8823,4535],{"emptyLinePlaceholder":4534},[2986,8825,8826,8828,8830],{"class":2988,"line":4884},[2986,8827,6631],{"class":2999},[2986,8829,8728],{"class":3024},[2986,8831,4529],{"class":3003},[2986,8833,8834],{"class":2988,"line":4900},[2986,8835,4373],{"class":3003},[2986,8837,8838],{"class":2988,"line":4916},[2986,8839,4535],{"emptyLinePlaceholder":4534},[2986,8841,8842,8844,8846,8848],{"class":2988,"line":4921},[2986,8843,8592],{"class":2992},[2986,8845,4135],{"class":8595},[2986,8847,8599],{"class":8598},[2986,8849,8602],{"class":8595},[2986,8851,8852],{"class":2988,"line":4930},[2986,8853,8854],{"class":2992},"    /// Переказ коштів між рахунками\n",[2986,8856,8857,8859,8861,8863],{"class":2988,"line":4941},[2986,8858,8592],{"class":2992},[2986,8860,8614],{"class":8595},[2986,8862,8599],{"class":8598},[2986,8864,8602],{"class":8595},[2986,8866,8867,8869,8872,8874,8877],{"class":2988,"line":4951},[2986,8868,5559],{"class":3003},[2986,8870,8871],{"class":4006},"HttpPost",[2986,8873,3035],{"class":3003},[2986,8875,8876],{"class":3085},"\"transfer\"",[2986,8878,5579],{"class":3003},[2986,8880,8881,8883,8885,8887,8889,8891,8893],{"class":2988,"line":4965},[2986,8882,5559],{"class":3003},[2986,8884,8639],{"class":4006},[2986,8886,3035],{"class":3003},[2986,8888,7257],{"class":3024},[2986,8890,3028],{"class":3003},[2986,8892,8658],{"class":3024},[2986,8894,5579],{"class":3003},[2986,8896,8897,8899,8901,8903,8905,8907,8909,8911,8913,8915,8917],{"class":2988,"line":4974},[2986,8898,5559],{"class":3003},[2986,8900,8639],{"class":4006},[2986,8902,3035],{"class":3003},[2986,8904,3076],{"class":3010},[2986,8906,3035],{"class":3003},[2986,8908,4170],{"class":4006},[2986,8910,8651],{"class":3003},[2986,8912,7257],{"class":3024},[2986,8914,3028],{"class":3003},[2986,8916,5382],{"class":3024},[2986,8918,5579],{"class":3003},[2986,8920,8921,8923,8925,8927,8929,8931,8933,8935,8937,8939,8941],{"class":2988,"line":5025},[2986,8922,5559],{"class":3003},[2986,8924,8639],{"class":4006},[2986,8926,3035],{"class":3003},[2986,8928,3076],{"class":3010},[2986,8930,3035],{"class":3003},[2986,8932,3248],{"class":4006},[2986,8934,8651],{"class":3003},[2986,8936,7257],{"class":3024},[2986,8938,3028],{"class":3003},[2986,8940,4797],{"class":3024},[2986,8942,5579],{"class":3003},[2986,8944,8945,8947,8949,8951,8953,8955,8957,8959,8961,8963,8965],{"class":2988,"line":5037},[2986,8946,5559],{"class":3003},[2986,8948,8639],{"class":4006},[2986,8950,3035],{"class":3003},[2986,8952,3076],{"class":3010},[2986,8954,3035],{"class":3003},[2986,8956,3248],{"class":4006},[2986,8958,8651],{"class":3003},[2986,8960,7257],{"class":3024},[2986,8962,3028],{"class":3003},[2986,8964,5032],{"class":3024},[2986,8966,5579],{"class":3003},[2986,8968,8969,8971,8973,8975,8977,8980,8982,8985,8987,8990,8993],{"class":2988,"line":5045},[2986,8970,4016],{"class":3010},[2986,8972,6249],{"class":3010},[2986,8974,8693],{"class":4006},[2986,8976,4135],{"class":3003},[2986,8978,8979],{"class":4006},"IActionResult",[2986,8981,6150],{"class":3003},[2986,8983,8984],{"class":3031},"Transfer",[2986,8986,3035],{"class":3003},[2986,8988,8989],{"class":4006},"TransferRequest",[2986,8991,8992],{"class":3024}," request",[2986,8994,4651],{"class":3003},[2986,8996,8997],{"class":2988,"line":5050},[2986,8998,4656],{"class":3003},[2986,9000,9001,9003,9005,9008],{"class":2988,"line":5062},[2986,9002,6216],{"class":3024},[2986,9004,3028],{"class":3003},[2986,9006,9007],{"class":3031},"LogInformation",[2986,9009,4605],{"class":3003},[2986,9011,9012,9015],{"class":2988,"line":5074},[2986,9013,9014],{"class":3085},"            \"Transfer request: {From} -> {To}, Amount: {Amount}\"",[2986,9016,3308],{"class":3003},[2986,9018,9019,9022,9024,9027],{"class":2988,"line":5086},[2986,9020,9021],{"class":3024},"            request",[2986,9023,3028],{"class":3003},[2986,9025,9026],{"class":3024},"FromAccountNumber",[2986,9028,3308],{"class":3003},[2986,9030,9031,9033,9035,9038],{"class":2988,"line":5091},[2986,9032,9021],{"class":3024},[2986,9034,3028],{"class":3003},[2986,9036,9037],{"class":3024},"ToAccountNumber",[2986,9039,3308],{"class":3003},[2986,9041,9042,9044,9046,9049],{"class":2988,"line":5096},[2986,9043,9021],{"class":3024},[2986,9045,3028],{"class":3003},[2986,9047,9048],{"class":3024},"Amount",[2986,9050,3041],{"class":3003},[2986,9052,9053],{"class":2988,"line":5101},[2986,9054,4535],{"emptyLinePlaceholder":4534},[2986,9056,9057],{"class":2988,"line":5107},[2986,9058,9059],{"class":2992},"        // Валідація: не можна переказувати на той самий рахунок\n",[2986,9061,9062,9064,9066,9069,9071,9073,9075,9077,9079,9081],{"class":2988,"line":5121},[2986,9063,7488],{"class":2999},[2986,9065,3053],{"class":3003},[2986,9067,9068],{"class":3024},"request",[2986,9070,3028],{"class":3003},[2986,9072,9026],{"class":3024},[2986,9074,8764],{"class":3003},[2986,9076,9068],{"class":3024},[2986,9078,3028],{"class":3003},[2986,9080,9037],{"class":3024},[2986,9082,4651],{"class":3003},[2986,9084,9085],{"class":2988,"line":5126},[2986,9086,6406],{"class":3003},[2986,9088,9089,9091,9093,9095],{"class":2988,"line":5142},[2986,9090,8804],{"class":2999},[2986,9092,8807],{"class":3010},[2986,9094,5300],{"class":4006},[2986,9096,4605],{"class":3003},[2986,9098,9099,9102],{"class":2988,"line":5161},[2986,9100,9101],{"class":3085},"                \"Cannot transfer to the same account\"",[2986,9103,3041],{"class":3003},[2986,9105,9106],{"class":2988,"line":5166},[2986,9107,7137],{"class":3003},[2986,9109,9110],{"class":2988,"line":5197},[2986,9111,4535],{"emptyLinePlaceholder":4534},[2986,9113,9114],{"class":2988,"line":5206},[2986,9115,9116],{"class":2992},"        // Знаходимо рахунки\n",[2986,9118,9119,9121,9124,9126,9128,9130,9132],{"class":2988,"line":5224},[2986,9120,6303],{"class":3010},[2986,9122,9123],{"class":3024}," fromAccount",[2986,9125,3018],{"class":3003},[2986,9127,3021],{"class":3010},[2986,9129,8501],{"class":3024},[2986,9131,3028],{"class":3003},[2986,9133,8739],{"class":3024},[2986,9135,9136,9138,9140,9142,9144,9146,9148,9150,9152,9154,9156,9158,9160],{"class":2988,"line":5235},[2986,9137,8744],{"class":3003},[2986,9139,8747],{"class":3031},[2986,9141,3035],{"class":3003},[2986,9143,8752],{"class":3024},[2986,9145,6422],{"class":3003},[2986,9147,8752],{"class":3024},[2986,9149,3028],{"class":3003},[2986,9151,8761],{"class":3024},[2986,9153,8764],{"class":3003},[2986,9155,9068],{"class":3024},[2986,9157,3028],{"class":3003},[2986,9159,9026],{"class":3024},[2986,9161,3041],{"class":3003},[2986,9163,9164],{"class":2988,"line":5243},[2986,9165,4535],{"emptyLinePlaceholder":4534},[2986,9167,9168,9170,9172,9175,9177,9179],{"class":2988,"line":5248},[2986,9169,7488],{"class":2999},[2986,9171,3053],{"class":3003},[2986,9173,9174],{"class":3024},"fromAccount",[2986,9176,8785],{"class":3010},[2986,9178,8788],{"class":3010},[2986,9180,4651],{"class":3003},[2986,9182,9183],{"class":2988,"line":5260},[2986,9184,6406],{"class":3003},[2986,9186,9187,9189,9191,9193,9195,9197,9199,9201],{"class":2988,"line":5272},[2986,9188,8804],{"class":2999},[2986,9190,8807],{"class":3010},[2986,9192,4709],{"class":4006},[2986,9194,3035],{"class":3003},[2986,9196,9068],{"class":3024},[2986,9198,3028],{"class":3003},[2986,9200,9026],{"class":3024},[2986,9202,3041],{"class":3003},[2986,9204,9205],{"class":2988,"line":5277},[2986,9206,7137],{"class":3003},[2986,9208,9209],{"class":2988,"line":5282},[2986,9210,4535],{"emptyLinePlaceholder":4534},[2986,9212,9213,9215,9218,9220,9222,9224,9226],{"class":2988,"line":5287},[2986,9214,6303],{"class":3010},[2986,9216,9217],{"class":3024}," toAccount",[2986,9219,3018],{"class":3003},[2986,9221,3021],{"class":3010},[2986,9223,8501],{"class":3024},[2986,9225,3028],{"class":3003},[2986,9227,8739],{"class":3024},[2986,9229,9230,9232,9234,9236,9238,9240,9242,9244,9246,9248,9250,9252,9254],{"class":2988,"line":5293},[2986,9231,8744],{"class":3003},[2986,9233,8747],{"class":3031},[2986,9235,3035],{"class":3003},[2986,9237,8752],{"class":3024},[2986,9239,6422],{"class":3003},[2986,9241,8752],{"class":3024},[2986,9243,3028],{"class":3003},[2986,9245,8761],{"class":3024},[2986,9247,8764],{"class":3003},[2986,9249,9068],{"class":3024},[2986,9251,3028],{"class":3003},[2986,9253,9037],{"class":3024},[2986,9255,3041],{"class":3003},[2986,9257,9258],{"class":2988,"line":5307},[2986,9259,4535],{"emptyLinePlaceholder":4534},[2986,9261,9262,9264,9266,9269,9271,9273],{"class":2988,"line":5312},[2986,9263,7488],{"class":2999},[2986,9265,3053],{"class":3003},[2986,9267,9268],{"class":3024},"toAccount",[2986,9270,8785],{"class":3010},[2986,9272,8788],{"class":3010},[2986,9274,4651],{"class":3003},[2986,9276,9277],{"class":2988,"line":5328},[2986,9278,6406],{"class":3003},[2986,9280,9281,9283,9285,9287,9289,9291,9293,9295],{"class":2988,"line":5333},[2986,9282,8804],{"class":2999},[2986,9284,8807],{"class":3010},[2986,9286,4709],{"class":4006},[2986,9288,3035],{"class":3003},[2986,9290,9068],{"class":3024},[2986,9292,3028],{"class":3003},[2986,9294,9037],{"class":3024},[2986,9296,3041],{"class":3003},[2986,9298,9299],{"class":2988,"line":5349},[2986,9300,7137],{"class":3003},[2986,9302,9303],{"class":2988,"line":5358},[2986,9304,4535],{"emptyLinePlaceholder":4534},[2986,9306,9307],{"class":2988,"line":5375},[2986,9308,9309],{"class":2992},"        // Перевірка: чи не заблокований рахунок\n",[2986,9311,9312,9314,9316,9318,9320,9323],{"class":2988,"line":5387},[2986,9313,7488],{"class":2999},[2986,9315,3053],{"class":3003},[2986,9317,9174],{"class":3024},[2986,9319,3028],{"class":3003},[2986,9321,9322],{"class":3024},"IsLocked",[2986,9324,4651],{"class":3003},[2986,9326,9327],{"class":2988,"line":5395},[2986,9328,6406],{"class":3003},[2986,9330,9331,9333,9335,9337],{"class":2988,"line":5400},[2986,9332,8804],{"class":2999},[2986,9334,8807],{"class":3010},[2986,9336,5114],{"class":4006},[2986,9338,4605],{"class":3003},[2986,9340,9341,9344,9346,9348,9350,9353],{"class":2988,"line":5412},[2986,9342,9343],{"class":3024},"                fromAccount",[2986,9345,3028],{"class":3003},[2986,9347,5772],{"class":3024},[2986,9349,6325],{"class":3003},[2986,9351,9352],{"class":3085},"\"Account is locked\"",[2986,9354,3041],{"class":3003},[2986,9356,9357],{"class":2988,"line":5417},[2986,9358,7137],{"class":3003},[2986,9360,9361],{"class":2988,"line":6972},[2986,9362,4535],{"emptyLinePlaceholder":4534},[2986,9364,9365],{"class":2988,"line":6977},[2986,9366,9367],{"class":2992},"        // Перевірка: чи достатньо коштів\n",[2986,9369,9370,9372,9374,9376,9378,9380,9383,9385,9387,9389],{"class":2988,"line":6989},[2986,9371,7488],{"class":2999},[2986,9373,3053],{"class":3003},[2986,9375,9174],{"class":3024},[2986,9377,3028],{"class":3003},[2986,9379,5456],{"class":3024},[2986,9381,9382],{"class":3003}," \u003C ",[2986,9384,9068],{"class":3024},[2986,9386,3028],{"class":3003},[2986,9388,9048],{"class":3024},[2986,9390,4651],{"class":3003},[2986,9392,9393],{"class":2988,"line":7014},[2986,9394,6406],{"class":3003},[2986,9396,9397,9399,9401,9403],{"class":2988,"line":7035},[2986,9398,8804],{"class":2999},[2986,9400,8807],{"class":3010},[2986,9402,4855],{"class":4006},[2986,9404,4605],{"class":3003},[2986,9406,9407,9409,9411,9413],{"class":2988,"line":7041},[2986,9408,9343],{"class":3024},[2986,9410,3028],{"class":3003},[2986,9412,5456],{"class":3024},[2986,9414,3308],{"class":3003},[2986,9416,9417,9420,9422,9424],{"class":2988,"line":7071},[2986,9418,9419],{"class":3024},"                request",[2986,9421,3028],{"class":3003},[2986,9423,9048],{"class":3024},[2986,9425,3308],{"class":3003},[2986,9427,9428,9430,9432,9434],{"class":2988,"line":7077},[2986,9429,9343],{"class":3024},[2986,9431,3028],{"class":3003},[2986,9433,6960],{"class":3024},[2986,9435,3041],{"class":3003},[2986,9437,9438],{"class":2988,"line":7084},[2986,9439,7137],{"class":3003},[2986,9441,9442],{"class":2988,"line":7089},[2986,9443,4535],{"emptyLinePlaceholder":4534},[2986,9445,9446],{"class":2988,"line":7101},[2986,9447,9448],{"class":2992},"        // Виконуємо переказ\n",[2986,9450,9451,9454,9456,9458,9461,9463,9465,9467],{"class":2988,"line":7127},[2986,9452,9453],{"class":3024},"        fromAccount",[2986,9455,3028],{"class":3003},[2986,9457,5456],{"class":3024},[2986,9459,9460],{"class":3003}," -= ",[2986,9462,9068],{"class":3024},[2986,9464,3028],{"class":3003},[2986,9466,9048],{"class":3024},[2986,9468,4529],{"class":3003},[2986,9470,9471,9474,9476,9478,9481,9483,9485,9487],{"class":2988,"line":7134},[2986,9472,9473],{"class":3024},"        toAccount",[2986,9475,3028],{"class":3003},[2986,9477,5456],{"class":3024},[2986,9479,9480],{"class":3003}," += ",[2986,9482,9068],{"class":3024},[2986,9484,3028],{"class":3003},[2986,9486,9048],{"class":3024},[2986,9488,4529],{"class":3003},[2986,9490,9491],{"class":2988,"line":7140},[2986,9492,4535],{"emptyLinePlaceholder":4534},[2986,9494,9495,9497,9499,9501,9504],{"class":2988,"line":7145},[2986,9496,6600],{"class":3010},[2986,9498,8501],{"class":3024},[2986,9500,3028],{"class":3003},[2986,9502,9503],{"class":3031},"SaveChangesAsync",[2986,9505,8041],{"class":3003},[2986,9507,9508],{"class":2988,"line":7154},[2986,9509,4535],{"emptyLinePlaceholder":4534},[2986,9511,9512,9514,9516,9518],{"class":2988,"line":7159},[2986,9513,6216],{"class":3024},[2986,9515,3028],{"class":3003},[2986,9517,9007],{"class":3031},[2986,9519,4605],{"class":3003},[2986,9521,9522,9525],{"class":2988,"line":7164},[2986,9523,9524],{"class":3085},"            \"Transfer completed: {From} -> {To}, Amount: {Amount}\"",[2986,9526,3308],{"class":3003},[2986,9528,9529,9531,9533,9535],{"class":2988,"line":7176},[2986,9530,9021],{"class":3024},[2986,9532,3028],{"class":3003},[2986,9534,9026],{"class":3024},[2986,9536,3308],{"class":3003},[2986,9538,9539,9541,9543,9545],{"class":2988,"line":7186},[2986,9540,9021],{"class":3024},[2986,9542,3028],{"class":3003},[2986,9544,9037],{"class":3024},[2986,9546,3308],{"class":3003},[2986,9548,9549,9551,9553,9555],{"class":2988,"line":7195},[2986,9550,9021],{"class":3024},[2986,9552,3028],{"class":3003},[2986,9554,9048],{"class":3024},[2986,9556,3041],{"class":3003},[2986,9558,9559],{"class":2988,"line":7204},[2986,9560,4535],{"emptyLinePlaceholder":4534},[2986,9562,9563,9565,9568,9570],{"class":2988,"line":7209},[2986,9564,6631],{"class":2999},[2986,9566,9567],{"class":3031}," Ok",[2986,9569,3035],{"class":3003},[2986,9571,9572],{"class":3010},"new\n",[2986,9574,9575],{"class":2988,"line":7223},[2986,9576,6406],{"class":3003},[2986,9578,9579,9582,9584,9587],{"class":2988,"line":7228},[2986,9580,9581],{"class":3024},"            message",[2986,9583,3018],{"class":3003},[2986,9585,9586],{"class":3085},"\"Transfer completed successfully\"",[2986,9588,3308],{"class":3003},[2986,9590,9591,9594,9596,9598,9600,9602],{"class":2988,"line":7239},[2986,9592,9593],{"class":3024},"            fromBalance",[2986,9595,3018],{"class":3003},[2986,9597,9174],{"class":3024},[2986,9599,3028],{"class":3003},[2986,9601,5456],{"class":3024},[2986,9603,3308],{"class":3003},[2986,9605,9606,9609,9611,9613,9615],{"class":2988,"line":7250},[2986,9607,9608],{"class":3024},"            toBalance",[2986,9610,3018],{"class":3003},[2986,9612,9268],{"class":3024},[2986,9614,3028],{"class":3003},[2986,9616,9617],{"class":3024},"Balance\n",[2986,9619,9620],{"class":2988,"line":7266},[2986,9621,9622],{"class":3003},"        });\n",[2986,9624,9625],{"class":2988,"line":7281},[2986,9626,4373],{"class":3003},[2986,9628,9629],{"class":2988,"line":7298},[2986,9630,4535],{"emptyLinePlaceholder":4534},[2986,9632,9633,9635,9637,9639],{"class":2988,"line":7303},[2986,9634,8592],{"class":2992},[2986,9636,4135],{"class":8595},[2986,9638,8599],{"class":8598},[2986,9640,8602],{"class":8595},[2986,9642,9643],{"class":2988,"line":7308},[2986,9644,9645],{"class":2992},"    /// Заблокувати рахунок\n",[2986,9647,9648,9650,9652,9654],{"class":2988,"line":7327},[2986,9649,8592],{"class":2992},[2986,9651,8614],{"class":8595},[2986,9653,8599],{"class":8598},[2986,9655,8602],{"class":8595},[2986,9657,9658,9660,9662,9664,9667],{"class":2988,"line":7332},[2986,9659,5559],{"class":3003},[2986,9661,8871],{"class":4006},[2986,9663,3035],{"class":3003},[2986,9665,9666],{"class":3085},"\"{accountNumber}/lock\"",[2986,9668,5579],{"class":3003},[2986,9670,9671,9673,9675,9677,9679,9681,9683],{"class":2988,"line":7341},[2986,9672,5559],{"class":3003},[2986,9674,8639],{"class":4006},[2986,9676,3035],{"class":3003},[2986,9678,7257],{"class":3024},[2986,9680,3028],{"class":3003},[2986,9682,8658],{"class":3024},[2986,9684,5579],{"class":3003},[2986,9686,9687,9689,9691,9693,9695,9697,9699,9701,9703,9705,9707],{"class":2988,"line":7346},[2986,9688,5559],{"class":3003},[2986,9690,8639],{"class":4006},[2986,9692,3035],{"class":3003},[2986,9694,3076],{"class":3010},[2986,9696,3035],{"class":3003},[2986,9698,3248],{"class":4006},[2986,9700,8651],{"class":3003},[2986,9702,7257],{"class":3024},[2986,9704,3028],{"class":3003},[2986,9706,4797],{"class":3024},[2986,9708,5579],{"class":3003},[2986,9710,9711,9713,9715,9717,9719,9721,9723,9726],{"class":2988,"line":7351},[2986,9712,4016],{"class":3010},[2986,9714,6249],{"class":3010},[2986,9716,8693],{"class":4006},[2986,9718,4135],{"class":3003},[2986,9720,8979],{"class":4006},[2986,9722,6150],{"class":3003},[2986,9724,9725],{"class":3031},"LockAccount",[2986,9727,4605],{"class":3003},[2986,9729,9730,9732,9734],{"class":2988,"line":7363},[2986,9731,4610],{"class":3010},[2986,9733,8715],{"class":3024},[2986,9735,3308],{"class":3003},[2986,9737,9738,9741,9744,9747,9749,9751],{"class":2988,"line":7372},[2986,9739,9740],{"class":3003},"        [",[2986,9742,9743],{"class":4006},"FromBody",[2986,9745,9746],{"class":3003},"] ",[2986,9748,3733],{"class":3010},[2986,9750,5177],{"class":3024},[2986,9752,4651],{"class":3003},[2986,9754,9755],{"class":2988,"line":7381},[2986,9756,4656],{"class":3003},[2986,9758,9759,9761,9763,9765,9767,9769,9771],{"class":2988,"line":7390},[2986,9760,6303],{"class":3010},[2986,9762,8728],{"class":3024},[2986,9764,3018],{"class":3003},[2986,9766,3021],{"class":3010},[2986,9768,8501],{"class":3024},[2986,9770,3028],{"class":3003},[2986,9772,8739],{"class":3024},[2986,9774,9775,9777,9779,9781,9783,9785,9787,9789,9791,9793,9795],{"class":2988,"line":7395},[2986,9776,8744],{"class":3003},[2986,9778,8747],{"class":3031},[2986,9780,3035],{"class":3003},[2986,9782,8752],{"class":3024},[2986,9784,6422],{"class":3003},[2986,9786,8752],{"class":3024},[2986,9788,3028],{"class":3003},[2986,9790,8761],{"class":3024},[2986,9792,8764],{"class":3003},[2986,9794,8767],{"class":3024},[2986,9796,3041],{"class":3003},[2986,9798,9799],{"class":2988,"line":7408},[2986,9800,4535],{"emptyLinePlaceholder":4534},[2986,9802,9803,9805,9807,9809,9811,9813],{"class":2988,"line":7413},[2986,9804,7488],{"class":2999},[2986,9806,3053],{"class":3003},[2986,9808,8782],{"class":3024},[2986,9810,8785],{"class":3010},[2986,9812,8788],{"class":3010},[2986,9814,4651],{"class":3003},[2986,9816,9817],{"class":2988,"line":7424},[2986,9818,6406],{"class":3003},[2986,9820,9821,9823,9825,9827,9829,9831],{"class":2988,"line":7436},[2986,9822,8804],{"class":2999},[2986,9824,8807],{"class":3010},[2986,9826,4709],{"class":4006},[2986,9828,3035],{"class":3003},[2986,9830,8767],{"class":3024},[2986,9832,3041],{"class":3003},[2986,9834,9835],{"class":2988,"line":7452},[2986,9836,7137],{"class":3003},[2986,9838,9839],{"class":2988,"line":7469},[2986,9840,4535],{"emptyLinePlaceholder":4534},[2986,9842,9843,9846,9848,9850,9852,9855],{"class":2988,"line":7474},[2986,9844,9845],{"class":3024},"        account",[2986,9847,3028],{"class":3003},[2986,9849,9322],{"class":3024},[2986,9851,3018],{"class":3003},[2986,9853,9854],{"class":3010},"true",[2986,9856,4529],{"class":3003},[2986,9858,9859,9861,9863,9865,9867,9869],{"class":2988,"line":7479},[2986,9860,9845],{"class":3024},[2986,9862,3028],{"class":3003},[2986,9864,5772],{"class":3024},[2986,9866,3018],{"class":3003},[2986,9868,5214],{"class":3024},[2986,9870,4529],{"class":3003},[2986,9872,9873],{"class":2988,"line":7485},[2986,9874,4535],{"emptyLinePlaceholder":4534},[2986,9876,9877,9879,9881,9883,9885],{"class":2988,"line":7504},[2986,9878,6600],{"class":3010},[2986,9880,8501],{"class":3024},[2986,9882,3028],{"class":3003},[2986,9884,9503],{"class":3031},[2986,9886,8041],{"class":3003},[2986,9888,9889],{"class":2988,"line":7509},[2986,9890,4535],{"emptyLinePlaceholder":4534},[2986,9892,9893,9895,9897,9899,9901,9903,9905,9907,9910],{"class":2988,"line":7529},[2986,9894,6631],{"class":2999},[2986,9896,9567],{"class":3031},[2986,9898,3035],{"class":3003},[2986,9900,6700],{"class":3010},[2986,9902,4028],{"class":3003},[2986,9904,3121],{"class":3024},[2986,9906,3018],{"class":3003},[2986,9908,9909],{"class":3085},"\"Account locked successfully\"",[2986,9911,9912],{"class":3003}," });\n",[2986,9914,9915],{"class":2988,"line":7554},[2986,9916,4373],{"class":3003},[2986,9918,9919],{"class":2988,"line":7559},[2986,9920,3242],{"class":3003},[2964,9922,9923],{},[2971,9924,8314],{},[5426,9926,9927,9935,9941,9947],{},[3574,9928,9929,5453,9932],{},[2971,9930,9931],{},"Кидаємо винятки замість повернення результатів",[2983,9933,9934],{},"throw new AccountNotFoundException()",[3574,9936,9937,9940],{},[2971,9938,9939],{},"GlobalExceptionHandler автоматично обробляє"," — перетворює у ProblemDetails",[3574,9942,9943,9946],{},[2971,9944,9945],{},"Бізнес-логіка чиста"," — не захаращена обробкою помилок",[3574,9948,9949,9951],{},[2971,9950,7671],{}," — важливі операції логуються для аудиту",[3597,9953],{},[3262,9955,9957],{"id":9956},"крок-4-тестування-обробки-помилок","Крок 4: Тестування обробки помилок",[4441,9959,9960,9970,9977,9980,9987,9997,10003,10016,10027,10035,10046,10056,10066,10072,10075,10082,10092,10099,10106,10112,10121,10131,10138,10145,10152,10161,10167,10170,10177,10186,10192,10199,10205,10214,10223,10230,10240,10252,10263,10269],{"title":4443},[4445,9961,9963,4453,9966],{"className":9962},[2988],[2986,9964,4452],{"className":9965},[4451],[2971,9967,9969],{"className":9968},[4457],"dotnet run",[4445,9971,9973,9976],{"className":9972},[2988],[2986,9974,4497],{"className":9975},[4465,4457],": Now listening on: https://localhost:5001",[4445,9978],{"className":9979},[2988],[4445,9981,9983],{"className":9982},[2988],[2986,9984,9986],{"className":9985},[4451],"# Тест 1: Account Not Found (404)",[4445,9988,9990,4453,9993],{"className":9989},[2988],[2986,9991,4452],{"className":9992},[4451],[2971,9994,9996],{"className":9995},[4457],"curl https://localhost:5001/api/accounts/INVALID123",[4445,9998,10000],{"className":9999},[2988],[2986,10001,4775],{"className":10002},[4496],[4445,10004,10006,10007,3302,10011,10015],{"className":10005},[2988],"  ",[2986,10008,10010],{"className":10009},[4465],"\"type\"",[2986,10012,3305],{"className":10013},[10014],"text-yellow-400",",",[4445,10017,10006,10019,3302,10023,10015],{"className":10018},[2988],[2986,10020,10022],{"className":10021},[4465],"\"title\"",[2986,10024,10026],{"className":10025},[10014],"\"AccountNotFound\"",[4445,10028,10006,10030,10034],{"className":10029},[2988],[2986,10031,10033],{"className":10032},[4465],"\"status\"",": 404,",[4445,10036,10006,10038,3302,10042,10015],{"className":10037},[2988],[2986,10039,10041],{"className":10040},[4465],"\"detail\"",[2986,10043,10045],{"className":10044},[10014],"\"Account with ID 'INVALID123' does not exist\"",[4445,10047,10006,10049,3302,10052,10015],{"className":10048},[2988],[2986,10050,7112],{"className":10051},[4465],[2986,10053,10055],{"className":10054},[10014],"\"INVALID123\"",[4445,10057,10006,10059,3302,10062],{"className":10058},[2988],[2986,10060,6845],{"className":10061},[4465],[2986,10063,10065],{"className":10064},[10014],"\"00-a1b2c3d4e5f6-7890abcdef-00\"",[4445,10067,10069],{"className":10068},[2988],[2986,10070,4781],{"className":10071},[4496],[4445,10073],{"className":10074},[2988],[4445,10076,10078],{"className":10077},[2988],[2986,10079,10081],{"className":10080},[4451],"# Тест 2: Insufficient Funds (409)",[4445,10083,10085,4453,10088],{"className":10084},[2988],[2986,10086,4452],{"className":10087},[4451],[2971,10089,10091],{"className":10090},[4457],"curl -X POST https://localhost:5001/api/accounts/transfer \\",[4445,10093,10006,10095],{"className":10094},[2988],[2971,10096,10098],{"className":10097},[4457],"-H \"Content-Type: application/json\" \\",[4445,10100,10006,10102],{"className":10101},[2988],[2971,10103,10105],{"className":10104},[4457],"-d '{\"fromAccountNumber\":\"ACC001\",\"toAccountNumber\":\"ACC002\",\"amount\":5000}'",[4445,10107,10109],{"className":10108},[2988],[2986,10110,4775],{"className":10111},[4496],[4445,10113,10006,10115,3302,10118,10015],{"className":10114},[2988],[2986,10116,10010],{"className":10117},[4465],[2986,10119,3494],{"className":10120},[10014],[4445,10122,10006,10124,3302,10127,10015],{"className":10123},[2988],[2986,10125,10022],{"className":10126},[4465],[2986,10128,10130],{"className":10129},[10014],"\"InsufficientFunds\"",[4445,10132,10006,10134,10137],{"className":10133},[2988],[2986,10135,10033],{"className":10136},[4465],": 409,",[4445,10139,10006,10141,10144],{"className":10140},[2988],[2986,10142,6904],{"className":10143},[4465],": 100.00,",[4445,10146,10006,10148,10151],{"className":10147},[2988],[2986,10149,6928],{"className":10150},[4465],": 5000.00,",[4445,10153,10006,10155,3302,10158],{"className":10154},[2988],[2986,10156,6951],{"className":10157},[4465],[2986,10159,3891],{"className":10160},[10014],[4445,10162,10164],{"className":10163},[2988],[2986,10165,4781],{"className":10166},[4496],[4445,10168],{"className":10169},[2988],[4445,10171,10173],{"className":10172},[2988],[2986,10174,10176],{"className":10175},[4451],"# Тест 3: Validation Error (400)",[4445,10178,10180,4453,10183],{"className":10179},[2988],[2986,10181,4452],{"className":10182},[4451],[2971,10184,10091],{"className":10185},[4457],[4445,10187,10006,10189],{"className":10188},[2988],[2971,10190,10098],{"className":10191},[4457],[4445,10193,10006,10195],{"className":10194},[2988],[2971,10196,10198],{"className":10197},[4457],"-d '{\"amount\":-100}'",[4445,10200,10202],{"className":10201},[2988],[2986,10203,4775],{"className":10204},[4496],[4445,10206,10006,10208,3302,10211,10015],{"className":10207},[2988],[2986,10209,10010],{"className":10210},[4465],[2986,10212,3394],{"className":10213},[10014],[4445,10215,10006,10217,3302,10220,10015],{"className":10216},[2988],[2986,10218,10022],{"className":10219},[4465],[2986,10221,3405],{"className":10222},[10014],[4445,10224,10006,10226,10229],{"className":10225},[2988],[2986,10227,10033],{"className":10228},[4465],": 400,",[4445,10231,10006,10233,3302,10237],{"className":10232},[2988],[2986,10234,10236],{"className":10235},[4465],"\"errors\"",[2986,10238,4775],{"className":10239},[4496],[4445,10241,10243,10244,3434,10248,10251],{"className":10242},[2988],"    ",[2986,10245,10247],{"className":10246},[4465],"\"fromAccountNumber\"",[2986,10249,5852],{"className":10250},[10014],"],",[4445,10253,10243,10255,3434,10259,10262],{"className":10254},[2988],[2986,10256,10258],{"className":10257},[4465],"\"amount\"",[2986,10260,5947],{"className":10261},[10014],"]",[4445,10264,10006,10266],{"className":10265},[2988],[2986,10267,4781],{"className":10268},[4496],[4445,10270,10272],{"className":10271},[2988],[2986,10273,4781],{"className":10274},[4496],[3597,10276],{},[2959,10278,10280],{"id":10279},"альтернативні-підходи-до-обробки-помилок","Альтернативні підходи до обробки помилок",[3262,10282,10284],{"id":10283},"підхід-1-exception-filter-legacy","Підхід 1: Exception Filter (Legacy)",[2964,10286,10287,10288,3276],{},"До .NET 8 використовувався ",[2983,10289,10290],{},"IExceptionFilter",[2976,10292,10294],{"className":3991,"code":10293,"language":3993,"meta":2981,"style":2981},"public class GlobalExceptionFilter : IExceptionFilter\n{\n    private readonly ILogger\u003CGlobalExceptionFilter> _logger;\n\n    public GlobalExceptionFilter(ILogger\u003CGlobalExceptionFilter> logger)\n    {\n        _logger = logger;\n    }\n\n    public void OnException(ExceptionContext context)\n    {\n        _logger.LogError(context.Exception, \"Unhandled exception occurred\");\n\n        var problemDetails = context.Exception switch\n        {\n            BusinessException businessEx => new ProblemDetails\n            {\n                Status = businessEx.StatusCode,\n                Title = businessEx.GetType().Name,\n                Detail = businessEx.Message\n            },\n            _ => new ProblemDetails\n            {\n                Status = 500,\n                Title = \"Internal Server Error\",\n                Detail = \"An unexpected error occurred\"\n            }\n        };\n\n        context.Result = new ObjectResult(problemDetails)\n        {\n            StatusCode = problemDetails.Status\n        };\n\n        context.ExceptionHandled = true;\n    }\n}\n\n// Реєстрація\nbuilder.Services.AddControllers(options =>\n{\n    options.Filters.Add\u003CGlobalExceptionFilter>();\n});\n",[2983,10295,10296,10310,10314,10333,10337,10357,10361,10371,10375,10379,10398,10402,10426,10430,10446,10450,10462,10467,10483,10502,10516,10521,10531,10535,10545,10556,10565,10570,10574,10578,10600,10604,10618,10622,10626,10641,10645,10649,10653,10658,10676,10680,10700],{"__ignoreMap":2981},[2986,10297,10298,10300,10302,10305,10307],{"class":2988,"line":2989},[2986,10299,4000],{"class":3010},[2986,10301,4003],{"class":3010},[2986,10303,10304],{"class":4006}," GlobalExceptionFilter",[2986,10306,4191],{"class":3003},[2986,10308,10309],{"class":4006},"IExceptionFilter\n",[2986,10311,10312],{"class":2988,"line":2996},[2986,10313,3293],{"class":3003},[2986,10315,10316,10318,10320,10322,10324,10327,10329,10331],{"class":2988,"line":3007},[2986,10317,6136],{"class":3010},[2986,10319,6139],{"class":3010},[2986,10321,6142],{"class":4006},[2986,10323,4135],{"class":3003},[2986,10325,10326],{"class":4006},"GlobalExceptionFilter",[2986,10328,6150],{"class":3003},[2986,10330,6153],{"class":3024},[2986,10332,4529],{"class":3003},[2986,10334,10335],{"class":2988,"line":3044},[2986,10336,4535],{"emptyLinePlaceholder":4534},[2986,10338,10339,10341,10343,10345,10347,10349,10351,10353,10355],{"class":2988,"line":3062},[2986,10340,4016],{"class":3010},[2986,10342,10304],{"class":3031},[2986,10344,3035],{"class":3003},[2986,10346,8543],{"class":4006},[2986,10348,4135],{"class":3003},[2986,10350,10326],{"class":4006},[2986,10352,6150],{"class":3003},[2986,10354,6195],{"class":3024},[2986,10356,4651],{"class":3003},[2986,10358,10359],{"class":2988,"line":3068},[2986,10360,4656],{"class":3003},[2986,10362,10363,10365,10367,10369],{"class":2988,"line":3091},[2986,10364,6216],{"class":3024},[2986,10366,3018],{"class":3003},[2986,10368,6195],{"class":3024},[2986,10370,4529],{"class":3003},[2986,10372,10373],{"class":2988,"line":3103},[2986,10374,4373],{"class":3003},[2986,10376,10377],{"class":2988,"line":3126},[2986,10378,4535],{"emptyLinePlaceholder":4534},[2986,10380,10381,10383,10386,10389,10391,10394,10396],{"class":2988,"line":3141},[2986,10382,4016],{"class":3010},[2986,10384,10385],{"class":3010}," void",[2986,10387,10388],{"class":3031}," OnException",[2986,10390,3035],{"class":3003},[2986,10392,10393],{"class":4006},"ExceptionContext",[2986,10395,6675],{"class":3024},[2986,10397,4651],{"class":3003},[2986,10399,10400],{"class":2988,"line":3161},[2986,10401,4656],{"class":3003},[2986,10403,10404,10406,10408,10410,10412,10414,10416,10419,10421,10424],{"class":2988,"line":3177},[2986,10405,6216],{"class":3024},[2986,10407,3028],{"class":3003},[2986,10409,6348],{"class":3031},[2986,10411,3035],{"class":3003},[2986,10413,6807],{"class":3024},[2986,10415,3028],{"class":3003},[2986,10417,10418],{"class":3024},"Exception",[2986,10420,4140],{"class":3003},[2986,10422,10423],{"class":3085},"\"Unhandled exception occurred\"",[2986,10425,3041],{"class":3003},[2986,10427,10428],{"class":2988,"line":3197},[2986,10429,4535],{"emptyLinePlaceholder":4534},[2986,10431,10432,10434,10436,10438,10440,10442,10444],{"class":2988,"line":3212},[2986,10433,6303],{"class":3010},[2986,10435,6393],{"class":3024},[2986,10437,3018],{"class":3003},[2986,10439,6807],{"class":3024},[2986,10441,3028],{"class":3003},[2986,10443,10418],{"class":3024},[2986,10445,6401],{"class":2999},[2986,10447,10448],{"class":2988,"line":3221},[2986,10449,6406],{"class":3003},[2986,10451,10452,10454,10456,10458,10460],{"class":2988,"line":3233},[2986,10453,6416],{"class":4006},[2986,10455,6419],{"class":3024},[2986,10457,6422],{"class":3003},[2986,10459,6700],{"class":3010},[2986,10461,4007],{"class":4006},[2986,10463,10464],{"class":2988,"line":3239},[2986,10465,10466],{"class":3003},"            {\n",[2986,10468,10469,10472,10474,10477,10479,10481],{"class":2988,"line":4413},[2986,10470,10471],{"class":3024},"                Status",[2986,10473,3018],{"class":3003},[2986,10475,10476],{"class":3024},"businessEx",[2986,10478,3028],{"class":3003},[2986,10480,5438],{"class":3024},[2986,10482,3308],{"class":3003},[2986,10484,10485,10488,10490,10492,10494,10496,10498,10500],{"class":2988,"line":4691},[2986,10486,10487],{"class":3024},"                Title",[2986,10489,3018],{"class":3003},[2986,10491,10476],{"class":3024},[2986,10493,3028],{"class":3003},[2986,10495,6744],{"class":3031},[2986,10497,6747],{"class":3003},[2986,10499,6750],{"class":3024},[2986,10501,3308],{"class":3003},[2986,10503,10504,10507,10509,10511,10513],{"class":2988,"line":4696},[2986,10505,10506],{"class":3024},"                Detail",[2986,10508,3018],{"class":3003},[2986,10510,10476],{"class":3024},[2986,10512,3028],{"class":3003},[2986,10514,10515],{"class":3024},"Message\n",[2986,10517,10518],{"class":2988,"line":4702},[2986,10519,10520],{"class":3003},"            },\n",[2986,10522,10523,10525,10527,10529],{"class":2988,"line":4717},[2986,10524,6506],{"class":3010},[2986,10526,6422],{"class":3003},[2986,10528,6700],{"class":3010},[2986,10530,4007],{"class":4006},[2986,10532,10533],{"class":2988,"line":4722},[2986,10534,10466],{"class":3003},[2986,10536,10537,10539,10541,10543],{"class":2988,"line":4738},[2986,10538,10471],{"class":3024},[2986,10540,3018],{"class":3003},[2986,10542,6569],{"class":3330},[2986,10544,3308],{"class":3003},[2986,10546,10547,10549,10551,10554],{"class":2988,"line":4743},[2986,10548,10487],{"class":3024},[2986,10550,3018],{"class":3003},[2986,10552,10553],{"class":3085},"\"Internal Server Error\"",[2986,10555,3308],{"class":3003},[2986,10557,10558,10560,10562],{"class":2988,"line":4759},[2986,10559,10506],{"class":3024},[2986,10561,3018],{"class":3003},[2986,10563,10564],{"class":3085},"\"An unexpected error occurred\"\n",[2986,10566,10567],{"class":2988,"line":4768},[2986,10568,10569],{"class":3003},"            }\n",[2986,10571,10572],{"class":2988,"line":4789},[2986,10573,6537],{"class":3003},[2986,10575,10576],{"class":2988,"line":4802},[2986,10577,4535],{"emptyLinePlaceholder":4534},[2986,10579,10580,10582,10584,10587,10589,10591,10594,10596,10598],{"class":2988,"line":4810},[2986,10581,7988],{"class":3024},[2986,10583,3028],{"class":3003},[2986,10585,10586],{"class":3024},"Result",[2986,10588,3018],{"class":3003},[2986,10590,6700],{"class":3010},[2986,10592,10593],{"class":4006}," ObjectResult",[2986,10595,3035],{"class":3003},[2986,10597,6560],{"class":3024},[2986,10599,4651],{"class":3003},[2986,10601,10602],{"class":2988,"line":4815},[2986,10603,6406],{"class":3003},[2986,10605,10606,10609,10611,10613,10615],{"class":2988,"line":4827},[2986,10607,10608],{"class":3024},"            StatusCode",[2986,10610,3018],{"class":3003},[2986,10612,6560],{"class":3024},[2986,10614,3028],{"class":3003},[2986,10616,10617],{"class":3024},"Status\n",[2986,10619,10620],{"class":2988,"line":4832},[2986,10621,6537],{"class":3003},[2986,10623,10624],{"class":2988,"line":4837},[2986,10625,4535],{"emptyLinePlaceholder":4534},[2986,10627,10628,10630,10632,10635,10637,10639],{"class":2988,"line":4842},[2986,10629,7988],{"class":3024},[2986,10631,3028],{"class":3003},[2986,10633,10634],{"class":3024},"ExceptionHandled",[2986,10636,3018],{"class":3003},[2986,10638,9854],{"class":3010},[2986,10640,4529],{"class":3003},[2986,10642,10643],{"class":2988,"line":4848},[2986,10644,4373],{"class":3003},[2986,10646,10647],{"class":2988,"line":4862},[2986,10648,3242],{"class":3003},[2986,10650,10651],{"class":2988,"line":4867},[2986,10652,4535],{"emptyLinePlaceholder":4534},[2986,10654,10655],{"class":2988,"line":4884},[2986,10656,10657],{"class":2992},"// Реєстрація\n",[2986,10659,10660,10662,10664,10666,10668,10670,10672,10674],{"class":2988,"line":4900},[2986,10661,7786],{"class":3024},[2986,10663,3028],{"class":3003},[2986,10665,7791],{"class":3024},[2986,10667,3028],{"class":3003},[2986,10669,8038],{"class":3031},[2986,10671,3035],{"class":3003},[2986,10673,7807],{"class":3024},[2986,10675,7810],{"class":3003},[2986,10677,10678],{"class":2988,"line":4916},[2986,10679,3293],{"class":3003},[2986,10681,10682,10684,10686,10689,10691,10694,10696,10698],{"class":2988,"line":4921},[2986,10683,7815],{"class":3024},[2986,10685,3028],{"class":3003},[2986,10687,10688],{"class":3024},"Filters",[2986,10690,3028],{"class":3003},[2986,10692,10693],{"class":3031},"Add",[2986,10695,4135],{"class":3003},[2986,10697,10326],{"class":4006},[2986,10699,7857],{"class":3003},[2986,10701,10702],{"class":2988,"line":4930},[2986,10703,8021],{"class":3003},[2964,10705,10706],{},[2971,10707,10708],{},"Недоліки:",[3571,10710,10711,10714,10719],{},[3574,10712,10713],{},"Працює тільки для MVC/API Controllers (не для Minimal API)",[3574,10715,10716,10717],{},"Менш гнучкий за ",[2983,10718,3585],{},[3574,10720,10721],{},"Складніше тестувати",[3262,10723,10725],{"id":10724},"підхід-2-useexceptionhandler-з-lambda","Підхід 2: UseExceptionHandler з lambda",[2964,10727,10728],{},"Простий підхід для невеликих проєктів:",[2976,10730,10732],{"className":3991,"code":10731,"language":3993,"meta":2981,"style":2981},"app.UseExceptionHandler(exceptionHandlerApp =>\n{\n    exceptionHandlerApp.Run(async context =>\n    {\n        var exceptionHandlerFeature = context.Features\n            .Get\u003CIExceptionHandlerFeature>();\n\n        var exception = exceptionHandlerFeature?.Error;\n\n        var problemDetails = new ProblemDetails\n        {\n            Status = StatusCodes.Status500InternalServerError,\n            Title = \"An error occurred\",\n            Detail = exception?.Message\n        };\n\n        context.Response.StatusCode = 500;\n        context.Response.ContentType = \"application/problem+json\";\n\n        await context.Response.WriteAsJsonAsync(problemDetails);\n    });\n});\n",[2983,10733,10734,10749,10753,10771,10775,10791,10805,10809,10827,10831,10843,10847,10861,10872,10884,10888,10892,10910,10928,10932,10952,10957],{"__ignoreMap":2981},[2986,10735,10736,10738,10740,10742,10744,10747],{"class":2988,"line":2989},[2986,10737,8118],{"class":3024},[2986,10739,3028],{"class":3003},[2986,10741,8255],{"class":3031},[2986,10743,3035],{"class":3003},[2986,10745,10746],{"class":3024},"exceptionHandlerApp",[2986,10748,7810],{"class":3003},[2986,10750,10751],{"class":2988,"line":2996},[2986,10752,3293],{"class":3003},[2986,10754,10755,10758,10760,10762,10764,10767,10769],{"class":2988,"line":3007},[2986,10756,10757],{"class":3024},"    exceptionHandlerApp",[2986,10759,3028],{"class":3003},[2986,10761,8307],{"class":3031},[2986,10763,3035],{"class":3003},[2986,10765,10766],{"class":3010},"async",[2986,10768,6675],{"class":3024},[2986,10770,7810],{"class":3003},[2986,10772,10773],{"class":2988,"line":3044},[2986,10774,4656],{"class":3003},[2986,10776,10777,10779,10782,10784,10786,10788],{"class":2988,"line":3062},[2986,10778,6303],{"class":3010},[2986,10780,10781],{"class":3024}," exceptionHandlerFeature",[2986,10783,3018],{"class":3003},[2986,10785,6807],{"class":3024},[2986,10787,3028],{"class":3003},[2986,10789,10790],{"class":3024},"Features\n",[2986,10792,10793,10795,10798,10800,10803],{"class":2988,"line":3068},[2986,10794,8744],{"class":3003},[2986,10796,10797],{"class":3031},"Get",[2986,10799,4135],{"class":3003},[2986,10801,10802],{"class":4006},"IExceptionHandlerFeature",[2986,10804,7857],{"class":3003},[2986,10806,10807],{"class":2988,"line":3091},[2986,10808,4535],{"emptyLinePlaceholder":4534},[2986,10810,10811,10813,10815,10817,10820,10822,10825],{"class":2988,"line":3103},[2986,10812,6303],{"class":3010},[2986,10814,6282],{"class":3024},[2986,10816,3018],{"class":3003},[2986,10818,10819],{"class":3024},"exceptionHandlerFeature",[2986,10821,6319],{"class":3003},[2986,10823,10824],{"class":3024},"Error",[2986,10826,4529],{"class":3003},[2986,10828,10829],{"class":2988,"line":3126},[2986,10830,4535],{"emptyLinePlaceholder":4534},[2986,10832,10833,10835,10837,10839,10841],{"class":2988,"line":3141},[2986,10834,6303],{"class":3010},[2986,10836,6393],{"class":3024},[2986,10838,3018],{"class":3003},[2986,10840,6700],{"class":3010},[2986,10842,4007],{"class":4006},[2986,10844,10845],{"class":2988,"line":3161},[2986,10846,6406],{"class":3003},[2986,10848,10849,10851,10853,10855,10857,10859],{"class":2988,"line":3177},[2986,10850,6772],{"class":3024},[2986,10852,3018],{"class":3003},[2986,10854,7257],{"class":3024},[2986,10856,3028],{"class":3003},[2986,10858,7447],{"class":3024},[2986,10860,3308],{"class":3003},[2986,10862,10863,10865,10867,10870],{"class":2988,"line":3197},[2986,10864,6735],{"class":3024},[2986,10866,3018],{"class":3003},[2986,10868,10869],{"class":3085},"\"An error occurred\"",[2986,10871,3308],{"class":3003},[2986,10873,10874,10876,10878,10880,10882],{"class":2988,"line":3212},[2986,10875,6787],{"class":3024},[2986,10877,3018],{"class":3003},[2986,10879,6398],{"class":3024},[2986,10881,6319],{"class":3003},[2986,10883,10515],{"class":3024},[2986,10885,10886],{"class":2988,"line":3221},[2986,10887,6537],{"class":3003},[2986,10889,10890],{"class":2988,"line":3233},[2986,10891,4535],{"emptyLinePlaceholder":4534},[2986,10893,10894,10896,10898,10900,10902,10904,10906,10908],{"class":2988,"line":3239},[2986,10895,7988],{"class":3024},[2986,10897,3028],{"class":3003},[2986,10899,6551],{"class":3024},[2986,10901,3028],{"class":3003},[2986,10903,5438],{"class":3024},[2986,10905,3018],{"class":3003},[2986,10907,6569],{"class":3330},[2986,10909,4529],{"class":3003},[2986,10911,10912,10914,10916,10918,10920,10922,10924,10926],{"class":2988,"line":4413},[2986,10913,7988],{"class":3024},[2986,10915,3028],{"class":3003},[2986,10917,6551],{"class":3024},[2986,10919,3028],{"class":3003},[2986,10921,6584],{"class":3024},[2986,10923,3018],{"class":3003},[2986,10925,6589],{"class":3085},[2986,10927,4529],{"class":3003},[2986,10929,10930],{"class":2988,"line":4691},[2986,10931,4535],{"emptyLinePlaceholder":4534},[2986,10933,10934,10936,10938,10940,10942,10944,10946,10948,10950],{"class":2988,"line":4696},[2986,10935,6600],{"class":3010},[2986,10937,6675],{"class":3024},[2986,10939,3028],{"class":3003},[2986,10941,6551],{"class":3024},[2986,10943,3028],{"class":3003},[2986,10945,6611],{"class":3031},[2986,10947,3035],{"class":3003},[2986,10949,6560],{"class":3024},[2986,10951,3041],{"class":3003},[2986,10953,10954],{"class":2988,"line":4702},[2986,10955,10956],{"class":3003},"    });\n",[2986,10958,10959],{"class":2988,"line":4717},[2986,10960,8021],{"class":3003},[2964,10962,10963],{},[2971,10964,10708],{},[3571,10966,10967,10970,10973],{},[3574,10968,10969],{},"Важко розширювати",[3574,10971,10972],{},"Немає dependency injection",[3574,10974,10975],{},"Складно тестувати",[3262,10977,10979],{"id":10978},"підхід-3-result-pattern-без-винятків","Підхід 3: Result Pattern (без винятків)",[2964,10981,10982,10983,10986],{},"Деякі команди віддають перевагу ",[2971,10984,10985],{},"Result Pattern"," замість винятків:",[2976,10988,10990],{"className":3991,"code":10989,"language":3993,"meta":2981,"style":2981},"public record Result\u003CT>\n{\n    public bool IsSuccess { get; init; }\n    public T? Value { get; init; }\n    public string? Error { get; init; }\n    public int StatusCode { get; init; }\n\n    public static Result\u003CT> Success(T value) => new()\n    {\n        IsSuccess = true,\n        Value = value,\n        StatusCode = 200\n    };\n\n    public static Result\u003CT> Failure(string error, int statusCode) => new()\n    {\n        IsSuccess = false,\n        Error = error,\n        StatusCode = statusCode\n    };\n}\n\n// Використання\n[HttpGet(\"{id}\")]\npublic async Task\u003CIActionResult> GetAccount(string id)\n{\n    var result = await _accountService.GetByIdAsync(id);\n\n    if (!result.IsSuccess)\n    {\n        return StatusCode(result.StatusCode, new ProblemDetails\n        {\n            Status = result.StatusCode,\n            Detail = result.Error\n        });\n    }\n\n    return Ok(result.Value);\n}\n",[2983,10991,10992,11008,11012,11031,11052,11072,11090,11094,11127,11131,11142,11154,11163,11167,11171,11207,11211,11222,11233,11242,11246,11250,11254,11259,11272,11298,11302,11327,11331,11349,11353,11373,11377,11391,11404,11408,11412,11416,11433],{"__ignoreMap":2981},[2986,10993,10994,10996,10998,11001,11003,11006],{"class":2988,"line":2989},[2986,10995,4000],{"class":3010},[2986,10997,5829],{"class":3010},[2986,10999,11000],{"class":4006}," Result",[2986,11002,4135],{"class":3003},[2986,11004,11005],{"class":4006},"T",[2986,11007,8602],{"class":3003},[2986,11009,11010],{"class":2988,"line":2996},[2986,11011,3293],{"class":3003},[2986,11013,11014,11016,11018,11021,11023,11025,11027,11029],{"class":2988,"line":3007},[2986,11015,4016],{"class":3010},[2986,11017,5744],{"class":3010},[2986,11019,11020],{"class":3024}," IsSuccess",[2986,11022,4028],{"class":3003},[2986,11024,4031],{"class":3010},[2986,11026,4034],{"class":3003},[2986,11028,5874],{"class":3010},[2986,11030,4040],{"class":3003},[2986,11032,11033,11035,11038,11040,11042,11044,11046,11048,11050],{"class":2988,"line":3044},[2986,11034,4016],{"class":3010},[2986,11036,11037],{"class":4006}," T",[2986,11039,4022],{"class":3003},[2986,11041,7066],{"class":3024},[2986,11043,4028],{"class":3003},[2986,11045,4031],{"class":3010},[2986,11047,4034],{"class":3003},[2986,11049,5874],{"class":3010},[2986,11051,4040],{"class":3003},[2986,11053,11054,11056,11058,11060,11062,11064,11066,11068,11070],{"class":2988,"line":3062},[2986,11055,4016],{"class":3010},[2986,11057,4019],{"class":3010},[2986,11059,4022],{"class":3003},[2986,11061,10824],{"class":3024},[2986,11063,4028],{"class":3003},[2986,11065,4031],{"class":3010},[2986,11067,4034],{"class":3003},[2986,11069,5874],{"class":3010},[2986,11071,4040],{"class":3003},[2986,11073,11074,11076,11078,11080,11082,11084,11086,11088],{"class":2988,"line":3068},[2986,11075,4016],{"class":3010},[2986,11077,4068],{"class":3010},[2986,11079,4570],{"class":3024},[2986,11081,4028],{"class":3003},[2986,11083,4031],{"class":3010},[2986,11085,4034],{"class":3003},[2986,11087,5874],{"class":3010},[2986,11089,4040],{"class":3003},[2986,11091,11092],{"class":2988,"line":3091},[2986,11093,4535],{"emptyLinePlaceholder":4534},[2986,11095,11096,11098,11101,11103,11105,11107,11109,11112,11114,11116,11119,11122,11124],{"class":2988,"line":3103},[2986,11097,4016],{"class":3010},[2986,11099,11100],{"class":3010}," static",[2986,11102,11000],{"class":4006},[2986,11104,4135],{"class":3003},[2986,11106,11005],{"class":4006},[2986,11108,6150],{"class":3003},[2986,11110,11111],{"class":3031},"Success",[2986,11113,3035],{"class":3003},[2986,11115,11005],{"class":4006},[2986,11117,11118],{"class":3024}," value",[2986,11120,11121],{"class":3003},") => ",[2986,11123,6700],{"class":3010},[2986,11125,11126],{"class":3003},"()\n",[2986,11128,11129],{"class":2988,"line":3126},[2986,11130,4656],{"class":3003},[2986,11132,11133,11136,11138,11140],{"class":2988,"line":3141},[2986,11134,11135],{"class":3024},"        IsSuccess",[2986,11137,3018],{"class":3003},[2986,11139,9854],{"class":3010},[2986,11141,3308],{"class":3003},[2986,11143,11144,11147,11149,11152],{"class":2988,"line":3161},[2986,11145,11146],{"class":3024},"        Value",[2986,11148,3018],{"class":3003},[2986,11150,11151],{"class":3024},"value",[2986,11153,3308],{"class":3003},[2986,11155,11156,11158,11160],{"class":2988,"line":3177},[2986,11157,4661],{"class":3024},[2986,11159,3018],{"class":3003},[2986,11161,11162],{"class":3330},"200\n",[2986,11164,11165],{"class":2988,"line":3197},[2986,11166,8016],{"class":3003},[2986,11168,11169],{"class":2988,"line":3212},[2986,11170,4535],{"emptyLinePlaceholder":4534},[2986,11172,11173,11175,11177,11179,11181,11183,11185,11188,11190,11192,11194,11196,11199,11201,11203,11205],{"class":2988,"line":3221},[2986,11174,4016],{"class":3010},[2986,11176,11100],{"class":3010},[2986,11178,11000],{"class":4006},[2986,11180,4135],{"class":3003},[2986,11182,11005],{"class":4006},[2986,11184,6150],{"class":3003},[2986,11186,11187],{"class":3031},"Failure",[2986,11189,3035],{"class":3003},[2986,11191,3733],{"class":3010},[2986,11193,3079],{"class":3024},[2986,11195,4140],{"class":3003},[2986,11197,11198],{"class":3010},"int",[2986,11200,4624],{"class":3024},[2986,11202,11121],{"class":3003},[2986,11204,6700],{"class":3010},[2986,11206,11126],{"class":3003},[2986,11208,11209],{"class":2988,"line":3233},[2986,11210,4656],{"class":3003},[2986,11212,11213,11215,11217,11220],{"class":2988,"line":3239},[2986,11214,11135],{"class":3024},[2986,11216,3018],{"class":3003},[2986,11218,11219],{"class":3010},"false",[2986,11221,3308],{"class":3003},[2986,11223,11224,11227,11229,11231],{"class":2988,"line":4413},[2986,11225,11226],{"class":3024},"        Error",[2986,11228,3018],{"class":3003},[2986,11230,3056],{"class":3024},[2986,11232,3308],{"class":3003},[2986,11234,11235,11237,11239],{"class":2988,"line":4691},[2986,11236,4661],{"class":3024},[2986,11238,3018],{"class":3003},[2986,11240,11241],{"class":3024},"statusCode\n",[2986,11243,11244],{"class":2988,"line":4696},[2986,11245,8016],{"class":3003},[2986,11247,11248],{"class":2988,"line":4702},[2986,11249,3242],{"class":3003},[2986,11251,11252],{"class":2988,"line":4717},[2986,11253,4535],{"emptyLinePlaceholder":4534},[2986,11255,11256],{"class":2988,"line":4722},[2986,11257,11258],{"class":2992},"// Використання\n",[2986,11260,11261,11263,11265,11267,11270],{"class":2988,"line":4738},[2986,11262,6842],{"class":3003},[2986,11264,8625],{"class":4006},[2986,11266,3035],{"class":3003},[2986,11268,11269],{"class":3085},"\"{id}\"",[2986,11271,5579],{"class":3003},[2986,11273,11274,11276,11278,11280,11282,11284,11286,11289,11291,11293,11296],{"class":2988,"line":4743},[2986,11275,4000],{"class":3010},[2986,11277,6249],{"class":3010},[2986,11279,8693],{"class":4006},[2986,11281,4135],{"class":3003},[2986,11283,8979],{"class":4006},[2986,11285,6150],{"class":3003},[2986,11287,11288],{"class":3031},"GetAccount",[2986,11290,3035],{"class":3003},[2986,11292,3733],{"class":3010},[2986,11294,11295],{"class":3024}," id",[2986,11297,4651],{"class":3003},[2986,11299,11300],{"class":2988,"line":4759},[2986,11301,3293],{"class":3003},[2986,11303,11304,11306,11309,11311,11313,11316,11318,11321,11323,11325],{"class":2988,"line":4768},[2986,11305,8138],{"class":3010},[2986,11307,11308],{"class":3024}," result",[2986,11310,3018],{"class":3003},[2986,11312,3021],{"class":3010},[2986,11314,11315],{"class":3024}," _accountService",[2986,11317,3028],{"class":3003},[2986,11319,11320],{"class":3031},"GetByIdAsync",[2986,11322,3035],{"class":3003},[2986,11324,3038],{"class":3024},[2986,11326,3041],{"class":3003},[2986,11328,11329],{"class":2988,"line":4789},[2986,11330,4535],{"emptyLinePlaceholder":4534},[2986,11332,11333,11336,11339,11342,11344,11347],{"class":2988,"line":4802},[2986,11334,11335],{"class":2999},"    if",[2986,11337,11338],{"class":3003}," (!",[2986,11340,11341],{"class":3024},"result",[2986,11343,3028],{"class":3003},[2986,11345,11346],{"class":3024},"IsSuccess",[2986,11348,4651],{"class":3003},[2986,11350,11351],{"class":2988,"line":4810},[2986,11352,4656],{"class":3003},[2986,11354,11355,11357,11359,11361,11363,11365,11367,11369,11371],{"class":2988,"line":4815},[2986,11356,6631],{"class":2999},[2986,11358,4570],{"class":3031},[2986,11360,3035],{"class":3003},[2986,11362,11341],{"class":3024},[2986,11364,3028],{"class":3003},[2986,11366,5438],{"class":3024},[2986,11368,4140],{"class":3003},[2986,11370,6700],{"class":3010},[2986,11372,4007],{"class":4006},[2986,11374,11375],{"class":2988,"line":4827},[2986,11376,6406],{"class":3003},[2986,11378,11379,11381,11383,11385,11387,11389],{"class":2988,"line":4832},[2986,11380,6772],{"class":3024},[2986,11382,3018],{"class":3003},[2986,11384,11341],{"class":3024},[2986,11386,3028],{"class":3003},[2986,11388,5438],{"class":3024},[2986,11390,3308],{"class":3003},[2986,11392,11393,11395,11397,11399,11401],{"class":2988,"line":4837},[2986,11394,6787],{"class":3024},[2986,11396,3018],{"class":3003},[2986,11398,11341],{"class":3024},[2986,11400,3028],{"class":3003},[2986,11402,11403],{"class":3024},"Error\n",[2986,11405,11406],{"class":2988,"line":4842},[2986,11407,9622],{"class":3003},[2986,11409,11410],{"class":2988,"line":4848},[2986,11411,4373],{"class":3003},[2986,11413,11414],{"class":2988,"line":4862},[2986,11415,4535],{"emptyLinePlaceholder":4534},[2986,11417,11418,11421,11423,11425,11427,11429,11431],{"class":2988,"line":4867},[2986,11419,11420],{"class":2999},"    return",[2986,11422,9567],{"class":3031},[2986,11424,3035],{"class":3003},[2986,11426,11341],{"class":3024},[2986,11428,3028],{"class":3003},[2986,11430,7066],{"class":3024},[2986,11432,3041],{"class":3003},[2986,11434,11435],{"class":2988,"line":4884},[2986,11436,3242],{"class":3003},[2964,11438,11439],{},[2971,11440,11441],{},"Переваги:",[3571,11443,11444,11447,11450],{},[3574,11445,11446],{},"Явний control flow (без винятків)",[3574,11448,11449],{},"Легше тестувати",[3574,11451,11452],{},"Продуктивніше (немає overhead винятків)",[2964,11454,11455],{},[2971,11456,10708],{},[3571,11458,11459,11462,11465],{},[3574,11460,11461],{},"Більше boilerplate-коду",[3574,11463,11464],{},"Потрібна дисципліна команди",[3574,11466,11467],{},"Не підходить для несподіваних помилок",[11469,11470,11471,11474,11475,11477],"tip",{},[2971,11472,11473],{},"Рекомендація:"," Для більшості проєктів використовуйте ",[2971,11476,3585],{}," (.NET 8+) — це найсучасніший та найгнучкіший підхід. Result Pattern підходить для high-performance систем або функціонального стилю програмування.",[3597,11479],{},[2959,11481,11483],{"id":11482},"просунуті-техніки","Просунуті техніки",[3262,11485,11487],{"id":11486},"correlation-id-та-distributed-tracing","Correlation ID та Distributed Tracing",[2964,11489,11490],{},"Для мікросервісної архітектури критично важливо відстежувати запити через кілька сервісів:",[2976,11492,11494],{"className":3991,"code":11493,"language":3993,"meta":2981,"style":2981},"// Middleware для додавання Correlation ID\npublic class CorrelationIdMiddleware\n{\n    private readonly RequestDelegate _next;\n    private const string CorrelationIdHeader = \"X-Correlation-ID\";\n\n    public CorrelationIdMiddleware(RequestDelegate next)\n    {\n        _next = next;\n    }\n\n    public async Task InvokeAsync(HttpContext context)\n    {\n        // Отримуємо або генеруємо Correlation ID\n        var correlationId = context.Request.Headers[CorrelationIdHeader]\n            .FirstOrDefault() ?? Guid.NewGuid().ToString();\n\n        // Додаємо до response headers\n        context.Response.Headers.Append(CorrelationIdHeader, correlationId);\n\n        // Додаємо до Activity для distributed tracing\n        Activity.Current?.SetTag(\"correlation.id\", correlationId);\n\n        // Додаємо до HttpContext для доступу в контролерах\n        context.Items[\"CorrelationId\"] = correlationId;\n\n        await _next(context);\n    }\n}\n\n// Використання в GlobalExceptionHandler\nvar correlationId = httpContext.Items[\"CorrelationId\"]?.ToString() \n    ?? Activity.Current?.Id \n    ?? httpContext.TraceIdentifier;\n\nproblemDetails.Extensions[\"correlationId\"] = correlationId;\n",[2983,11495,11496,11501,11510,11514,11528,11547,11551,11568,11572,11584,11588,11592,11612,11616,11621,11648,11673,11677,11682,11710,11714,11719,11744,11748,11753,11773,11777,11789,11793,11797,11801,11806,11832,11850,11862,11866],{"__ignoreMap":2981},[2986,11497,11498],{"class":2988,"line":2989},[2986,11499,11500],{"class":2992},"// Middleware для додавання Correlation ID\n",[2986,11502,11503,11505,11507],{"class":2988,"line":2996},[2986,11504,4000],{"class":3010},[2986,11506,4003],{"class":3010},[2986,11508,11509],{"class":4006}," CorrelationIdMiddleware\n",[2986,11511,11512],{"class":2988,"line":3007},[2986,11513,3293],{"class":3003},[2986,11515,11516,11518,11520,11523,11526],{"class":2988,"line":3044},[2986,11517,6136],{"class":3010},[2986,11519,6139],{"class":3010},[2986,11521,11522],{"class":4006}," RequestDelegate",[2986,11524,11525],{"class":3024}," _next",[2986,11527,4529],{"class":3003},[2986,11529,11530,11532,11535,11537,11540,11542,11545],{"class":2988,"line":3062},[2986,11531,6136],{"class":3010},[2986,11533,11534],{"class":3010}," const",[2986,11536,4019],{"class":3010},[2986,11538,11539],{"class":3024}," CorrelationIdHeader",[2986,11541,3018],{"class":3003},[2986,11543,11544],{"class":3085},"\"X-Correlation-ID\"",[2986,11546,4529],{"class":3003},[2986,11548,11549],{"class":2988,"line":3068},[2986,11550,4535],{"emptyLinePlaceholder":4534},[2986,11552,11553,11555,11558,11560,11563,11566],{"class":2988,"line":3091},[2986,11554,4016],{"class":3010},[2986,11556,11557],{"class":3031}," CorrelationIdMiddleware",[2986,11559,3035],{"class":3003},[2986,11561,11562],{"class":4006},"RequestDelegate",[2986,11564,11565],{"class":3024}," next",[2986,11567,4651],{"class":3003},[2986,11569,11570],{"class":2988,"line":3103},[2986,11571,4656],{"class":3003},[2986,11573,11574,11577,11579,11582],{"class":2988,"line":3126},[2986,11575,11576],{"class":3024},"        _next",[2986,11578,3018],{"class":3003},[2986,11580,11581],{"class":3024},"next",[2986,11583,4529],{"class":3003},[2986,11585,11586],{"class":2988,"line":3141},[2986,11587,4373],{"class":3003},[2986,11589,11590],{"class":2988,"line":3161},[2986,11591,4535],{"emptyLinePlaceholder":4534},[2986,11593,11594,11596,11598,11600,11603,11605,11608,11610],{"class":2988,"line":3177},[2986,11595,4016],{"class":3010},[2986,11597,6249],{"class":3010},[2986,11599,8693],{"class":4006},[2986,11601,11602],{"class":3031}," InvokeAsync",[2986,11604,3035],{"class":3003},[2986,11606,11607],{"class":4006},"HttpContext",[2986,11609,6675],{"class":3024},[2986,11611,4651],{"class":3003},[2986,11613,11614],{"class":2988,"line":3197},[2986,11615,4656],{"class":3003},[2986,11617,11618],{"class":2988,"line":3212},[2986,11619,11620],{"class":2992},"        // Отримуємо або генеруємо Correlation ID\n",[2986,11622,11623,11625,11628,11630,11632,11634,11636,11638,11641,11643,11646],{"class":2988,"line":3221},[2986,11624,6303],{"class":3010},[2986,11626,11627],{"class":3024}," correlationId",[2986,11629,3018],{"class":3003},[2986,11631,6807],{"class":3024},[2986,11633,3028],{"class":3003},[2986,11635,6812],{"class":3024},[2986,11637,3028],{"class":3003},[2986,11639,11640],{"class":3024},"Headers",[2986,11642,6842],{"class":3003},[2986,11644,11645],{"class":3024},"CorrelationIdHeader",[2986,11647,3453],{"class":3003},[2986,11649,11650,11652,11655,11658,11661,11663,11666,11668,11671],{"class":2988,"line":3233},[2986,11651,8744],{"class":3003},[2986,11653,11654],{"class":3031},"FirstOrDefault",[2986,11656,11657],{"class":3003},"() ?? ",[2986,11659,11660],{"class":3024},"Guid",[2986,11662,3028],{"class":3003},[2986,11664,11665],{"class":3031},"NewGuid",[2986,11667,6747],{"class":3003},[2986,11669,11670],{"class":3031},"ToString",[2986,11672,8041],{"class":3003},[2986,11674,11675],{"class":2988,"line":3239},[2986,11676,4535],{"emptyLinePlaceholder":4534},[2986,11678,11679],{"class":2988,"line":4413},[2986,11680,11681],{"class":2992},"        // Додаємо до response headers\n",[2986,11683,11684,11686,11688,11690,11692,11694,11696,11699,11701,11703,11705,11708],{"class":2988,"line":4691},[2986,11685,7988],{"class":3024},[2986,11687,3028],{"class":3003},[2986,11689,6551],{"class":3024},[2986,11691,3028],{"class":3003},[2986,11693,11640],{"class":3024},[2986,11695,3028],{"class":3003},[2986,11697,11698],{"class":3031},"Append",[2986,11700,3035],{"class":3003},[2986,11702,11645],{"class":3024},[2986,11704,4140],{"class":3003},[2986,11706,11707],{"class":3024},"correlationId",[2986,11709,3041],{"class":3003},[2986,11711,11712],{"class":2988,"line":4696},[2986,11713,4535],{"emptyLinePlaceholder":4534},[2986,11715,11716],{"class":2988,"line":4702},[2986,11717,11718],{"class":2992},"        // Додаємо до Activity для distributed tracing\n",[2986,11720,11721,11724,11726,11728,11730,11733,11735,11738,11740,11742],{"class":2988,"line":4717},[2986,11722,11723],{"class":3024},"        Activity",[2986,11725,3028],{"class":3003},[2986,11727,6316],{"class":3024},[2986,11729,6319],{"class":3003},[2986,11731,11732],{"class":3031},"SetTag",[2986,11734,3035],{"class":3003},[2986,11736,11737],{"class":3085},"\"correlation.id\"",[2986,11739,4140],{"class":3003},[2986,11741,11707],{"class":3024},[2986,11743,3041],{"class":3003},[2986,11745,11746],{"class":2988,"line":4722},[2986,11747,4535],{"emptyLinePlaceholder":4534},[2986,11749,11750],{"class":2988,"line":4738},[2986,11751,11752],{"class":2992},"        // Додаємо до HttpContext для доступу в контролерах\n",[2986,11754,11755,11757,11759,11762,11764,11767,11769,11771],{"class":2988,"line":4743},[2986,11756,7988],{"class":3024},[2986,11758,3028],{"class":3003},[2986,11760,11761],{"class":3024},"Items",[2986,11763,6842],{"class":3003},[2986,11765,11766],{"class":3085},"\"CorrelationId\"",[2986,11768,6848],{"class":3003},[2986,11770,11707],{"class":3024},[2986,11772,4529],{"class":3003},[2986,11774,11775],{"class":2988,"line":4759},[2986,11776,4535],{"emptyLinePlaceholder":4534},[2986,11778,11779,11781,11783,11785,11787],{"class":2988,"line":4768},[2986,11780,6600],{"class":3010},[2986,11782,11525],{"class":3031},[2986,11784,3035],{"class":3003},[2986,11786,6807],{"class":3024},[2986,11788,3041],{"class":3003},[2986,11790,11791],{"class":2988,"line":4789},[2986,11792,4373],{"class":3003},[2986,11794,11795],{"class":2988,"line":4802},[2986,11796,3242],{"class":3003},[2986,11798,11799],{"class":2988,"line":4810},[2986,11800,4535],{"emptyLinePlaceholder":4534},[2986,11802,11803],{"class":2988,"line":4815},[2986,11804,11805],{"class":2992},"// Використання в GlobalExceptionHandler\n",[2986,11807,11808,11810,11812,11814,11816,11818,11820,11822,11824,11827,11829],{"class":2988,"line":4827},[2986,11809,7752],{"class":3010},[2986,11811,11627],{"class":3024},[2986,11813,3018],{"class":3003},[2986,11815,6328],{"class":3024},[2986,11817,3028],{"class":3003},[2986,11819,11761],{"class":3024},[2986,11821,6842],{"class":3003},[2986,11823,11766],{"class":3085},[2986,11825,11826],{"class":3003},"]?.",[2986,11828,11670],{"class":3031},[2986,11830,11831],{"class":3003},"() \n",[2986,11833,11834,11837,11839,11841,11843,11845,11847],{"class":2988,"line":4832},[2986,11835,11836],{"class":3003},"    ?? ",[2986,11838,6311],{"class":3024},[2986,11840,3028],{"class":3003},[2986,11842,6316],{"class":3024},[2986,11844,6319],{"class":3003},[2986,11846,6322],{"class":3024},[2986,11848,11849],{"class":3003}," \n",[2986,11851,11852,11854,11856,11858,11860],{"class":2988,"line":4837},[2986,11853,11836],{"class":3003},[2986,11855,6328],{"class":3024},[2986,11857,3028],{"class":3003},[2986,11859,6333],{"class":3024},[2986,11861,4529],{"class":3003},[2986,11863,11864],{"class":2988,"line":4842},[2986,11865,4535],{"emptyLinePlaceholder":4534},[2986,11867,11868,11870,11872,11874,11876,11879,11881,11883],{"class":2988,"line":4848},[2986,11869,6560],{"class":3024},[2986,11871,3028],{"class":3003},[2986,11873,4149],{"class":3024},[2986,11875,6842],{"class":3003},[2986,11877,11878],{"class":3085},"\"correlationId\"",[2986,11880,6848],{"class":3003},[2986,11882,11707],{"class":3024},[2986,11884,4529],{"class":3003},[3262,11886,11888],{"id":11887},"локалізація-помилок","Локалізація помилок",[2964,11890,11891],{},"Підтримка багатомовних повідомлень:",[2976,11893,11895],{"className":3991,"code":11894,"language":3993,"meta":2981,"style":2981},"public class LocalizedExceptionHandler : IExceptionHandler\n{\n    private readonly IStringLocalizer\u003CSharedResources> _localizer;\n\n    public LocalizedExceptionHandler(IStringLocalizer\u003CSharedResources> localizer)\n    {\n        _localizer = localizer;\n    }\n\n    public async ValueTask\u003Cbool> TryHandleAsync(\n        HttpContext httpContext,\n        Exception exception,\n        CancellationToken cancellationToken)\n    {\n        var problemDetails = exception switch\n        {\n            AccountNotFoundException ex => new ProblemDetails\n            {\n                Title = _localizer[\"AccountNotFound\"],\n                Detail = _localizer[\"AccountNotFoundDetail\", ex.AccountId],\n                Status = 404\n            },\n            _ => new ProblemDetails\n            {\n                Title = _localizer[\"InternalError\"],\n                Status = 500\n            }\n        };\n\n        await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken);\n        return true;\n    }\n}\n\n// Resources/SharedResources.uk.resx\n// AccountNotFound = \"Рахунок не знайдено\"\n// AccountNotFoundDetail = \"Рахунок з ID '{0}' не існує\"\n",[2983,11896,11897,11910,11914,11935,11939,11961,11965,11976,11980,11984,12002,12010,12018,12026,12030,12042,12046,12060,12064,12078,12102,12111,12115,12125,12129,12144,12153,12157,12161,12165,12189,12197,12201,12205,12209,12214,12219],{"__ignoreMap":2981},[2986,11898,11899,11901,11903,11906,11908],{"class":2988,"line":2989},[2986,11900,4000],{"class":3010},[2986,11902,4003],{"class":3010},[2986,11904,11905],{"class":4006}," LocalizedExceptionHandler",[2986,11907,4191],{"class":3003},[2986,11909,6127],{"class":4006},[2986,11911,11912],{"class":2988,"line":2996},[2986,11913,3293],{"class":3003},[2986,11915,11916,11918,11920,11923,11925,11928,11930,11933],{"class":2988,"line":3007},[2986,11917,6136],{"class":3010},[2986,11919,6139],{"class":3010},[2986,11921,11922],{"class":4006}," IStringLocalizer",[2986,11924,4135],{"class":3003},[2986,11926,11927],{"class":4006},"SharedResources",[2986,11929,6150],{"class":3003},[2986,11931,11932],{"class":3024},"_localizer",[2986,11934,4529],{"class":3003},[2986,11936,11937],{"class":2988,"line":3044},[2986,11938,4535],{"emptyLinePlaceholder":4534},[2986,11940,11941,11943,11945,11947,11950,11952,11954,11956,11959],{"class":2988,"line":3062},[2986,11942,4016],{"class":3010},[2986,11944,11905],{"class":3031},[2986,11946,3035],{"class":3003},[2986,11948,11949],{"class":4006},"IStringLocalizer",[2986,11951,4135],{"class":3003},[2986,11953,11927],{"class":4006},[2986,11955,6150],{"class":3003},[2986,11957,11958],{"class":3024},"localizer",[2986,11960,4651],{"class":3003},[2986,11962,11963],{"class":2988,"line":3068},[2986,11964,4656],{"class":3003},[2986,11966,11967,11970,11972,11974],{"class":2988,"line":3091},[2986,11968,11969],{"class":3024},"        _localizer",[2986,11971,3018],{"class":3003},[2986,11973,11958],{"class":3024},[2986,11975,4529],{"class":3003},[2986,11977,11978],{"class":2988,"line":3103},[2986,11979,4373],{"class":3003},[2986,11981,11982],{"class":2988,"line":3126},[2986,11983,4535],{"emptyLinePlaceholder":4534},[2986,11985,11986,11988,11990,11992,11994,11996,11998,12000],{"class":2988,"line":3141},[2986,11987,4016],{"class":3010},[2986,11989,6249],{"class":3010},[2986,11991,6252],{"class":4006},[2986,11993,4135],{"class":3003},[2986,11995,6257],{"class":3010},[2986,11997,6150],{"class":3003},[2986,11999,6262],{"class":3031},[2986,12001,4605],{"class":3003},[2986,12003,12004,12006,12008],{"class":2988,"line":3161},[2986,12005,6269],{"class":4006},[2986,12007,6272],{"class":3024},[2986,12009,3308],{"class":3003},[2986,12011,12012,12014,12016],{"class":2988,"line":3177},[2986,12013,6279],{"class":4006},[2986,12015,6282],{"class":3024},[2986,12017,3308],{"class":3003},[2986,12019,12020,12022,12024],{"class":2988,"line":3197},[2986,12021,6289],{"class":4006},[2986,12023,6292],{"class":3024},[2986,12025,4651],{"class":3003},[2986,12027,12028],{"class":2988,"line":3212},[2986,12029,4656],{"class":3003},[2986,12031,12032,12034,12036,12038,12040],{"class":2988,"line":3221},[2986,12033,6303],{"class":3010},[2986,12035,6393],{"class":3024},[2986,12037,3018],{"class":3003},[2986,12039,6398],{"class":3024},[2986,12041,6401],{"class":2999},[2986,12043,12044],{"class":2988,"line":3233},[2986,12045,6406],{"class":3003},[2986,12047,12048,12051,12054,12056,12058],{"class":2988,"line":3239},[2986,12049,12050],{"class":4006},"            AccountNotFoundException",[2986,12052,12053],{"class":3024}," ex",[2986,12055,6422],{"class":3003},[2986,12057,6700],{"class":3010},[2986,12059,4007],{"class":4006},[2986,12061,12062],{"class":2988,"line":4413},[2986,12063,10466],{"class":3003},[2986,12065,12066,12068,12070,12072,12074,12076],{"class":2988,"line":4691},[2986,12067,10487],{"class":3024},[2986,12069,3018],{"class":3003},[2986,12071,11932],{"class":3024},[2986,12073,6842],{"class":3003},[2986,12075,10026],{"class":3085},[2986,12077,3440],{"class":3003},[2986,12079,12080,12082,12084,12086,12088,12091,12093,12096,12098,12100],{"class":2988,"line":4696},[2986,12081,10506],{"class":3024},[2986,12083,3018],{"class":3003},[2986,12085,11932],{"class":3024},[2986,12087,6842],{"class":3003},[2986,12089,12090],{"class":3085},"\"AccountNotFoundDetail\"",[2986,12092,4140],{"class":3003},[2986,12094,12095],{"class":3024},"ex",[2986,12097,3028],{"class":3003},[2986,12099,7122],{"class":3024},[2986,12101,3440],{"class":3003},[2986,12103,12104,12106,12108],{"class":2988,"line":4702},[2986,12105,10471],{"class":3024},[2986,12107,3018],{"class":3003},[2986,12109,12110],{"class":3330},"404\n",[2986,12112,12113],{"class":2988,"line":4717},[2986,12114,10520],{"class":3003},[2986,12116,12117,12119,12121,12123],{"class":2988,"line":4722},[2986,12118,6506],{"class":3010},[2986,12120,6422],{"class":3003},[2986,12122,6700],{"class":3010},[2986,12124,4007],{"class":4006},[2986,12126,12127],{"class":2988,"line":4738},[2986,12128,10466],{"class":3003},[2986,12130,12131,12133,12135,12137,12139,12142],{"class":2988,"line":4743},[2986,12132,10487],{"class":3024},[2986,12134,3018],{"class":3003},[2986,12136,11932],{"class":3024},[2986,12138,6842],{"class":3003},[2986,12140,12141],{"class":3085},"\"InternalError\"",[2986,12143,3440],{"class":3003},[2986,12145,12146,12148,12150],{"class":2988,"line":4759},[2986,12147,10471],{"class":3024},[2986,12149,3018],{"class":3003},[2986,12151,12152],{"class":3330},"500\n",[2986,12154,12155],{"class":2988,"line":4768},[2986,12156,10569],{"class":3003},[2986,12158,12159],{"class":2988,"line":4789},[2986,12160,6537],{"class":3003},[2986,12162,12163],{"class":2988,"line":4802},[2986,12164,4535],{"emptyLinePlaceholder":4534},[2986,12166,12167,12169,12171,12173,12175,12177,12179,12181,12183,12185,12187],{"class":2988,"line":4810},[2986,12168,6600],{"class":3010},[2986,12170,6272],{"class":3024},[2986,12172,3028],{"class":3003},[2986,12174,6551],{"class":3024},[2986,12176,3028],{"class":3003},[2986,12178,6611],{"class":3031},[2986,12180,3035],{"class":3003},[2986,12182,6560],{"class":3024},[2986,12184,4140],{"class":3003},[2986,12186,6620],{"class":3024},[2986,12188,3041],{"class":3003},[2986,12190,12191,12193,12195],{"class":2988,"line":4815},[2986,12192,6631],{"class":2999},[2986,12194,6634],{"class":3010},[2986,12196,4529],{"class":3003},[2986,12198,12199],{"class":2988,"line":4827},[2986,12200,4373],{"class":3003},[2986,12202,12203],{"class":2988,"line":4832},[2986,12204,3242],{"class":3003},[2986,12206,12207],{"class":2988,"line":4837},[2986,12208,4535],{"emptyLinePlaceholder":4534},[2986,12210,12211],{"class":2988,"line":4842},[2986,12212,12213],{"class":2992},"// Resources/SharedResources.uk.resx\n",[2986,12215,12216],{"class":2988,"line":4848},[2986,12217,12218],{"class":2992},"// AccountNotFound = \"Рахунок не знайдено\"\n",[2986,12220,12221],{"class":2988,"line":4862},[2986,12222,12223],{"class":2992},"// AccountNotFoundDetail = \"Рахунок з ID '{0}' не існує\"\n",[3262,12225,12227],{"id":12226},"error-codes-для-програмної-обробки","Error Codes для програмної обробки",[2964,12229,12230],{},"Додавання унікальних кодів помилок:",[2976,12232,12234],{"className":3991,"code":12233,"language":3993,"meta":2981,"style":2981},"public abstract class BusinessException : Exception\n{\n    public string ErrorCode { get; }\n    \n    protected BusinessException(string message, string errorCode) \n        : base(message)\n    {\n        ErrorCode = errorCode;\n    }\n}\n\npublic class InsufficientFundsException : BusinessException\n{\n    public InsufficientFundsException(decimal balance, decimal required)\n        : base(\n            $\"Insufficient funds: {balance} \u003C {required}\",\n            \"BANK_001\") // Унікальний код\n    {\n    }\n}\n\n// У ProblemDetails\nproblemDetails.Extensions[\"errorCode\"] = exception.ErrorCode;\n",[2983,12235,12236,12250,12254,12269,12273,12294,12306,12310,12322,12326,12330,12334,12346,12350,12371,12379,12403,12411,12415,12419,12423,12427,12432],{"__ignoreMap":2981},[2986,12237,12238,12240,12242,12244,12246,12248],{"class":2988,"line":2989},[2986,12239,4000],{"class":3010},[2986,12241,4547],{"class":3010},[2986,12243,4003],{"class":3010},[2986,12245,4552],{"class":4006},[2986,12247,4191],{"class":3003},[2986,12249,4557],{"class":4006},[2986,12251,12252],{"class":2988,"line":2996},[2986,12253,3293],{"class":3003},[2986,12255,12256,12258,12260,12263,12265,12267],{"class":2988,"line":3007},[2986,12257,4016],{"class":3010},[2986,12259,4019],{"class":3010},[2986,12261,12262],{"class":3024}," ErrorCode",[2986,12264,4028],{"class":3003},[2986,12266,4031],{"class":3010},[2986,12268,4040],{"class":3003},[2986,12270,12271],{"class":2988,"line":3044},[2986,12272,4378],{"class":3003},[2986,12274,12275,12277,12279,12281,12283,12285,12287,12289,12292],{"class":2988,"line":3062},[2986,12276,4600],{"class":3010},[2986,12278,4552],{"class":3031},[2986,12280,3035],{"class":3003},[2986,12282,3733],{"class":3010},[2986,12284,4613],{"class":3024},[2986,12286,4140],{"class":3003},[2986,12288,3733],{"class":3010},[2986,12290,12291],{"class":3024}," errorCode",[2986,12293,4636],{"class":3003},[2986,12295,12296,12298,12300,12302,12304],{"class":2988,"line":3068},[2986,12297,4641],{"class":3003},[2986,12299,4644],{"class":3010},[2986,12301,3035],{"class":3003},[2986,12303,3121],{"class":3024},[2986,12305,4651],{"class":3003},[2986,12307,12308],{"class":2988,"line":3091},[2986,12309,4656],{"class":3003},[2986,12311,12312,12315,12317,12320],{"class":2988,"line":3103},[2986,12313,12314],{"class":3024},"        ErrorCode",[2986,12316,3018],{"class":3003},[2986,12318,12319],{"class":3024},"errorCode",[2986,12321,4529],{"class":3003},[2986,12323,12324],{"class":2988,"line":3126},[2986,12325,4373],{"class":3003},[2986,12327,12328],{"class":2988,"line":3141},[2986,12329,3242],{"class":3003},[2986,12331,12332],{"class":2988,"line":3161},[2986,12333,4535],{"emptyLinePlaceholder":4534},[2986,12335,12336,12338,12340,12342,12344],{"class":2988,"line":3177},[2986,12337,4000],{"class":3010},[2986,12339,4003],{"class":3010},[2986,12341,4855],{"class":4006},[2986,12343,4191],{"class":3003},[2986,12345,4714],{"class":4006},[2986,12347,12348],{"class":2988,"line":3197},[2986,12349,3293],{"class":3003},[2986,12351,12352,12354,12356,12358,12361,12363,12365,12367,12369],{"class":2988,"line":3212},[2986,12353,4016],{"class":3010},[2986,12355,4855],{"class":3031},[2986,12357,3035],{"class":3003},[2986,12359,12360],{"class":3010},"decimal",[2986,12362,4936],{"class":3024},[2986,12364,4140],{"class":3003},[2986,12366,12360],{"class":3010},[2986,12368,5586],{"class":3024},[2986,12370,4651],{"class":3003},[2986,12372,12373,12375,12377],{"class":2988,"line":3221},[2986,12374,4641],{"class":3003},[2986,12376,4644],{"class":3010},[2986,12378,4605],{"class":3003},[2986,12380,12381,12384,12386,12388,12390,12392,12394,12397,12399,12401],{"class":2988,"line":3233},[2986,12382,12383],{"class":3085},"            $\"Insufficient funds: ",[2986,12385,4775],{"class":4774},[2986,12387,4982],{"class":3024},[2986,12389,4781],{"class":4774},[2986,12391,9382],{"class":3085},[2986,12393,4775],{"class":4774},[2986,12395,12396],{"class":3024},"required",[2986,12398,4781],{"class":4774},[2986,12400,5219],{"class":3085},[2986,12402,3308],{"class":3003},[2986,12404,12405,12408],{"class":2988,"line":3239},[2986,12406,12407],{"class":3085},"            \"BANK_001\"",[2986,12409,12410],{"class":3003},") // Унікальний код\n",[2986,12412,12413],{"class":2988,"line":4413},[2986,12414,4656],{"class":3003},[2986,12416,12417],{"class":2988,"line":4691},[2986,12418,4373],{"class":3003},[2986,12420,12421],{"class":2988,"line":4696},[2986,12422,3242],{"class":3003},[2986,12424,12425],{"class":2988,"line":4702},[2986,12426,4535],{"emptyLinePlaceholder":4534},[2986,12428,12429],{"class":2988,"line":4717},[2986,12430,12431],{"class":2992},"// У ProblemDetails\n",[2986,12433,12434,12436,12438,12440,12442,12445,12447,12449,12451,12454],{"class":2988,"line":4722},[2986,12435,6560],{"class":3024},[2986,12437,3028],{"class":3003},[2986,12439,4149],{"class":3024},[2986,12441,6842],{"class":3003},[2986,12443,12444],{"class":3085},"\"errorCode\"",[2986,12446,6848],{"class":3003},[2986,12448,6398],{"class":3024},[2986,12450,3028],{"class":3003},[2986,12452,12453],{"class":3024},"ErrorCode",[2986,12455,4529],{"class":3003},[2964,12457,12458],{},"Клієнт може обробляти за кодом:",[2976,12460,12462],{"className":2978,"code":12461,"language":2980,"meta":2981,"style":2981},"if (error.errorCode === 'BANK_001') {\n  showInsufficientFundsDialog();\n} else if (error.errorCode === 'BANK_002') {\n  showAccountLockedDialog();\n}\n",[2983,12463,12464,12483,12490,12513,12520],{"__ignoreMap":2981},[2986,12465,12466,12468,12470,12472,12474,12476,12478,12481],{"class":2988,"line":2989},[2986,12467,8192],{"class":2999},[2986,12469,3053],{"class":3003},[2986,12471,3056],{"class":3024},[2986,12473,3028],{"class":3003},[2986,12475,12319],{"class":3024},[2986,12477,3082],{"class":3003},[2986,12479,12480],{"class":3085},"'BANK_001'",[2986,12482,3059],{"class":3003},[2986,12484,12485,12488],{"class":2988,"line":2996},[2986,12486,12487],{"class":3031},"  showInsufficientFundsDialog",[2986,12489,8041],{"class":3003},[2986,12491,12492,12494,12496,12498,12500,12502,12504,12506,12508,12511],{"class":2988,"line":3007},[2986,12493,3047],{"class":3003},[2986,12495,3109],{"class":2999},[2986,12497,3112],{"class":2999},[2986,12499,3053],{"class":3003},[2986,12501,3056],{"class":3024},[2986,12503,3028],{"class":3003},[2986,12505,12319],{"class":3024},[2986,12507,3082],{"class":3003},[2986,12509,12510],{"class":3085},"'BANK_002'",[2986,12512,3059],{"class":3003},[2986,12514,12515,12518],{"class":2988,"line":3044},[2986,12516,12517],{"class":3031},"  showAccountLockedDialog",[2986,12519,8041],{"class":3003},[2986,12521,12522],{"class":2988,"line":3062},[2986,12523,3242],{"class":3003},[3597,12525],{},[2959,12527,12529],{"id":12528},"практичні-завдання","Практичні завдання",[3262,12531,12533],{"id":12532},"рівень-1-базове-розуміння","Рівень 1: Базове розуміння",[4434,12535,12536,12540,12543,12587,12591,12594,12614],{},[3262,12537,12539],{"id":12538},"завдання-11-структура-problemdetails","Завдання 1.1: Структура ProblemDetails",[2964,12541,12542],{},"Які поля є обов'язковими у ProblemDetails згідно з RFC 9457?",[12544,12545,12547,12551,12568,12572],"collapsible",{"title":12546},"Показати відповідь",[2964,12548,12549],{},[2971,12550,3684],{},[3571,12552,12553,12558,12563],{},[3574,12554,12555,12557],{},[2983,12556,3714],{}," (string, URI)",[3574,12559,12560,12562],{},[2983,12561,3730],{}," (string)",[3574,12564,12565,12567],{},[2983,12566,3743],{}," (number)",[2964,12569,12570],{},[2971,12571,3754],{},[3571,12573,12574,12578,12582],{},[3574,12575,12576,12562],{},[2983,12577,3775],{},[3574,12579,12580,12557],{},[2983,12581,3787],{},[3574,12583,12584,12585],{},"Будь-які кастомні поля через ",[2983,12586,4149],{},[3262,12588,12590],{"id":12589},"завдання-12-вибір-http-коду","Завдання 1.2: Вибір HTTP-коду",[2964,12592,12593],{},"Який HTTP-код використати для кожної помилки?",[5426,12595,12596,12599,12602,12605,12608,12611],{},[3574,12597,12598],{},"Користувач не автентифікований",[3574,12600,12601],{},"Користувач автентифікований, але немає прав",[3574,12603,12604],{},"Невалідні дані у запиті",[3574,12606,12607],{},"Ресурс не знайдено",[3574,12609,12610],{},"Конфлікт бізнес-логіки (недостатньо коштів)",[3574,12612,12613],{},"Необроблена помилка сервера",[12544,12615,12617],{"title":12616},"Показати відповіді",[5426,12618,12619,12625,12631,12637,12643,12649],{},[3574,12620,12621,12624],{},[2971,12622,12623],{},"401 Unauthorized"," — не автентифікований",[3574,12626,12627,12630],{},[2971,12628,12629],{},"403 Forbidden"," — немає прав",[3574,12632,12633,12636],{},[2971,12634,12635],{},"400 Bad Request"," — невалідні дані",[3574,12638,12639,12642],{},[2971,12640,12641],{},"404 Not Found"," — ресурс не існує",[3574,12644,12645,12648],{},[2971,12646,12647],{},"409 Conflict"," — бізнес-правило порушено",[3574,12650,12651,12654],{},[2971,12652,12653],{},"500 Internal Server Error"," — несподівана помилка",[3597,12656],{},[3262,12658,12660],{"id":12659},"рівень-2-логіка-та-розширення","Рівень 2: Логіка та розширення",[4434,12662,12663,12667,12674,13024,13028,13035],{},[3262,12664,12666],{"id":12665},"завдання-21-кастомний-виняток","Завдання 2.1: Кастомний виняток",[2964,12668,12669,12670,12673],{},"Створіть виняток ",[2983,12671,12672],{},"DuplicateEmailException"," для ситуації, коли користувач намагається зареєструватися з email, що вже існує:",[12544,12675,12677,12931,12934],{"title":12676},"Показати рішення",[2976,12678,12680],{"className":3991,"code":12679,"language":3993,"meta":2981,"style":2981},"public class DuplicateEmailException : BusinessException\n{\n    public string Email { get; }\n    public int ExistingUserId { get; }\n\n    public DuplicateEmailException(string email, int existingUserId)\n        : base(\n            $\"User with email '{email}' already exists\",\n            StatusCodes.Status409Conflict,\n            \"duplicate-email\")\n    {\n        Email = email;\n        ExistingUserId = existingUserId;\n    }\n}\n\n// Обробка у GlobalExceptionHandler\ncase DuplicateEmailException duplicateEmail:\n    problemDetails.Extensions[\"email\"] = duplicateEmail.Email;\n    problemDetails.Extensions[\"existingUserId\"] = duplicateEmail.ExistingUserId;\n    problemDetails.Extensions[\"suggestion\"] = \"Try logging in or use password reset\";\n    break;\n",[2983,12681,12682,12695,12699,12714,12729,12733,12755,12763,12780,12790,12797,12801,12812,12824,12828,12832,12836,12841,12854,12880,12904,12924],{"__ignoreMap":2981},[2986,12683,12684,12686,12688,12691,12693],{"class":2988,"line":2989},[2986,12685,4000],{"class":3010},[2986,12687,4003],{"class":3010},[2986,12689,12690],{"class":4006}," DuplicateEmailException",[2986,12692,4191],{"class":3003},[2986,12694,4714],{"class":4006},[2986,12696,12697],{"class":2988,"line":2996},[2986,12698,3293],{"class":3003},[2986,12700,12701,12703,12705,12708,12710,12712],{"class":2988,"line":3007},[2986,12702,4016],{"class":3010},[2986,12704,4019],{"class":3010},[2986,12706,12707],{"class":3024}," Email",[2986,12709,4028],{"class":3003},[2986,12711,4031],{"class":3010},[2986,12713,4040],{"class":3003},[2986,12715,12716,12718,12720,12723,12725,12727],{"class":2988,"line":3044},[2986,12717,4016],{"class":3010},[2986,12719,4068],{"class":3010},[2986,12721,12722],{"class":3024}," ExistingUserId",[2986,12724,4028],{"class":3003},[2986,12726,4031],{"class":3010},[2986,12728,4040],{"class":3003},[2986,12730,12731],{"class":2988,"line":3062},[2986,12732,4535],{"emptyLinePlaceholder":4534},[2986,12734,12735,12737,12739,12741,12743,12746,12748,12750,12753],{"class":2988,"line":3068},[2986,12736,4016],{"class":3010},[2986,12738,12690],{"class":3031},[2986,12740,3035],{"class":3003},[2986,12742,3733],{"class":3010},[2986,12744,12745],{"class":3024}," email",[2986,12747,4140],{"class":3003},[2986,12749,11198],{"class":3010},[2986,12751,12752],{"class":3024}," existingUserId",[2986,12754,4651],{"class":3003},[2986,12756,12757,12759,12761],{"class":2988,"line":3091},[2986,12758,4641],{"class":3003},[2986,12760,4644],{"class":3010},[2986,12762,4605],{"class":3003},[2986,12764,12765,12768,12770,12773,12775,12778],{"class":2988,"line":3103},[2986,12766,12767],{"class":3085},"            $\"User with email '",[2986,12769,4775],{"class":4774},[2986,12771,12772],{"class":3024},"email",[2986,12774,4781],{"class":4774},[2986,12776,12777],{"class":3085},"' already exists\"",[2986,12779,3308],{"class":3003},[2986,12781,12782,12784,12786,12788],{"class":2988,"line":3126},[2986,12783,4792],{"class":3024},[2986,12785,3028],{"class":3003},[2986,12787,5032],{"class":3024},[2986,12789,3308],{"class":3003},[2986,12791,12792,12795],{"class":2988,"line":3141},[2986,12793,12794],{"class":3085},"            \"duplicate-email\"",[2986,12796,4651],{"class":3003},[2986,12798,12799],{"class":2988,"line":3161},[2986,12800,4656],{"class":3003},[2986,12802,12803,12806,12808,12810],{"class":2988,"line":3177},[2986,12804,12805],{"class":3024},"        Email",[2986,12807,3018],{"class":3003},[2986,12809,12772],{"class":3024},[2986,12811,4529],{"class":3003},[2986,12813,12814,12817,12819,12822],{"class":2988,"line":3197},[2986,12815,12816],{"class":3024},"        ExistingUserId",[2986,12818,3018],{"class":3003},[2986,12820,12821],{"class":3024},"existingUserId",[2986,12823,4529],{"class":3003},[2986,12825,12826],{"class":2988,"line":3212},[2986,12827,4373],{"class":3003},[2986,12829,12830],{"class":2988,"line":3221},[2986,12831,3242],{"class":3003},[2986,12833,12834],{"class":2988,"line":3233},[2986,12835,4535],{"emptyLinePlaceholder":4534},[2986,12837,12838],{"class":2988,"line":3239},[2986,12839,12840],{"class":2992},"// Обробка у GlobalExceptionHandler\n",[2986,12842,12843,12846,12848,12852],{"class":2988,"line":4413},[2986,12844,12845],{"class":3024},"case",[2986,12847,12690],{"class":3024},[2986,12849,12851],{"class":12850},"s5IvJ"," duplicateEmail",[2986,12853,6890],{"class":3003},[2986,12855,12856,12859,12861,12863,12865,12868,12870,12873,12875,12878],{"class":2988,"line":4691},[2986,12857,12858],{"class":3024},"    problemDetails",[2986,12860,3028],{"class":3003},[2986,12862,4149],{"class":3024},[2986,12864,6842],{"class":3003},[2986,12866,12867],{"class":3085},"\"email\"",[2986,12869,6848],{"class":3003},[2986,12871,12872],{"class":3024},"duplicateEmail",[2986,12874,3028],{"class":3003},[2986,12876,12877],{"class":3024},"Email",[2986,12879,4529],{"class":3003},[2986,12881,12882,12884,12886,12888,12890,12893,12895,12897,12899,12902],{"class":2988,"line":4696},[2986,12883,12858],{"class":3024},[2986,12885,3028],{"class":3003},[2986,12887,4149],{"class":3024},[2986,12889,6842],{"class":3003},[2986,12891,12892],{"class":3085},"\"existingUserId\"",[2986,12894,6848],{"class":3003},[2986,12896,12872],{"class":3024},[2986,12898,3028],{"class":3003},[2986,12900,12901],{"class":3024},"ExistingUserId",[2986,12903,4529],{"class":3003},[2986,12905,12906,12908,12910,12912,12914,12917,12919,12922],{"class":2988,"line":4702},[2986,12907,12858],{"class":3024},[2986,12909,3028],{"class":3003},[2986,12911,4149],{"class":3024},[2986,12913,6842],{"class":3003},[2986,12915,12916],{"class":3085},"\"suggestion\"",[2986,12918,6848],{"class":3003},[2986,12920,12921],{"class":3085},"\"Try logging in or use password reset\"",[2986,12923,4529],{"class":3003},[2986,12925,12926,12929],{"class":2988,"line":4717},[2986,12927,12928],{"class":2999},"    break",[2986,12930,4529],{"class":3003},[2964,12932,12933],{},"Відповідь:",[2976,12935,12937],{"className":3284,"code":12936,"language":3286,"meta":2981,"style":2981},"{\n  \"type\": \"https://api.example.com/errors/duplicate-email\",\n  \"title\": \"DuplicateEmail\",\n  \"status\": 409,\n  \"detail\": \"User with email 'john@example.com' already exists\",\n  \"email\": \"john@example.com\",\n  \"existingUserId\": 42,\n  \"suggestion\": \"Try logging in or use password reset\"\n}\n",[2983,12938,12939,12943,12954,12965,12975,12986,12998,13010,13020],{"__ignoreMap":2981},[2986,12940,12941],{"class":2988,"line":2989},[2986,12942,3293],{"class":3003},[2986,12944,12945,12947,12949,12952],{"class":2988,"line":2996},[2986,12946,3299],{"class":3298},[2986,12948,3302],{"class":3003},[2986,12950,12951],{"class":3085},"\"https://api.example.com/errors/duplicate-email\"",[2986,12953,3308],{"class":3003},[2986,12955,12956,12958,12960,12963],{"class":2988,"line":3007},[2986,12957,3313],{"class":3298},[2986,12959,3302],{"class":3003},[2986,12961,12962],{"class":3085},"\"DuplicateEmail\"",[2986,12964,3308],{"class":3003},[2986,12966,12967,12969,12971,12973],{"class":2988,"line":3044},[2986,12968,3325],{"class":3298},[2986,12970,3302],{"class":3003},[2986,12972,3516],{"class":3330},[2986,12974,3308],{"class":3003},[2986,12976,12977,12979,12981,12984],{"class":2988,"line":3062},[2986,12978,3338],{"class":3298},[2986,12980,3302],{"class":3003},[2986,12982,12983],{"class":3085},"\"User with email 'john@example.com' already exists\"",[2986,12985,3308],{"class":3003},[2986,12987,12988,12991,12993,12996],{"class":2988,"line":3068},[2986,12989,12990],{"class":3298},"  \"email\"",[2986,12992,3302],{"class":3003},[2986,12994,12995],{"class":3085},"\"john@example.com\"",[2986,12997,3308],{"class":3003},[2986,12999,13000,13003,13005,13008],{"class":2988,"line":3091},[2986,13001,13002],{"class":3298},"  \"existingUserId\"",[2986,13004,3302],{"class":3003},[2986,13006,13007],{"class":3330},"42",[2986,13009,3308],{"class":3003},[2986,13011,13012,13015,13017],{"class":2988,"line":3103},[2986,13013,13014],{"class":3298},"  \"suggestion\"",[2986,13016,3302],{"class":3003},[2986,13018,13019],{"class":3085},"\"Try logging in or use password reset\"\n",[2986,13021,13022],{"class":2988,"line":3126},[2986,13023,3242],{"class":3003},[3262,13025,13027],{"id":13026},"завдання-22-retry-after-header","Завдання 2.2: Retry-After header",[2964,13029,13030,13031,13034],{},"Додайте підтримку ",[2983,13032,13033],{},"Retry-After"," header для помилок rate limiting:",[12544,13036,13037],{"title":12676},[2976,13038,13040],{"className":3991,"code":13039,"language":3993,"meta":2981,"style":2981},"public class RateLimitExceededException : BusinessException\n{\n    public int RetryAfterSeconds { get; }\n\n    public RateLimitExceededException(int retryAfterSeconds)\n        : base(\n            $\"Rate limit exceeded. Retry after {retryAfterSeconds} seconds\",\n            StatusCodes.Status429TooManyRequests,\n            \"rate-limit-exceeded\")\n    {\n        RetryAfterSeconds = retryAfterSeconds;\n    }\n}\n\n// У GlobalExceptionHandler\ncase RateLimitExceededException rateLimitEx:\n    httpContext.Response.Headers.Append(\n        \"Retry-After\", \n        rateLimitEx.RetryAfterSeconds.ToString());\n    \n    problemDetails.Extensions[\"retryAfter\"] = rateLimitEx.RetryAfterSeconds;\n    break;\n",[2983,13041,13042,13055,13059,13074,13078,13093,13101,13118,13129,13136,13140,13151,13155,13159,13163,13168,13179,13198,13205,13222,13226,13250],{"__ignoreMap":2981},[2986,13043,13044,13046,13048,13051,13053],{"class":2988,"line":2989},[2986,13045,4000],{"class":3010},[2986,13047,4003],{"class":3010},[2986,13049,13050],{"class":4006}," RateLimitExceededException",[2986,13052,4191],{"class":3003},[2986,13054,4714],{"class":4006},[2986,13056,13057],{"class":2988,"line":2996},[2986,13058,3293],{"class":3003},[2986,13060,13061,13063,13065,13068,13070,13072],{"class":2988,"line":3007},[2986,13062,4016],{"class":3010},[2986,13064,4068],{"class":3010},[2986,13066,13067],{"class":3024}," RetryAfterSeconds",[2986,13069,4028],{"class":3003},[2986,13071,4031],{"class":3010},[2986,13073,4040],{"class":3003},[2986,13075,13076],{"class":2988,"line":3044},[2986,13077,4535],{"emptyLinePlaceholder":4534},[2986,13079,13080,13082,13084,13086,13088,13091],{"class":2988,"line":3062},[2986,13081,4016],{"class":3010},[2986,13083,13050],{"class":3031},[2986,13085,3035],{"class":3003},[2986,13087,11198],{"class":3010},[2986,13089,13090],{"class":3024}," retryAfterSeconds",[2986,13092,4651],{"class":3003},[2986,13094,13095,13097,13099],{"class":2988,"line":3068},[2986,13096,4641],{"class":3003},[2986,13098,4644],{"class":3010},[2986,13100,4605],{"class":3003},[2986,13102,13103,13106,13108,13111,13113,13116],{"class":2988,"line":3091},[2986,13104,13105],{"class":3085},"            $\"Rate limit exceeded. Retry after ",[2986,13107,4775],{"class":4774},[2986,13109,13110],{"class":3024},"retryAfterSeconds",[2986,13112,4781],{"class":4774},[2986,13114,13115],{"class":3085}," seconds\"",[2986,13117,3308],{"class":3003},[2986,13119,13120,13122,13124,13127],{"class":2988,"line":3103},[2986,13121,4792],{"class":3024},[2986,13123,3028],{"class":3003},[2986,13125,13126],{"class":3024},"Status429TooManyRequests",[2986,13128,3308],{"class":3003},[2986,13130,13131,13134],{"class":2988,"line":3126},[2986,13132,13133],{"class":3085},"            \"rate-limit-exceeded\"",[2986,13135,4651],{"class":3003},[2986,13137,13138],{"class":2988,"line":3141},[2986,13139,4656],{"class":3003},[2986,13141,13142,13145,13147,13149],{"class":2988,"line":3161},[2986,13143,13144],{"class":3024},"        RetryAfterSeconds",[2986,13146,3018],{"class":3003},[2986,13148,13110],{"class":3024},[2986,13150,4529],{"class":3003},[2986,13152,13153],{"class":2988,"line":3177},[2986,13154,4373],{"class":3003},[2986,13156,13157],{"class":2988,"line":3197},[2986,13158,3242],{"class":3003},[2986,13160,13161],{"class":2988,"line":3212},[2986,13162,4535],{"emptyLinePlaceholder":4534},[2986,13164,13165],{"class":2988,"line":3221},[2986,13166,13167],{"class":2992},"// У GlobalExceptionHandler\n",[2986,13169,13170,13172,13174,13177],{"class":2988,"line":3233},[2986,13171,12845],{"class":3024},[2986,13173,13050],{"class":3024},[2986,13175,13176],{"class":12850}," rateLimitEx",[2986,13178,6890],{"class":3003},[2986,13180,13181,13184,13186,13188,13190,13192,13194,13196],{"class":2988,"line":3239},[2986,13182,13183],{"class":3024},"    httpContext",[2986,13185,3028],{"class":3003},[2986,13187,6551],{"class":3024},[2986,13189,3028],{"class":3003},[2986,13191,11640],{"class":3024},[2986,13193,3028],{"class":3003},[2986,13195,11698],{"class":3031},[2986,13197,4605],{"class":3003},[2986,13199,13200,13203],{"class":2988,"line":4413},[2986,13201,13202],{"class":3085},"        \"Retry-After\"",[2986,13204,4616],{"class":3003},[2986,13206,13207,13210,13212,13215,13217,13219],{"class":2988,"line":4691},[2986,13208,13209],{"class":3024},"        rateLimitEx",[2986,13211,3028],{"class":3003},[2986,13213,13214],{"class":3024},"RetryAfterSeconds",[2986,13216,3028],{"class":3003},[2986,13218,11670],{"class":3031},[2986,13220,13221],{"class":3003},"());\n",[2986,13223,13224],{"class":2988,"line":4696},[2986,13225,4378],{"class":3003},[2986,13227,13228,13230,13232,13234,13236,13239,13241,13244,13246,13248],{"class":2988,"line":4702},[2986,13229,12858],{"class":3024},[2986,13231,3028],{"class":3003},[2986,13233,4149],{"class":3024},[2986,13235,6842],{"class":3003},[2986,13237,13238],{"class":3085},"\"retryAfter\"",[2986,13240,6848],{"class":3003},[2986,13242,13243],{"class":3024},"rateLimitEx",[2986,13245,3028],{"class":3003},[2986,13247,13214],{"class":3024},[2986,13249,4529],{"class":3003},[2986,13251,13252,13254],{"class":2988,"line":4717},[2986,13253,12928],{"class":2999},[2986,13255,4529],{"class":3003},[3597,13257],{},[3262,13259,13261],{"id":13260},"рівень-3-архітектура-та-створення","Рівень 3: Архітектура та створення",[4434,13263,13264,13268,13271],{},[3262,13265,13267],{"id":13266},"завдання-31-централізована-система-error-codes","Завдання 3.1: Централізована система error codes",[2964,13269,13270],{},"Створіть систему для управління error codes з документацією:",[12544,13272,13274,13693,13697],{"title":13273},"Показати структуру рішення",[2976,13275,13277],{"className":3991,"code":13276,"language":3993,"meta":2981,"style":2981},"// ErrorCatalog.cs\npublic static class ErrorCatalog\n{\n    public static class Banking\n    {\n        public static readonly ErrorDefinition AccountNotFound = new(\n            Code: \"BANK_001\",\n            Title: \"Account Not Found\",\n            Description: \"The specified account does not exist\",\n            HttpStatus: 404,\n            DocumentationUrl: \"https://docs.api.com/errors/BANK_001\"\n        );\n\n        public static readonly ErrorDefinition InsufficientFunds = new(\n            Code: \"BANK_002\",\n            Title: \"Insufficient Funds\",\n            Description: \"Account balance is insufficient for the transaction\",\n            HttpStatus: 409,\n            DocumentationUrl: \"https://docs.api.com/errors/BANK_002\"\n        );\n    }\n}\n\npublic record ErrorDefinition(\n    string Code,\n    string Title,\n    string Description,\n    int HttpStatus,\n    string DocumentationUrl\n);\n\n// Використання\npublic class AccountNotFoundException : BusinessException\n{\n    public AccountNotFoundException(string accountId)\n        : base(\n            ErrorCatalog.Banking.AccountNotFound,\n            $\"Account '{accountId}' does not exist\")\n    {\n    }\n}\n\n// У ProblemDetails\nproblemDetails.Type = exception.ErrorDefinition.DocumentationUrl;\nproblemDetails.Extensions[\"errorCode\"] = exception.ErrorDefinition.Code;\n",[2983,13278,13279,13284,13295,13299,13310,13314,13335,13347,13357,13369,13380,13390,13395,13399,13418,13429,13439,13450,13460,13469,13473,13477,13481,13485,13495,13505,13514,13523,13533,13540,13544,13548,13552,13564,13568,13582,13590,13607,13622,13626,13630,13634,13638,13642,13666],{"__ignoreMap":2981},[2986,13280,13281],{"class":2988,"line":2989},[2986,13282,13283],{"class":2992},"// ErrorCatalog.cs\n",[2986,13285,13286,13288,13290,13292],{"class":2988,"line":2996},[2986,13287,4000],{"class":3010},[2986,13289,11100],{"class":3010},[2986,13291,4003],{"class":3010},[2986,13293,13294],{"class":4006}," ErrorCatalog\n",[2986,13296,13297],{"class":2988,"line":3007},[2986,13298,3293],{"class":3003},[2986,13300,13301,13303,13305,13307],{"class":2988,"line":3044},[2986,13302,4016],{"class":3010},[2986,13304,11100],{"class":3010},[2986,13306,4003],{"class":3010},[2986,13308,13309],{"class":4006}," Banking\n",[2986,13311,13312],{"class":2988,"line":3062},[2986,13313,4656],{"class":3003},[2986,13315,13316,13319,13321,13323,13326,13329,13331,13333],{"class":2988,"line":3068},[2986,13317,13318],{"class":3010},"        public",[2986,13320,11100],{"class":3010},[2986,13322,6139],{"class":3010},[2986,13324,13325],{"class":4006}," ErrorDefinition",[2986,13327,13328],{"class":3024}," AccountNotFound",[2986,13330,3018],{"class":3003},[2986,13332,6700],{"class":3010},[2986,13334,4605],{"class":3003},[2986,13336,13337,13340,13342,13345],{"class":2988,"line":3091},[2986,13338,13339],{"class":3024},"            Code",[2986,13341,3302],{"class":3003},[2986,13343,13344],{"class":3085},"\"BANK_001\"",[2986,13346,3308],{"class":3003},[2986,13348,13349,13351,13353,13355],{"class":2988,"line":3103},[2986,13350,6735],{"class":3024},[2986,13352,3302],{"class":3003},[2986,13354,3318],{"class":3085},[2986,13356,3308],{"class":3003},[2986,13358,13359,13362,13364,13367],{"class":2988,"line":3126},[2986,13360,13361],{"class":3024},"            Description",[2986,13363,3302],{"class":3003},[2986,13365,13366],{"class":3085},"\"The specified account does not exist\"",[2986,13368,3308],{"class":3003},[2986,13370,13371,13374,13376,13378],{"class":2988,"line":3141},[2986,13372,13373],{"class":3024},"            HttpStatus",[2986,13375,3302],{"class":3003},[2986,13377,3331],{"class":3330},[2986,13379,3308],{"class":3003},[2986,13381,13382,13385,13387],{"class":2988,"line":3161},[2986,13383,13384],{"class":3024},"            DocumentationUrl",[2986,13386,3302],{"class":3003},[2986,13388,13389],{"class":3085},"\"https://docs.api.com/errors/BANK_001\"\n",[2986,13391,13392],{"class":2988,"line":3177},[2986,13393,13394],{"class":3003},"        );\n",[2986,13396,13397],{"class":2988,"line":3197},[2986,13398,4535],{"emptyLinePlaceholder":4534},[2986,13400,13401,13403,13405,13407,13409,13412,13414,13416],{"class":2988,"line":3212},[2986,13402,13318],{"class":3010},[2986,13404,11100],{"class":3010},[2986,13406,6139],{"class":3010},[2986,13408,13325],{"class":4006},[2986,13410,13411],{"class":3024}," InsufficientFunds",[2986,13413,3018],{"class":3003},[2986,13415,6700],{"class":3010},[2986,13417,4605],{"class":3003},[2986,13419,13420,13422,13424,13427],{"class":2988,"line":3221},[2986,13421,13339],{"class":3024},[2986,13423,3302],{"class":3003},[2986,13425,13426],{"class":3085},"\"BANK_002\"",[2986,13428,3308],{"class":3003},[2986,13430,13431,13433,13435,13437],{"class":2988,"line":3233},[2986,13432,6735],{"class":3024},[2986,13434,3302],{"class":3003},[2986,13436,3505],{"class":3085},[2986,13438,3308],{"class":3003},[2986,13440,13441,13443,13445,13448],{"class":2988,"line":3239},[2986,13442,13361],{"class":3024},[2986,13444,3302],{"class":3003},[2986,13446,13447],{"class":3085},"\"Account balance is insufficient for the transaction\"",[2986,13449,3308],{"class":3003},[2986,13451,13452,13454,13456,13458],{"class":2988,"line":4413},[2986,13453,13373],{"class":3024},[2986,13455,3302],{"class":3003},[2986,13457,3516],{"class":3330},[2986,13459,3308],{"class":3003},[2986,13461,13462,13464,13466],{"class":2988,"line":4691},[2986,13463,13384],{"class":3024},[2986,13465,3302],{"class":3003},[2986,13467,13468],{"class":3085},"\"https://docs.api.com/errors/BANK_002\"\n",[2986,13470,13471],{"class":2988,"line":4696},[2986,13472,13394],{"class":3003},[2986,13474,13475],{"class":2988,"line":4702},[2986,13476,4373],{"class":3003},[2986,13478,13479],{"class":2988,"line":4717},[2986,13480,3242],{"class":3003},[2986,13482,13483],{"class":2988,"line":4722},[2986,13484,4535],{"emptyLinePlaceholder":4534},[2986,13486,13487,13489,13491,13493],{"class":2988,"line":4738},[2986,13488,4000],{"class":3010},[2986,13490,5829],{"class":3010},[2986,13492,13325],{"class":4006},[2986,13494,4605],{"class":3003},[2986,13496,13497,13500,13503],{"class":2988,"line":4743},[2986,13498,13499],{"class":3010},"    string",[2986,13501,13502],{"class":3024}," Code",[2986,13504,3308],{"class":3003},[2986,13506,13507,13509,13512],{"class":2988,"line":4759},[2986,13508,13499],{"class":3010},[2986,13510,13511],{"class":3024}," Title",[2986,13513,3308],{"class":3003},[2986,13515,13516,13518,13521],{"class":2988,"line":4768},[2986,13517,13499],{"class":3010},[2986,13519,13520],{"class":3024}," Description",[2986,13522,3308],{"class":3003},[2986,13524,13525,13528,13531],{"class":2988,"line":4789},[2986,13526,13527],{"class":3010},"    int",[2986,13529,13530],{"class":3024}," HttpStatus",[2986,13532,3308],{"class":3003},[2986,13534,13535,13537],{"class":2988,"line":4802},[2986,13536,13499],{"class":3010},[2986,13538,13539],{"class":3024}," DocumentationUrl\n",[2986,13541,13542],{"class":2988,"line":4810},[2986,13543,3041],{"class":3003},[2986,13545,13546],{"class":2988,"line":4815},[2986,13547,4535],{"emptyLinePlaceholder":4534},[2986,13549,13550],{"class":2988,"line":4827},[2986,13551,11258],{"class":2992},[2986,13553,13554,13556,13558,13560,13562],{"class":2988,"line":4832},[2986,13555,4000],{"class":3010},[2986,13557,4003],{"class":3010},[2986,13559,4709],{"class":4006},[2986,13561,4191],{"class":3003},[2986,13563,4714],{"class":4006},[2986,13565,13566],{"class":2988,"line":4837},[2986,13567,3293],{"class":3003},[2986,13569,13570,13572,13574,13576,13578,13580],{"class":2988,"line":4842},[2986,13571,4016],{"class":3010},[2986,13573,4709],{"class":3031},[2986,13575,3035],{"class":3003},[2986,13577,3733],{"class":3010},[2986,13579,4754],{"class":3024},[2986,13581,4651],{"class":3003},[2986,13583,13584,13586,13588],{"class":2988,"line":4848},[2986,13585,4641],{"class":3003},[2986,13587,4644],{"class":3010},[2986,13589,4605],{"class":3003},[2986,13591,13592,13595,13597,13600,13602,13605],{"class":2988,"line":4862},[2986,13593,13594],{"class":3024},"            ErrorCatalog",[2986,13596,3028],{"class":3003},[2986,13598,13599],{"class":3024},"Banking",[2986,13601,3028],{"class":3003},[2986,13603,13604],{"class":3024},"AccountNotFound",[2986,13606,3308],{"class":3003},[2986,13608,13609,13612,13614,13616,13618,13620],{"class":2988,"line":4867},[2986,13610,13611],{"class":3085},"            $\"Account '",[2986,13613,4775],{"class":4774},[2986,13615,4778],{"class":3024},[2986,13617,4781],{"class":4774},[2986,13619,4784],{"class":3085},[2986,13621,4651],{"class":3003},[2986,13623,13624],{"class":2988,"line":4884},[2986,13625,4656],{"class":3003},[2986,13627,13628],{"class":2988,"line":4900},[2986,13629,4373],{"class":3003},[2986,13631,13632],{"class":2988,"line":4916},[2986,13633,3242],{"class":3003},[2986,13635,13636],{"class":2988,"line":4921},[2986,13637,4535],{"emptyLinePlaceholder":4534},[2986,13639,13640],{"class":2988,"line":4930},[2986,13641,12431],{"class":2992},[2986,13643,13644,13646,13648,13650,13652,13654,13656,13659,13661,13664],{"class":2988,"line":4941},[2986,13645,6560],{"class":3024},[2986,13647,3028],{"class":3003},[2986,13649,4025],{"class":3024},[2986,13651,3018],{"class":3003},[2986,13653,6398],{"class":3024},[2986,13655,3028],{"class":3003},[2986,13657,13658],{"class":3024},"ErrorDefinition",[2986,13660,3028],{"class":3003},[2986,13662,13663],{"class":3024},"DocumentationUrl",[2986,13665,4529],{"class":3003},[2986,13667,13668,13670,13672,13674,13676,13678,13680,13682,13684,13686,13688,13691],{"class":2988,"line":4951},[2986,13669,6560],{"class":3024},[2986,13671,3028],{"class":3003},[2986,13673,4149],{"class":3024},[2986,13675,6842],{"class":3003},[2986,13677,12444],{"class":3085},[2986,13679,6848],{"class":3003},[2986,13681,6398],{"class":3024},[2986,13683,3028],{"class":3003},[2986,13685,13658],{"class":3024},[2986,13687,3028],{"class":3003},[2986,13689,13690],{"class":3024},"Code",[2986,13692,4529],{"class":3003},[2964,13694,13695],{},[2971,13696,11441],{},[3571,13698,13699,13702,13705],{},[3574,13700,13701],{},"Централізована документація помилок",[3574,13703,13704],{},"Легко генерувати error catalog для клієнтів",[3574,13706,13707],{},"Консистентність кодів та повідомлень",[3597,13709],{},[2959,13711,13713],{"id":13712},"підсумок","Підсумок",[2964,13715,13716,13717,13720],{},"У цій статті ми опанували професійну обробку помилок у Web API через стандарт RFC 9457 ProblemDetails. Ви навчилися не просто повертати помилки, а ",[2971,13718,13719],{},"створювати консистентну мову спілкування"," між сервером та клієнтом про проблеми.",[2964,13722,13723],{},[2971,13724,13725],{},"Ключові висновки:",[5426,13727,13728,13734,13740,13755,13761,13767],{},[3574,13729,13730,13733],{},[2971,13731,13732],{},"ProblemDetails — це стандарт:"," RFC 9457 забезпечує консистентність помилок у всьому API. Клієнт пише обробку помилок один раз для всіх endpoints.",[3574,13735,13736,13739],{},[2971,13737,13738],{},"IExceptionHandler — сучасний підхід:"," .NET 8+ надає потужний механізм централізованої обробки винятків з повною підтримкою DI та async/await.",[3574,13741,13742,13745,13746,4140,13749,13752,13753,3028],{},[2971,13743,13744],{},"Кастомні винятки для бізнес-логіки:"," Створюйте спеціалізовані винятки (",[2983,13747,13748],{},"InsufficientFundsException",[2983,13750,13751],{},"AccountLockedException",") з релевантними властивостями замість generic ",[2983,13754,10418],{},[3574,13756,13757,13760],{},[2971,13758,13759],{},"TraceId критичний для debugging:"," Додавайте correlation IDs до всіх помилок для відстеження запитів через distributed systems.",[3574,13762,13763,13766],{},[2971,13764,13765],{},"Environment-aware обробка:"," У development показуйте stack traces, у production — приховуйте деталі реалізації.",[3574,13768,13769,13772,13773,4140,13775,4140,13777,13779],{},[2971,13770,13771],{},"Кастомні поля через Extensions:"," Додавайте релевантний контекст (",[2983,13774,4982],{},[2983,13776,5005],{},[2983,13778,12319],{},") для кращої обробки на клієнті.",[2964,13781,13782,13783,13785],{},"У наступній статті ми розглянемо ",[2971,13784,1315],{}," — як використовувати action filters, exception filters та result filters для cross-cutting concerns.",[3597,13787],{},[2959,13789,13791],{"id":13790},"додаткові-ресурси","Додаткові ресурси",[3917,13793,13794,13800,13805,13811],{},[3920,13795,13799],{"icon":15,"title":13796,"target":13797,"to":13798},"RFC 9457 (ProblemDetails)","_blank","https://www.rfc-editor.org/rfc/rfc9457.html","Офіційна специфікація ProblemDetails",[3920,13801,13804],{"icon":13802,"title":3585,"target":13797,"to":13803},"i-lucide-shield-alert","https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling","Microsoft Docs: Error Handling в ASP.NET Core",[3920,13806,13810],{"icon":13807,"title":13808,"target":13797,"to":13809},"i-lucide-alert-triangle","Problem Details for HTTP APIs","https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails","API Reference: ProblemDetails клас",[3920,13812,13816],{"icon":13813,"title":13814,"target":13797,"to":13815},"i-lucide-git-branch","Distributed Tracing","https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing","Distributed Tracing у .NET",[3597,13818],{},[3255,13820,13821,4453,13824,13826],{},[2971,13822,13823],{},"Наступна стаття:",[8752,13825,1315],{"href":1316}," — Action Filters, Exception Filters, Result Filters для API. Валідація DTO, response wrapping, correlation IDs.",[13828,13829,13830],"style",{},"html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sCDza, html code.shiki .sCDza{--shiki-light:#AF00DB;--shiki-default:#CE92A4;--shiki-dark:#CE92A4}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .s0P7L, html code.shiki .s0P7L{--shiki-light:#800000;--shiki-default:#808080;--shiki-dark:#808080}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s5IvJ, html code.shiki .s5IvJ{--shiki-light:#000000;--shiki-default:#C8C8C8;--shiki-dark:#C8C8C8}",{"title":2981,"searchDepth":2996,"depth":2996,"links":13832},[13833,13836,13841,13851,13856,13861,13871,13872],{"id":2961,"depth":2996,"text":2962,"children":13834},[13835],{"id":3264,"depth":3007,"text":3265},{"id":3601,"depth":2996,"text":3602,"children":13837},[13838,13839,13840],{"id":3605,"depth":3007,"text":3606},{"id":3914,"depth":3007,"text":3915},{"id":3973,"depth":3007,"text":3974},{"id":4421,"depth":2996,"text":4422,"children":13842},[13843,13844,13845,13846,13847,13848,13849,13850],{"id":4431,"depth":3007,"text":4432},{"id":4438,"depth":3007,"text":4439},{"id":4501,"depth":3007,"text":4502},{"id":5466,"depth":3007,"text":5467},{"id":6015,"depth":3007,"text":6016},{"id":7699,"depth":3007,"text":7700},{"id":8352,"depth":3007,"text":8353},{"id":9956,"depth":3007,"text":9957},{"id":10279,"depth":2996,"text":10280,"children":13852},[13853,13854,13855],{"id":10283,"depth":3007,"text":10284},{"id":10724,"depth":3007,"text":10725},{"id":10978,"depth":3007,"text":10979},{"id":11482,"depth":2996,"text":11483,"children":13857},[13858,13859,13860],{"id":11486,"depth":3007,"text":11487},{"id":11887,"depth":3007,"text":11888},{"id":12226,"depth":3007,"text":12227},{"id":12528,"depth":2996,"text":12529,"children":13862},[13863,13864,13865,13866,13867,13868,13869,13870],{"id":12532,"depth":3007,"text":12533},{"id":12538,"depth":3007,"text":12539},{"id":12589,"depth":3007,"text":12590},{"id":12659,"depth":3007,"text":12660},{"id":12665,"depth":3007,"text":12666},{"id":13026,"depth":3007,"text":13027},{"id":13260,"depth":3007,"text":13261},{"id":13266,"depth":3007,"text":13267},{"id":13712,"depth":2996,"text":13713},{"id":13790,"depth":2996,"text":13791},"Реалізація RFC 9457 для консистентних помилок API. GlobalExceptionHandler, IExceptionHandler, IProblemDetailsService, кастомні error codes та traceability.","md",null,{},{"title":1311,"description":13873},"drDrFvW6jWbevdraOzQxRQJrG2Uff4XxLmkDWY9MJsw",[13880,13882],{"title":1307,"path":1308,"stem":1309,"description":13881,"children":-1},"Стратегії версіонування REST API для управління breaking changes. URL path, query string, HTTP headers, media type versioning. Пакет Asp.Versioning.Mvc, deprecation flow та migration guides.",{"title":1315,"path":1316,"stem":1317,"description":13883,"children":-1},"Action Filters, Exception Filters, Result Filters для API. Централізована валідація DTO, response wrapping (envelope pattern), correlation IDs, API key authentication та performance monitoring.",1777912428514]