All work

CASE STUDY · 01

Q-Balance

Income and expense tracking with per-user data and reports.

  • Next.js 16
  • React 19
  • TypeScript
  • Server Actions
  • MariaDB
  • Better Auth
  • Tailwind CSS

No sign-up needed: browse six months of sample data, or use the one-click demo account to add and edit records.

q-balance.next-nexus.devQ-Balance dashboard with an income and expense chart, sidebar navigation, and recent income and expense panels

Overview

Q-Balance tracks income and expenses. Transactions are built from reusable items, items belong to categories, and the dashboard compares daily income with spending over a week, a month, or six months.

The aim was a small but realistic line-of-business app: authentication with email verification, data that belongs to a user, CRUD screens, filters, and reports. These are the same building blocks as a customer portal or an internal dashboard.

Engineering decisions

  1. 01

    User ownership in every query

    Each read and write is scoped to its owner in SQL, and the schema enforces it again.

    Every query for categories, items, and transactions filters by the owner's ID, using parameterized SQL through mysql2 rather than an ORM. Reads go through a helper that resolves the data owner (the signed-in user, or the read-only showcase account for guests), while writes require a real signed-in user. Composite foreign keys in the schema guarantee that a transaction's item, and an item's category, belong to the same user, so a bug in application code cannot link one user's data to another's.

  2. 02

    Two demo modes, zero friction

    Guests browse a read-only showcase; the demo account gets its own resettable copy.

    Visitors can explore immediately without an account. Guests read a password-less showcase account that nobody can sign in to or modify. The one-click demo account has its own copy of the sample data, so demo edits never leak into what guests see. Both are regenerated once a day on first use, without a cron job, and each calendar date produces the same deterministic data, so the history moves forward a day at a time instead of being reshuffled.

  3. 03

    Server Actions for mutations

    Forms post to Server Actions with pending states, revalidation, and tested calculations.

    Creating and editing records uses Server Actions with useActionState for validation messages and pending feedback, followed by path revalidation. Money is stored as DECIMAL(15, 2) and quantities as DECIMAL(15, 4). The discount calculation and password rules are covered by tests that run with the Node.js test runner.

Architecture

Rendering
Server Components load data directly on the server. Client Components handle forms, filters, navigation, and the Recharts chart.
Mutations
Server Actions validate input, check the writer, run parameterized SQL, and revalidate affected paths.
Data
MariaDB through a shared mysql2 connection pool. Seven tables with foreign keys, unique constraints, and query indexes.
Auth
Better Auth with email/password, required email verification, password reset, and session revocation on password changes.

What I would build next

  • CSV import and export of transactions.
  • Recurring transactions and monthly budgets per category.
  • End-to-end tests for the main flows with Playwright.

HAVE SOMETHING IN MIND?

Let’s build something
that holds up.

Freelance projects, contract work, or a permanent role. I work remotely from Lithuania, in the EU time zone. Tell me what you are building.

LET’S CONNECT

Start a conversation.

Tell me about your project. I’ll reply to the email address you provide.

Your details are used to respond to your enquiry.