CodingNic

Architecture and Data

Trace a Transaction Through the App

Architecture and Data 18 min read

Trace a Transaction Through the App

Open these files in this order:

text
client/src/pages/LedgerPage.jsx
client/src/hooks/useMonthTransactions.js
client/src/context/BudgetContext.jsx
client/src/lib/api.js
server/src/app.js
server/src/routes/transactions.js
server/src/db.js

We are not changing code in this lesson. We are tracing one real transaction so the next lessons have a clear mental model.

1. Start at the page

LedgerPage.jsx assembles the main Ledger screen. It does not fetch data itself. Instead, it places components such as SummaryStrip, EntryForm, and TransactionList on the page.

The page is therefore the composition layer: it decides which pieces appear together.

2. Find the filtered records

useMonthTransactions.js reads transactions and cursor from useBudget() and produces the transactions for the selected month.

The important distinction is:

text
transactions = the complete client-side collection
cursor       = the month the user is looking at
monthTx      = the subset to render now

The filter does not delete or modify the complete transaction collection. It creates a view of it.

3. Follow the shared state

BudgetContext.jsx owns the client-side collections:

javascript
const [transactions, setTransactions] = useState([]);
const [categories, setCategories] = useState([]);

It also owns cursor, which tells the application which month is selected.

The context is the shared bridge between the pages/components and the API functions.

4. Follow the API call

client/src/lib/api.js contains the functions that make HTTP requests. For example:

javascript
export const getTransactions = () => request("/transactions");

The component does not need to know the server’s port or how fetch is configured. It asks the API helper for transactions.

5. Find the server route

server/src/app.js mounts the transaction router here:

javascript
app.use("/api/transactions", transactionsRouter);

That means a client request for /api/transactions is handled by server/src/routes/transactions.js.

The GET route reads the database and returns its transactions collection:

javascript
router.get("/", async (req, res) => {
  const db = await getDb();
  res.json(db.transactions);
});

getDb() comes from server/src/db.js. That module loads server/data/db.json into memory for the server to use.

Put the whole path together

text
server/data/db.json
        ↓
     db.js
        ↓
transactions route
        ↓
     api.js
        ↓
 BudgetContext
        ↓
useMonthTransactions
        ↓
   Ledger UI

The response moves upward through these layers. Each layer has one job, which keeps the application easier to understand and change.

Test it

Reload the Ledger and open your browser’s Network panel.

Select the request for /api/transactions and verify that its response contains the same transaction records you saw in server/data/db.json.

Checkpoint

You can follow one transaction from the JSON file all the way to the row rendered by the Ledger, and you know what each layer contributes along the way.