Skip to content
← All starter build updates

SaaS starter

Tempo

A focused time-tracking workspace for independent studios and small teams.

Live on VuraUpdated

The tracker shows its running block and elapsed time, guards pending creation and invalidates late responses on reset. Keyboard editing remains stable; denied storage is explicitly session-only.

Tempo: 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 workspace with explicit static route entries and a real bounded serverless API; demo data boundaries documented.

Learning journal

How to read this starter

Tempo is a hybrid time-tracking SaaS reference: the browser owns workspace state and two serverless endpoints validate entries and summarize reports.

Source map

Reactive workspace store

src/state.js

Signals hold editable state, computed values derive summaries, and navigation is a tiny path signal.

Relative seed data

src/domain.js

seedWorkspace(now) derives demo entry days from the visitor clock so today never renders empty by accident.

Editable row UI

src/app.jsx

Keyed For rows preserve focused inputs while immutable entry updates replace objects.

Bounded request parser

src/api/bounded-json.js

The function endpoint enforces byte limits while streaming the body as Uint8Array chunks.

Responsive application stylesheet

src/styles.css

32px headings and 44px controls cover timer, projects, reports and build routes.

Code patterns worth copying

Seed demo rows relative to now

src/domain.js

The seed data is stable enough for tests but relative enough that the Today panel always has current-day rows.

export function seedWorkspace(now = Date.now()) {
  const day = (offset) => isoToday(new Date(now + offset * 86400000));
  return {
    workspaceId: 'demo-' + Math.random().toString(36).slice(2, 8),
    running: null,

Keep focused rows stable during immutable edits

src/app.jsx

Each EntryRow receives a signal-wrapped accessor. The row can read entry().note and update by id without replacing the focused DOM node.

<For each={() => todaysEntries()} key={(entry) => entry.id} fallback={<EmptyEntries />}>

Bound function input by bytes, not text length

src/api/bounded-json.js

This avoids UTF-16 string-length mistakes and cancels the request stream as soon as the payload exceeds the endpoint budget.

const chunk = value instanceof Uint8Array ? value : new Uint8Array(value);

Let only the current workspace accept an async report

src/state.js

Reset advances the workspace generation; request counters also make the newer report win. Success, validation failures and network failures all check ownership.

const ownsResponse = () => generation === workspaceGeneration && request === reportRequest;

Real issues and fixes

Large JSON bodies need stream-level limits

Problem
A report endpoint can receive user-controlled JSON. Counting decoded text would miss the actual byte budget and keep reading after the limit.
Fix
Both Tempo and Lens use a Uint8Array accumulator, cancel the reader on overflow and decode with fatal UTF-8 handling.
Proof
The API parser returns 413 before parsing an oversized body and reports malformed JSON as a 400 response.
Takeaway
Serverless demos should show request boundaries even when the data is synthetic.

Mapped editable rows can drop input focus

Problem
The entries list updates immutably. A row that captures an immutable item can go stale, and some mapped render shapes can replace the input while the user is typing, leaving only the first typed character and moving focus to the body.
Fix
Render today’s entries with keyed For and pass the row accessor into EntryRow.
Proof
The browser regression marks the note and minutes inputs, performs select-all/backspace/type, and confirms the same DOM node stays focused.
Takeaway
Use keyed accessors for editable repeated state when objects are replaced immutably.

Reset must invalidate pending work

Problem
A delayed entry or report response could arrive after Reset and repopulate cleared state; a stale failure could clear the next pending guard.
Fix
Capture workspaceGeneration plus request counters before awaiting. Guard every result and cleanup, and reject duplicate timer/manual starts while validation is pending.
Proof
Controlled browser fetches delay entries and reports, reset, then release success and failure responses; the reset state or newer report remains authoritative.
Takeaway
Reset is an asynchronous ownership boundary, not just a group of signal writes.

Style checks need a required delivery gate

Problem
Unit tests and builds do not establish narrow-layout geometry, navigation target sizes or visible keyboard focus.
Fix
Run test:style in CI alongside behavior checks using the existing production-preview harness.
Proof
The CI workflow runs npm run test:style; modern-ui checks primary/build routes at desktop and mobile widths, controls, overflow and focus.
Takeaway
Keep style regressions in the delivery path alongside behavior checks.

What went smoothly

  • The local app and serverless validation share the same domain helpers, so UI and API constraints stayed aligned.
  • The HMR disposal path made timer, effect and popstate cleanup explicit during development.
  • The entry/report ownership checks fit the existing shared store and retained the continuous keyboard-edit regression without introducing a second workspace.
  • Compact timer typography and 44px native controls preserve continuous entry editing; portable keyboard shortcuts keep the same checks useful across operating systems.

Boundaries to preserve

  • Workspace data is browser-local seed data, not a multi-user database.
  • Serverless functions validate and summarize posted data; they do not persist account records.

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

    The tracker shows its running block and elapsed time, guards pending creation and invalidates late responses on reset. Keyboard editing remains stable; denied storage is explicitly session-only.

  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

    Repairing duplicate pending timer starts, honest storage-failure feedback and running-block 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 current-date tracker shows clear budget health and keeps the same note/minute input nodes during continuous typing. Full text and37minutes persisted after the live reload check.

  6. · Live on Vura

    Design refinement released for live workflow review

    The revised time tracker shows current-date demo entries, a clear empty state and budget health. Live typing found a row-identity issue; the focused-input repair is verified locally and awaiting its next release.

  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; documentation-only refinements did not change application code.

  10. · Live on Vura

    Locked quick start aligned with CI

    The README uses npm ci rather than npm install, so clean-machine setup reproduces the reviewed lockfile before installing Chromium. This documentation-only refinement does not change the hosted app.

  11. · 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.

  12. · 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.

  13. · 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.

  14. · 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.

  15. · In review

    Local implementation ready for review

    The first implementation is available locally. It is not yet a published source reference or a verified Vura deployment.

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.