System Architecture — Overview¶
SmartSoft Inventory is a layered WinForms desktop application. The application project is deliberately thin; the substance lives in the shared SmartSoft FrameWork DLLs and in the SQL Server database.
The layers¶
flowchart TB
subgraph P["① Presentation — WinForms"]
FRM["Forms (frmXxx.vb)<br/>Master · Transaksi · Proses · Laporan"]
MENU["MenuUtama<br/>(main menu + login)"]
end
subgraph A["② Application logic (thin)"]
CLS["Transaction classes<br/>INVENTORY/Class/*.vb"]
MOD["Modules / globals<br/>VariablePublic.vb"]
end
subgraph F["③ SmartSoft FrameWork (shared DLLs)"]
DAC["DataAccessControl<br/>(HAKDAC)"]
BLL["Business logic<br/>(cSTOK = BLL_STOCK, promos, closing)"]
TYP["Typed data-access classes<br/>(tbMaster_*, tv_*)"]
SVC["Cross-cutting<br/>(GUI, Struk, Net, Parameter, MyLib)"]
end
subgraph D["④ Data — SQL Server"]
DB[("Tables · Views · Stored procs")]
end
FRM --> CLS --> BLL
FRM --> DAC
MENU --> MOD
BLL --> DAC
TYP --> DAC
DAC -->|ADO.NET| DB
MOD -.session/globals.-> FRM
MOD -.session/globals.-> CLS
style F fill:#e8eaf6,stroke:#3f51b5
style D fill:#e0f2f1,stroke:#00897b
style MOD fill:#fff3e0,stroke:#fb8c00
| Layer | Where | Holds |
|---|---|---|
| ① Presentation | INVENTORY/Form/, MenuUtama.vb |
WinForms screens; the menu; login UI. |
| ② Application logic | INVENTORY/Class/, INVENTORY/Module/ |
Per-transaction posting glue; global session state; Sub Main. |
| ③ FrameWork | framework_smartsoft/* (as DLLs) |
Data-access gateway, stock/costing BLL, typed table classes, printing, config. |
| ④ Data | Microsoft SQL Server | The real source of truth: tables, views, stored procedures. |
It's layered, but not strictly clean
Forms can — and do — call the FrameWork data gateway (HAKDAC) directly, not only
through the Class/ layer. Session state is read from globals rather than passed
down. So the layering is a tendency, not an enforced boundary. Expect a form to run
SQL directly for a quick lookup.
Anatomy of one action (goods receipt)¶
The clearest way to understand the architecture is to trace a single transaction from click to committed rows.
sequenceDiagram
autonumber
actor U as User
participant Frm as frmInputPenerimaanBarang
participant Cls as PenerimaanBarang (Class)
participant Stk as cSTOK (BLL_STOCK)
participant Dac as HAKDAC
participant DB as SQL Server
U->>Frm: Enter supplier, items, qty, cost → Save
Frm->>Frm: Read session globals (memUserID, cPRSH.PRSH_KODE, memTanggal)
Frm->>Cls: Build header + detail rows
Cls->>DB: Doc number = MAX(field)+1
Cls->>Stk: Recompute average cost (GetAvgCost)
Stk-->>Cls: newAvg
Cls->>Dac: INSERT header/detail (string-built SQL)
Cls->>Dac: UPDATE tbMaster_Stock buckets (+ST_QTYBELI), ST_AVGCOST
Dac->>DB: Execute
DB-->>U: Saved — receipt/label printed via Struk
Two things to notice, because they characterise the whole system:
- Stock is updated immediately and in place — the transaction increments bucket
columns on
tbMaster_Stock(there is no movement ledger). See Stock & Costing. - Document numbers come from
MAX(field)+1— no counter table, which is a known race condition under concurrent posting. See Known Issues.
The application ↔ FrameWork split¶
flowchart LR
subgraph App["smartsoft_inventory (this repo)"]
UI["Screens + thin transaction glue"]
end
subgraph FW["framework_smartsoft (shared DLLs)"]
direction TB
B1["BLL — stock, costing, promos, closing"]
B2["General — data access, config, conversion"]
B3["GUI — base forms, controls, skinning"]
B4["Struk / Net / Laporan / CetakGiro"]
B5["DataAccessControl — typed table classes"]
B6["Parameter / MyLib — config, licensing, login"]
end
UI -->|references DLLs| FW
FW -->|shared across| Products["POS · Service · Inventory products"]
style FW fill:#e8eaf6,stroke:#3f51b5
Why the split matters: the FrameWork is shared across SmartSoft's product line (Inventory, POS, Service). A change in the FrameWork affects every product, which is why the Inventory app treats it as a compiled dependency rather than editing it casually.
Deployment topology¶
flowchart TB
subgraph Store["Store / Branch"]
T1["Till PC<br/>(app + printer)"]
T2["Till PC"]
BO["Back-office PC<br/>(reports, admin)"]
end
SRV[("SQL Server<br/>(store or HQ)")]
T1 -->|ADO.NET| SRV
T2 -->|ADO.NET| SRV
BO -->|ADO.NET| SRV
SRV -.closing / sync.-> HQ[("HQ / other branches")]
style SRV fill:#e0f2f1,stroke:#00897b
Each PC runs the full fat client and connects directly to SQL Server — there is no middle tier. Branches integrate through shared tables and closing/sync processes, not through services or an API.
Read next¶
- The SmartSoft FrameWork — what each shared assembly does.
- The Inventory Application — how the app's own folders are organised.
- Data Access Patterns — how SQL actually gets run.
- Session State & Globals — the global variables that carry context.