diff --git a/ivideon/puml/9159.puml b/ivideon/puml/9159.puml new file mode 100644 index 0000000..f7c22f4 --- /dev/null +++ b/ivideon/puml/9159.puml @@ -0,0 +1,75 @@ +@startuml +package "api_concept.entities/persmission_grant" { + class PermissionGrantInterface { + + object_type : str + } +} + +note left of PermissionGrantInterface::object_type + Тип объекта выдаваемого доступа +endnote + +package "api_concept.entities/maas" { + class MaasOrganizationInterface { + } +} + +package "maas/api/impl/organization" { + class MaasOrganization { + } +} + +package "api_concept.backend/impl/permission_grant" { + class PermissionGrant { + + find() + } + + class ALL_OBJECT_TYPES { + + items : list = ['camera', 'cashbox', 'face_gallery', 'folder'] + } +} + +package "utils/folder.tree" { + class NodeType { + + camera : Camera + + cashbox : Cashbox + + face_gallery : FaceGallery + } +} + +package "utils/folder.node"{ + class Node + class Camera + class Cashbox + class FaceGallery +} + +note left of Node +Базовый класс для концевых узлов дерева +(объекты, содержащиеся в Folders) +end note + +note right of PermissionGrant +Метод поиска грантов (find) +end note + +note top of ALL_OBJECT_TYPES +Перечисление объектов, +которые можно искать +end note + +Node <|-- Camera +Node <|-- Cashbox +Node <|-- FaceGallery + +ALL_OBJECT_TYPES .. NodeType + +NodeType::camera .. Camera +NodeType::cashbox .. Cashbox +NodeType::face_gallery .. FaceGallery + +PermissionGrantInterface <|-- PermissionGrant + +MaasOrganizationInterface <|-- MaasOrganization + +@enduml \ No newline at end of file diff --git a/ivideon/puml/MaaS/1.wsd b/ivideon/puml/MaaS/1.wsd new file mode 100644 index 0000000..c2244f7 --- /dev/null +++ b/ivideon/puml/MaaS/1.wsd @@ -0,0 +1,16 @@ +@startuml +title ER-диаграмма MaaS (упрощённо) + +hide circle +skinparam linetype ortho + +entity "ORGANIZATION" as Organization +entity "FACILITY" as Facility +entity "CHECKLIST" as Checklist +entity "REVIEW_TASK" as ReviewTask + +Organization ||--o{ Facility : "1:N" +Organization ||--o{ Checklist : "1:N" +Checklist }o--o{ Facility : "sources (список ID)" +Checklist ||--o{ ReviewTask : "генерируется планировщиком" +@enduml diff --git a/ivideon/puml/MaaS/2.wsd b/ivideon/puml/MaaS/2.wsd new file mode 100644 index 0000000..24d6bbd --- /dev/null +++ b/ivideon/puml/MaaS/2.wsd @@ -0,0 +1,17 @@ +@startuml +title Планировщик: генерация задач (activity) + +start +:cron/loop\nscheduler/__main__.py; +:task_generator.run(); +:Загрузка чек-листов\nс расписанием и источниками; +:Для каждого источника (facility)\nвзять last_mark; +:calc_allowed_interval(schedule_mark,\nnow, schedule, tz); +if ("Есть интервал\nи он завершился?") then (Да) + :Создать REVIEW_TASK\n(snapshot checklist + facility); + :Обновить метку в чек-листе\n_marks[facility_id] = now; +else (Нет) + :Пропустить; +endif +stop +@enduml diff --git a/ivideon/puml/MaaS/3.wsd b/ivideon/puml/MaaS/3.wsd new file mode 100644 index 0000000..f54bea3 --- /dev/null +++ b/ivideon/puml/MaaS/3.wsd @@ -0,0 +1,15 @@ +@startuml +title Системные события → обновления коллекций (sequence) + +actor "Система" as Sys +participant "api/system_events" as API +database "MongoDB" as DB + +Sys -> API : camera.deleted +API -> DB : update_many(checklists/facilities,\n $pull: {camera_id: }) +API <-- DB : result + +Sys -> API : permission_grant.revoked +API -> DB : update_many(checklists/facilities,\n $pull: {camera_id: }) +API <-- DB : result +@enduml diff --git a/ivideon/puml/MaaS/4.wsd b/ivideon/puml/MaaS/4.wsd new file mode 100644 index 0000000..7a00e0d --- /dev/null +++ b/ivideon/puml/MaaS/4.wsd @@ -0,0 +1,114 @@ +@startuml +title MaaS — сущности и поля (MongoDB документы) + +hide circle +skinparam linetype ortho + +entity "maas.organizations\n(MaasOrganization)" as Organization { + == Идентификаторы == + _id: string <<= owner_id>> + owner_id: string + + == Данные == + name: string + violations: string[] (опц.) + + == Служебные поля == + created_at: int <> + updated_at: int (опц.) + deleted: bool + deleted_at: int (опц.) +} + +entity "maas.facilities\n(MaasFacility)" as Facility { + _id: string + organization_id: string + owner_id: string + + name: string + timezone: string <> + camera_ids: string[] + + created_at: int <> + updated_at: int (опц.) + deleted: bool + deleted_at: int (опц.) +} + +entity "maas.checklists\n(MaasChecklist)" as Checklist { + _id: string + organization_id: string + owner_id: string + + name: string + type: enum('process','state') + priority: enum('medium','high') (опц.) + description: string (опц.) + enabled: bool + include_violations: bool + + schedule: Schedule + sources: Source[] + questions: Question[] + + _marks: map < last_gen_ts>> (опц.) + + created_at: int <> + updated_at: int (опц.) + deleted: bool + deleted_at: int (опц.) +} + +entity "maas.review_tasks\n(MaasReviewTask)" as ReviewTask { + _id: string + organization_id: string + owner_id: string + + checklist_id: string + sources: Source <<ровно один Source>> + type: enum('process','state') + status: enum('open','in_progress','closed'?)* // в коде используются 'open','in_progress' + assignee_id: string <<'NOT_SET' или user_id>> + + interval: int[2] <<[start_ts,end_ts]>> + questions: Question[] <> + checklist: dict <> + facility: dict <> + + violations: any[] <<пока пустой список>> + created_at: int <> + updated_at: int (опц.) + deleted: bool +} + +' --- Вложенные типы --- +entity "Schedule" as Schedule { + intervals: Interval[] +} +entity "Interval" as Interval { + start_weekday: string <<'Monday'..'Sunday'>> + start_time: string <<'HH:mm:ss'>> + end_weekday: string + end_time: string +} + +entity "Source" as Source { + facility: string <> + cameras: string[] <> +} + +entity "Question" as Question { + description_text: string + instruction_text: string (опц.) + description_image_url: string (опц.) + // во время/после ревью могут добавляться: + // comment: string (опц.) + // proof_image_url: string (опц.) +} + +Organization ||--o{ Facility : "1:N" +Organization ||--o{ Checklist : "1:N" +Checklist }o--o{ Facility : "M:N через sources" +Checklist ||--o{ ReviewTask : "по расписанию" +Facility ||--o{ ReviewTask : "через sources" +@enduml diff --git a/ivideon/puml/MaaS/5.wsd b/ivideon/puml/MaaS/5.wsd new file mode 100644 index 0000000..7b86d0e --- /dev/null +++ b/ivideon/puml/MaaS/5.wsd @@ -0,0 +1,75 @@ +@startuml +title MaaS — end-to-end (process-checklist). Пример с MSK 2024-12-04 + +autonumber + +actor "Владелец" as Owner +actor "Оператор" as Operator +participant "API.Organization" as OrgAPI +participant "API.Facility" as FacAPI +participant "API.Checklist" as ChkAPI +participant "API.ReviewTask" as RTAPI +participant "Validators/Schedule" as Val +participant "Boilerplates/Images" as Img +participant "Scheduler (task_generator)" as Sched +participant "IntervalCalculator" as Calc +database "MongoDB (maas.*)" as DB + +== Создание организации == +Owner -> OrgAPI : create(name, owner_id="user_123") +OrgAPI -> DB : insert into maas.organizations\n{_id=owner_id, name, created_at, deleted=false} +DB --> OrgAPI : ok + +== Создание заведения == +Owner -> FacAPI : create(name="Shop #1", tz="Europe/Moscow", camera_ids=["cam_a"]) +FacAPI -> Val : cameras_have_rights(["cam_a"]) +Val --> FacAPI : ok +FacAPI -> DB : insert into maas.facilities\n{_id="fac_001", organization_id, tz, camera_ids} +DB --> FacAPI : ok + +== Создание чек-листа (type=process) == +Owner -> ChkAPI : create(name, type="process", enabled=true,\nschedule, sources=[{facility:"fac_001", cameras:["cam_a"]}], questions) +ChkAPI -> Val : validate {schedule, sources, enums} +Val --> ChkAPI : ok +ChkAPI -> Img : normalize/upload description_image(s) +Img --> ChkAPI : description_image_url(s) +ChkAPI -> DB : insert into maas.checklists\n{_id="chk_001", schedule, sources, questions,\n_marks:{}, created_at, deleted=false} +DB --> ChkAPI : ok + +== Генерация задачи планировщиком == +note over Sched + now = 2024-12-05 06:06:06 MSK + mark = _marks["fac_001"] или created_at + schedule: ср/пт 15:00–16:59:59 +end note +Sched -> DB : aggregate активные чек-листы + lookup facilities +Sched -> Calc : calc_allowed_interval(mark, now, schedule, tz="Europe/Moscow") +note right of Calc + Возврат: окно, которое завершилось + [2024-12-04 15:00:00, 16:59:59] MSK +end note +Calc --> Sched : interval=[start_ts, end_ts] + +alt найдён завершившийся интервал + Sched -> DB : insert into maas.review_tasks\n{organization_id, owner_id, checklist_id="chk_001",\n sources:{facility:"fac_001", cameras:["cam_a"]},\n type="process", status="open", assignee_id="NOT_SET",\n interval:[start_ts, end_ts], questions(snapshot),\n checklist(snapshot), facility(snapshot), created_at} + DB --> Sched : ok + Sched -> DB : update maas.checklists\n{$set: {"_marks.fac_001": now_ts}, updated_at} + DB --> Sched : ok +else интервал не найден + Sched -> Sched: пропуск генерации +end + +== Назначение и выполнение == +Operator -> RTAPI : take_next() +RTAPI -> DB : findOneAndUpdate в maas.review_tasks\n{status:"open"} -> {status:"in_progress", assignee_id=Operator} +DB --> RTAPI : возвращает задачу +RTAPI --> Operator: детали задачи (interval, questions, sources, ...) + +== Отметка результата вопроса == +Operator -> RTAPI : update_question_result(task_id, qidx=0,\n comment="OK", proof_image=...) +RTAPI -> Img : upload proof_image\n→ proof_image_url +Img --> RTAPI : url +RTAPI -> DB : update maas.review_tasks\n{questions[0].comment, questions[0].proof_image_url,\n updated_at} +DB --> RTAPI : ok + +@enduml