Skip to content
← All starter build updates

Finance starter

Tally

A freelancer invoice workspace for organizing line items and understanding totals.

Live on VuraUpdated

Invoice lines can be removed and recovered, dates and draft status are clear, and line/export calculations use the same safe operands. Focus, totals, receipt and responsive labels passed.

Tally: actual released desktop product view after the shared typography refinement.
Preview captured · Explore the product ↗

Build phase

  1. PlannedComplete
  2. BuildingComplete
  3. Local checks passedComplete
  4. In reviewComplete
  5. Live on VuraCurrent phase

This tracks the recorded release phase. The checks below include later findings and ongoing refinements.

Product scope and intended patterns

The following describes the intended reference. Features are not a verification claim; recorded check results below define what has actually been tested.

Client-rendered application served from explicit static route entries; browser-local state, not a shared server database.

Learning journal

How to read this starter

Tally is a client invoice workspace with editable drafts, computed totals, direct receipt routes and local JSON export.

Source map

Invoice store

src/state/workspace.js

Signals store invoice drafts, selected client, save status and export status.

Invoice math

src/data/invoices.js

Pure helpers calculate finite money totals before UI and exports use them.

Alias generation

scripts/static-aliases.mjs

The build writes direct client, invoice and receipt paths plus 404.html.

Unit tests

test/invoices.test.js

Tests cover subtotal/tax/total math and invalid money coercion.

Recoverable line editor

src/pages/InvoiceDetail.jsx

Keyed For accessors preserve input identity, per-operand clamping matches calculations, and empty drafts can start again.

Responsive application stylesheet

src/styles.css

Fixed line-total tracks and visible mobile field labels remain intact alongside bounded headings.

Code patterns worth copying

Keep invoice totals derived

src/state/workspace.js

Draft state changes once; all financial summaries derive from current invoice lines.

export const invoiceSummaries = computed(() => invoices().map((invoice) => ({
  ...invoice,
  client: clientById(invoice.clientId),
  totals: calculateInvoice(invoice),
})));

export const workspaceTotals = computed(() => invoiceSummaries().reduce((totals, invoice) => ({
  drafts: totals.drafts + (invoice.status === 'draft' ? 1 : 0),
  saved: totals.saved + (invoice.status === 'saved' ? 1 : 0),
  outstanding: Math.round((totals.outstanding + invoice.totals.total) * 100) / 100,
}), { drafts: 0, saved: 0, outstanding: 0 }));

Preserve line identity while editing

src/pages/InvoiceDetail.jsx

The accessor row lets Tally replace line objects immutably while the current input keeps focus.

<For each={() => invoice().lines} key={(line) => line.id} fallback={<p class="empty-state">No invoice lines yet. Add a line to start this local draft.</p>}>

Generate every direct invoice URL

scripts/static-aliases.mjs

Static hosting receives concrete pages for both editable drafts and read-only receipt previews.

