Browse Source

first commit on gogs

ssensager 1 tháng trước cách đây
commit
5afc478f1a
86 tập tin đã thay đổi với 7376 bổ sung0 xóa
  1. 105 0
      diagrams/C4_Component.puml
  2. 111 0
      diagrams/C4_Container.puml
  3. 448 0
      diagrams/C4_Context.puml
  4. 3 0
      diagrams/DFD-2bussines.drawio.svg
  5. 372 0
      diagrams/DFD.drawio
  6. 3 0
      diagrams/IDEF0(MAIN)(1).svg
  7. 3 0
      diagrams/IDEF0(check_role).svg
  8. 3 0
      diagrams/IDEF0(decomp).svg
  9. 3 0
      diagrams/IDEF0(main).svg
  10. 100 0
      diagrams/IDEF0.drawio
  11. 3 0
      diagrams/System schemas.svg
  12. 3 0
      diagrams/System_interaction_schemas.svg
  13. 3 0
      diagrams/System_resource_schemas.svg
  14. 3 0
      diagrams/System_schemas.svg
  15. 3 0
      diagrams/System_working_schemas.svg
  16. BIN
      diagrams/UML(Classes)(1).drawio.png
  17. 3 0
      diagrams/UML(Classes)(1).svg
  18. 3 0
      diagrams/UML(activity).svg
  19. 140 0
      diagrams/Untitled Diagram.drawio
  20. 3 0
      diagrams/Untitled Diagram.drawio.svg
  21. 3 0
      diagrams/algorithm_system_work.svg
  22. 50 0
      diagrams/c4-component.puml
  23. 28 0
      diagrams/c4-container.puml
  24. 17 0
      diagrams/c4-context.puml
  25. 3 0
      diagrams/data_schemas.svg
  26. 3 0
      diagrams/system_works_schemas.svg
  27. 3 0
      diagrams/usecase(bussiness).svg
  28. 3 0
      diagrams/usecase(concept).drawio.svg
  29. 3 0
      diagrams/Диаграмма без названия.drawio(6).svg
  30. 3 0
      diagrams/Диаграмма без названия.drawio(7).svg
  31. 3 0
      diagrams/Диаграмма без названия.drawio(8).svg
  32. 3 0
      diagrams/Диаграмма без названия.drawio(9).svg
  33. 153 0
      diagrams/декомпозиция.drawio
  34. 139 0
      lab11/dumb.sql
  35. 80 0
      lab11/erd.markup
  36. BIN
      lab11/erd.png
  37. 15 0
      lab11/indexes.sql
  38. BIN
      lab11/lab11.docx
  39. BIN
      lab11/phys.png
  40. 105 0
      lab11/requests.sql
  41. 55 0
      lab11/topol.plantuml
  42. BIN
      lab11/topol.png
  43. 25 0
      lab11/views.sql
  44. BIN
      lab11/~$11. Работа с PostgresPro.docx
  45. BIN
      lab11/ЛР11. Работа с PostgresPro.docx
  46. BIN
      lab11/Пример спецификации для приложения базы данных.docx
  47. 52 0
      lab12/src/config/config.ovpn
  48. 2 0
      lab12/src/config/login.txt
  49. BIN
      lab12/src/openvpn-connect-3.8.0.4528_signed.msi
  50. BIN
      lab12/ЛР12. Работа с MongoDB.docx
  51. 1 0
      lab14/GovTaskManager.gui
  52. 3428 0
      lab14/Pravila_oformlenia.pdf
  53. 3 0
      lab14/readme.md
  54. BIN
      lab14/ЛР14 Документирование.docx
  55. BIN
      lab14/СТО 1.701-2010 Текстовые документы. Общие требования к построению и оформлению (2).doc
  56. BIN
      lab6/lab6.docx
  57. BIN
      lab7/lab7.docx
  58. 9 0
      lab9/LibraryManagmentSystem/.gitignore
  59. 37 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Database/DatabaseManager.cs
  60. 13 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Database/DbConfig.cs
  61. 19 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/LibraryManagementSystem.Console.csproj
  62. 37 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Models/Book.cs
  63. 32 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Models/User.cs
  64. 312 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Program.cs
  65. 162 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/BookRepository.cs
  66. 19 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/IBookRepository.cs
  67. 19 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/IUserRepository.cs
  68. 208 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/UserRepository.cs
  69. 22 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Utils/LoggerConfigurator.cs
  70. 33 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Utils/PasswordHasher.cs
  71. 24 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/DatabaseTests.cs
  72. 28 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/LibraryManagementSystem.Tests.csproj
  73. 28 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/TestHelper.cs
  74. 10 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/UnitTest1.cs
  75. 138 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/UserRepositoryTests.cs
  76. 4 0
      lab9/LibraryManagmentSystem/LibraryManagementSystem.slnx
  77. 24 0
      lab9/LibraryManagmentSystem/docker-compose.yml
  78. 32 0
      lab9/LibraryManagmentSystem/docker/init/init.sql
  79. 13 0
      lab9/LibraryManagmentSystem/dotnet-tools.json
  80. 125 0
      lab9/uml.plantuml
  81. BIN
      lab9/uml.png
  82. BIN
      others/information_system.docx
  83. BIN
      others/lab1(1).docx
  84. 533 0
      others/overview.md
  85. BIN
      others/schemas.docx
  86. BIN
      others/План-график (ИС).docx

+ 105 - 0
diagrams/C4_Component.puml

