{ "schema_version": 1, "diagram_type": "sequence", "meta": { "title": "낙상 1건 — 감지에서 통보까지", "output": "move-detect-fall-sequence.html", "quality_profile": "showcase", "column_fit": "spread", "views": [ { "id": "on-site", "label": "현장에서 끝나는 3초", "focus": [ "cam", "edge", "beacon" ], "note": "확정부터 점등까지 서버를 거치지 않는다. 회선이 끊겨도 여기까지는 동작한다." }, { "id": "what-leaves", "label": "밖으로 나가는 것", "focus": [ "edge", "api", "db" ], "note": "영상이 아니라 얼굴 블러된 3프레임. 블러는 전송 전, 노드에서." }, { "id": "notify-lag", "label": "통보까지의 실제 지연", "focus": [ "cron", "db", "staff" ], "note": "경광등은 즉시, 메일은 크론 주기만큼 늦다. 그 간격이 이 그림의 요점이다." } ], "viewBox": [ 1060, 560 ] }, "participants": [ { "id": "cam", "type": "external", "label": "카메라", "sublabel": "12fps" }, { "id": "edge", "type": "backend", "label": "엣지 노드", "sublabel": "Pi 5 + Hailo-8" }, { "id": "beacon", "type": "external", "label": "경광등", "sublabel": "GPIO" }, { "id": "api", "type": "security", "label": "수집 API", "sublabel": "HMAC 검증" }, { "id": "db", "type": "database", "label": "MySQL", "sublabel": "move_events" }, { "id": "cron", "type": "backend", "label": "1분 크론", "sublabel": "dispatch_alerts" }, { "id": "staff", "type": "external", "label": "담당자", "sublabel": "메일 · 웹훅" } ], "segments": [ { "from": 152, "to": 190, "label": "감지 — 자세 3초" }, { "from": 198, "to": 320, "label": "현장 대응 · 기록" }, { "from": 330, "to": 366, "label": "미동 없음 13초" }, { "from": 374, "to": 466, "label": "통보 — 크론 주기 지연" } ], "messages": [ { "id": "frames", "from": "cam", "to": "edge", "y": 168, "label": "프레임 · 12fps", "variant": "default", "note": "0.0초 쓰러짐 → 1초 위험 자세 → 3초 확정" }, { "id": "gpio", "from": "edge", "to": "beacon", "y": 206, "label": "넘어짐 확정(3초) → GPIO 점등", "variant": "emphasis", "note": "3.0초 · 서버도 인터넷도 거치지 않는다" }, { "id": "post", "from": "edge", "to": "api", "y": 244, "label": "HMAC POST · 3프레임", "variant": "security", "note": "얼굴 블러는 전송 전, 노드에서" }, { "id": "insert", "from": "api", "to": "db", "y": 276, "label": "INSERT", "variant": "default" }, { "id": "accepted", "from": "api", "to": "edge", "y": 306, "label": "202 Accepted", "variant": "return" }, { "id": "nomotion", "from": "edge", "to": "api", "y": 344, "label": "미동 없음 · 10초", "variant": "emphasis", "note": "13.0초 — 최상위 위급" }, { "id": "poll", "from": "cron", "to": "db", "y": 384, "label": "통보 대상 조회 · 최대 60초 뒤", "variant": "default", "note": "최대 60초 뒤 — 크론이 1분마다 돈다" }, { "id": "send", "from": "cron", "to": "staff", "y": 418, "label": "메일 · 웹훅 (링크만)", "variant": "emphasis" }, { "id": "escalate", "from": "cron", "to": "db", "y": 452, "label": "5분 미확인 → 상위 확대", "variant": "dashed" } ], "activations": [ { "participant": "edge", "from": 196, "to": 352, "type": "backend" }, { "participant": "beacon", "from": 201, "to": 232, "type": "external" }, { "participant": "api", "from": 239, "to": 312, "type": "security" }, { "participant": "db", "from": 271, "to": 300, "type": "database" }, { "participant": "cron", "from": 379, "to": 458, "type": "backend" }, { "participant": "staff", "from": 413, "to": 442, "type": "external" } ], "cards": [ { "dot": "cyan", "title": "현장에서 끝나는 3초", "items": [ "자세가 3초 지속돼야 확정한다", "확정 즉시 GPIO 점등 — 서버 불필요", "서버가 죽어도 여기까지는 동작" ] }, { "dot": "rose", "title": "밖으로 나가는 것", "items": [ "영상이 아니라 3프레임", "얼굴 블러는 전송 전, 노드에서", "블러 전 이미지는 서버에 없다" ] }, { "dot": "amber", "title": "두 지연은 다르다", "items": [ "경광등은 즉시", "메일은 크론 주기만큼 늦다", "\"1분 통보\"는 대기를 포함한 값" ] } ] }