const routes = [
  ['/', 'Tally — Freelance invoice workspace', 'Edit invoice drafts, calculate finite totals, preview receipts, and export JSON locally.'],
  ['/clients', 'Clients — Tally', 'Synthetic freelance client ledger with direct detail routes.'],
  ...clients.map((client) => [`/clients/${client.id}`, `${client.name} — Tally`, client.notes]),

Use the shared stylesheet on application routes

src/styles.css

Fixed line-total tracks and visible mobile field labels remain intact alongside bounded headings.

h1 { margin: 0 0 16px; font-size: 32px; line-height: 1.2; letter-spacing: -.02em; font-weight: 600; }

Real issues and fixes

Immutable line edits need keyed row accessors

Problem
Quantity, unit-price and description edits replace line objects. Raw keyed mapping may retain DOM while holding an older object; some render shapes can also replace focused inputs.
Fix
InvoiceDetail renders invoice lines with keyed For and reads line().quantity, line().unitPrice and line().description inside the row.
Proof
Playwright marks the focused node, clears and types in existing plus newly added line fields, and verifies focus and totals stay correct.
Takeaway
Editable tables should use identity-preserving loops before reaching for imperative refocus code.

Invoice totals need a fixed track before responsive labels take over

Problem
Currency widths made independent line-row grids drift on desktop, while mobile cards relied on a detached header that was no longer visible.
Fix
Use a fixed 7.5rem total track on desktop and expose Description, Qty, Unit price and Line total labels inside each mobile row card.
Proof
Browser tests measure row column alignment at 1440px and require mobile row labels after the header is hidden.
Takeaway
Dense editor grids need both column math and responsive labeling, not one or the other.

Money inputs can briefly be invalid

Problem
Editable number inputs can produce empty, negative or non-finite values while a user is typing.
Fix
The calculation helper coerces invalid money to zero before subtotal, tax and total math.
Proof
The unit test asserts finiteMoney returns zero for bad and negative inputs while accepting numeric strings.
Takeaway
Derived financial UI should guard calculations even when persistence is local-only.

Removing lines must preserve finite and recoverable drafts

Problem
An accidental row had no recovery path, and clamping a multiplied line amount let two negative operands become a positive displayed total.
Fix
Remove by line id, show a zero-total empty state and allow Add line to restart. Clamp quantity and price individually with finiteMoney before multiplying, matching the shared calculation.
Proof
Browser tests add/remove rows, remove every row, require zero totals, add again and enter two negatives. Existing focus and column-alignment regressions remain.
Takeaway
Editor recovery and displayed math should follow the same canonical operands as exported totals.

What went smoothly

  • Computed invoice summaries allow draft list, client detail and receipt preview to agree on totals.
  • The same seed invoices generate static aliases for both invoice editor and receipt paths.
  • Line removal reused immutable invoice state and keyed For accessors; draft dates/status added context without changing local export or receipt boundaries.
  • Ledger, line editor and receipt share bounded typography and 44px targets; Meta-or-Ctrl keyboard replacement still verifies keyed row identity.

Boundaries to preserve

  • Exports are local JSON only; no invoice is sent, paid or filed.
  • The starter does not claim tax, payment, compliance or accounting coverage.

Verification record

Build journal

  1. · Live on Vura

    Shared typography release captured from production

    Published shared typography and responsive control refinements are tied to the exact live deployment and source revision. Actual released captures replace the previous gallery preview; existing product behavior and source-grounded lessons are retained.

  2. · Live on Vura

    Product-depth iteration released and exercised

    Invoice lines can be removed and recovered, dates and draft status are clear, and line/export calculations use the same safe operands. Focus, totals, receipt and responsive labels passed.

  3. · Live on Vura

    Reviewed source ready for release verification

    Unique product identities and deeper workflows are implemented and independently reviewed. Existing releases remain accessible while new source is published and fresh deployments are exercised.

  4. · Live on Vura

    Product-depth iteration in progress

    Adding reversible line removal and clearer invoice dates, draft state and mobile ledger context. The current source and deployment links still identify the previous verified release.

  5. · Live on Vura

    Live corrections verified after independent follow-up

    The invoice editor now keeps typing focus, aligns every desktop column and labels each mobile field. Live quantity, description and price updates preserve DOM identity and correct totals.

  6. · Live on Vura

    Design refinement released for live workflow review

    The invoice desk and editor have clearer actions and accurate tax/total labels. Live testing found input focus loss; keyed accessor rows fix it locally and await release proof.

  7. · Live on Vura

    Independent live design review started

    The existing public app remains available while a new design review examines hierarchy, typography, navigation and workflow clarity. Actual findings and before/after repairs will be recorded as they are verified.

  8. · Live on Vura

    Hosted reference rechecked after documentation review

    Public source, green CI and the live app were checked together after the clean-machine documentation pass. Lessons and limitations now reflect the implemented code rather than pending pre-release work.

  9. · Live on Vura

    Final source and CI checkpoint verified

    The public source and build reference match the released learning journal, and the source workflow is green. The demo remains live at the same verified deployment; README and CI-only refinements did not change application code.

  10. · Live on Vura

    Clean-machine browser setup documented

    The README now installs the locked Chromium engine after npm ci and explains the Linux system-library prerequisite. The hosted application is unchanged; code examples, repair notes and boundaries remain source-backed.

  11. · Live on Vura

    Public template and Vura release

    The reviewed implementation is available from its independent repository and real hosted URL. Detailed code examples and actual repair notes are linked below.

  12. · In review

    Design review cleared; release verification underway

    The local implementation is complete and revised visual evidence has passed review. Source and demo links will appear only after publication and hosted verification.

  13. · Building

    Implementation started

    The standalone project files exist and the product build is active. No local verification or live release is claimed yet.

  14. · Planned

    Product scope recorded

    This is a planned starter, not a working release. Implementation, tests, public source and deployment evidence will be added as they are completed.

Implementation lessons

Known limitations

Remaining work and blockers

No release blockers are recorded for this snapshot.

Using this as an agent reference

Read the public README and BUILD.md, reproduce the recorded checks and inspect the source before adapting the starter. A live demo, where available, provides separate deployed evidence.