@@ -0,0 +1,105 @@
+' convert it with additional command line argument -DRELATIVE_INCLUDE="relative/absolute" to use locally
+!if %variable_exists("RELATIVE_INCLUDE")
+  !include ./C4_Container.puml
+!else
+  !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
+!endif
+
+' Scope: A single container.
+' Primary elements: Components within the container in scope.
+' Supporting elements: Containers (within the software system in scope) plus people and software systems directly connected to the components.
+' Intended audience: Software architects and developers.
+
+' Colors
+' ##################################
+
+!$COMPONENT_FONT_COLOR ?= "#000000"
+!$COMPONENT_BG_COLOR ?= "#85BBF0"
+!$COMPONENT_BORDER_COLOR ?= "#78A8D8"
+
+!$EXTERNAL_COMPONENT_LEGEND_TEXT ?= "external component"
+!$EXTERNAL_COMPONENT_FONT_COLOR ?= $COMPONENT_FONT_COLOR
+!$EXTERNAL_COMPONENT_BG_COLOR ?= "#CCCCCC"
+!$EXTERNAL_COMPONENT_BORDER_COLOR ?= "#BFBFBF"
+
+' New C4 style automatically swaps font and background colors, but with those settings the component/node background would be black.
+' Therefore the colors should be displayed unchanged (the init colors have to be swapped too).
+!$NEW_C4_USE_ORIGINAL_COMPONENT_COLORS ?= 1
+!$componentColorsSwappedAlready ?= 0
+!if (NEW_C4_STYLE == 1 && $NEW_C4_USE_ORIGINAL_COMPONENT_COLORS == 1 && $componentColorsSwappedAlready == 0)
+  !$swap=$COMPONENT_BG_COLOR
+  !$COMPONENT_BG_COLOR=$COMPONENT_FONT_COLOR
+  !$COMPONENT_FONT_COLOR=$swap
+  !$swap=$EXTERNAL_COMPONENT_BG_COLOR
+  !$EXTERNAL_COMPONENT_BG_COLOR=$EXTERNAL_COMPONENT_FONT_COLOR
+  !$EXTERNAL_COMPONENT_FONT_COLOR=$swap
+  ' don't swap them again below if C4_... included again
+  !$componentColorsSwappedAlready=1
+!endif
+
+' Labels
+' ##################################
+
+!$COMPONENT_LEGEND_TEXT ?= "component"
+!$EXTERNAL_COMPONENT_LEGEND_TEXT ?= "external component"
+
+' Styling
+' ##################################
+
+UpdateElementStyle("component", $COMPONENT_BG_COLOR, $COMPONENT_FONT_COLOR, $COMPONENT_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$COMPONENT_LEGEND_TEXT")
+UpdateElementStyle("external_component", $EXTERNAL_COMPONENT_BG_COLOR, $EXTERNAL_COMPONENT_FONT_COLOR, $EXTERNAL_COMPONENT_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$EXTERNAL_COMPONENT_LEGEND_TEXT")
+
+' shortcuts with default colors
+!unquoted procedure AddComponentTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $techn="", $legendText="", $legendSprite="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("component", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $techn, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+!unquoted procedure AddExternalComponentTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $techn="", $legendText="", $legendSprite="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("external_component", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $techn, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+
+' Layout
+' ##################################
+
+SetDefaultLegendEntries("person\nsystem\ncontainer\ncomponent\nexternal_person\nexternal_system\nexternal_container\nexternal_component\nenterprise_boundary\nsystem_boundary\ncontainer_boundary\nboundary")
+
+!procedure LAYOUT_WITH_LEGEND()
+hide stereotype
+legend right
+|<color:$LEGEND_TITLE_COLOR>**Legend**</color> |
+|<$PERSON_BG_COLOR> person |
+|<$SYSTEM_BG_COLOR> system |
+|<$CONTAINER_BG_COLOR> container |
+|<$COMPONENT_BG_COLOR> component |
+|<$EXTERNAL_PERSON_BG_COLOR> external person |
+|<$EXTERNAL_SYSTEM_BG_COLOR> external system |
+|<$EXTERNAL_CONTAINER_BG_COLOR> external container |
+|<$EXTERNAL_COMPONENT_BG_COLOR> external component |
+endlegend
+!endprocedure
+
+' Elements
+' ##################################
+
+!unquoted procedure Component($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle")
+  $getElementLine($baseShape, "component", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ComponentDb($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("database", "component", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ComponentQueue($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("queue", "component", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure Component_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle")
+  $getElementLine($baseShape, "external_component", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ComponentDb_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("database", "external_component", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ComponentQueue_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("queue", "external_component", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure

+ 111 - 0
diagrams/C4_Container.puml

@@ -0,0 +1,111 @@
+' convert it with additional command line argument -DRELATIVE_INCLUDE="relative/absolute" to use locally
+!if %variable_exists("RELATIVE_INCLUDE")
+  !include ./C4_Context.puml
+!else
+  !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
+!endif
+
+' Scope: A single software system.
+' Primary elements: Containers within the software system in scope.
+' Supporting elements: People and software systems directly connected to the containers.
+' Intended audience: Technical people inside and outside of the software development team; including software architects, developers and operations/support staff.
+
+' Colors
+' ##################################
+
+!$CONTAINER_FONT_COLOR ?= $ELEMENT_FONT_COLOR
+!$CONTAINER_BG_COLOR ?= "#438DD5"
+!$CONTAINER_BORDER_COLOR ?= "#3C7FC0"
+
+!$CONTAINER_BOUNDARY_COLOR ?= $BOUNDARY_COLOR
+!$CONTAINER_BOUNDARY_BG_COLOR ?= $BOUNDARY_BG_COLOR
+!$CONTAINER_BOUNDARY_BORDER_STYLE ?= $BOUNDARY_BORDER_STYLE
+
+!$EXTERNAL_CONTAINER_FONT_COLOR ?= $ELEMENT_FONT_COLOR
+!$EXTERNAL_CONTAINER_BG_COLOR ?= "#B3B3B3"
+!$EXTERNAL_CONTAINER_BORDER_COLOR ?= "#A6A6A6"
+
+' Labels
+' ##################################
+
+!$CONTAINER_LEGEND_TEXT ?= "container"
+!$CONTAINER_BOUNDARY_TYPE ?= "container"
+!$CONTAINER_BOUNDARY_LEGEND_TEXT ?= "container boundary"
+!$EXTERNAL_CONTAINER_LEGEND_TEXT ?= "external container"
+
+' Styling
+' ##################################
+UpdateElementStyle("container", $CONTAINER_BG_COLOR, $CONTAINER_FONT_COLOR, $CONTAINER_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$CONTAINER_LEGEND_TEXT")
+UpdateElementStyle("external_container", $EXTERNAL_CONTAINER_BG_COLOR, $EXTERNAL_CONTAINER_FONT_COLOR, $EXTERNAL_CONTAINER_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$EXTERNAL_CONTAINER_LEGEND_TEXT")
+
+UpdateBoundaryStyle("container", $bgColor=$CONTAINER_BOUNDARY_BG_COLOR, $fontColor=$CONTAINER_BOUNDARY_COLOR, $borderColor=$CONTAINER_BOUNDARY_COLOR, $type="$CONTAINER_BOUNDARY_TYPE", $shape=$DEFAULT_SHAPE, $legendText="$CONTAINER_BOUNDARY_LEGEND_TEXT")
+
+' shortcuts with default colors
+!unquoted procedure AddContainerTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $techn="", $legendText="", $legendSprite="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("container", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $techn, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+!unquoted procedure AddExternalContainerTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $techn="", $legendText="", $legendSprite="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("external_container", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $techn, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+
+!unquoted procedure UpdateContainerBoundaryStyle($bgColor=$CONTAINER_BOUNDARY_BG_COLOR, $fontColor=$CONTAINER_BOUNDARY_COLOR, $borderColor=$CONTAINER_BOUNDARY_COLOR, $shadowing="", $shape="", $type="Container", $legendText="", $borderStyle="", $borderThickness="", $sprite="", $legendSprite="")
+  UpdateBoundaryStyle("container", $bgColor, $fontColor, $borderColor, $shadowing, $shape, $type, $legendText, $borderStyle, $borderThickness, $sprite, $legendSprite)
+!endprocedure
+
+' Layout
+' ##################################
+
+SetDefaultLegendEntries("person\nsystem\ncontainer\nexternal_person\nexternal_system\nexternal_container\nenterprise_boundary\nsystem_boundary\ncontainer_boundary\nboundary")
+
+!procedure LAYOUT_WITH_LEGEND()
+hide stereotype
+legend right
+|<color:$LEGEND_TITLE_COLOR>**Legend**</color> |
+|<$PERSON_BG_COLOR> person |
+|<$SYSTEM_BG_COLOR> system |
+|<$CONTAINER_BG_COLOR> container |
+|<$EXTERNAL_PERSON_BG_COLOR> external person |
+|<$EXTERNAL_SYSTEM_BG_COLOR> external system |
+|<$EXTERNAL_CONTAINER_BG_COLOR> external container |
+endlegend
+!endprocedure
+
+' Elements
+' ##################################
+
+!unquoted procedure Container($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle")
+  $getElementLine($baseShape , "container", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ContainerDb($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("database", "container", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ContainerQueue($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("queue", "container", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure Container_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="", $baseShape="rectangle")
+  $getElementLine($baseShape , "external_container", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ContainerDb_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("database", "external_container", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure ContainerQueue_Ext($alias, $label, $techn="", $descr="", $sprite="", $tags="", $link="")
+  $getElementLine("queue", "external_container", $alias, $label, $techn, $descr, $sprite, $tags, $link)
+!endprocedure
+
+' Boundaries
+' ##################################
+
+!unquoted procedure Container_Boundary($alias, $label, $tags="", $link="", $descr = "")
+  !if ($tags != "")
+    !$allTags = $tags + '+container'
+  !else
+    !$allTags = 'container'
+  !endif
+  ' $type defined via $tag style
+  Boundary($alias, $label, "", $allTags, $link, $descr)
+!endprocedure

+ 448 - 0
diagrams/C4_Context.puml

@@ -0,0 +1,448 @@
+' convert it with additional command line argument -DRELATIVE_INCLUDE="relative/absolute" to use locally
+!if %variable_exists("RELATIVE_INCLUDE")
+  !include ./C4.puml
+!else
+  !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4.puml
+!endif
+
+' Scope: A single software system.
+' Primary elements: The software system in scope.
+' Supporting elements: People and software systems directly connected to the software system in scope.
+' Intended audience: Everybody, both technical and non-technical people, inside and outside of the software development team.
+
+' Colors
+' ##################################
+
+!$PERSON_FONT_COLOR ?= $ELEMENT_FONT_COLOR
+!$PERSON_BG_COLOR ?= "#08427B"
+!$PERSON_BORDER_COLOR ?= "#073B6F"
+
+!$EXTERNAL_PERSON_FONT_COLOR ?= $ELEMENT_FONT_COLOR
+!$EXTERNAL_PERSON_BG_COLOR ?= "#686868"
+!$EXTERNAL_PERSON_BORDER_COLOR ?= "#8A8A8A"
+
+!$SYSTEM_FONT_COLOR ?= $ELEMENT_FONT_COLOR
+!$SYSTEM_BG_COLOR ?= "#1168BD"
+!$SYSTEM_BORDER_COLOR ?= "#3C7FC0"
+
+!$SYSTEM_BOUNDARY_COLOR ?= $BOUNDARY_COLOR
+!$SYSTEM_BOUNDARY_BG_COLOR ?= $BOUNDARY_BG_COLOR
+!$SYSTEM_BOUNDARY_BORDER_STYLE ?= $BOUNDARY_BORDER_STYLE
+
+!$EXTERNAL_SYSTEM_FONT_COLOR ?= $ELEMENT_FONT_COLOR
+!$EXTERNAL_SYSTEM_BG_COLOR ?= "#999999"
+!$EXTERNAL_SYSTEM_BORDER_COLOR ?= "#8A8A8A"
+
+!$ENTERPRISE_BOUNDARY_COLOR ?= $BOUNDARY_COLOR
+!$ENTERPRISE_BOUNDARY_BG_COLOR ?= $BOUNDARY_BG_COLOR
+!$ENTERPRISE_BOUNDARY_BORDER_STYLE ?= $BOUNDARY_BORDER_STYLE
+
+' Labels
+' ##################################
+
+!$PERSON_LEGEND_TEXT ?= "person"
+!$EXTERNAL_PERSON_LEGEND_TEXT ?= "external person"
+
+!$SYSTEM_LEGEND_TEXT ?= "system"
+!$SYSTEM_BOUNDARY_TYPE ?= "system"
+!$SYSTEM_BOUNDARY_LEGEND_TEXT ?= "system boundary"
+!$EXTERNAL_SYSTEM_LEGEND_TEXT ?= "external system"
+
+!$ENTERPRISE_BOUNDARY_TYPE ?= "enterprise"
+!$ENTERPRISE_BOUNDARY_LEGEND_TEXT ?= "enterprise boundary"
+
+' Styling
+' ##################################
+
+UpdateElementStyle("person", $PERSON_BG_COLOR, $PERSON_FONT_COLOR, $PERSON_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$PERSON_LEGEND_TEXT")
+UpdateElementStyle("external_person", $EXTERNAL_PERSON_BG_COLOR, $EXTERNAL_PERSON_FONT_COLOR, $EXTERNAL_PERSON_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$EXTERNAL_PERSON_LEGEND_TEXT")
+UpdateElementStyle("system", $SYSTEM_BG_COLOR, $SYSTEM_FONT_COLOR, $SYSTEM_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$SYSTEM_LEGEND_TEXT")
+UpdateElementStyle("external_system", $EXTERNAL_SYSTEM_BG_COLOR, $EXTERNAL_SYSTEM_FONT_COLOR, $EXTERNAL_SYSTEM_BORDER_COLOR, $shape=$DEFAULT_SHAPE, $legendText="$EXTERNAL_SYSTEM_LEGEND_TEXT")
+
+UpdateBoundaryStyle("system", $bgColor=$SYSTEM_BOUNDARY_BG_COLOR, $fontColor=$SYSTEM_BOUNDARY_COLOR, $borderColor=$SYSTEM_BOUNDARY_COLOR, $type="$SYSTEM_BOUNDARY_TYPE", $shape=$DEFAULT_SHAPE, $legendText="$SYSTEM_BOUNDARY_LEGEND_TEXT")
+UpdateBoundaryStyle("enterprise", $bgColor=$ENTERPRISE_BOUNDARY_BG_COLOR, $fontColor=$ENTERPRISE_BOUNDARY_COLOR, $borderColor=$ENTERPRISE_BOUNDARY_COLOR, $type="$ENTERPRISE_BOUNDARY_TYPE", $shape=$DEFAULT_SHAPE, $legendText="$ENTERPRISE_BOUNDARY_LEGEND_TEXT")
+
+' shortcuts with default colors
+!unquoted procedure AddPersonTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $legendText="", $legendSprite="", $type="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("person", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $type, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+!unquoted procedure AddExternalPersonTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $legendText="", $legendSprite="", $type="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("external_person", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $type, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+!unquoted procedure AddSystemTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $legendText="", $legendSprite="", $type="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("system", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $type, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+!unquoted procedure AddExternalSystemTag($tagStereo, $bgColor="", $fontColor="", $borderColor="", $shadowing="", $shape="", $sprite="", $legendText="", $legendSprite="", $type="", $borderStyle="", $borderThickness="")
+  $addElementTagInclReuse("external_system", $tagStereo, $bgColor, $fontColor, $borderColor, $shadowing, $shape, $sprite, $type, $legendText, $legendSprite, $borderStyle, $borderThickness)
+!endprocedure
+
+!unquoted procedure UpdateEnterpriseBoundaryStyle($bgColor=$ENTERPRISE_BOUNDARY_BG_COLOR, $fontColor=$ENTERPRISE_BOUNDARY_COLOR, $borderColor=$ENTERPRISE_BOUNDARY_COLOR, $shadowing="", $shape="", $type="Enterprise", $legendText="", $borderStyle="", $borderThickness="", $sprite="", $legendSprite="")
+  UpdateBoundaryStyle("enterprise", $bgColor, $fontColor, $borderColor, $shadowing, $shape, $type, $legendText, $borderStyle, $borderThickness, $sprite, $legendSprite)
+!endprocedure
+!unquoted procedure UpdateSystemBoundaryStyle($bgColor=$SYSTEM_BOUNDARY_BG_COLOR, $fontColor=$SYSTEM_BOUNDARY_COLOR, $borderColor=$SYSTEM_BOUNDARY_COLOR, $shadowing="", $shape="", $type="System", $legendText="", $borderStyle="", $borderThickness="", $sprite="", $legendSprite="")
+  UpdateBoundaryStyle("system", $bgColor, $fontColor, $borderColor, $shadowing, $shape, $type, $legendText, $borderStyle, $borderThickness, $sprite, $legendSprite)
+!endprocedure
+
+' Sprites
+' ##################################
+
+sprite $person [48x48/16] {
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+0000000000000000000049BCCA7200000000000000000000
+0000000000000000006EFFFFFFFFB3000000000000000000
+00000000000000001CFFFFFFFFFFFF700000000000000000
+0000000000000001EFFFFFFFFFFFFFF80000000000000000
+000000000000000CFFFFFFFFFFFFFFFF6000000000000000
+000000000000007FFFFFFFFFFFFFFFFFF100000000000000
+00000000000001FFFFFFFFFFFFFFFFFFF900000000000000
+00000000000006FFFFFFFFFFFFFFFFFFFF00000000000000
+0000000000000BFFFFFFFFFFFFFFFFFFFF40000000000000
+0000000000000EFFFFFFFFFFFFFFFFFFFF70000000000000
+0000000000000FFFFFFFFFFFFFFFFFFFFF80000000000000
+0000000000000FFFFFFFFFFFFFFFFFFFFF80000000000000
+0000000000000DFFFFFFFFFFFFFFFFFFFF60000000000000
+0000000000000AFFFFFFFFFFFFFFFFFFFF40000000000000
+00000000000006FFFFFFFFFFFFFFFFFFFE00000000000000
+00000000000000EFFFFFFFFFFFFFFFFFF800000000000000
+000000000000007FFFFFFFFFFFFFFFFFF100000000000000
+000000000000000BFFFFFFFFFFFFFFFF5000000000000000
+0000000000000001DFFFFFFFFFFFFFF70000000000000000
+00000000000000000BFFFFFFFFFFFF500000000000000000
+0000000000000000005DFFFFFFFFA1000000000000000000
+0000000000000000000037ABB96100000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000025788300000000005886410000000000000
+000000000007DFFFFFFD9643347BFFFFFFFB400000000000
+0000000004EFFFFFFFFFFFFFFFFFFFFFFFFFFB1000000000
+000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFD200000000
+00000006FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE10000000
+0000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0000000
+000000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5000000
+000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD000000
+000009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF200000
+00000DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF600000
+00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000
+00001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA00000
+00001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB00000
+00001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB00000
+00001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB00000
+00001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA00000
+00000EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF700000
+000006FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE100000
+0000008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3000000
+000000014555555555555555555555555555555300000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+}
+
+sprite $person2 [48x48/16] {
+0000000000000000000049BCCA7200000000000000000000
+0000000000000000006EFFFFFFFFB3000000000000000000
+00000000000000001CFFFFFFFFFFFF700000000000000000
+0000000000000001EFFFFFFFFFFFFFF80000000000000000
+000000000000000CFFFFFFFFFFFFFFFF6000000000000000
+000000000000007FFFFFFFFFFFFFFFFFF100000000000000
+00000000000001FFFFFFFFFFFFFFFFFFF900000000000000
+00000000000006FFFFFFFFFFFFFFFFFFFF00000000000000
+0000000000000BFFFFFFFFFFFFFFFFFFFF40000000000000
+0000000000000EFFFFFFFFFFFFFFFFFFFF70000000000000
+0000000000000FFFFFFFFFFFFFFFFFFFFF80000000000000
+0000000000000FFFFFFFFFFFFFFFFFFFFF80000000000000
+0000000000000DFFFFFFFFFFFFFFFFFFFF60000000000000
+0000000000000AFFFFFFFFFFFFFFFFFFFF40000000000000
+00000000000006FFFFFFFFFFFFFFFFFFFE00000000000000
+00000000000000EFFFFFFFFFFFFFFFFFF800000000000000
+000000000000007FFFFFFFFFFFFFFFFFF100000000000000
+000000000000000BFFFFFFFFFFFFFFFF5000000000000000
+0000000000000001DFFFFFFFFFFFFFF70000000000000000
+00000000000000000BFFFFFFFFFFFF500000000000000000
+0000000000000000005DFFFFFFFFA1000000000000000000
+0000000000000000000037ABB96100000000000000000000
+000000000002578888300000000005888864100000000000
+0000000007DFFFFFFFFD9643347BFFFFFFFFFB4000000000
+00000004EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB10000000
+0000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2000000
+000006FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE100000
+00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB00000
+0000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50000
+0003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0000
+0009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2000
+000DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6000
+000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB000
+001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB000
+001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB000
+001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA000
+000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+000DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6000
+0009FFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFF2000
+0003FFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFD0000
+0000BFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFF50000
+00003FFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFB00000
+000006FFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFE100000
+0000007FFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFD2000000
+00000004EFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFB10000000
+0000000007DF8FFFFFFFFFFFFFFFFFFFFFF8FB4000000000
+000000000002578888888888888888888864100000000000
+}
+
+sprite $robot [48x48/16] {
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000005BFFFFFFFFFFFFFFFFFFFFFE9100000000000
+0000000000AFFFFFFFFFFFFFFFFFFFFFFFFFE30000000000
+0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFE1000000000
+000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000000000
+000000004FFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000
+000000005FFFFFFFFFFFFFFFFFFFFFFFFFFFFFD000000000
+000000005FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE000000000
+000000005FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE000000000
+000699405FFFFFFC427FFFFFFFFFC427FFFFFFE009982000
+008FFF705FFFFFE10006FFFFFFFE00007FFFFFE00FFFF100
+00CFFF705FFFFFA00001FFFFFFF900002FFFFFE00FFFF500
+00DFFF705FFFFFB00002FFFFFFFA00003FFFFFE00FFFF500
+00DFFF705FFFFFF4000AFFFFFFFF3000BFFFFFE00FFFF500
+00DFFF705FFFFFFFA8DFFFFFFFFFFA8DFFFFFFE00FFFF500
+00DFFF705FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00FFFF500
+00DFFF705FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00FFFF500
+00DFFF705FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00FFFF500
+00DFFF705FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00FFFF500
+00DFFF705FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00FFFF500
+00CFFF705FFFFFF87777777777777777CFFFFFE00FFFF500
+008FFF705FFFFFF100000000000000009FFFFFE00FFFF100
+000699405FFFFFF76666666666666666CFFFFFE009982000
+000000005FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE000000000
+000000005FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE000000000
+000000004FFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000
+000000000EFFFFFFFFFFFFFFFFFFFFFFFFFFFF7000000000
+0000000005FFFFFFFFFFFFFFFFFFFFFFFFFFFD0000000000
+00000000004CFFFFFFFFFFFFFFFFFFFFFFFF910000000000
+000000000000011111111111111111111110000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+}
+
+sprite $robot2 [48x48/16] {
+000000000000000088888888888888880000000000000000
+000000000000000AFFFFFFFFFFFFFFFFA000000000000000
+00000000000000CFFFFFFFFFFFFFFFFFFC00000000000000
+00000000000004EFFFFFFFFFFFFFFFFFFE40000000000000
+0000000000000AFFFFFFFFFFFFFFFFFFFFA0000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000888FFFFFFFFFFFFFFFFFFFF88800000000000
+00000000008FF8FFFFFFFFFFFFFFFFFFFF8FF80000000000
+00000000008FF8FFFFFFFFFFFFFFFFFFFF8FF80000000000
+00000000008FF8FFFFFFFFFFFFFFFFFFFF8FF80000000000
+00000000008FF8FFFFFFFFFFFFFFFFFFFF8FF80000000000
+00000000008FF8FFFFFFFFFFFFFFFFFFFF8FF80000000000
+00000000008FF8FFFFFFFFFFFFFFFFFFFF8FF80000000000
+00000000000888FFFFFFFFFFFFFFFFFFFF88800000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000008FFFFFFFFFFFFFFFFFFFF80000000000000
+00000000000004CFFFFFFFFFFFFFFFFFFC40000000000000
+000000488888848CFFFFFFFFFFFFFFFFC848888884000000
+00000CFFFFFFFFC888888888888888888CFFFFFFFFC00000
+00008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000
+0000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000
+0008FFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFF8000
+0008FFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFF8000
+0008FFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFF8000
+0008FFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFF8000
+0000CFFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFFC0000
+00008FFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFF80000
+00000CFFFFFF8FFFFFFFFFFFFFFFFFFFFFF8FFFFFFC00000
+000000488887578888888888888888888864688884000000
+000000000000000000000000000000000000000000000000
+}
+
+' Layout
+' ##################################
+
+SetDefaultLegendEntries("person\nsystem\nexternal_person\nexternal_system\nenterprise_boundary\nsystem_boundary\nboundary")
+
+!procedure LAYOUT_WITH_LEGEND()
+hide stereotype
+legend right
+|<color:$LEGEND_TITLE_COLOR>**Legend**</color> |
+|<$PERSON_BG_COLOR> person |
+|<$SYSTEM_BG_COLOR> system|
+|<$EXTERNAL_PERSON_BG_COLOR> external person |
+|<$EXTERNAL_SYSTEM_BG_COLOR> external system |
+endlegend
+!endprocedure
+
+!global $defaultPersonSprite = "person"
+!$dummy = $restoreEmpty("person", "sprite", $defaultPersonSprite, %true())
+UpdateElementStyle("person")
+' workaround of plantuml.jar bug - person overwrites external_person setting
+!$dummy = $restoreEmpty("external_person", "sprite", $defaultPersonSprite, %true())
+UpdateElementStyle("external_person")
+!global $portraitPerson = "false"
+
+!procedure $clearPersonRestore()
+  !$dummy = $clearRestore("person", "sprite")
+  !$dummy = $clearRestore("person", "legendSprite")
+  %set_variable_value("$" + "person" + "ElementTagSprite", "")
+  UpdateElementStyle("person")
+  ' workaround of plantuml.jar bug - person overwrites external_person setting
+  !$dummy = $clearRestore("external_person", "sprite")
+  !$dummy = $clearRestore("external_person", "legendSprite")
+  %set_variable_value("$" + "external_person" + "ElementTagSprite", "")
+  UpdateElementStyle("external_person")
+!endprocedure
+
+!procedure HIDE_PERSON_SPRITE()
+  !$defaultPersonSprite = ""
+  !$portraitPerson = "false"
+  $clearPersonRestore()
+!endprocedure
+
+!unquoted procedure SHOW_PERSON_SPRITE($sprite="")
+  !if ($sprite == "")
+    !$defaultPersonSprite = "person"
+  !else
+    !$defaultPersonSprite = $sprite
+  !endif
+  !$dummy = $restoreEmpty("person", "sprite", $defaultPersonSprite, %true())
+  UpdateElementStyle("person")
+  ' workaround of plantuml.jar bug - person overwrites external_person setting
+  !$dummy = $restoreEmpty("external_person", "sprite", $defaultPersonSprite, %true())
+  UpdateElementStyle("external_person")
+  !$portraitPerson = "false"
+!endprocedure
+
+!unquoted procedure SHOW_PERSON_PORTRAIT()
+  !$defaultPersonSprite = ""
+  !$portraitPerson = "portrait"
+  $clearPersonRestore()
+!endprocedure
+
+!unquoted procedure SHOW_PERSON_OUTLINE()
+  !$defaultPersonSprite = ""
+  !$portraitPerson = "outline"
+  $clearPersonRestore()
+!endprocedure
+
+' Elements
+' ##################################
+
+!function $getPerson($label, $type, $descr, $sprite)
+  !if ($sprite == "") && ($defaultPersonSprite != "")
+    !$sprite = $defaultPersonSprite
+  !endif
+  !return $getElementBase($label, $type, $descr, $sprite)
+!endfunction
+
+!unquoted procedure Person($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="")
+!$sprite=$toElementArg($sprite, $tags, "ElementTagSprite", "person")
+' $type reuses $techn definition of $tags
+!$type=$toElementArg($type, $tags, "ElementTagTechn", "person")
+!if ($portraitPerson == "portrait") && ($sprite == "")
+actor "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("person", $tags) as $alias $getLink($link)
+!elseif ($portraitPerson == "outline") && ($sprite == "")
+person "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("person", $tags) as $alias $getLink($link)
+!else
+rectangle "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("person", $tags) as $alias $getLink($link)
+!endif
+!endprocedure
+
+!unquoted procedure Person_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="")
+!$sprite=$toElementArg($sprite, $tags, "ElementTagSprite", "external_person")
+' $type reuses $techn definition of $tags
+!$type=$toElementArg($type, $tags, "ElementTagTechn", "external_person")
+!if ($portraitPerson == "portrait") && ($sprite == "")
+actor "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("external_person", $tags) as $alias $getLink($link)
+!elseif ($portraitPerson == "outline") && ($sprite == "")
+person "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("external_person", $tags) as $alias $getLink($link)
+!else
+rectangle "$getPerson($label, $type, $descr, $sprite)$getProps()" $toStereos("external_person", $tags) as $alias $getLink($link)
+!endif
+!endprocedure
+
+!unquoted procedure System($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="", $baseShape="rectangle")
+  ' $type reuses $techn definition of $tags
+  $getElementLine($baseShape, "system", $alias, $label, $type, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure SystemDb($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="")
+  ' $type reuses $techn definition of $tags
+  $getElementLine("database", "system", $alias, $label, $type, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure SystemQueue($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="")
+  ' $type reuses $techn definition of $tags
+  $getElementLine("queue", "system", $alias, $label, $type, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure System_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="", $baseShape="rectangle")
+  ' $type reuses $techn definition of $tags
+  $getElementLine($baseShape , "external_system", $alias, $label, $type, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure SystemDb_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="")
+  ' $type reuses $techn definition of $tags
+  $getElementLine("database", "external_system", $alias, $label, $type, $descr, $sprite, $tags, $link)
+!endprocedure
+
+!unquoted procedure SystemQueue_Ext($alias, $label, $descr="", $sprite="", $tags="", $link="", $type="")
+  ' $type reuses $techn definition of $tags
+  $getElementLine("queue", "external_system", $alias, $label, $type, $descr, $sprite, $tags, $link)
+!endprocedure
+
+' Boundaries
+' ##################################
+
+!unquoted procedure Enterprise_Boundary($alias, $label, $tags="", $link="", $descr = "")
+  !if ($tags != "")
+    !$allTags = $tags + '+enterprise'
+  !else
+    !$allTags = 'enterprise'
+  !endif
+  ' $type defined via $tag style
+  Boundary($alias, $label, "", $allTags, $link, $descr)
+!endprocedure
+
+!unquoted procedure System_Boundary($alias, $label, $tags="", $link="", $descr = "")
+  !if ($tags != "")
+    !$allTags = $tags + '+system'
+  !else
+    !$allTags = 'system'
+  !endif
+  ' $type defined via $tag style
+  Boundary($alias, $label, "", $allTags, $link, $descr)
+!endprocedure

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/DFD-2bussines.drawio.svg


+ 372 - 0
diagrams/DFD.drawio

@@ -0,0 +1,372 @@
+<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0" version="29.4.0">
+  <diagram name="Страница-1" id="Wx3iRwWdJO6kyBYsCdXE">
+    <mxGraphModel dx="2431" dy="1340" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-62" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-60">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-63" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-62" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Данные поручения" vertex="1">
+          <mxGeometry relative="1" x="-0.0584" y="-1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-58" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="Руководитель" vertex="1">
+          <mxGeometry height="90" width="160" x="60" y="120" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-66" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-60" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-64">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-67" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-66" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Зарегистрированное&lt;br&gt;поручение" vertex="1">
+          <mxGeometry relative="1" x="-0.0134" y="2" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-60" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="Процедура постановки поручения" vertex="1">
+          <mxGeometry height="90" width="160" x="350" y="120" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-61" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-60" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" target="2iEHDvxkmJq4oPHskJAr-60" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="270" y="280" as="sourcePoint" />
+            <mxPoint x="320" y="230" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-68" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="Руководитель" vertex="1">
+          <mxGeometry height="90" width="160" x="60" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-77" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="350" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-75" parent="2iEHDvxkmJq4oPHskJAr-77" style="rounded=1;whiteSpace=wrap;html=1;" value="Формирование поручения" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-76" edge="1" parent="2iEHDvxkmJq4oPHskJAr-77" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-78" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="35" width="190" x="680" y="147.5" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-64" parent="2iEHDvxkmJq4oPHskJAr-78" style="rounded=0;whiteSpace=wrap;html=1;" value="База поручений" vertex="1">
+          <mxGeometry height="35" width="190" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-65" edge="1" parent="2iEHDvxkmJq4oPHskJAr-78" style="endArrow=none;html=1;rounded=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="30" y="35" as="sourcePoint" />
+            <mxPoint x="30" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-79" edge="1" parent="1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;">
+          <mxGeometry relative="1" as="geometry">
+            <mxPoint x="220" y="370" as="sourcePoint" />
+            <mxPoint x="350" y="370" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-80" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-79" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Данные поручения" vertex="1">
+          <mxGeometry relative="1" x="-0.0584" y="-1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-81" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="680" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-82" parent="2iEHDvxkmJq4oPHskJAr-81" style="rounded=1;whiteSpace=wrap;html=1;" value="Запрос данных пользователя" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-83" edge="1" parent="2iEHDvxkmJq4oPHskJAr-81" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-85" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-75" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-82">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-87" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-85" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Подготовленные данные" vertex="1">
+          <mxGeometry relative="1" x="0.0487" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-88" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="35" width="190" x="665" y="500" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-89" parent="2iEHDvxkmJq4oPHskJAr-88" style="rounded=0;whiteSpace=wrap;html=1;" value="База пользователей" vertex="1">
+          <mxGeometry height="35" width="190" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-90" edge="1" parent="2iEHDvxkmJq4oPHskJAr-88" style="endArrow=none;html=1;rounded=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="30" y="35" as="sourcePoint" />
+            <mxPoint x="30" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-92" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-82" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-89">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-93" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-92" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Запрос данных о пользователе" vertex="1">
+          <mxGeometry relative="1" x="-0.1505" y="-3" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-94" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="1290" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-95" parent="2iEHDvxkmJq4oPHskJAr-94" style="rounded=1;whiteSpace=wrap;html=1;" value="Регистрация поручения" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-96" edge="1" parent="2iEHDvxkmJq4oPHskJAr-94" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-99" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="1640" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-100" parent="2iEHDvxkmJq4oPHskJAr-99" style="rounded=1;whiteSpace=wrap;html=1;" value="Уведомление исполнителя" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-101" edge="1" parent="2iEHDvxkmJq4oPHskJAr-99" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-102" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-95" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-100">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-103" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-102" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Зарегистрированное поручение" vertex="1">
+          <mxGeometry relative="1" x="-0.1446" y="2" as="geometry">
+            <mxPoint x="6" y="2" as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-107" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="Исполнитель" vertex="1">
+          <mxGeometry height="90" width="160" x="1944" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-108" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-100" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-107">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-109" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-108" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Назначенное&lt;br&gt;поручение" vertex="1">
+          <mxGeometry relative="1" y="-1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-110" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="980" y="320" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-111" parent="2iEHDvxkmJq4oPHskJAr-110" style="rounded=1;whiteSpace=wrap;html=1;" value="Проверка полномочий" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-112" edge="1" parent="2iEHDvxkmJq4oPHskJAr-110" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-113" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-89" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-111">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="1060" y="518" />
+            </Array>
+            <mxPoint x="1070" y="440" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-114" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-113" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Данные о роли&lt;br&gt;пользователя" vertex="1">
+          <mxGeometry relative="1" x="0.1034" y="3" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-115" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-82" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-111">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-118" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-115" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Идентификация&lt;br&gt;пользователя" vertex="1">
+          <mxGeometry relative="1" x="-0.1552" y="1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-119" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-111" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-95">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-120" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-119" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Подтвержденные данные&lt;br&gt;поручения" vertex="1">
+          <mxGeometry relative="1" x="-0.2286" y="-1" as="geometry">
+            <mxPoint x="12" y="-1" as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-121" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="База поручений" vertex="1">
+          <mxGeometry height="35" width="190" x="1275" y="500" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-122" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-95" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-121">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-123" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-122" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Запись о поручении" vertex="1">
+          <mxGeometry relative="1" x="-0.0503" y="1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-124" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="Web-client" vertex="1">
+          <mxGeometry height="90" width="160" x="60" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-125" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="350" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-126" parent="2iEHDvxkmJq4oPHskJAr-125" style="rounded=1;whiteSpace=wrap;html=1;" value="Frontend" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-127" edge="1" parent="2iEHDvxkmJq4oPHskJAr-125" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-128" edge="1" parent="1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;">
+          <mxGeometry relative="1" as="geometry">
+            <mxPoint x="220" y="700" as="sourcePoint" />
+            <mxPoint x="350" y="700" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-129" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-128" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTPS POST&lt;br&gt;/api/tasks" vertex="1">
+          <mxGeometry relative="1" x="-0.0584" y="-1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-130" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="680" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-131" parent="2iEHDvxkmJq4oPHskJAr-130" style="rounded=1;whiteSpace=wrap;html=1;" value="REST API" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-132" edge="1" parent="2iEHDvxkmJq4oPHskJAr-130" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-133" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-126" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-131">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-134" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-133" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Form Data" vertex="1">
+          <mxGeometry relative="1" x="0.0487" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-135" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="35" width="190" x="665" y="830" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-136" parent="2iEHDvxkmJq4oPHskJAr-135" style="rounded=0;whiteSpace=wrap;html=1;" value="SQL table &quot;users&quot;" vertex="1">
+          <mxGeometry height="35" width="190" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-137" edge="1" parent="2iEHDvxkmJq4oPHskJAr-135" style="endArrow=none;html=1;rounded=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="30" y="35" as="sourcePoint" />
+            <mxPoint x="30" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-138" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-131" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-136">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-139" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-138" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="SQL SELECT" vertex="1">
+          <mxGeometry relative="1" x="-0.1505" y="-3" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-140" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="1290" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-141" parent="2iEHDvxkmJq4oPHskJAr-140" style="rounded=1;whiteSpace=wrap;html=1;" value="Service Layer" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-142" edge="1" parent="2iEHDvxkmJq4oPHskJAr-140" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-143" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="1640" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-144" parent="2iEHDvxkmJq4oPHskJAr-143" style="rounded=1;whiteSpace=wrap;html=1;" value="Notification Service" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-145" edge="1" parent="2iEHDvxkmJq4oPHskJAr-143" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-146" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-141" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-144">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-147" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-146" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Validation request" vertex="1">
+          <mxGeometry relative="1" x="-0.1446" y="2" as="geometry">
+            <mxPoint x="6" y="2" as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-148" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="Browser" vertex="1">
+          <mxGeometry height="90" width="160" x="1944" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-149" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-144" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-148">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-150" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-149" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Notification event" vertex="1">
+          <mxGeometry relative="1" y="-1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-151" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="160" x="980" y="650" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-152" parent="2iEHDvxkmJq4oPHskJAr-151" style="rounded=1;whiteSpace=wrap;html=1;" value="RBAC Middleware" vertex="1">
+          <mxGeometry height="90" width="160" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-153" edge="1" parent="2iEHDvxkmJq4oPHskJAr-151" style="endArrow=none;html=1;rounded=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;exitX=0;exitY=0.25;exitDx=0;exitDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint y="20.5" as="sourcePoint" />
+            <mxPoint x="160" y="20.5" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-154" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-136" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-152">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="1060" y="848" />
+            </Array>
+            <mxPoint x="1070" y="770" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-155" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-154" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="role_id, status" vertex="1">
+          <mxGeometry relative="1" x="0.1034" y="3" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-156" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-131" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-152">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-157" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-156" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="User identity" vertex="1">
+          <mxGeometry relative="1" x="-0.1552" y="1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-158" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-152" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-141">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-159" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-158" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="role_id == &quot;manager&quot;" vertex="1">
+          <mxGeometry relative="1" x="-0.2286" y="-1" as="geometry">
+            <mxPoint x="12" y="-1" as="offset" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-160" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="SQL table &quot;task&quot;" vertex="1">
+          <mxGeometry height="35" width="190" x="1275" y="830" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-161" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-141" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-160">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-162" connectable="0" parent="2iEHDvxkmJq4oPHskJAr-161" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="SQL INSERT" vertex="1">
+          <mxGeometry relative="1" x="-0.0503" y="1" as="geometry">
+            <mxPoint as="offset" />
+          </mxGeometry>
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/IDEF0(MAIN)(1).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/IDEF0(check_role).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/IDEF0(decomp).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/IDEF0(main).svg


+ 100 - 0
diagrams/IDEF0.drawio

@@ -0,0 +1,100 @@
+<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0" version="29.4.0">
+  <diagram name="Страница-1" id="Wx3iRwWdJO6kyBYsCdXE">
+    <mxGraphModel dx="1425" dy="786" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-192" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="90" width="250" x="350" y="210" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-190" parent="2iEHDvxkmJq4oPHskJAr-192" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=bottom;align=right;" value="А0" vertex="1">
+          <mxGeometry height="90" width="250.00000000000003" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-191" parent="2iEHDvxkmJq4oPHskJAr-192" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Постановка поручения" vertex="1">
+          <mxGeometry height="30" width="76.53061224489798" x="86.73469387755104" y="30" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-193" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-190" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="210" y="255" as="sourcePoint" />
+            <mxPoint x="340" y="250" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-194" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Данные поручения" vertex="1">
+          <mxGeometry height="30" width="130" x="200" y="230" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-195" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="600" y="235" as="sourcePoint" />
+            <mxPoint x="810" y="235" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-196" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Зарегистрированное поручение" vertex="1">
+          <mxGeometry height="30" width="190" x="610" y="210" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-197" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="600" y="285" as="sourcePoint" />
+            <mxPoint x="810" y="285" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-198" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Уведомление исполнителю" vertex="1">
+          <mxGeometry height="30" width="170" x="610" y="260" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-202" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="360" y="440" as="sourcePoint" />
+            <mxPoint x="360" y="300" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-203" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="430" y="440" as="sourcePoint" />
+            <mxPoint x="430" y="300" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-204" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="550" y="440" as="sourcePoint" />
+            <mxPoint x="550" y="300" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-205" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Политика ИБ" vertex="1">
+          <mxGeometry height="30" width="60" x="360" y="410" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-206" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="&lt;div&gt;Организационная структура&lt;/div&gt;" vertex="1">
+          <mxGeometry height="30" width="110" x="430" y="410" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-207" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Нормативные&lt;br&gt;требования" vertex="1">
+          <mxGeometry height="30" width="110" x="550" y="410" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-208" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="360" y="110" as="sourcePoint" />
+            <mxPoint x="359.9999999999998" y="210" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-209" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="450" y="110" as="sourcePoint" />
+            <mxPoint x="449.9999999999998" y="210" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-210" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Руководитель" vertex="1">
+          <mxGeometry height="30" width="60" x="360" y="110" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-211" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Информационные системы" vertex="1">
+          <mxGeometry height="30" width="60" x="451" y="110" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-212" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="560" y="110" as="sourcePoint" />
+            <mxPoint x="559.9999999999998" y="210" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-213" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="База данных" vertex="1">
+          <mxGeometry height="30" width="60" x="560" y="110" as="geometry" />
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/System schemas.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/System_interaction_schemas.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/System_resource_schemas.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/System_schemas.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/System_working_schemas.svg


BIN
diagrams/UML(Classes)(1).drawio.png


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/UML(Classes)(1).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/UML(activity).svg


+ 140 - 0
diagrams/Untitled Diagram.drawio

@@ -0,0 +1,140 @@
+<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" version="29.6.0">
+  <diagram name="Страница-1" id="DzfRdOe1r8T0A6-DZtQq">
+    <mxGraphModel dx="2597" dy="1029" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-1" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="180" y="120" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-2" parent="BnptAzzjZ6ytsXlMcD3X-1" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="1" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-3" parent="BnptAzzjZ6ytsXlMcD3X-1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Получение данных пользователя" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-4" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="BnptAzzjZ6ytsXlMcD3X-2" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="-50" y="180" as="sourcePoint" />
+            <mxPoint x="150" y="220" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-5" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Подготовленные данные поручения" vertex="1">
+          <mxGeometry height="30" width="220" x="-40" y="150" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-6" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="BnptAzzjZ6ytsXlMcD3X-2" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="265" y="40" as="sourcePoint" />
+            <mxPoint x="270" y="90" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-7" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Информационная система" vertex="1">
+          <mxGeometry height="30" width="60" x="270" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-38" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="BnptAzzjZ6ytsXlMcD3X-2" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="264" y="720" as="sourcePoint" />
+            <mxPoint x="310" y="280" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-39" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Политика ИБ" vertex="1">
+          <mxGeometry height="30" width="60" x="270" y="690" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-40" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="510" y="300" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-41" parent="BnptAzzjZ6ytsXlMcD3X-40" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="2" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-42" parent="BnptAzzjZ6ytsXlMcD3X-40" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Получение роли пользователя" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-43" edge="1" parent="1" source="BnptAzzjZ6ytsXlMcD3X-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="BnptAzzjZ6ytsXlMcD3X-41">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-44" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Идентификатор пользователя" vertex="1">
+          <mxGeometry height="30" width="60" x="440" y="250" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-45" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="990" y="510" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-63" edge="1" parent="BnptAzzjZ6ytsXlMcD3X-45" source="BnptAzzjZ6ytsXlMcD3X-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;">
+          <mxGeometry relative="1" as="geometry">
+            <mxPoint x="390" y="60" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-46" parent="BnptAzzjZ6ytsXlMcD3X-45" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="3" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-47" parent="BnptAzzjZ6ytsXlMcD3X-45" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Проверка полномочий" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-48" edge="1" parent="1" source="BnptAzzjZ6ytsXlMcD3X-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.158;entryDx=0;entryDy=0;entryPerimeter=0;" target="BnptAzzjZ6ytsXlMcD3X-46">
+          <mxGeometry relative="1" as="geometry">
+            <mxPoint x="750" y="560" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-49" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Данные о роли пользователя" vertex="1">
+          <mxGeometry height="30" width="60" x="840" y="430" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-50" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="750" y="600" as="sourcePoint" />
+            <mxPoint x="990" y="600.0000000000001" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-51" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Подготовленные данные поручения" vertex="1">
+          <mxGeometry height="30" width="220" x="770" y="570" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-52" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="База данных" vertex="1">
+          <mxGeometry height="30" width="60" x="600" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-53" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="BnptAzzjZ6ytsXlMcD3X-41" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="595" y="40" as="sourcePoint" />
+            <mxPoint x="600" y="140" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-54" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Регламент доступа" vertex="1">
+          <mxGeometry height="30" width="60" x="600" y="690" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-55" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="595" y="720" as="sourcePoint" />
+            <mxPoint x="595" y="400" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-56" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Политика ИБ" vertex="1">
+          <mxGeometry height="30" width="60" x="1005" y="690" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-57" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="1000" y="720" as="sourcePoint" />
+            <mxPoint x="1000" y="610" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-59" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="1074" y="40" as="sourcePoint" />
+            <mxPoint x="1075" y="530" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-60" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Информационная система" vertex="1">
+          <mxGeometry height="30" width="60" x="1080" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-61" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Организационная структура" vertex="1">
+          <mxGeometry height="30" width="60" x="1100" y="690" as="geometry" />
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-62" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="1095" y="720" as="sourcePoint" />
+            <mxPoint x="1095" y="610" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="BnptAzzjZ6ytsXlMcD3X-64" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Подтвержденные данные поручения" vertex="1">
+          <mxGeometry height="30" width="210" x="1170" y="540" as="geometry" />
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/Untitled Diagram.drawio.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/algorithm_system_work.svg


+ 50 - 0
diagrams/c4-component.puml

@@ -0,0 +1,50 @@
+@startuml
+!include C4_Component.puml
+
+LAYOUT_WITH_LEGEND()
+
+Container_Boundary(api, "Сервер приложения") {
+
+    Component(api_controller, "Access API", "ASP.NET Core", "Принимает запросы на проверку доступа")
+
+    Component(admin_controller, "Admin API", "ASP.NET Core", "Управление политиками и хостами")
+
+    Component(decision_service, "Decision Service", "C#", "Принимает решение по доступу")
+
+    Component(policy_service, "Policy Service", "C#", "Работа с политиками доступа")
+
+    Component(audit_service, "Audit Service", "C#", "Логирование событий доступа")
+
+    Component(management_service, "Management Service", "C#", "Управление сущностями системы")
+
+    Component(policy_repo, "Policy Repository", "EF Core", "Доступ к данным политик")
+
+    Component(audit_repo, "Audit Repository", "EF Core", "Доступ к журналу")
+
+    Component(management_repo, "Management Repository", "EF Core", "Доступ к данным системы")
+
+}
+
+ContainerDb(db, "Database", "PostgreSQL", "Хранение данных системы")
+
+Rel(api_controller, decision_service, "Передаёт контекст запроса")
+
+Rel(decision_service, policy_service, "Запрашивает политики")
+
+Rel(policy_service, policy_repo, "Читает политики")
+
+Rel(decision_service, audit_service, "Передаёт результат")
+
+Rel(audit_service, audit_repo, "Записывает лог")
+
+Rel(admin_controller, management_service, "Управляет системой")
+
+Rel(management_service, management_repo, "Работа с данными")
+
+Rel(policy_repo, db, "Читает/пишет", "SQL")
+
+Rel(audit_repo, db, "Читает/пишет", "SQL")
+
+Rel(management_repo, db, "Читает/пишет", "SQL")
+
+@enduml

+ 28 - 0
diagrams/c4-container.puml

@@ -0,0 +1,28 @@
+@startuml
+!include C4_Container.puml
+
+LAYOUT_WITH_LEGEND()
+
+Person(admin, "Администратор\n[Person]", "Управляет системой, настраивает пользователей и доступ")
+
+System_Ext(client, "Веб-клиент\n[External System]", "Интерфейс пользователя для работы с поручениями")
+
+System_Boundary(system, "КИС управления поручениями") {
+
+    Container(web, "Web Admin UI", "React", "Интерфейс администратора для управления системой")
+
+    Container(api, "Application API", "ASP.NET Core (C#)", "Обрабатывает бизнес-логику поручений")
+
+    ContainerDb(db, "Database", "PostgreSQL", "Хранит данные о поручениях, пользователях и сроках")
+
+}
+
+Rel(admin, web, "Работает через", "HTTPS")
+
+Rel(client, web, "Использует интерфейс", "HTTPS")
+
+Rel(web, api, "Отправляет запросы", "HTTPS/JSON")
+
+Rel(api, db, "Читает и записывает", "SQL")
+
+@enduml

+ 17 - 0
diagrams/c4-context.puml

@@ -0,0 +1,17 @@
+@startuml
+
+!include C4_Context.puml
+
+LAYOUT_WITH_LEGEND()
+
+Person(admin, "Администратор\n[Person]", "Управляет системой, настраивает пользователей и доступ")
+
+System_Ext(client, "Веб-клиент\n[External System]", "Интерфейс пользователя для работы с поручениями")
+
+System(system, "КИС управления поручениями\n[System]", "Система управления поручениями и сроками")
+
+Rel(admin, system, "Настраивает систему", "HTTPS")
+
+Rel(client, system, "Работа с поручениями", "HTTPS/JSON")
+
+@enduml

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/data_schemas.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/system_works_schemas.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/usecase(bussiness).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/usecase(concept).drawio.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/Диаграмма без названия.drawio(6).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/Диаграмма без названия.drawio(7).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/Диаграмма без названия.drawio(8).svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
diagrams/Диаграмма без названия.drawio(9).svg


+ 153 - 0
diagrams/декомпозиция.drawio

@@ -0,0 +1,153 @@
+<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0" version="29.4.0">
+  <diagram name="Страница-1" id="Wx3iRwWdJO6kyBYsCdXE">
+    <mxGraphModel dx="2175" dy="1199" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-216" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="180" y="120" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-214" parent="2iEHDvxkmJq4oPHskJAr-216" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="1" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-215" parent="2iEHDvxkmJq4oPHskJAr-216" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Формирование поручения" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-217" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-214" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="30" y="180" as="sourcePoint" />
+            <mxPoint x="150" y="220" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-218" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Данные поручения" vertex="1">
+          <mxGeometry height="30" width="130" x="20" y="150" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-219" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-214" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="265" y="40" as="sourcePoint" />
+            <mxPoint x="270" y="90" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-220" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Руководитель" vertex="1">
+          <mxGeometry height="30" width="60" x="270" y="30" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-221" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-214" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="265" y="790" as="sourcePoint" />
+            <mxPoint x="320" y="320" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-222" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="&lt;div align=&quot;left&quot;&gt;Организационная структура&lt;/div&gt;" vertex="1">
+          <mxGeometry height="30" width="60" x="270" y="760" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-226" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="510" y="270" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-227" parent="2iEHDvxkmJq4oPHskJAr-226" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="2" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-228" parent="2iEHDvxkmJq4oPHskJAr-226" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Проверка полномочий" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-230" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-214" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-227">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-231" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Подготовленные данные поручения" vertex="1">
+          <mxGeometry height="30" width="100" x="440" y="230" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-232" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-227" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="595" y="40" as="sourcePoint" />
+            <mxPoint x="600" y="140" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-233" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Информационная система" vertex="1">
+          <mxGeometry height="30" width="60" x="600" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-236" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Политики ИБ" vertex="1">
+          <mxGeometry height="30" width="60" x="600" y="760" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-237" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="595" y="790" as="sourcePoint" />
+            <mxPoint x="595" y="370" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-238" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="840" y="410" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-239" parent="2iEHDvxkmJq4oPHskJAr-238" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="3" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-240" parent="2iEHDvxkmJq4oPHskJAr-238" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Регистрация поручения" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-242" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-227" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-239">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-243" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Подтвержденные данные поручения" vertex="1">
+          <mxGeometry height="30" width="100" x="770" y="370" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-244" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="База данных" vertex="1">
+          <mxGeometry height="30" width="60" x="930" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-245" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-239" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="925" y="40" as="sourcePoint" />
+            <mxPoint x="920" y="290" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-248" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="925" y="790" as="sourcePoint" />
+            <mxPoint x="925" y="510" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-249" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Нормативные требования" vertex="1">
+          <mxGeometry height="30" width="60" x="930" y="760" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-251" connectable="0" parent="1" style="group" value="" vertex="1">
+          <mxGeometry height="120" width="170" x="1150" y="600" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-265" edge="1" parent="2iEHDvxkmJq4oPHskJAr-251" source="2iEHDvxkmJq4oPHskJAr-252" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;">
+          <mxGeometry relative="1" as="geometry">
+            <mxPoint x="330" y="60" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-252" parent="2iEHDvxkmJq4oPHskJAr-251" style="rounded=0;whiteSpace=wrap;html=1;align=right;verticalAlign=bottom;" value="4" vertex="1">
+          <mxGeometry height="80" width="170" y="20" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-253" parent="2iEHDvxkmJq4oPHskJAr-251" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="Уведомление исполнителя" vertex="1">
+          <mxGeometry height="40" width="110" x="30" y="40" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-254" edge="1" parent="1" source="2iEHDvxkmJq4oPHskJAr-239" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-252">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-255" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Зарегистрированное поручение" vertex="1">
+          <mxGeometry height="30" width="100" x="1090" y="540" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-257" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="SLA" vertex="1">
+          <mxGeometry height="30" width="60" x="1235" y="770" as="geometry" />
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-258" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <mxPoint x="1230" y="790" as="sourcePoint" />
+            <mxPoint x="1230" y="700" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-263" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="2iEHDvxkmJq4oPHskJAr-252" value="">
+          <mxGeometry height="50" relative="1" width="50" as="geometry">
+            <Array as="points">
+              <mxPoint x="1235" y="80" />
+            </Array>
+            <mxPoint x="595" y="80" as="sourcePoint" />
+            <mxPoint x="1229.9999999999995" y="540" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="2iEHDvxkmJq4oPHskJAr-267" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" value="Уведомление исполнителю" vertex="1">
+          <mxGeometry height="30" width="160" x="1320" y="630" as="geometry" />
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>

+ 139 - 0
lab11/dumb.sql

@@ -0,0 +1,139 @@
+CREATE TABLE faculties (
+    faculty_id SERIAL PRIMARY KEY,
+    faculty_name VARCHAR(100) NOT NULL UNIQUE
+);
+
+CREATE TABLE departments (
+    department_id SERIAL PRIMARY KEY,
+    faculty_id INTEGER NOT NULL REFERENCES faculties(faculty_id),
+    department_name VARCHAR(150) NOT NULL
+);
+
+CREATE TABLE groups (
+    group_id SERIAL PRIMARY KEY,
+    faculty_id INTEGER NOT NULL REFERENCES faculties(faculty_id),
+    group_name VARCHAR(20) NOT NULL,
+    course INTEGER NOT NULL CHECK(course BETWEEN 1 AND 6)
+);
+
+CREATE TABLE students (
+    student_id SERIAL PRIMARY KEY,
+    group_id INTEGER NOT NULL REFERENCES groups(group_id),
+    last_name VARCHAR(50) NOT NULL,
+    first_name VARCHAR(50) NOT NULL,
+    middle_name VARCHAR(50),
+    gender VARCHAR(10) CHECK(gender IN ('М','Ж')),
+    birth_date DATE NOT NULL,
+    scholarship NUMERIC(10,2) DEFAULT 0,
+    has_children BOOLEAN DEFAULT FALSE
+);
+
+CREATE TABLE teachers (
+    teacher_id SERIAL PRIMARY KEY,
+    department_id INTEGER NOT NULL REFERENCES departments(department_id),
+    last_name VARCHAR(50) NOT NULL,
+    first_name VARCHAR(50) NOT NULL,
+    middle_name VARCHAR(50),
+    category VARCHAR(50) NOT NULL,
+    salary NUMERIC(10,2) NOT NULL CHECK(salary > 0),
+    academic_degree VARCHAR(50)
+);
+
+CREATE TABLE disciplines (
+    discipline_id SERIAL PRIMARY KEY,
+    discipline_name VARCHAR(150) NOT NULL UNIQUE
+);
+
+CREATE TABLE semesters (
+    semester_id SERIAL PRIMARY KEY,
+    semester_number INTEGER NOT NULL CHECK(semester_number BETWEEN 1 AND 12),
+    academic_year VARCHAR(20) NOT NULL
+);
+
+CREATE TABLE teaching_assignments (
+    assignment_id SERIAL PRIMARY KEY,
+    teacher_id INTEGER NOT NULL REFERENCES teachers(teacher_id),
+    discipline_id INTEGER NOT NULL REFERENCES disciplines(discipline_id),
+    group_id INTEGER NOT NULL REFERENCES groups(group_id),
+    semester_id INTEGER NOT NULL REFERENCES semesters(semester_id),
+    lecture_hours INTEGER DEFAULT 0,
+    practice_hours INTEGER DEFAULT 0,
+    lab_hours INTEGER DEFAULT 0
+);
+
+CREATE TABLE exams (
+    exam_id SERIAL PRIMARY KEY,
+    student_id INTEGER NOT NULL REFERENCES students(student_id),
+    discipline_id INTEGER NOT NULL REFERENCES disciplines(discipline_id),
+    teacher_id INTEGER NOT NULL REFERENCES teachers(teacher_id),
+    semester_id INTEGER NOT NULL REFERENCES semesters(semester_id),
+    exam_date DATE NOT NULL,
+    grade INTEGER CHECK(grade BETWEEN 2 AND 5)
+);
+
+-- Заполнение таблицы students
+INSERT INTO students
+(group_id, last_name, first_name, middle_name, gender, birth_date, scholarship, has_children)
+VALUES
+(1, 'Иванов', 'Артём', 'Сергеевич', 'М', '2004-03-15', 15000, FALSE),
+(1, 'Петров', 'Даниил', 'Олегович', 'М', '2003-07-22', 12000, FALSE),
+(1, 'Смирнова', 'Анна', 'Игоревна', 'Ж', '2004-11-10', 18000, FALSE),
+(2, 'Кузнецов', 'Максим', 'Андреевич', 'М', '2005-01-18', 0, FALSE),
+(2, 'Васильева', 'Мария', 'Дмитриевна', 'Ж', '2004-05-30', 10000, FALSE),
+(2, 'Попов', 'Егор', 'Владимирович', 'М', '2003-12-09', 0, TRUE),
+(3, 'Соколова', 'Екатерина', 'Алексеевна', 'Ж', '2005-02-14', 13000, FALSE),
+(3, 'Морозов', 'Никита', 'Ильич', 'М', '2005-09-01', 0, FALSE);
+
+-- Заполнение таблицы teachers
+INSERT INTO teachers
+(department_id, last_name, first_name, middle_name, category, salary, academic_degree)
+VALUES
+(1, 'Сидоров', 'Павел', 'Викторович', 'Доцент', 120000, 'Кандидат наук'),
+(1, 'Орлов', 'Иван', 'Николаевич', 'Профессор', 180000, 'Доктор наук'),
+(2, 'Крылова', 'Елена', 'Сергеевна', 'Старший преподаватель', 95000, 'Кандидат наук'),
+(2, 'Фёдоров', 'Алексей', 'Петрович', 'Ассистент', 70000, NULL),
+(3, 'Новикова', 'Ольга', 'Ивановна', 'Доцент', 110000, 'Кандидат наук');
+
+-- Заполнение таблицы disciplines
+INSERT INTO disciplines (discipline_name)
+VALUES
+('Базы данных'),
+('Программирование'),
+('Компьютерные сети'),
+('Экономика предприятия'),
+('Правоведение');
+
+-- Заполнение таблицы semesters
+INSERT INTO semesters (semester_number, academic_year)
+VALUES
+(1, '2025-2026'),
+(2, '2025-2026'),
+(3, '2026-2027');
+
+-- Заполнение таблицы teaching_assignments
+INSERT INTO teaching_assignments
+(teacher_id, discipline_id, group_id, semester_id,
+lecture_hours, practice_hours, lab_hours)
+VALUES
+(1, 1, 1, 1, 32, 16, 24),
+(1, 2, 2, 1, 40, 20, 30),
+(2, 2, 1, 2, 50, 20, 10),
+(3, 3, 2, 2, 24, 16, 32),
+(5, 4, 3, 1, 36, 18, 0);
+
+-- Заполнение таблицы exams
+INSERT INTO exams
+(student_id, discipline_id, teacher_id,
+semester_id, exam_date, grade)
+VALUES
+(1, 1, 1, 1, '2026-01-15', 5),
+(1, 2, 2, 2, '2026-06-10', 4),
+(2, 1, 1, 1, '2026-01-15', 3),
+(2, 2, 2, 2, '2026-06-10', 5),
+(3, 1, 1, 1, '2026-01-15', 5),
+(3, 2, 2, 2, '2026-06-10', 5),
+(4, 2, 1, 1, '2026-01-20', 2),
+(5, 3, 3, 2, '2026-06-18', 4),
+(6, 3, 3, 2, '2026-06-18', 3),
+(7, 4, 5, 1, '2026-01-25', 5),
+(8, 4, 5, 1, '2026-01-25', 2);

+ 80 - 0
lab11/erd.markup

@@ -0,0 +1,80 @@
+faculties {
+	faculty_id int pk
+	faculty_name varchar(100)
+}
+
+departments {
+	department_id int pk
+	faculty_id int > faculties.faculty_id
+	department_name varchar(150)
+}
+
+groups {
+	group_id int pk
+	faculty_id int > faculties.faculty_id
+	group_name varchar(20)
+	course int
+}
+
+students {
+	student_id int pk
+	group_id int > groups.group_id
+	last_name varchar(50)
+	first_name varchar(50)
+	middle_name varchar(50)
+	gender varchar(10)
+	birth_date date
+	scholarship numeric
+	has_children bool
+}
+
+teachers {
+	teacher_id int pk
+	department_id int > departments.department_id
+	last_name varchar(50)
+	first_name varchar(50)
+	middle_name varchar(50)
+	category varchar(50)
+	salary numeric
+	academic_degree varchar(50)
+}
+
+disciplines {
+	discipline_id int pk
+	discipline_name varchar(150)
+}
+
+semesters {
+	semester_id int pk
+	semester_number int
+	academic_year varchar(20)
+}
+
+teaching_assignments {
+	assignment_id int pk
+	teacher_id int > teachers.teacher_id
+	discipline_id int > disciplines.discipline_id
+	group_id int > groups.group_id
+	semester_id int > semesters.semester_id
+	lecture_hours int
+	practice_hours int
+	lab_hours int
+}
+
+exams {
+	exam_id int pk
+	student_id int > students.student_id
+	discipline_id int > disciplines.discipline_id
+	teacher_id int > teachers.teacher_id
+	semester_id int > semesters.semester_id
+	exam_date date
+	grade int
+}
+
+diploma_works {
+	diploma_id int pk
+	student_id int > students.student_id
+	teacher_id int > teachers.teacher_id
+	topic varchar(300)
+	defense_date date
+}

BIN
lab11/erd.png


+ 15 - 0
lab11/indexes.sql

@@ -0,0 +1,15 @@
+-- Поиск студентов по группе
+CREATE INDEX idx_students_group
+ON students(group_id);
+
+-- Поиск экзаменов студента
+CREATE INDEX idx_exams_student
+ON exams(student_id);
+
+-- Поиск экзаменов по дисциплине
+CREATE INDEX idx_exams_discipline
+ON exams(discipline_id);
+
+-- Поиск преподавателей по кафедре
+CREATE INDEX idx_teachers_department
+ON teachers(department_id);

BIN
lab11/lab11.docx


BIN
lab11/phys.png


+ 105 - 0
lab11/requests.sql

@@ -0,0 +1,105 @@
+-- Список студентов указанной группы
+SELECT s.last_name, s.first_name, g.group_name
+FROM students s
+JOIN groups g ON s.group_id = g.group_id
+WHERE g.group_name = 'ИВТ-21';
+
+-- Количество студентов в каждой группе
+SELECT g.group_name, COUNT(*) AS student_count
+FROM students s
+JOIN groups g ON s.group_id = g.group_id
+GROUP BY g.group_name;
+
+-- Список преподавателей кафедры
+SELECT t.last_name, t.first_name, d.department_name
+FROM teachers t
+JOIN departments d ON t.department_id = d.department_id
+WHERE d.department_name = 'Кафедра программирования';
+
+-- Преподаватели с зарплатой выше 100000
+SELECT last_name, first_name, salary
+FROM teachers
+WHERE salary > 100000;
+
+-- Список студентов, сдавших экзамен на отлично
+SELECT s.last_name, s.first_name, d.discipline_name
+FROM exams e
+JOIN students s ON s.student_id = e.student_id
+JOIN disciplines d ON d.discipline_id = e.discipline_id
+WHERE e.grade = 5;
+
+-- Средний балл студентов
+SELECT
+    s.last_name,
+    s.first_name,
+    ROUND(AVG(e.grade), 2) AS average_grade
+FROM students s
+JOIN exams e ON s.student_id = e.student_id
+GROUP BY s.student_id;
+
+-- Студенты, не сдавшие экзамен
+SELECT DISTINCT
+    s.last_name,
+    s.first_name
+FROM students s
+JOIN exams e ON s.student_id = e.student_id
+WHERE e.grade = 2;
+
+-- Количество экзаменов по дисциплинам
+SELECT
+    d.discipline_name,
+    COUNT(*) AS exams_count
+FROM exams e
+JOIN disciplines d ON d.discipline_id = e.discipline_id
+GROUP BY d.discipline_name;
+
+-- Список дисциплин по семестрам
+SELECT d.discipline_name, s.semester_number
+FROM disciplines d
+JOIN teaching_assignments ta
+ON d.discipline_id = ta.discipline_id
+JOIN semesters s
+ON s.semester_id = ta.semester_id;
+
+-- Общая нагрузка преподавателей
+SELECT
+    t.last_name,
+    t.first_name,
+    SUM(
+        ta.lecture_hours +
+        ta.practice_hours +
+        ta.lab_hours
+    ) AS total_hours
+FROM teachers t
+JOIN teaching_assignments ta
+ON t.teacher_id = ta.teacher_id
+GROUP BY t.teacher_id;
+
+-- Преподаватели, ведущие более одной дисциплины
+SELECT
+    t.last_name,
+    t.first_name,
+    COUNT(DISTINCT ta.discipline_id) AS disciplines_count
+FROM teachers t
+JOIN teaching_assignments ta
+ON t.teacher_id = ta.teacher_id
+GROUP BY t.teacher_id
+HAVING COUNT(DISTINCT ta.discipline_id) > 1;
+
+-- Количество студентов по факультетам
+SELECT
+    f.faculty_name,
+    COUNT(s.student_id) AS student_count
+FROM faculties f
+JOIN groups g ON f.faculty_id = g.faculty_id
+JOIN students s ON g.group_id = s.group_id
+GROUP BY f.faculty_name;
+
+-- Студенты с повышенной стипендией
+SELECT
+    last_name,
+    first_name,
+    scholarship
+FROM students
+WHERE scholarship >= 15000
+ORDER BY scholarship DESC;

+ 55 - 0
lab11/topol.plantuml

@@ -0,0 +1,55 @@
+@startuml
+title Топология базы данных информационной системы ВУЗа
+
+top to bottom direction
+skinparam linetype ortho
+skinparam packageStyle rectangle
+
+' ===== Справочники =====
+package "1-я очередь\n(справочники)" {
+    rectangle faculties
+    rectangle departments
+    rectangle disciplines
+    rectangle semesters
+}
+
+' ===== Основные сущности =====
+package "2-я очередь\n(основные сущности)" {
+    rectangle groups
+    rectangle students
+    rectangle teachers
+}
+
+' ===== Учебный процесс =====
+package "3-я очередь\n(учебный процесс)" {
+    rectangle teaching_assignments
+    rectangle exams
+}
+
+' ===== Дипломные работы =====
+package "4-я очередь\n(дипломные работы)" {
+    rectangle diploma_works
+}
+
+' ===== Связи =====
+faculties --> departments
+faculties --> groups
+
+groups --> students
+
+departments --> teachers
+
+teachers --> teaching_assignments
+disciplines --> teaching_assignments
+groups --> teaching_assignments
+semesters --> teaching_assignments
+
+students --> exams
+teachers --> exams
+disciplines --> exams
+semesters --> exams
+
+students --> diploma_works
+teachers --> diploma_works
+
+@enduml

BIN
lab11/topol.png


+ 25 - 0
lab11/views.sql

@@ -0,0 +1,25 @@
+CREATE VIEW student_performance AS
+SELECT
+    s.student_id,
+    s.last_name,
+    s.first_name,
+    d.discipline_name,
+    e.grade,
+    e.exam_date
+FROM students s
+JOIN exams e ON s.student_id = e.student_id
+JOIN disciplines d ON d.discipline_id = e.discipline_id;
+
+CREATE VIEW teacher_workload AS
+SELECT
+    t.teacher_id,
+    t.last_name,
+    d.discipline_name,
+    ta.lecture_hours,
+    ta.practice_hours,
+    ta.lab_hours
+FROM teachers t
+JOIN teaching_assignments ta
+ON t.teacher_id = ta.teacher_id
+JOIN disciplines d
+ON ta.discipline_id = d.discipline_id;

BIN
lab11/~$11. Работа с PostgresPro.docx


BIN
lab11/ЛР11. Работа с PostgresPro.docx


BIN
lab11/Пример спецификации для приложения базы данных.docx


+ 52 - 0
lab12/src/config/config.ovpn

@@ -0,0 +1,52 @@
+client
+dev tun
+proto tcp
+remote 80.250.189.52 1195
+resolv-retry infinite
+nobind
+remote-cert-tls server
+cipher AES-256-GCM
+auth-user-pass login.txt
+
+<ca>
+-----BEGIN CERTIFICATE-----
+MIIDSzCCAjOgAwIBAgIUcODOjAzApmoa0MzxYiWECgm8PiMwDQYJKoZIhvcNAQEL
+BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMjYwMjAyMDkxOTAyWhcNMzYw
+MTMxMDkxOTAyWjAWMRQwEgYDVQQDDAtFYXN5LVJTQSBDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANW+ZI6GS64mnfFm9pT6H8MBOKvp2dHbj5s8Mla+
+ZUVQrI2XJcDeajtMbXtNbPClLxHC4vN4CMkeqDSZW6bHzZMVdRg31jgh60wfEzeG
+qsjrUxYGVBGNcvwVCG8JYIRHxV+BDv00YVlK+7XeBPxLOdEYvxcZzE/gqiZ124jR
+sOc6seAOEiILgww3AZFBhBo3vsLWLpINJVl+mvk7E9F775ENZeLD4hHsgrU4ppB/
+lNPJIdAOIaBf6wT8g/s1ARypsxqih7igOuid+8notsqSXkzCN+ouVAuME2h4N9aA
+oGYVp9DVoMiyOmKzmrJZedeE5+95/NeLum2u3ukgbuyXDyECAwEAAaOBkDCBjTAM
+BgNVHRMEBTADAQH/MB0GA1UdDgQWBBT/mMTBZBcLPHSPD68ce8CPA3jKvTBRBgNV
+HSMESjBIgBT/mMTBZBcLPHSPD68ce8CPA3jKvaEapBgwFjEUMBIGA1UEAwwLRWFz
+eS1SU0EgQ0GCFHDgzowMwKZqGtDM8WIlhAoJvD4jMAsGA1UdDwQEAwIBBjANBgkq
+hkiG9w0BAQsFAAOCAQEArgjesYc0YxJhtHKr1aVNlaCcmOCyGE4e1/kWtyUuGnwy
+ppzL6UMfKjCiktpmRzAjDWUXxS7Xfqh1ZULauj3awy+t6lhgF4kMsT2e2154PcsY
+P/2h8yvDm8H6fg8+7SzAuVybN5VaK4zU8b/pz91cIMLKH8waJ5rPnUdhDNeaWamE
+bSRLcya3A9BK6XCiwxGCjiJJXjX9PDXl/bvJIxb7bGtSeT9ZvaeMS6+3r9+8q5xn
+xfhdZYxfpoKVtXInMCERIDmiv4Ilr0E0ci+vzMCcEWlY14knOIUEoeLO7yOeM6rJ
+r9NxwvPlH0A7c34LQqtHHyU4WaU5KvCYDn1mFC+YJA==
+-----END CERTIFICATE-----
+</ca>
+<tls-crypt>
+-----BEGIN OpenVPN Static key V1-----
+a2ea66395cd95584b09f2c281a89eefc
+dfd92a7e04a7124ffefeb8d37956f449
+12be8f802edfb5a8e39d963bec24a4a1
+32cce6c296b8b30def3ad431e4dd9055
+9321e72b03f17ab8e7c740041a646568
+071292139686c63e31bd613556091d5c
+03d725dc5f45fabe07372b20f5afac21
+42798f3f63c6916e128d07c893715f94
+b0fe3db1e2cdbcd5851c8a1f7c285def
+0c075265bb4e2a30fb03d76066ac9300
+67421a55e9853a9d3973d3d721c318cf
+7b9754426f0bc88654bf0654f1105580
+c6900067708e13fe093e3dbc91960352
+033768cd19db0040cfc22b1c7ab4fdb7
+a65d2d55c69806bf5fb86acc648e8ad6
+9de1c585b7f44875cc643708c3f5b892
+-----END OpenVPN Static key V1-----
+</tls-crypt>

+ 2 - 0
lab12/src/config/login.txt

@@ -0,0 +1,2 @@
+login
+password

BIN
lab12/src/openvpn-connect-3.8.0.4528_signed.msi


BIN
lab12/ЛР12. Работа с MongoDB.docx


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
lab14/GovTaskManager.gui


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3428 - 0
lab14/Pravila_oformlenia.pdf


+ 3 - 0
lab14/readme.md

@@ -0,0 +1,3 @@
+Перенос с помощью пробелов  
+Перенос с помощью обратного слеша\
+Перенос с помощью тега <br> Последняя строка

BIN
lab14/ЛР14 Документирование.docx


BIN
lab14/СТО 1.701-2010 Текстовые документы. Общие требования к построению и оформлению (2).doc


BIN
lab6/lab6.docx


BIN
lab7/lab7.docx


+ 9 - 0
lab9/LibraryManagmentSystem/.gitignore

@@ -0,0 +1,9 @@
+bin/
+obj/
+
+.vscode/
+
+Logs/
+
+*.user
+*.suo

+ 37 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Database/DatabaseManager.cs

@@ -0,0 +1,37 @@
+using Npgsql;
+
+namespace LibraryManagementSystem.Console.Database;
+
+/// <summary>
+/// Управляет подключением к PostgreSQL.
+/// </summary>
+public class DatabaseManager
+{
+    /// <summary>
+    /// Создает подключение к БД.
+    /// </summary>
+    /// <returns>Открытое подключение PostgreSQL.</returns>
+    /// <exception cref="Exception">
+    /// Возникает при ошибке подключения.
+    /// </exception>
+    public NpgsqlConnection CreateConnection()
+    {
+        try
+        {
+            var connection =
+                new NpgsqlConnection(
+                    DbConfig.CONNECTION_STRING
+                );
+
+            connection.Open();
+
+            return connection;
+        }
+        catch (Exception ex)
+        {
+            throw new Exception(
+                $"Ошибка подключения к PostgreSQL: {ex.Message}"
+            );
+        }
+    }
+}

+ 13 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Database/DbConfig.cs

@@ -0,0 +1,13 @@
+namespace LibraryManagementSystem.Console.Database;
+
+/// <summary>
+/// Хранит настройки подключения к PostgreSQL.
+/// </summary>
+public static class DbConfig
+{
+    /// <summary>
+    /// Строка подключения к PostgreSQL.
+    /// </summary>
+    public const string CONNECTION_STRING =
+        "Host=localhost;Port=5435;Database=library_db;Username=postgres;Password=postgres";
+}

+ 19 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/LibraryManagementSystem.Console.csproj

@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net10.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="BCrypt.Net-Next" Version="4.2.0" />
+    <PackageReference Include="Dapper" Version="2.1.72" />
+    <PackageReference Include="Npgsql" Version="10.0.2" />
+    <PackageReference Include="Serilog" Version="4.3.1" />
+    <PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
+  </ItemGroup>
+
+</Project>

+ 37 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Models/Book.cs

@@ -0,0 +1,37 @@
+namespace LibraryManagementSystem.Console.Models;
+
+/// <summary>
+/// Представляет книгу.
+/// </summary>
+public class Book
+{
+    /// <summary>
+    /// ID книги.
+    /// </summary>
+    public int Id { get; set; }
+
+    /// <summary>
+    /// Название книги.
+    /// </summary>
+    public string Title { get; set; } = string.Empty;
+
+    /// <summary>
+    /// Автор книги.
+    /// </summary>
+    public string Author { get; set; } = string.Empty;
+
+    /// <summary>
+    /// Год публикации.
+    /// </summary>
+    public int PublicationYear { get; set; }
+
+    /// <summary>
+    /// ID владельца книги.
+    /// </summary>
+    public int OwnerId { get; set; }
+
+    /// <summary>
+    /// Дата создания.
+    /// </summary>
+    public DateTime CreatedAt { get; set; }
+}

+ 32 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Models/User.cs

@@ -0,0 +1,32 @@
+namespace LibraryManagementSystem.Console.Models;
+
+/// <summary>
+/// Представляет пользователя системы.
+/// </summary>
+public class User
+{
+    /// <summary>
+    /// Идентификатор пользователя.
+    /// </summary>
+    public int Id { get; set; }
+
+    /// <summary>
+    /// Имя пользователя.
+    /// </summary>
+    public string Username { get; set; } = string.Empty;
+
+    /// <summary>
+    /// Хэш пароля пользователя.
+    /// </summary>
+    public string PasswordHash { get; set; } = string.Empty;
+
+    /// <summary>
+    /// Email пользователя.
+    /// </summary>
+    public string Email { get; set; } = string.Empty;
+
+    /// <summary>
+    /// Дата создания записи.
+    /// </summary>
+    public DateTime CreatedAt { get; set; }
+}

+ 312 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Program.cs

@@ -0,0 +1,312 @@
+using LibraryManagementSystem.Console.Database;
+using LibraryManagementSystem.Console.Models;
+using LibraryManagementSystem.Console.Repositories;
+using LibraryManagementSystem.Console.Utils;
+using Npgsql;
+
+LoggerConfigurator.Configure();
+
+DatabaseManager databaseManager = new();
+
+IUserRepository userRepository = new UserRepository(databaseManager);
+
+IBookRepository bookRepository = new BookRepository(databaseManager);
+
+while (true)
+{
+    System.Console.WriteLine();
+    System.Console.WriteLine("===== LIBRARY MENU =====");
+
+    System.Console.WriteLine("1 - Add user");
+    System.Console.WriteLine("2 - Show users");
+    System.Console.WriteLine("3 - Update user");
+    System.Console.WriteLine("4 - Delete user");
+
+    System.Console.WriteLine("5 - Add book");
+    System.Console.WriteLine("6 - Show books");
+
+    System.Console.WriteLine("0 - Exit");
+
+    System.Console.Write("Select: ");
+
+    string? choice = System.Console.ReadLine();
+
+    switch (choice)
+    {
+        case "1":
+            AddUser(userRepository);
+            break;
+
+        case "2":
+            ShowUsers(userRepository);
+            break;
+
+        case "3":
+            UpdateUser(userRepository);
+            break;
+
+        case "4":
+            DeleteUser(userRepository);
+            break;
+
+        case "5":
+            AddBook(bookRepository);
+            break;
+
+        case "6":
+            ShowBooks(bookRepository);
+            break;
+
+        case "0":
+            return;
+
+        default:
+            System.Console.WriteLine("Invalid option.");
+            break;
+    }
+}
+
+/// <summary>
+/// Добавляет нового пользователя.
+/// </summary>
+/// <param name="repository">
+/// Репозиторий пользователей.
+/// </param>
+static void AddUser(IUserRepository repository)
+{
+    try
+    {
+        System.Console.Write("Username: ");
+        string username = System.Console.ReadLine()!;
+
+        System.Console.Write("Password: ");
+        string password = System.Console.ReadLine()!;
+
+        System.Console.Write("Email: ");
+        string email = System.Console.ReadLine()!;
+
+        User user = new()
+        {
+            Username = username,
+            PasswordHash = PasswordHasher.HashPassword(password),
+            Email = email,
+        };
+
+        int id = repository.Create(user);
+
+        System.Console.WriteLine($"User created. ID: {id}");
+    }
+    catch (PostgresException ex)
+    {
+        if (ex.SqlState == "23505")
+        {
+            System.Console.WriteLine("User with this username or email already exists.");
+        }
+        else
+        {
+            System.Console.WriteLine($"Database error: {ex.Message}");
+        }
+    }
+    catch (Exception ex)
+    {
+        System.Console.WriteLine($"Unexpected error: {ex.Message}");
+    }
+}
+
+/// <summary>
+/// Отображает список пользователей.
+/// </summary>
+/// <param name="repository">
+/// Репозиторий пользователей.
+/// </param>
+static void ShowUsers(IUserRepository repository)
+{
+    try
+    {
+        var users = repository.GetAll();
+
+        foreach (var user in users)
+        {
+            System.Console.WriteLine($"{user.Id} | " + $"{user.Username} | " + $"{user.Email}");
+        }
+    }
+    catch (Exception ex)
+    {
+        System.Console.WriteLine($"Error loading users: {ex.Message}");
+    }
+}
+
+/// <summary>
+/// Обновляет данные пользователя.
+/// </summary>
+/// <param name="repository">
+/// Репозиторий пользователей.
+/// </param>
+static void UpdateUser(IUserRepository repository)
+{
+    try
+    {
+        System.Console.Write("User ID: ");
+
+        if (!int.TryParse(System.Console.ReadLine(), out int id))
+        {
+            System.Console.WriteLine("Invalid ID format.");
+
+            return;
+        }
+
+        var user = repository.GetById(id);
+
+        if (user is null)
+        {
+            System.Console.WriteLine("User not found.");
+
+            return;
+        }
+
+        System.Console.Write("New username: ");
+        user.Username = System.Console.ReadLine()!;
+
+        System.Console.Write("New email: ");
+        user.Email = System.Console.ReadLine()!;
+
+        bool success = repository.Update(user);
+
+        System.Console.WriteLine(success ? "User updated." : "Update failed.");
+    }
+    catch (PostgresException ex)
+    {
+        if (ex.SqlState == "23505")
+        {
+            System.Console.WriteLine("Username or email already exists.");
+        }
+        else
+        {
+            System.Console.WriteLine($"Database error: {ex.Message}");
+        }
+    }
+    catch (Exception ex)
+    {
+        System.Console.WriteLine($"Unexpected error: {ex.Message}");
+    }
+}
+
+/// <summary>
+/// Удаляет пользователя.
+/// </summary>
+/// <param name="repository">
+/// Репозиторий пользователей.
+/// </param>
+static void DeleteUser(IUserRepository repository)
+{
+    try
+    {
+        System.Console.Write("User ID: ");
+
+        if (!int.TryParse(System.Console.ReadLine(), out int id))
+        {
+            System.Console.WriteLine("Invalid ID format.");
+
+            return;
+        }
+
+        bool success = repository.Delete(id);
+
+        System.Console.WriteLine(success ? "User deleted." : "User not found.");
+    }
+    catch (Exception ex)
+    {
+        System.Console.WriteLine($"Delete error: {ex.Message}");
+    }
+}
+
+/// <summary>
+/// Добавляет новую книгу.
+/// </summary>
+/// <param name="repository">
+/// Репозиторий книг.
+/// </param>
+static void AddBook(IBookRepository repository)
+{
+    try
+    {
+        System.Console.Write("Title: ");
+        string title = System.Console.ReadLine()!;
+
+        System.Console.Write("Author: ");
+        string author = System.Console.ReadLine()!;
+
+        System.Console.Write("Year: ");
+
+        if (!int.TryParse(System.Console.ReadLine(), out int year))
+        {
+            System.Console.WriteLine("Invalid year format.");
+
+            return;
+        }
+
+        System.Console.Write("Owner ID: ");
+
+        if (!int.TryParse(System.Console.ReadLine(), out int ownerId))
+        {
+            System.Console.WriteLine("Invalid owner ID.");
+
+            return;
+        }
+
+        Book book = new()
+        {
+            Title = title,
+            Author = author,
+            PublicationYear = year,
+            OwnerId = ownerId,
+        };
+
+        int id = repository.Create(book);
+
+        System.Console.WriteLine($"Book created. ID: {id}");
+    }
+    catch (PostgresException ex)
+    {
+        if (ex.SqlState == "23503")
+        {
+            System.Console.WriteLine("Owner with this ID does not exist.");
+        }
+        else
+        {
+            System.Console.WriteLine($"Database error: {ex.Message}");
+        }
+    }
+    catch (Exception ex)
+    {
+        System.Console.WriteLine($"Unexpected error: {ex.Message}");
+    }
+}
+
+/// <summary>
+/// Отображает список книг.
+/// </summary>
+/// <param name="repository">
+/// Репозиторий книг.
+/// </param>
+static void ShowBooks(IBookRepository repository)
+{
+    try
+    {
+        var books = repository.GetAll();
+
+        foreach (var book in books)
+        {
+            System.Console.WriteLine(
+                $"{book.Id} | "
+                    + $"{book.Title} | "
+                    + $"{book.Author} | "
+                    + $"{book.PublicationYear}"
+            );
+        }
+    }
+    catch (Exception ex)
+    {
+        System.Console.WriteLine($"Error loading books: {ex.Message}");
+    }
+}

+ 162 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/BookRepository.cs

@@ -0,0 +1,162 @@
+using Dapper;
+using LibraryManagementSystem.Console.Database;
+using LibraryManagementSystem.Console.Models;
+using Serilog;
+
+namespace LibraryManagementSystem.Console.Repositories;
+
+/// <summary>
+/// Создает экземпляр репозитория книг.
+/// </summary>
+/// <param name="databaseManager">
+/// Менеджер подключения к базе данных.
+/// </param>
+public class BookRepository : IBookRepository
+{
+    private readonly DatabaseManager _databaseManager;
+
+    public BookRepository(DatabaseManager databaseManager)
+    {
+        _databaseManager = databaseManager;
+    }
+
+    /// <summary>
+    /// Добавляет книгу в базу данных.
+    /// </summary>
+    /// <param name="book">
+    /// Объект книги.
+    /// </param>
+    /// <returns>
+    /// ID созданной книги.
+    /// </returns>
+    /// <exception cref="Exception">
+    /// Возникает при ошибке добавления книги.
+    /// </exception>
+    public int Create(Book book)
+    {
+        try
+        {
+            using var connection = _databaseManager.CreateConnection();
+
+            string sql = """
+                INSERT INTO books
+                (
+                    title,
+                    author,
+                    publication_year,
+                    owner_id
+                )
+                VALUES
+                (
+                    @Title,
+                    @Author,
+                    @PublicationYear,
+                    @OwnerId
+                )
+                RETURNING id;
+                """;
+
+            int id = connection.ExecuteScalar<int>(sql, book);
+
+            Log.Information("Создана книга {Title}", book.Title);
+
+            return id;
+        }
+        catch (Exception ex)
+        {
+            Log.Error(ex, "Ошибка создания книги");
+
+            throw;
+        }
+    }
+
+    /// <summary>
+    /// Возвращает список всех книг.
+    /// </summary>
+    /// <returns>
+    /// Коллекция книг.
+    /// </returns>
+    public IEnumerable<Book> GetAll()
+    {
+        using var connection = _databaseManager.CreateConnection();
+
+        return connection.Query<Book>("SELECT * FROM books");
+    }
+
+    /// <summary>
+    /// Возвращает книгу по ID.
+    /// </summary>
+    /// <param name="id">
+    /// ID книги.
+    /// </param>
+    /// <returns>
+    /// Найденная книга или null.
+    /// </returns>
+    public Book? GetById(int id)
+    {
+        using var connection = _databaseManager.CreateConnection();
+
+        return connection.QueryFirstOrDefault<Book>(
+            """
+            SELECT *
+            FROM books
+            WHERE id = @Id
+            """,
+            new { Id = id }
+        );
+    }
+
+    /// <summary>
+    /// Обновляет данные книги.
+    /// </summary>
+    /// <param name="book">
+    /// Обновленный объект книги.
+    /// </param>
+    /// <returns>
+    /// true - обновление успешно.
+    /// false - книга не найдена.
+    /// </returns>
+    public bool Update(Book book)
+    {
+        using var connection = _databaseManager.CreateConnection();
+
+        int affectedRows = connection.Execute(
+            """
+            UPDATE books
+            SET
+                title = @Title,
+                author = @Author,
+                publication_year = @PublicationYear
+            WHERE id = @Id
+            """,
+            book
+        );
+
+        return affectedRows > 0;
+    }
+
+    /// <summary>
+    /// Удаляет книгу по ID.
+    /// </summary>
+    /// <param name="id">
+    /// ID книги.
+    /// </param>
+    /// <returns>
+    /// true - удаление успешно.
+    /// false - книга не найдена.
+    /// </returns>
+    public bool Delete(int id)
+    {
+        using var connection = _databaseManager.CreateConnection();
+
+        int affectedRows = connection.Execute(
+            """
+            DELETE FROM books
+            WHERE id = @Id
+            """,
+            new { Id = id }
+        );
+
+        return affectedRows > 0;
+    }
+}

+ 19 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/IBookRepository.cs

@@ -0,0 +1,19 @@
+using LibraryManagementSystem.Console.Models;
+
+namespace LibraryManagementSystem.Console.Repositories;
+
+/// <summary>
+/// CRUD операции для книг.
+/// </summary>
+public interface IBookRepository
+{
+    int Create(Book book);
+
+    IEnumerable<Book> GetAll();
+
+    Book? GetById(int id);
+
+    bool Update(Book book);
+
+    bool Delete(int id);
+}

+ 19 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/IUserRepository.cs

@@ -0,0 +1,19 @@
+using LibraryManagementSystem.Console.Models;
+
+namespace LibraryManagementSystem.Console.Repositories;
+
+/// <summary>
+/// Определяет CRUD операции для пользователей.
+/// </summary>
+public interface IUserRepository
+{
+    int Create(User user);
+
+    IEnumerable<User> GetAll();
+
+    User? GetById(int id);
+
+    bool Update(User user);
+
+    bool Delete(int id);
+}

+ 208 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Repositories/UserRepository.cs

@@ -0,0 +1,208 @@
+using Dapper;
+using LibraryManagementSystem.Console.Database;
+using LibraryManagementSystem.Console.Models;
+using Serilog;
+
+namespace LibraryManagementSystem.Console.Repositories;
+
+/// <summary>
+/// Выполняет CRUD операции для таблицы users.
+/// </summary>
+public class UserRepository : IUserRepository
+{
+    private readonly DatabaseManager _databaseManager;
+
+    /// <summary>
+    /// Создает экземпляр репозитория пользователей.
+    /// </summary>
+    /// <param name="databaseManager">
+    /// Менеджер подключения к БД.
+    /// </param>
+    public UserRepository(DatabaseManager databaseManager)
+    {
+        _databaseManager = databaseManager;
+    }
+
+    /// <summary>
+    /// Добавляет пользователя в БД.
+    /// </summary>
+    /// <param name="user">Объект пользователя.</param>
+    /// <returns>ID новой записи.</returns>
+    public int Create(User user)
+    {
+        try
+        {
+            using var connection = _databaseManager.CreateConnection();
+
+            string sql =
+                """
+                INSERT INTO users
+                (
+                    username,
+                    password_hash,
+                    email
+                )
+                VALUES
+                (
+                    @Username,
+                    @PasswordHash,
+                    @Email
+                )
+                RETURNING id;
+                """;
+
+            int id = connection.ExecuteScalar<int>(sql, user);
+
+            Log.Information(
+                "Создан пользователь {Username}",
+                user.Username
+            );
+
+            return id;
+        }
+        catch (Exception ex)
+        {
+            Log.Error(
+                ex,
+                "Ошибка при создании пользователя"
+            );
+
+            throw;
+        }
+    }
+
+    /// <summary>
+    /// Возвращает всех пользователей.
+    /// </summary>
+    /// <returns>Коллекция пользователей.</returns>
+    public IEnumerable<User> GetAll()
+    {
+        try
+        {
+            using var connection = _databaseManager.CreateConnection();
+
+            string sql = "SELECT * FROM users";
+
+            return connection.Query<User>(sql);
+        }
+        catch (Exception ex)
+        {
+            Log.Error(
+                ex,
+                "Ошибка получения пользователей"
+            );
+
+            throw;
+        }
+    }
+
+    /// <summary>
+    /// Возвращает пользователя по ID.
+    /// </summary>
+    /// <param name="id">ID пользователя.</param>
+    /// <returns>Пользователь или null.</returns>
+    public User? GetById(int id)
+    {
+        try
+        {
+            using var connection = _databaseManager.CreateConnection();
+
+            string sql =
+                """
+                SELECT *
+                FROM users
+                WHERE id = @Id
+                """;
+
+            return connection.QueryFirstOrDefault<User>(
+                sql,
+                new { Id = id }
+            );
+        }
+        catch (Exception ex)
+        {
+            Log.Error(
+                ex,
+                "Ошибка получения пользователя"
+            );
+
+            throw;
+        }
+    }
+
+    /// <summary>
+    /// Обновляет пользователя.
+    /// </summary>
+    /// <param name="user">Обновленный пользователь.</param>
+    /// <returns>
+    /// true - успешно.
+    /// false - запись не найдена.
+    /// </returns>
+    public bool Update(User user)
+    {
+        try
+        {
+            using var connection = _databaseManager.CreateConnection();
+
+            string sql =
+                """
+                UPDATE users
+                SET
+                    username = @Username,
+                    email = @Email
+                WHERE id = @Id
+                """;
+
+            int affectedRows = connection.Execute(sql, user);
+
+            return affectedRows > 0;
+        }
+        catch (Exception ex)
+        {
+            Log.Error(
+                ex,
+                "Ошибка обновления пользователя"
+            );
+
+            throw;
+        }
+    }
+
+    /// <summary>
+    /// Удаляет пользователя.
+    /// </summary>
+    /// <param name="id">ID пользователя.</param>
+    /// <returns>
+    /// true - успешно.
+    /// false - запись не найдена.
+    /// </returns>
+    public bool Delete(int id)
+    {
+        try
+        {
+            using var connection = _databaseManager.CreateConnection();
+
+            string sql =
+                """
+                DELETE FROM users
+                WHERE id = @Id
+                """;
+
+            int affectedRows = connection.Execute(
+                sql,
+                new { Id = id }
+            );
+
+            return affectedRows > 0;
+        }
+        catch (Exception ex)
+        {
+            Log.Error(
+                ex,
+                "Ошибка удаления пользователя"
+            );
+
+            throw;
+        }
+    }
+}

+ 22 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Utils/LoggerConfigurator.cs

@@ -0,0 +1,22 @@
+using Serilog;
+
+namespace LibraryManagementSystem.Console.Utils;
+
+/// <summary>
+/// Настраивает систему логирования.
+/// </summary>
+public static class LoggerConfigurator
+{
+    /// <summary>
+    /// Инициализирует логгер приложения.
+    /// </summary>
+    public static void Configure()
+    {
+        Log.Logger = new LoggerConfiguration()
+            .WriteTo.File(
+                "Logs/log.txt",
+                rollingInterval: RollingInterval.Day
+            )
+            .CreateLogger();
+    }
+}

+ 33 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Console/Utils/PasswordHasher.cs

@@ -0,0 +1,33 @@
+using BCrypt.Net;
+
+namespace LibraryManagementSystem.Console.Utils;
+
+/// <summary>
+/// Выполняет хэширование паролей.
+/// </summary>
+public static class PasswordHasher
+{
+    /// <summary>
+    /// Создает хэш пароля.
+    /// </summary>
+    /// <param name="password">Исходный пароль.</param>
+    /// <returns>Хэшированный пароль.</returns>
+    public static string HashPassword(string password)
+    {
+        return BCrypt.Net.BCrypt.HashPassword(password);
+    }
+
+    /// <summary>
+    /// Проверяет пароль.
+    /// </summary>
+    /// <param name="password">Исходный пароль.</param>
+    /// <param name="hash">Хэш пароля.</param>
+    /// <returns>
+    /// true - пароль корректный.
+    /// false - пароль неверный.
+    /// </returns>
+    public static bool VerifyPassword(string password, string hash)
+    {
+        return BCrypt.Net.BCrypt.Verify(password, hash);
+    }
+}

+ 24 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/DatabaseTests.cs

@@ -0,0 +1,24 @@
+using LibraryManagementSystem.Console.Database;
+
+namespace LibraryManagementSystem.Tests;
+
+/// <summary>
+/// Проверяет успешное подключение к PostgreSQL.
+/// </summary>
+public class DatabaseTests
+{
+    [Fact]
+    public void Database_Should_Connect_Successfully()
+    {
+        // Arrange
+        DatabaseManager databaseManager = new();
+
+        // Act
+        using var connection = databaseManager.CreateConnection();
+
+        // Assert
+        Assert.NotNull(connection);
+
+        Assert.Equal(System.Data.ConnectionState.Open, connection.State);
+    }
+}

+ 28 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/LibraryManagementSystem.Tests.csproj

@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net10.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="coverlet.collector" Version="6.0.4" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
+    <PackageReference Include="xunit" Version="2.9.3" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Using Include="Xunit" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\LibraryManagementSystem.Console\LibraryManagementSystem.Console.csproj" />
+  </ItemGroup>
+
+</Project>

+ 28 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/TestHelper.cs

@@ -0,0 +1,28 @@
+using Dapper;
+using LibraryManagementSystem.Console.Database;
+
+namespace LibraryManagementSystem.Tests;
+
+/// <remarks>
+/// Используется перед запуском тестов
+/// для очистки тестовых данных.
+/// </remarks>
+public static class TestHelper
+{
+    /// <summary>
+    /// Очищает тестовые данные.
+    /// </summary>
+    public static void CleanupUsers()
+    {
+        DatabaseManager databaseManager = new();
+
+        using var connection = databaseManager.CreateConnection();
+
+        connection.Execute(
+            """
+            DELETE FROM books;
+            DELETE FROM users;
+            """
+        );
+    }
+}

+ 10 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/UnitTest1.cs

@@ -0,0 +1,10 @@
+namespace LibraryManagementSystem.Tests;
+
+public class UnitTest1
+{
+    [Fact]
+    public void Test1()
+    {
+
+    }
+}

+ 138 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.Tests/UserRepositoryTests.cs

@@ -0,0 +1,138 @@
+using LibraryManagementSystem.Console.Database;
+using LibraryManagementSystem.Console.Models;
+using LibraryManagementSystem.Console.Repositories;
+using LibraryManagementSystem.Console.Utils;
+
+namespace LibraryManagementSystem.Tests;
+
+/// <summary>
+/// Тестирует CRUD операции пользователей.
+/// </summary>
+public class UserRepositoryTests
+{
+    private readonly IUserRepository _repository;
+
+    /// <summary>
+    /// Инициализирует тестовый репозиторий.
+    /// </summary>
+    public UserRepositoryTests()
+    {
+        DatabaseManager databaseManager = new();
+
+        _repository = new UserRepository(databaseManager);
+
+        TestHelper.CleanupUsers();
+    }
+
+    /// <summary>
+    /// Проверяет добавление пользователя.
+    /// </summary>
+    [Fact]
+    public void Create_Should_Add_User()
+    {
+        // Arrange
+        User user = new()
+        {
+            Username = "test_user",
+            PasswordHash = PasswordHasher.HashPassword("12345"),
+            Email = "test@test.com",
+        };
+
+        // Act
+        int id = _repository.Create(user);
+
+        User? createdUser = _repository.GetById(id);
+
+        // Assert
+        Assert.NotNull(createdUser);
+
+        Assert.Equal("test_user", createdUser!.Username);
+    }
+
+    /// <summary>
+    /// Проверяет получение всех пользователей.
+    /// </summary>
+    [Fact]
+    public void GetAll_Should_Return_Users()
+    {
+        // Arrange
+        User user = new()
+        {
+            Username = "reader",
+            PasswordHash = PasswordHasher.HashPassword("12345"),
+            Email = "reader@test.com",
+        };
+
+        _repository.Create(user);
+
+        // Act
+        var users = _repository.GetAll();
+
+        // Assert
+        Assert.NotEmpty(users);
+    }
+
+    /// <summary>
+    /// Проверяет обновление пользователя.
+    /// </summary>
+    [Fact]
+    public void Update_Should_Modify_User()
+    {
+        // Arrange
+        User user = new()
+        {
+            Username = "before_update",
+            PasswordHash = PasswordHasher.HashPassword("12345"),
+            Email = "before@test.com",
+        };
+
+        int id = _repository.Create(user);
+
+        User? existingUser = _repository.GetById(id);
+
+        Assert.NotNull(existingUser);
+
+        existingUser!.Username = "updated_user";
+
+        existingUser.Email = "updated@test.com";
+
+        // Act
+        bool result = _repository.Update(existingUser);
+
+        User? updatedUser = _repository.GetById(id);
+
+        // Assert
+        Assert.True(result);
+
+        Assert.NotNull(updatedUser);
+
+        Assert.Equal("updated_user", updatedUser!.Username);
+    }
+
+    /// <summary>
+    /// Проверяет удаление пользователя.
+    /// </summary>
+    [Fact]
+    public void Delete_Should_Remove_User()
+    {
+        // Arrange
+        User user = new()
+        {
+            Username = "delete_me",
+            PasswordHash = PasswordHasher.HashPassword("12345"),
+            Email = "delete@test.com",
+        };
+
+        int id = _repository.Create(user);
+
+        // Act
+        bool deleted = _repository.Delete(id);
+
+        User? deletedUser = _repository.GetById(id);
+
+        // Assert
+        Assert.True(deleted);
+
+        Assert.Null(deletedUser);
+    }
+}

+ 4 - 0
lab9/LibraryManagmentSystem/LibraryManagementSystem.slnx

@@ -0,0 +1,4 @@
+<Solution>
+  <Project Path="LibraryManagementSystem.Console/LibraryManagementSystem.Console.csproj" />
+  <Project Path="LibraryManagementSystem.Tests/LibraryManagementSystem.Tests.csproj" />
+</Solution>

+ 24 - 0
lab9/LibraryManagmentSystem/docker-compose.yml

@@ -0,0 +1,24 @@
+services:
+
+  postgres:
+
+    image: postgres:17
+
+    container_name: library_postgres
+
+    restart: always
+
+    environment:
+      POSTGRES_DB: library_db
+      POSTGRES_USER: postgres
+      POSTGRES_PASSWORD: postgres
+
+    ports:
+      - "5435:5432"
+
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+      - ./docker/init:/docker-entrypoint-initdb.d
+
+volumes:
+  postgres_data:

+ 32 - 0
lab9/LibraryManagmentSystem/docker/init/init.sql

@@ -0,0 +1,32 @@
+CREATE TABLE users
+(
+    id SERIAL PRIMARY KEY,
+
+    username VARCHAR(50) NOT NULL UNIQUE,
+
+    password_hash TEXT NOT NULL,
+
+    email VARCHAR(100) NOT NULL UNIQUE,
+
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE books
+(
+    id SERIAL PRIMARY KEY,
+
+    title VARCHAR(150) NOT NULL,
+
+    author VARCHAR(100) NOT NULL,
+
+    publication_year INT,
+
+    owner_id INT NOT NULL,
+
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+
+    CONSTRAINT fk_books_owner
+        FOREIGN KEY(owner_id)
+        REFERENCES users(id)
+        ON DELETE CASCADE
+);

+ 13 - 0
lab9/LibraryManagmentSystem/dotnet-tools.json

@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "isRoot": true,
+  "tools": {
+    "csharpier": {
+      "version": "1.2.6",
+      "commands": [
+        "csharpier"
+      ],
+      "rollForward": false
+    }
+  }
+}

+ 125 - 0
lab9/uml.plantuml

@@ -0,0 +1,125 @@
+@startuml
+
+top to bottom direction
+skinparam packageStyle rectangle
+skinparam linetype ortho
+
+package "Database" {
+
+    class DbConfig {
+        +CONNECTION_STRING : string
+    }
+
+    class DatabaseManager {
+        +CreateConnection() : NpgsqlConnection
+    }
+}
+
+package "Models" {
+
+    class User {
+        +Id : int
+        +Username : string
+        +PasswordHash : string
+        +Email : string
+        +CreatedAt : DateTime
+    }
+
+    class Book {
+        +Id : int
+        +Title : string
+        +Author : string
+        +PublicationYear : int
+        +OwnerId : int
+        +CreatedAt : DateTime
+    }
+}
+
+package "Repositories" {
+
+    interface IUserRepository {
+        +Create(user : User) : int
+        +GetAll() : IEnumerable<User>
+        +GetById(id : int) : User
+        +Update(user : User) : bool
+        +Delete(id : int) : bool
+    }
+
+    interface IBookRepository {
+        +Create(book : Book) : int
+        +GetAll() : IEnumerable<Book>
+        +GetById(id : int) : Book
+        +Update(book : Book) : bool
+        +Delete(id : int) : bool
+    }
+
+    class UserRepository {
+        -_databaseManager : DatabaseManager
+
+        +Create(user : User) : int
+        +GetAll() : IEnumerable<User>
+        +GetById(id : int) : User
+        +Update(user : User) : bool
+        +Delete(id : int) : bool
+    }
+
+    class BookRepository {
+        -_databaseManager : DatabaseManager
+
+        +Create(book : Book) : int
+        +GetAll() : IEnumerable<Book>
+        +GetById(id : int) : Book
+        +Update(book : Book) : bool
+        +Delete(id : int) : bool
+    }
+}
+
+package "Utils" {
+
+    class PasswordHasher {
+        +HashPassword(password : string) : string
+        +VerifyPassword(password : string, hash : string) : bool
+    }
+
+    class LoggerConfigurator {
+        +Configure()
+    }
+}
+
+package "Tests" {
+
+    class DatabaseTests {
+        +Database_Should_Connect_Successfully()
+    }
+
+    class UserRepositoryTests {
+        +Create_Should_Add_User()
+        +GetAll_Should_Return_Users()
+        +Update_Should_Modify_User()
+        +Delete_Should_Remove_User()
+    }
+
+    class TestHelper {
+        +CleanupUsers()
+    }
+}
+
+UserRepository --> DatabaseManager
+BookRepository --> DatabaseManager
+
+UserRepository ..|> IUserRepository
+BookRepository ..|> IBookRepository
+
+Book --> User : owner_id
+
+UserRepository --> User
+BookRepository --> Book
+
+UserRepositoryTests --> IUserRepository
+DatabaseTests --> DatabaseManager
+
+TestHelper --> DatabaseManager
+
+DbConfig <-- DatabaseManager
+
+@enduml

BIN
lab9/uml.png


BIN
others/information_system.docx


BIN
others/lab1(1).docx


+ 533 - 0
others/overview.md

@@ -0,0 +1,533 @@
+=== backend/overview.md ===
+📦 backend/Overview
+📂 Назначение backend
+Backend реализует REST API для системы управления задачами (TaskManager).
+Система покрывает:
+
+
+управление пользователями и ролями (RBAC)
+
+
+управление задачами (CRUD + статусы + история)
+
+
+комментарии
+
+
+события (календарь)
+
+
+отчёты и аналитика
+
+
+аудит действий пользователей
+
+
+
+🧱 Общая архитектура
+Архитектурный стиль
+Проект реализует упрощённую Clean Architecture:
+Controllers (Presentation)        ↓Services (Application / Business Logic)        ↓Data (EF Core / Infrastructure)        ↓Database (PostgreSQL)
+Дополнительно:
+Models (Domain)DTOs (Contracts)Extensions (Mapping Layer)
+
+🔄 End-to-End Flow
+Пример: создание задачи
+Client (frontend)   ↓ HTTP POST /api/tasksController (TasksController)   ↓TaskService.CreateAsync()   ↓AppDbContext (EF Core)   ↓PostgreSQLTaskService   ↓AuditService.LogAsync()TaskService   ↓MappingExtensions.ToDto()Controller   ↓HTTP 201 Created (TaskDto)
+
+⚙️ Конфигурация приложения
+📄 Program.cs
+Главная точка входа приложения.
+
+1. Подключение базы данных
+builder.Services.AddDbContext<AppDbContext>(opt =>    opt.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
+
+
+используется PostgreSQL
+
+
+ORM: Entity Framework Core
+
+
+
+2. Dependency Injection
+builder.Services.AddScoped<IUserService, UserService>();
+Регистрируются сервисы:
+
+
+IAuditService
+
+
+IAuthService
+
+
+IUserService
+
+
+ITaskService
+
+
+IReportService
+
+
+IEventService
+
+
+👉 lifetime: Scoped (на запрос)
+
+3. JWT Authentication
+builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+Параметры:
+
+
+Issuer
+
+
+Audience
+
+
+SigningKey
+
+
+👉 используется Symmetric Key (HMAC)
+
+4. Authorization
+builder.Services.AddAuthorization();
+Используется:
+
+
+[Authorize]
+
+
+[Authorize(Roles = "...")]
+
+
+
+5. Swagger (OpenAPI)
+builder.Services.AddSwaggerGen(...)
+Особенности:
+
+
+поддержка JWT
+
+
+UI доступен по /swagger
+
+
+
+6. CORS
+.WithOrigins(    "http://localhost:3000",    "http://localhost:5173",    "http://frontend")
+👉 разрешён доступ frontend-приложениям
+
+⚠️ Критическое поведение при старте
+❗ Полная пересоздача БД
+await db.Database.EnsureDeletedAsync();await db.Database.EnsureCreatedAsync();
+
+Последствия:
+
+
+❌ ВСЕ данные удаляются при каждом запуске
+
+
+❌ не используется миграции
+
+
+❌ невозможно использовать в production
+
+
+
+Затем:
+await DbSeeder.SeedAsync(db);
+👉 база заполняется начальными данными
+
+📌 Вывод:
+Это:
+
+
+подходит для разработки / демо
+
+
+НЕ подходит для production
+
+
+
+🐳 Docker
+Dockerfile
+Многоступенчатая сборка:
+
+
+build stage
+
+
+restore
+
+
+build
+
+
+publish
+
+
+
+
+runtime stage
+
+
+ASP.NET runtime
+
+
+запуск приложения
+
+
+
+
+ENTRYPOINT ["dotnet", "TaskManager.API.dll"]
+
+Особенности:
+
+
+порт: 8080
+
+
+production-ready image
+
+
+минимальный размер (без SDK)
+
+
+
+⚙️ Конфигурация (appsettings.json)
+
+1. Connection String
+"Host=localhost;Port=5432;Database=taskmanager"
+
+
+PostgreSQL
+
+
+user: postgres
+
+
+
+2. JWT
+"Key": "TaskManager_SuperSecret_Key..."
+👉 используется для подписи токенов
+
+3. Logging
+"Microsoft.EntityFrameworkCore.Database.Command": "Warning"
+👉 SQL-запросы не логируются подробно
+
+📦 Зависимости (.csproj)
+
+Основные библиотеки:
+EF Core
+
+
+Microsoft.EntityFrameworkCore
+
+
+Npgsql.EntityFrameworkCore.PostgreSQL
+
+
+
+Auth
+
+
+Microsoft.AspNetCore.Authentication.JwtBearer
+
+
+System.IdentityModel.Tokens.Jwt
+
+
+
+Security
+
+
+BCrypt.Net-Next
+
+
+👉 используется для хеширования паролей
+
+Swagger
+
+
+Swashbuckle.AspNetCore
+
+
+
+🔗 Связи между слоями
+Controllers   ↓Services   ↓DbContext   ↓DatabaseServices   ↓MappingExtensions   ↓DTOs
+
+💡 Ключевые архитектурные особенности
+
+1. Без Repository слоя
+Service → DbContext
+👉 упрощённая архитектура
+
+2. Mapping через Extension методы
+Entity → ToDto()
+👉 альтернатива AutoMapper
+
+3. Явный AuditService
+Service → AuditService
+👉 аудит встроен в бизнес-логику
+
+4. Role-based security
+
+
+JWT + Roles
+
+
+проверка:
+
+
+на уровне контроллеров
+
+
+внутри сервисов
+
+
+
+
+
+5. DTO-first API
+
+
+чёткое разделение:
+
+
+Request
+
+
+Response
+
+
+Brief
+
+
+Detail
+
+
+
+
+
+⚠️ Архитектурные проблемы
+
+1. ❗ Пересоздание БД при старте
+EnsureDeleted + EnsureCreated
+👉 критично для production
+
+2. Нет миграций
+👉 нельзя управлять схемой БД
+
+3. Нет Repository слоя
+👉 сильная связность сервисов с EF
+
+4. Бизнес-логика частично в Mapping
+IsOverdueStatusName comparisons
+
+5. Строковые статусы
+"Выполнена"
+👉 риск ошибок
+
+6. Нет централизованного error handling
+👉 отсутствует middleware
+
+7. Нет кэширования
+👉 отчёты пересчитываются каждый раз
+
+📌 Итог
+Backend представляет собой:
+
+
+хорошо структурированную систему
+
+
+с понятной логикой
+
+
+с упрощённой архитектурой
+
+
+Подходит для:
+
+
+MVP
+
+
+корпоративного внутреннего инструмента
+
+
+Требует доработки для:
+
+
+production
+
+
+масштабирования
+
+
+
+
+=== PROJECT_STRUCTURE.md ===
+📦 PROJECT STRUCTURE
+📁 Полное дерево проекта (backend)
+backend/│├── Controllers/│   ├── AuthController.cs│   ├── EventsController.cs│   ├── ReportsController.cs│   ├── TasksController.cs│   └── UsersController.cs│├── Models/│   ├── User.cs│   ├── Role.cs│   ├── Department.cs│   ├── TaskItem.cs│   ├── Status.cs│   ├── Comment.cs│   ├── TaskHistory.cs│   ├── Event.cs│   ├── Report.cs│   └── AuditLog.cs│├── DTOs/│   └── (все DTO-контракты)│├── Services/│   ├── AuthService.cs│   ├── UserService.cs│   ├── TaskService.cs│   ├── EventService.cs│   ├── ReportService.cs│   └── AuditService.cs│├── Data/│   ├── AppDbContext.cs│   └── DbSeeder.cs│├── Extensions/│   └── MappingExtensions.cs│├── Program.cs├── appsettings.json├── Dockerfile└── TaskManager.API.csproj
+
+📂 Уровни архитектуры
+
+1. Domain Layer (ядро)
+Models/
+Содержит:
+
+
+сущности системы
+
+
+связи между ними
+
+
+
+2. Contract Layer
+DTOs/
+Содержит:
+
+
+входные и выходные модели API
+
+
+
+3. Application Layer
+Services/
+Содержит:
+
+
+бизнес-логику
+
+
+use-case'ы
+
+
+
+4. Mapping Layer
+Extensions/
+Содержит:
+
+
+преобразование Entity → DTO
+
+
+
+5. Infrastructure Layer
+Data/
+Содержит:
+
+
+DbContext
+
+
+доступ к БД
+
+
+seed
+
+
+
+6. Presentation Layer
+Controllers/
+Содержит:
+
+
+API endpoints
+
+
+
+7. Composition Root
+Program.cs
+Содержит:
+
+
+DI
+
+
+конфигурацию
+
+
+middleware
+
+
+
+🔄 Полный поток данных
+[ Client (Frontend) ]        ↓ HTTP[ Controllers ]        ↓[ Services ]        ↓[ DbContext (EF Core) ]        ↓[ PostgreSQL ]        ↑[ Services ]        ↓[ MappingExtensions ]        ↓[ DTO ]        ↓[ Controllers ]        ↓ JSON[ Client ]
+
+📌 Как всё связано
+
+1. Controllers
+
+
+принимают HTTP
+
+
+вызывают Services
+
+
+
+2. Services
+
+
+реализуют бизнес-логику
+
+
+работают с DbContext
+
+
+вызывают AuditService
+
+
+используют MappingExtensions
+
+
+
+3. DbContext
+
+
+управляет БД
+
+
+хранит DbSet
+
+
+
+4. MappingExtensions
+
+
+преобразуют Entities → DTO
+
+
+
+5. DTOs
+
+
+формируют API ответы
+
+
+
+📌 Ключевые особенности проекта
+
+
+EF Core без Repository
+
+
+ручной mapping через extension
+
+
+JWT авторизация
+
+
+RBAC (roles)
+
+
+аудит действий
+
+
+аналитика (reports)

BIN
others/schemas.docx


BIN
others/План-график (ИС).docx


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác