MMCL/SOURCE/docs/Architecture.svg
2026-09-04 11:27:31 +09:00

168 lines
21 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1264.0090833333334 999.5" width="1264.0090833333334" height="999.5" style="--bg:#1F1F1F;--fg:#CCCCCC;--line:#CCCCCC;--accent:#0078D4;--muted:#CCCCCCCC;--surface:#181818;--border:#CCCCCC;background:var(--bg)">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&amp;display=swap');
text { font-family: 'Inter', system-ui, sans-serif; }
svg {
/* Derived from --bg and --fg (overridable via --line, --accent, etc.) */
--_text: var(--fg);
--_text-sec: var(--muted, color-mix(in srgb, var(--fg) 60%, var(--bg)));
--_text-muted: var(--muted, color-mix(in srgb, var(--fg) 40%, var(--bg)));
--_text-faint: color-mix(in srgb, var(--fg) 25%, var(--bg));
--_line: var(--line, color-mix(in srgb, var(--fg) 50%, var(--bg)));
--_arrow: var(--accent, color-mix(in srgb, var(--fg) 85%, var(--bg)));
--_node-fill: var(--surface, color-mix(in srgb, var(--fg) 3%, var(--bg)));
--_node-stroke: var(--border, color-mix(in srgb, var(--fg) 20%, var(--bg)));
--_group-fill: var(--bg);
--_group-hdr: color-mix(in srgb, var(--fg) 5%, var(--bg));
--_inner-stroke: color-mix(in srgb, var(--fg) 12%, var(--bg));
--_key-badge: color-mix(in srgb, var(--fg) 10%, var(--bg));
}
</style>
<defs>
<marker id="arrowhead" markerWidth="8" markerHeight="5" refX="7" refY="2.5" orient="auto">
<polygon points="0 0, 8 2.5, 0 5" fill="var(--_arrow)" stroke="var(--_arrow)" stroke-width="0.75" stroke-linejoin="round" />
</marker>
<marker id="arrowhead-start" markerWidth="8" markerHeight="5" refX="1" refY="2.5" orient="auto-start-reverse">
<polygon points="8 0, 0 2.5, 8 5" fill="var(--_arrow)" stroke="var(--_arrow)" stroke-width="0.75" stroke-linejoin="round" />
</marker>
</defs>
<g class="subgraph" data-id="Equipment_Layer" data-label="Equipment Layer">
<rect x="908.1970833333334" y="58" width="315.812" height="181.8" rx="0" ry="0" fill="var(--_group-fill)" stroke="var(--_node-stroke)" stroke-width="1" />
<rect x="908.1970833333334" y="58" width="315.812" height="28" rx="0" ry="0" fill="var(--_group-hdr)" stroke="var(--_node-stroke)" stroke-width="1" />
<text x="920.1970833333334" y="72" font-size="12" font-weight="600" fill="var(--_text-sec)" dy="4.199999999999999">Equipment Layer</text>
</g>
<g class="subgraph" data-id="Messaging__Agents_Layer" data-label="Messaging &amp; Agents Layer">
<rect x="771.1865833333334" y="368.1" width="307.28" height="352.20000000000005" rx="0" ry="0" fill="var(--_group-fill)" stroke="var(--_node-stroke)" stroke-width="1" />
<rect x="771.1865833333334" y="368.1" width="307.28" height="28" rx="0" ry="0" fill="var(--_group-hdr)" stroke="var(--_node-stroke)" stroke-width="1" />
<text x="783.1865833333334" y="382.1" font-size="12" font-weight="600" fill="var(--_text-sec)" dy="4.199999999999999">Messaging &amp; Agents Layer</text>
</g>
<g class="subgraph" data-id="Database_Layer_MariaDB" data-label="Database Layer (MariaDB)">
<rect x="460.8940833333334" y="848.6" width="546.559" height="110.9" rx="0" ry="0" fill="var(--_group-fill)" stroke="var(--_node-stroke)" stroke-width="1" />
<rect x="460.8940833333334" y="848.6" width="546.559" height="28" rx="0" ry="0" fill="var(--_group-hdr)" stroke="var(--_node-stroke)" stroke-width="1" />
<text x="472.8940833333334" y="862.6" font-size="12" font-weight="600" fill="var(--_text-sec)" dy="4.199999999999999">Database Layer (MariaDB)</text>
</g>
<g class="subgraph" data-id="Backend_API_PythonFastAPI" data-label="Backend API (Python/FastAPI)">
<rect x="259.15041666666673" y="58" width="200.65775000000002" height="181.8" rx="0" ry="0" fill="var(--_group-fill)" stroke="var(--_node-stroke)" stroke-width="1" />
<rect x="259.15041666666673" y="58" width="200.65775000000002" height="28" rx="0" ry="0" fill="var(--_group-hdr)" stroke="var(--_node-stroke)" stroke-width="1" />
<text x="271.15041666666673" y="72" font-size="12" font-weight="600" fill="var(--_text-sec)" dy="4.199999999999999">Backend API (Python/FastAPI)</text>
</g>
<g class="subgraph" data-id="Frontend_Web" data-label="Frontend Web">
<rect x="128.218" y="368.1" width="202.884" height="96.9" rx="0" ry="0" fill="var(--_group-fill)" stroke="var(--_node-stroke)" stroke-width="1" />
<rect x="128.218" y="368.1" width="202.884" height="28" rx="0" ry="0" fill="var(--_group-hdr)" stroke="var(--_node-stroke)" stroke-width="1" />
<text x="140.218" y="382.1" font-size="12" font-weight="600" fill="var(--_text-sec)" dy="4.199999999999999">Frontend Web</text>
</g>
<polyline class="edge" data-from="NILM_Equip" data-to="MQTT_Broker" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="1. MQTT Publish" points="992.9665833333333,223.8 992.9665833333333,412.1" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="NILM_Agent" data-to="DB_Sensor" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="3. 실시간 데이터 Update &amp; Log Insert" points="974.6129166666667,704.3000000000001 974.6129166666667,762.3000000000001 1047.574,762.3000000000001 1047.574,818.6 785.5774166666667,818.6 785.5774166666667,892.6" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="NILM_Agent" data-to="DB_Log" data-style="dotted" data-arrow-start="false" data-arrow-end="true" points="1011.32025,704.3000000000001 1011.32025,750.3000000000001 1161.9918333333333,750.3000000000001 1161.9918333333333,830.6 911.9390833333333,830.6 911.9390833333334,892.6" fill="none" stroke="var(--_line)" stroke-width="1" stroke-dasharray="4 4" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="UI" data-to="API_Server" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="4. 자연어 질의/명령" points="229.65999999999997,449 229.65999999999997,483 94,483 94,40 376.5206666666667,40 376.52066666666667,102" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="API_Server" data-to="DB_Sensor" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="5. 제어 '목표' 상태 Update" points="389.97816666666677,138.9 389.97816666666677,150.9 409.9774166666667,150.9 409.9774166666668,281.8 378.3020000000001,281.8 378.3020000000001,830.6 710.1867500000001,830.6 710.1867500000001,892.6" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="LED_Agent" data-to="DB_Sensor" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="6. 목표 상태 감지 (Polling)" points="848.5460833333334,704.3000000000001 848.5460833333334,762.3000000000001 703.7520000000001,762.3000000000001 703.7520000000001,806.6 747.8820833333334,806.6 747.8820833333334,892.6" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="LED_Agent" data-to="Warning_Light" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="7. 물리적 LED 제어" points="817.8663333333334,704.3000000000001 817.8663333333334,750.3000000000001 751.1865416666667,750.3000000000001 751.1865416666667,40 1168.58475,40 1168.58475,186.9" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="LED_Agent" data-to="DB_Sensor" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="8. 제어 완료 '현재' 상태 Update" points="879.2258333333334,704.3000000000001 879.2258333333334,762.3000000000001 862.642,762.3000000000001 862.642,806.6 766.72975,806.6 766.7297500000001,892.6" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="API_Server" data-to="DB_Sensor" data-style="dotted" data-arrow-start="false" data-arrow-end="true" data-label="9. Agent 완료 확인 (비동기 대기)" points="416.89316666666673,138.9 416.89316666666673,150.9 429.9349166666667,150.9 429.93491666666677,281.8 541.192,281.8 541.192,818.6 729.0344166666666,818.6 729.0344166666669,892.6" fill="none" stroke="var(--_line)" stroke-width="1" stroke-dasharray="4 4" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="API_Server" data-to="UI" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="10. '적용 완료' 자연어 응답" points="336.1481666666667,138.9 336.1481666666667,150.9 275.15041666666673,150.9 275.15041666666673,281.8 229.66000000000005,281.8 229.66000000000003,412.1" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="MACH" data-to="NILM_Equip" data-style="solid" data-arrow-start="false" data-arrow-end="false" points="1010.45575,138.9 1010.45575,162.9 992.9665833333333,162.9 992.9665833333333,186.9" fill="none" stroke="var(--_line)" stroke-width="1" />
<polyline class="edge" data-from="MACH" data-to="Warning_Light" data-style="solid" data-arrow-start="false" data-arrow-end="false" points="1010.45575,138.9 1010.45575,162.9 1148.8725833333333,162.9 1148.8725833333333,186.9" fill="none" stroke="var(--_line)" stroke-width="1" />
<polyline class="edge" data-from="MQTT_Broker" data-to="NILM_Agent" data-style="solid" data-arrow-start="false" data-arrow-end="true" data-label="2. Subscribe" points="992.9665833333333,551.1 992.9665833333333,667.4000000000001" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<polyline class="edge" data-from="API_Server" data-to="LLM" data-style="solid" data-arrow-start="true" data-arrow-end="true" points="363.06316666666675,138.9 363.06316666666675,150.9 343.0639166666667,150.9 343.0639166666667,186.9" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" marker-start="url(#arrowhead-start)" />
<g class="edge-label" data-from="NILM_Equip" data-to="MQTT_Broker" data-label="1. MQTT Publish">
<rect x="946.9665833333333" y="288.8" width="91.9" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="992.9165833333334" y="303.95" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">1. MQTT Publish</text>
</g>
<g class="edge-label" data-from="NILM_Agent" data-to="DB_Sensor" data-label="3. 실시간 데이터 Update &amp; Log Insert">
<rect x="950.5740000000002" y="769.3000000000001" width="193.474" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="1047.3110000000001" y="784.45" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">3. 실시간 데이터 Update &amp; Log Insert</text>
</g>
<g class="edge-label" data-from="UI" data-to="API_Server" data-label="4. 자연어 질의/명령">
<rect x="36.00000000000001" y="288.8" width="115.66000000000001" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="93.83000000000001" y="303.95" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">4. 자연어 질의/명령</text>
</g>
<g class="edge-label" data-from="API_Server" data-to="DB_Sensor" data-label="5. 제어 '목표' 상태 Update">
<rect x="306.802" y="288.8" width="142.39000000000001" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="377.997" y="303.95" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">5. 제어 &#39;목표&#39; 상태 Update</text>
</g>
<g class="edge-label" data-from="LED_Agent" data-to="DB_Sensor" data-label="6. 목표 상태 감지 (Polling)">
<rect x="632.2520000000002" y="769.3000000000001" width="142.39" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="703.4470000000001" y="784.45" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">6. 목표 상태 감지 (Polling)</text>
</g>
<g class="edge-label" data-from="LED_Agent" data-to="Warning_Light" data-label="7. 물리적 LED 제어">
<rect x="694.6865416666667" y="288.8" width="112.096" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="750.7345416666667" y="303.95" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">7. 물리적 LED 제어</text>
</g>
<g class="edge-label" data-from="LED_Agent" data-to="DB_Sensor" data-label="8. 제어 완료 '현재' 상태 Update">
<rect x="778.642" y="769.3000000000001" width="167.93200000000002" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="862.6080000000001" y="784.45" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">8. 제어 완료 &#39;현재&#39; 상태 Update</text>
</g>
<g class="edge-label" data-from="API_Server" data-to="DB_Sensor" data-label="9. Agent 완료 확인 (비동기 대기)">
<rect x="453.19199999999995" y="769.3000000000001" width="175.06000000000006" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="540.722" y="784.45" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">9. Agent 완료 확인 (비동기 대기)</text>
</g>
<g class="edge-label" data-from="API_Server" data-to="UI" data-label="10. '적용 완료' 자연어 응답">
<rect x="155.66000000000003" y="288.8" width="147.14200000000002" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="229.23100000000005" y="303.95" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">10. &#39;적용 완료&#39; 자연어 응답</text>
</g>
<g class="edge-label" data-from="MQTT_Broker" data-to="NILM_Agent" data-label="2. Subscribe">
<rect x="953.9665833333333" y="594.1" width="77.644" height="30.3" rx="2" ry="2" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="1" />
<text x="992.7885833333333" y="609.25" text-anchor="middle" font-size="11" font-weight="400" fill="var(--_text-sec)" dy="3.8499999999999996">2. Subscribe</text>
</g>
<g class="node" data-id="MACH" data-label="설비/기계" data-shape="rectangle">
<rect x="957.98825" y="102" width="104.93499999999999" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="1010.45575" y="120.45" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">설비/기계</text>
</g>
<g class="node" data-id="NILM_Equip" data-label="NILM 측정 센서" data-shape="rectangle">
<rect x="924.1970833333334" y="186.9" width="137.539" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="992.9665833333333" y="205.35000000000002" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">NILM 측정 센서</text>
</g>
<g class="node" data-id="Warning_Light" data-label="경광등 모듈" data-shape="rectangle">
<rect x="1089.7360833333332" y="186.9" width="118.273" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="1148.8725833333333" y="205.35000000000002" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">경광등 모듈</text>
</g>
<g class="node" data-id="MQTT_Broker" data-label="MQTT Broker" data-shape="circle">
<circle cx="992.9665833333333" cy="481.6" r="69.5" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="992.9665833333333" y="481.6" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">MQTT Broker</text>
</g>
<g class="node" data-id="NILM_Agent" data-label="NILM Agent" data-shape="rectangle">
<rect x="937.9055833333334" y="667.4000000000001" width="110.122" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="992.9665833333335" y="685.8500000000001" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">NILM Agent</text>
</g>
<g class="node" data-id="LED_Agent" data-label="경광등 Agent" data-shape="rectangle">
<rect x="787.1865833333334" y="667.4000000000001" width="122.71900000000001" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="848.5460833333334" y="685.8500000000001" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">경광등 Agent</text>
</g>
<g class="node" data-id="DB_Master" data-label="dev/pos/type/status_info" data-shape="cylinder">
<rect x="476.89408333333336" y="899.6" width="186.44499999999996" height="36.900000000000006" fill="var(--_node-fill)" stroke="none" />
<line x1="476.89408333333336" y1="899.6" x2="476.89408333333336" y2="936.5" stroke="var(--_node-stroke)" stroke-width="0.75" />
<line x1="663.3390833333333" y1="899.6" x2="663.3390833333333" y2="936.5" stroke="var(--_node-stroke)" stroke-width="0.75" />
<ellipse cx="570.1165833333333" cy="936.5" rx="93.22249999999998" ry="7" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<ellipse cx="570.1165833333333" cy="899.6" rx="93.22249999999998" ry="7" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="570.1165833333333" y="918.0500000000001" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">dev/pos/type/status_info</text>
</g>
<g class="node" data-id="DB_Sensor" data-label="sensor_info" data-shape="cylinder">
<rect x="691.3390833333333" y="899.6" width="113.086" height="36.900000000000006" fill="var(--_node-fill)" stroke="none" />
<line x1="691.3390833333333" y1="899.6" x2="691.3390833333333" y2="936.5" stroke="var(--_node-stroke)" stroke-width="0.75" />
<line x1="804.4250833333333" y1="899.6" x2="804.4250833333333" y2="936.5" stroke="var(--_node-stroke)" stroke-width="0.75" />
<ellipse cx="747.8820833333333" cy="936.5" rx="56.543" ry="7" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<ellipse cx="747.8820833333333" cy="899.6" rx="56.543" ry="7" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="747.8820833333333" y="918.0500000000001" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">sensor_info</text>
</g>
<g class="node" data-id="DB_Log" data-label="sensor_history_log" data-shape="cylinder">
<rect x="832.4250833333333" y="899.6" width="159.028" height="36.900000000000006" fill="var(--_node-fill)" stroke="none" />
<line x1="832.4250833333333" y1="899.6" x2="832.4250833333333" y2="936.5" stroke="var(--_node-stroke)" stroke-width="0.75" />
<line x1="991.4530833333333" y1="899.6" x2="991.4530833333333" y2="936.5" stroke="var(--_node-stroke)" stroke-width="0.75" />
<ellipse cx="911.9390833333333" cy="936.5" rx="79.514" ry="7" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<ellipse cx="911.9390833333333" cy="899.6" rx="79.514" ry="7" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="911.9390833333333" y="918.0500000000001" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">sensor_history_log</text>
</g>
<g class="node" data-id="API_Server" data-label="FastAPI Server" data-shape="rectangle">
<rect x="309.2331666666667" y="102" width="134.57500000000002" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="376.5206666666667" y="120.45" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">FastAPI Server</text>
</g>
<g class="node" data-id="LLM" data-label="Mistral LLM" data-shape="rectangle">
<rect x="286.15041666666673" y="186.9" width="113.827" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="343.0639166666667" y="205.35000000000002" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">Mistral LLM</text>
</g>
<g class="node" data-id="UI" data-label="React/Vite Dashboard" data-shape="rectangle">
<rect x="144.218" y="412.1" width="170.884" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="229.65999999999997" y="430.55" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">React/Vite Dashboard</text>
</g>
</svg>