Skip to content
Oswaldo Rodríguez

← All projects

2023Solo developer — API and frontend

Arithmetic Calculator — API + Vue SPA

A JWT-authenticated calculator API with per-operation credits and a Vue 3 SPA on top.

  • Node.js
  • Express
  • PostgreSQL
  • Sequelize
  • JWT
  • Zod
  • Vue 3
  • Vite
  • Pinia
  • PrimeVue

Problem

Most calculator demos are stateless and never answer the harder question: how do you make a compute service multi-user, metered and auditable? I wanted an exercise that forced the real machinery — auth, per-user accounting and a paper trail — not just arithmetic.

The result is an API where each operation has a credit cost charged against the user's balance, and every computation is stored as a record with full pagination, search and audit history.

Approach

Credit-based API, not free compute

Express + Sequelize + PostgreSQL. A catalog of operations (addition, subtraction, multiplication, division, square root, random string) each declares a credit cost. Creating a record runs the operation, charges the cost and stores the resulting balance. Records support pagination, sorting, text search and soft delete — because destroying an audit trail is usually the wrong default.

I rejected stateless compute endpoints: they make usage unaccountable by design, which is exactly the problem the exercise was about.

OpenAPI contract first

The full contract lives in `api_services_v1.yml` (OpenAPI 3.0). Zod validates every request at the boundary, `bcryptjs` hashes passwords, and JWTs authorize the protected routes. Jest + ts-jest cover the API.

I rejected ad-hoc validation scattered through handlers: with a written contract, the Vue UI can be built against the YAML instead of against implementation details.

Vue 3 SPA against the same contract

Vue 3 (Options API) + Vite + Pinia + PrimeVue + Axios. Sign-in stores the JWT locally; a dashboard shows available operations and the balance; a DataTable renders records with pagination, search and soft delete; a 401 response logs the user out and clears the token. Vitest covers the UI.

I rejected putting auth decisions in components: a single Axios interceptor owns the 401 handling, so every screen behaves the same way without knowing about sessions.

Results

  • Both halves are public and CI-tested (GitHub Actions): the API (OpenAPI 3.0 contract, Jest) and the Vue SPA (Vitest + @vue/test-utils).
  • Complete OSS reference for metered, multi-user REST: auth, catalog pricing, immutable-ish audit records and soft delete in one small codebase.