Correct TallyFlow architecture based on source code review in ~/src/

- Core is central and owns MongoDB (not Assets)
- Core: Go backend + Vue.js frontend (no Node.js)
- Verified against tallyflow-web, photomicroservice, tallyflow-iot, tallyflow_mobile, tallyflow-print
- Updated diagram, legend, cards, and description for accuracy
This commit is contained in:
TNB
2026-07-07 09:15:19 -04:00
parent 31d267a211
commit 0bbe00b75e
2 changed files with 108 additions and 106 deletions
+87 -92
View File
@@ -59,11 +59,11 @@
<div class="pulse-dot"></div>
<h1>TallyFlow Architecture</h1>
</div>
<p class="subtitle">Manufacturing Asset Tracking &amp; RFID Workflow Platform</p>
<p class="subtitle">Manufacturing Asset Tracking &amp; RFID Workflow Platform — Source-verified</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 620">
<svg viewBox="0 0 1000 640">
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#64748b" />
@@ -76,104 +76,99 @@
<!-- Background Grid -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- Central Core Region -->
<rect x="180" y="60" width="640" height="480" rx="16" fill="rgba(6, 78, 59, 0.08)" stroke="#34d399" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="200" y="85" fill="#34d399" font-size="11" font-weight="700">TallyFlow Core (Backend API + Web UI)</text>
<!-- Central Core Region (owns DB) -->
<rect x="160" y="50" width="680" height="510" rx="16" fill="rgba(6, 78, 59, 0.08)" stroke="#34d399" stroke-width="2" stroke-dasharray="6,3"/>
<text x="180" y="78" fill="#34d399" font-size="12" font-weight="700">TallyFlow Core (Central Hub)</text>
<!-- Core Component -->
<rect x="220" y="120" width="160" height="70" rx="8" fill="rgba(6, 78, 59, 0.45)" stroke="#34d399" stroke-width="2"/>
<text x="300" y="150" fill="white" font-size="13" font-weight="700" text-anchor="middle">Core</text>
<text x="300" y="168" fill="#94a3b8" font-size="9" text-anchor="middle">FastAPI / Node.js</text>
<text x="300" y="182" fill="#34d399" font-size="8" text-anchor="middle">REST + WebSocket</text>
<!-- Core Backend (Go) -->
<rect x="200" y="110" width="180" height="80" rx="8" fill="rgba(6, 78, 59, 0.5)" stroke="#34d399" stroke-width="2"/>
<text x="290" y="140" fill="white" font-size="14" font-weight="700" text-anchor="middle">Core Backend</text>
<text x="290" y="158" fill="#94a3b8" font-size="10" text-anchor="middle">Go (Echo / gRPC)</text>
<text x="290" y="174" fill="#34d399" font-size="9" text-anchor="middle">REST + WebSocket API</text>
<!-- Assets (Mobile) Component - corrected -->
<rect x="420" y="120" width="160" height="70" rx="8" fill="rgba(8, 51, 68, 0.45)" stroke="#22d3ee" stroke-width="2"/>
<text x="500" y="148" fill="white" font-size="13" font-weight="700" text-anchor="middle">Assets (Mobile)</text>
<text x="500" y="165" fill="#94a3b8" font-size="9" text-anchor="middle">Lightweight Inventory</text>
<text x="500" y="180" fill="#22d3ee" font-size="8" text-anchor="middle">Seek &amp; Find • Enrollment</text>
<!-- Core Frontend (Vue.js) -->
<rect x="420" y="110" width="180" height="80" rx="8" fill="rgba(8, 51, 68, 0.5)" stroke="#22d3ee" stroke-width="2"/>
<text x="510" y="140" fill="white" font-size="14" font-weight="700" text-anchor="middle">Core Web UI</text>
<text x="510" y="158" fill="#94a3b8" font-size="10" text-anchor="middle">Vue.js 2 + Webpack</text>
<text x="510" y="174" fill="#22d3ee" font-size="9" text-anchor="middle">Asset management, reporting</text>
<!-- Print Component - corrected to Zebra ZPL -->
<rect x="620" y="120" width="160" height="70" rx="8" fill="rgba(120, 53, 15, 0.4)" stroke="#fbbf24" stroke-width="2"/>
<text x="700" y="148" fill="white" font-size="13" font-weight="700" text-anchor="middle">Print</text>
<text x="700" y="165" fill="#94a3b8" font-size="9" text-anchor="middle">Zebra (ZPL compatible)</text>
<text x="700" y="180" fill="#fbbf24" font-size="8" text-anchor="middle">Label + RFID Encoding</text>
<!-- MongoDB (owned by Core) -->
<rect x="640" y="110" width="170" height="80" rx="8" fill="rgba(76, 29, 149, 0.45)" stroke="#a78bfa" stroke-width="2"/>
<text x="725" y="140" fill="white" font-size="14" font-weight="700" text-anchor="middle">MongoDB</text>
<text x="725" y="158" fill="#94a3b8" font-size="10" text-anchor="middle">Asset registry</text>
<text x="725" y="174" fill="#a78bfa" font-size="9" text-anchor="middle">Tags • Photos • Zones • Events</text>
<!-- Capture (PhotoTag) - corrected -->
<rect x="80" y="280" width="140" height="90" rx="8" fill="rgba(136, 19, 55, 0.4)" stroke="#fb7185" stroke-width="2"/>
<text x="150" y="308" fill="white" font-size="13" font-weight="700" text-anchor="middle">Capture</text>
<text x="150" y="326" fill="#94a3b8" font-size="9" text-anchor="middle">(PhotoTag)</text>
<text x="150" y="342" fill="#fb7185" font-size="8" text-anchor="middle">Photo + Barcode assoc</text>
<text x="150" y="356" fill="#94a3b8" font-size="8" text-anchor="middle">QC Documentation</text>
<!-- Assets (Mobile) - Flutter -->
<rect x="80" y="290" width="150" height="95" rx="8" fill="rgba(8, 51, 68, 0.45)" stroke="#22d3ee" stroke-width="2"/>
<text x="155" y="318" fill="white" font-size="13" font-weight="700" text-anchor="middle">Assets (Mobile)</text>
<text x="155" y="336" fill="#94a3b8" font-size="9" text-anchor="middle">Flutter</text>
<text x="155" y="352" fill="#22d3ee" font-size="8" text-anchor="middle">Seek &amp; Find • Inventory</text>
<text x="155" y="366" fill="#94a3b8" font-size="8" text-anchor="middle">Enrollment • Zones</text>
<!-- IoT / Fixed Readers + Sensors -->
<rect x="780" y="280" width="140" height="90" rx="8" fill="rgba(251, 146, 60, 0.35)" stroke="#fb923c" stroke-width="2"/>
<text x="850" y="308" fill="white" font-size="13" font-weight="700" text-anchor="middle">IoT</text>
<text x="850" y="326" fill="#94a3b8" font-size="9" text-anchor="middle">Fixed Readers + Sensors</text>
<text x="850" y="342" fill="#fb923c" font-size="8" text-anchor="middle">Impinj / Zebra</text>
<text x="850" y="356" fill="#94a3b8" font-size="8" text-anchor="middle">MQTT / HTTP / BLE</text>
<!-- Capture (PhotoTag) - Go microservice -->
<rect x="780" y="290" width="150" height="95" rx="8" fill="rgba(136, 19, 55, 0.4)" stroke="#fb7185" stroke-width="2"/>
<text x="855" y="318" fill="white" font-size="13" font-weight="700" text-anchor="middle">Capture</text>
<text x="855" y="336" fill="#94a3b8" font-size="9" text-anchor="middle">(PhotoTag)</text>
<text x="855" y="352" fill="#fb7185" font-size="8" text-anchor="middle">Go + Mongo</text>
<text x="855" y="366" fill="#94a3b8" font-size="8" text-anchor="middle">Photo + Barcode QC</text>
<!-- Database Layer - corrected to MongoDB -->
<rect x="320" y="420" width="360" height="70" rx="8" fill="rgba(76, 29, 149, 0.35)" stroke="#a78bfa" stroke-width="1.5"/>
<text x="500" y="450" fill="white" font-size="12" font-weight="700" text-anchor="middle">MongoDB</text>
<text x="500" y="468" fill="#94a3b8" font-size="9" text-anchor="middle">Asset registry • Event store • Audit</text>
<text x="500" y="482" fill="#a78bfa" font-size="8" text-anchor="middle">Tags, photos, zones, history</text>
<!-- Print (Zebra ZPL) -->
<rect x="280" y="420" width="160" height="80" rx="8" fill="rgba(120, 53, 15, 0.4)" stroke="#fbbf24" stroke-width="2"/>
<text x="360" y="448" fill="white" font-size="13" font-weight="700" text-anchor="middle">Print</text>
<text x="360" y="466" fill="#94a3b8" font-size="9" text-anchor="middle">Flutter + Rust</text>
<text x="360" y="482" fill="#fbbf24" font-size="8" text-anchor="middle">Zebra ZPL + RFID</text>
<!-- External Integrations / Excel -->
<rect x="80" y="420" width="120" height="60" rx="6" fill="rgba(30, 41, 59, 0.5)" stroke="#94a3b8" stroke-width="1.5"/>
<text x="140" y="445" fill="white" font-size="11" font-weight="600" text-anchor="middle">Excel Import</text>
<text x="140" y="462" fill="#94a3b8" font-size="8" text-anchor="middle">Bulk asset load</text>
<!-- IoT (Rust) -->
<rect x="560" y="420" width="160" height="80" rx="8" fill="rgba(251, 146, 60, 0.35)" stroke="#fb923c" stroke-width="2"/>
<text x="640" y="448" fill="white" font-size="13" font-weight="700" text-anchor="middle">IoT</text>
<text x="640" y="466" fill="#94a3b8" font-size="9" text-anchor="middle">Rust (tallyflow-iot)</text>
<text x="640" y="482" fill="#fb923c" font-size="8" text-anchor="middle">Fixed readers • Sensors</text>
<!-- Arrows / Flows -->
<!-- Arrows -->
<!-- Capture → Core -->
<line x1="222" y1="325" x2="280" y2="190" stroke="#fb7185" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="235" y="265" fill="#fb7185" font-size="9" font-weight="600">Photo + Data</text>
<!-- Assets (Mobile) → Core -->
<line x1="232" y1="335" x2="280" y2="190" stroke="#22d3ee" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="240" y="270" fill="#22d3ee" font-size="9" font-weight="600">Sync / Enroll</text>
<!-- Core ↔ Assets (Mobile) -->
<line x1="382" y1="155" x2="418" y2="155" stroke="#22d3ee" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="400" y="148" fill="#22d3ee" font-size="8">Sync</text>
<!-- Core Backend ↔ MongoDB -->
<line x1="382" y1="150" x2="638" y2="150" stroke="#a78bfa" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="510" y="143" fill="#a78bfa" font-size="9">Owns &amp; Persists</text>
<!-- Core → Print -->
<line x1="382" y1="155" x2="618" y2="155" stroke="#fbbf24" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="500" y="148" fill="#fbbf24" font-size="8">Print Jobs</text>
<line x1="360" y1="192" x2="360" y2="418" stroke="#fbbf24" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="375" y="310" fill="#fbbf24" font-size="9">Print Jobs</text>
<!-- IoT → Core -->
<line x1="778" y1="325" x2="720" y2="190" stroke="#fb923c" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="765" y="265" fill="#fb923c" font-size="9" font-weight="600">Tag Events</text>
<line x1="640" y1="418" x2="640" y2="192" stroke="#fb923c" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="655" y="310" fill="#fb923c" font-size="9">Tag Events</text>
<!-- Core ↔ MongoDB -->
<line x1="500" y1="192" x2="500" y2="418" stroke="#a78bfa" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="515" y="310" fill="#a78bfa" font-size="9">Persist</text>
<!-- Print ↔ MongoDB (via Core) -->
<line x1="700" y1="192" x2="680" y2="418" stroke="#fbbf24" stroke-width="1.5" stroke-dasharray="4,2" marker-end="url(#arrowhead)"/>
<!-- Capture ↔ Excel example flow -->
<line x1="140" y1="420" x2="140" y2="370" stroke="#94a3b8" stroke-width="1.5" stroke-dasharray="3,2" marker-end="url(#arrowhead)"/>
<!-- Capture → Core -->
<line x1="778" y1="335" x2="720" y2="190" stroke="#fb7185" stroke-width="2" marker-end="url(#arrowhead)"/>
<text x="765" y="270" fill="#fb7185" font-size="9" font-weight="600">Photos + Metadata</text>
<!-- Legend -->
<text x="80" y="560" fill="white" font-size="10" font-weight="700">Legend</text>
<text x="80" y="570" fill="white" font-size="10" font-weight="700">Legend</text>
<rect x="80" y="572" width="18" height="11" rx="2" fill="rgba(6, 78, 59, 0.45)" stroke="#34d399" stroke-width="1"/>
<text x="105" y="581" fill="#94a3b8" font-size="8">Core Backend</text>
<rect x="80" y="582" width="18" height="11" rx="2" fill="rgba(6, 78, 59, 0.5)" stroke="#34d399" stroke-width="1"/>
<text x="105" y="591" fill="#94a3b8" font-size="8">Core (Go + Vue.js)</text>
<rect x="200" y="572" width="18" height="11" rx="2" fill="rgba(8, 51, 68, 0.45)" stroke="#22d3ee" stroke-width="1"/>
<text x="225" y="581" fill="#94a3b8" font-size="8">Assets (Mobile)</text>
<rect x="230" y="582" width="18" height="11" rx="2" fill="rgba(8, 51, 68, 0.45)" stroke="#22d3ee" stroke-width="1"/>
<text x="255" y="591" fill="#94a3b8" font-size="8">Assets (Flutter)</text>
<rect x="330" y="572" width="18" height="11" rx="2" fill="rgba(136, 19, 55, 0.4)" stroke="#fb7185" stroke-width="1"/>
<text x="355" y="581" fill="#94a3b8" font-size="8">Capture (PhotoTag)</text>
<rect x="355" y="582" width="18" height="11" rx="2" fill="rgba(136, 19, 55, 0.4)" stroke="#fb7185" stroke-width="1"/>
<text x="380" y="591" fill="#94a3b8" font-size="8">Capture (Go)</text>
<rect x="485" y="572" width="18" height="11" rx="2" fill="rgba(120, 53, 15, 0.4)" stroke="#fbbf24" stroke-width="1"/>
<text x="510" y="581" fill="#94a3b8" font-size="8">Print (Zebra ZPL)</text>
<rect x="485" y="582" width="18" height="11" rx="2" fill="rgba(120, 53, 15, 0.4)" stroke="#fbbf24" stroke-width="1"/>
<text x="510" y="591" fill="#94a3b8" font-size="8">Print (Flutter/Rust)</text>
<rect x="610" y="572" width="18" height="11" rx="2" fill="rgba(251, 146, 60, 0.35)" stroke="#fb923c" stroke-width="1"/>
<text x="635" y="581" fill="#94a3b8" font-size="8">IoT / Edge</text>
<rect x="615" y="582" width="18" height="11" rx="2" fill="rgba(251, 146, 60, 0.35)" stroke="#fb923c" stroke-width="1"/>
<text x="640" y="591" fill="#94a3b8" font-size="8">IoT (Rust)</text>
<rect x="720" y="572" width="18" height="11" rx="2" fill="rgba(76, 29, 149, 0.35)" stroke="#a78bfa" stroke-width="1"/>
<text x="745" y="581" fill="#94a3b8" font-size="8">MongoDB</text>
<rect x="720" y="582" width="18" height="11" rx="2" fill="rgba(76, 29, 149, 0.45)" stroke="#a78bfa" stroke-width="1"/>
<text x="745" y="591" fill="#94a3b8" font-size="8">MongoDB (Core-owned)</text>
<line x1="850" y1="577" x2="868" y2="577" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<text x="875" y="581" fill="#94a3b8" font-size="8">Data Flow</text>
<line x1="870" y1="587" x2="888" y2="587" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<text x="895" y="591" fill="#94a3b8" font-size="8">API Flow</text>
</svg>
</div>
@@ -181,13 +176,13 @@
<div class="card">
<div class="card-header">
<div class="card-dot emerald"></div>
<h3>Core</h3>
<h3>Core (Central)</h3>
</div>
<ul>
<li>Central orchestration &amp; API hub</li>
<li>Web UI for asset management</li>
<li>Zone, category &amp; reporting config</li>
<li>• Integration point for all modules</li>
<li>Go backend (API, business logic)</li>
<li>Vue.js 2 web frontend</li>
<li>Owns MongoDB (assets, tags, photos, zones)</li>
<li>• Integration hub for all modules</li>
</ul>
</div>
<div class="card">
@@ -196,10 +191,10 @@
<h3>Assets (Mobile)</h3>
</div>
<ul>
<li>Lightweight inventory &amp; tracking</li>
<li>Geiger-style seek &amp; find</li>
<li>Fast enrollment &amp; editing</li>
<li>Zone moves &amp; shipping workflows</li>
<li>Flutter mobile app</li>
<li>Lightweight inventory &amp; seek/find</li>
<li>Enrollment, zone moves</li>
<li>Syncs with Core API</li>
</ul>
</div>
<div class="card">
@@ -208,10 +203,10 @@
<h3>Capture (PhotoTag)</h3>
</div>
<ul>
<li>• Go microservice + Mongo</li>
<li>• Photo + barcode association</li>
<li>• QC &amp; visual documentation</li>
<li>Work order / serial tagging</li>
<li>• Searchable photo records</li>
<li>Feeds Core via API</li>
</ul>
</div>
<div class="card">
@@ -220,16 +215,16 @@
<h3>Print + IoT</h3>
</div>
<ul>
<li>Zebra ZPL label printing &amp; encoding</li>
<li>Fixed RFID readers (Impinj/Zebra)</li>
<li>IoT sensors (location, temp, shock)</li>
<li>Excel bulk import support</li>
<li>Print: Flutter + Rust (Zebra ZPL)</li>
<li>IoT: Rust (fixed readers, sensors)</li>
<li>MQTT / HTTP / BLE ingestion</li>
<li>All route through Core</li>
</ul>
</div>
</div>
<p class="footer">
TallyFlow • Reducing manufacturing waste through intelligent RFID tracking • 2026
TallyFlow • Architecture verified against source in ~/src (tallyflow-web, photomicroservice, tallyflow-iot, tallyflow_mobile, tallyflow-print) • 2026
</p>
</div>
</body>
+21 -14
View File
@@ -2,26 +2,33 @@
**Diagram:** [[TallyFlow-Architecture-Diagram.html]]
## Overview
## Overview (Source-Verified)
TallyFlow is a modular asset tracking platform centered on **TallyFlow Core**, the central web backend and integration hub. All other components synchronize with Core for asset registration, configuration, reporting, and data consistency.
TallyFlow's architecture is centered on **TallyFlow Core**, which serves as the single integration hub and owns the primary data store.
**TallyFlow Assets (Mobile)** is the primary field application for lightweight inventory management, geiger-counter-style seek & find, fast enrollment, zone movements, and shipping workflows.
**Core** consists of:
- Go backend (API layer, business logic, using Echo/gRPC patterns)
- Vue.js 2 web frontend (tallyflow-web) for asset management, reporting, and configuration
- MongoDB database (owned by Core) storing the asset registry, tags, photo metadata, zones, events, and audit history
**TallyFlow Capture** (rebranded from PhotoTag) enables photo documentation by associating images with barcodes, work orders, serial numbers, and other metadata for quality control and visual record-keeping across incoming, in-process, and outgoing inspections.
All other components communicate exclusively through Core's REST + WebSocket APIs.
**TallyFlow Print** handles on-demand Zebra ZPL-compatible label printing and RFID encoding, with optional automatic registration back into Core.
**TallyFlow Assets (Mobile)** is a Flutter application focused on field operations: lightweight inventory, geiger-counter-style seek & find, fast enrollment, zone movements, and shipping workflows. It syncs with Core.
**IoT** provides real-time location, environmental sensor data (temperature, humidity, shock), and fixed RFID reader integration (Impinj, Zebra) via MQTT/HTTP/BLE, feeding live events into Core.
**TallyFlow Capture** (PhotoTag) is implemented as a Go microservice (photomicroservice) that handles photo + barcode association for quality control and visual documentation. It stores photo metadata in its own MongoDB collections but registers assets and events back to Core.
Data is persisted in **MongoDB**, which stores the asset registry, tag events, photo metadata, zones, and full audit history. Bulk onboarding is supported via Excel import. All modules communicate through Cores REST + WebSocket APIs, enabling unified visibility and waste reduction across manufacturing operations.
**TallyFlow Print** is a Flutter + Rust application that generates Zebra ZPL-compatible labels and RFID encodings, with optional auto-registration into Core.
**IoT** is a Rust-based service (tallyflow-iot) that ingests data from fixed RFID readers (Impinj, Zebra) and environmental sensors, pushing real-time tag events and sensor data to Core.
This structure was verified by inspecting the repositories in `~/src/` (tallyflow-web, photomicroservice, tallyflow-iot, tallyflow_mobile, tallyflow-print, etc.).
## Key Data Flows
- **Assets (Mobile) ↔ Core**: Sync inventory updates, enrollment, and seek/find data
- **Capture Core**: Photo + barcode metadata and QC records
- **Print → Core**: Print job submission + optional auto-registration
- **IoT → Core**: Real-time tag events and sensor data
- **Core ↔ MongoDB**: Persistent storage of all asset, tag, photo, and event data
- **Excel → Core**: Bulk asset and tag ingestion
- **Assets (Mobile) ↔ Core**: Enrollment, inventory updates, seek/find sync via API
- **Capture Core**: Photo metadata and QC records
- **Print → Core**: Print jobs and optional asset registration
- **IoT → Core**: Real-time tag/sensor events
- **Core ↔ MongoDB**: Core owns and directly manages all persistent data (assets, photos, zones, history)
- **Core Web UI (Vue.js)**: Operator interface for the full system
This architecture allows flexible deployment — from mobile-only inventory tracking to full IoT + automated capture environments — while keeping Core as the single source of truth.
Core is the only component that directly owns the database. All other modules are clients or data producers that route through Core.