Skip to content

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:

  1. Stock is updated immediately and in place — the transaction increments bucket columns on tbMaster_Stock (there is no movement ledger). See Stock & Costing.
  2. 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.