Skip to content

Repository files navigation

💰 Book-it-quick

Personal Online Bookkeeping System — Enterprise-grade financial management for the modern web.

Spring Boot Vue Java MySQL License Status i18n

Built during an intensive 2-week Software Production Internship at Shandong University of Science and Technology — a closed-loop personal finance assistant that puts data integrity and enterprise architecture above floating-point shortcuts.


📑 Table of Contents


🌟 Overview

Book-it-quick is a full-stack, enterprise-grade personal financial management system designed from the ground up to eliminate floating-point arithmetic errors and provide users with a highly intuitive, secure, and automated dashboard for tracking income, expenses, savings goals, and passive subscriptions.

The project was developed end-to-end during a fast-paced, two-week Software Production Internship at Shandong University of Science and Technology, where the goal was to ship a closed-loop financial assistant — capture, classify, visualize, and automate — backed by production-quality patterns (stateless auth, soft delete, scheduled jobs, RBAC, and a clean REST boundary).

🎯 Design Pillars

Pillar What it means in practice
Data Integrity BigDecimal end-to-end, DECIMAL(15,2) in MySQL, no double anywhere near money.
Security by Default BCrypt hashing, JWT access tokens, hashed & rotated refresh tokens, denylist, rate limiting, RBAC.
Automation Spring @Scheduled jobs for recurring bills, currency sync, trash cleanup, and token pruning.
User-First UX Element Plus, dark mode that persists, 5-locale i18n, real-time ECharts dashboards.
Enterprise Hygiene Soft-delete + Recycle Bin, idempotent migrations, structured logging, layered exceptions.

✨ Key Features

🔐 Security & Authentication

  • Stateless JWT authentication with io.jsonwebtoken (HS256), access tokens carrying a unique jti and the user's RBAC role claim.
  • Refresh Token Rotation — long-lived, opaque, server-stored as SHA-256 hashes. Every refresh issues a new pair and chains the old one via replaced_by, so a stolen token is good for one request only.
  • Access-Token Denylistt_token_denylist allows explicit revocation (logout, anomaly, admin force-logout) without sacrificing the stateless API. Rows self-prune once the original access token would have naturally expired (TokenCleanupScheduler).
  • BCrypt password hashing (Spring Security default cost factor).
  • Login Rate LimitingLoginRateLimitService throttles brute-force attempts per IP + username pair with a sliding window.
  • RBACUSER / ADMIN roles, gated with @PreAuthorize("hasRole('ADMIN')") on admin-only routes. First registered user is auto-promoted to ADMIN by the bootstrap migration.

💸 Financial Core

  • High-Precision Ledger — every monetary field is DECIMAL(15,2) in MySQL and BigDecimal in Java; zero floating-point drift across aggregation, conversion, and serialization.
  • Comprehensive Bill Management — full CRUD with pagination, category filtering, date-range queries, and GET /api/bills/page backed by an idempotent composite index on (user_id, bill_date).
  • Recurring Bill Templates — users define monthly templates (Netflix, rent, salary…) and RecurringBillScheduler posts them automatically on the configured day_of_month (clamped 1–28).
  • Monthly Budgets — per-user spending target with real-time burn-down reporting in the Budget view.
  • Smart Categorization — hybrid model: immutable system defaults
    • per-user custom categories with a unique (user_id, type, name) constraint.

🌍 Multi-Currency & i18n

  • Multi-Currency SupportuseCurrency composable + CurrencyScheduler keep a USD → * exchange-rate table fresh; users flip their display currency in the UI and all dashboards recompute instantly.

  • Automated Sync — daily cron at 11:00 Asia/Jakarta upserts supported codes from exchangerate-api.com, with a defensive try/catch so a single network blip never kills the job.

  • Internationalization (i18n)vue-i18n with 5 fully translated locales, switched at runtime via a LanguageSelector component:

    Locale File
    🇬🇧 English src/i18n/locales/en.json
    🇮🇩 Indonesian src/i18n/locales/id.json
    🇯🇵 Japanese src/i18n/locales/ja.json
    🇨🇳 Simplified Chinese src/i18n/locales/zh-CN.json
    🇹🇼 Traditional Chinese src/i18n/locales/zh-TW.json

📊 Visualization & Analytics

  • Real-Time ECharts — interactive pie charts for category distribution and line charts for income/expense trends.
  • Analytics View — time-series aggregations, top-spend categories, and net cash-flow at a glance.
  • Dashboard — KPI cards for income, expenses, balance, and active recurring bills, all in the user's selected currency.

🗑️ Enterprise Patterns

  • Trash / Recycle Bin (Soft Delete) — every "delete" is an UPDATE … SET is_deleted = 1; every read filters is_deleted = 0. The Trash view lets users restore deleted bills, categories, and recurring templates.
  • TrashScheduler — nightly cleanup that hard-deletes rows whose deleted_at is older than the retention window, keeping the table bounded.
  • TokenCleanupScheduler — purges expired refresh tokens and denylist entries past their natural expires_at.
  • Idempotent Migrationsdb-migration.sql uses INFORMATION_SCHEMA guards so it can be re-run safely on any MySQL 5.7+ / 8.x instance.
  • Layered Error Handling@RestControllerAdvice GlobalExceptionHandler maps validation, auth, and domain errors to consistent JSON envelopes.

🎨 UX & Theming

  • Dynamic Theming (Dark Mode) — a useTheme composable drives a pure-CSS-variable theming engine; the ThemeToggle component flips between light and dark and persists the choice in localStorage.
  • Element Plus UI library for accessible, well-tested components (tables, forms, dialogs, date pickers).
  • Pinia for reactive, type-friendly state management across auth, currency, theme, and bill lists.

🛠️ Tech Stack

Frontend

Layer Technology Version
Framework Vue 3 (Composition API) ^3.5.39
Build Tool Vite ^8.1.1
UI Library Element Plus ^2.4.4
State Pinia ^4.0.2
Routing Vue Router ^4.6.4
i18n Vue I18n ^9.14.5
HTTP Axios ^1.7.2
Charts ECharts ^5.4.3
Testing Vitest + @vue/test-utils + jsdom 4.x

Backend

Layer Technology Version
Language Java 25
Framework Spring Boot 3.5.16
Security Spring Security + JWT (io.jsonwebtoken) bundled
Validation Spring Boot Starter Validation bundled
ORM MyBatis 3.0.5
Scheduling Spring @Scheduled (@EnableScheduling) bundled
Build Maven (with ./mvnw wrapper) bundled

Database

Layer Technology Notes
RDBMS MySQL 5.7+ / 8.x utf8mb4_unicode_ci everywhere
Money types DECIMAL(15,2) / DECIMAL(20,8) BigDecimal in Java
Timezone serverTimezone=Asia/Jakarta matches scheduler zone

Tooling & Quality

  • mvnw wrapper for reproducible Maven builds
  • Vitest with v8 coverage for the frontend
  • api-test.http for end-to-end REST smoke tests (IntelliJ HTTP client)
  • Lombok for boilerplate-free DTOs/Mappers

🏗️ Architecture

┌────────────────────────────────────────────────────────────────────────┐
│                          Browser (Vue 3 SPA)                           │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│  │Dashboard │ │  Bills   │ │Analytics │ │  Trash   │ │  Saving  │     │
│  │   View   │ │   View   │ │   View   │ │   View   │ │  Goals   │     │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘     │
│       └───────────┴────── Pinia stores (auth, theme, currency) ───────┤
│                              │ Axios + JWT Bearer                      │
└──────────────────────────────┼─────────────────────────────────────────┘
                               │ HTTPS / JSON
                               ▼
┌────────────────────────────────────────────────────────────────────────┐
│                 Spring Boot 3.5 REST API  (port 8080)                 │
│                                                                        │
│  SecurityFilterChain  →  JwtAuthenticationFilter  →  Rate Limiter      │
│                                │                                       │
│  ┌──────────────────┐  ┌──────┴───────┐  ┌──────────────────┐         │
│  │  AuthController  │  │ BillController│  │ SavingGoalCtrl   │         │
│  │  CategoryCtrl    │  │ TrashCtrl     │  │ AdminCtrl        │         │
│  └────────┬─────────┘  └──────┬───────┘  └────────┬─────────┘         │
│           └──────────────────┬┴───────────────────┘                   │
│                              │                                         │
│              GlobalExceptionHandler  (RFC-7807-style envelopes)        │
│                              │                                         │
│   ┌──────────────────────┐   │   ┌──────────────────────────────┐      │
│   │   MyBatis Mappers    │   │   │  @Scheduled Cron Jobs        │      │
│   │  (User, Bill, Goal,  │   │   │  • CurrencyScheduler   11:00 │      │
│   │   Category, Token…)  │   │   │  • RecurringBillSched  00:05 │      │
│   └──────────┬───────────┘   │   │  • TrashScheduler      03:00 │      │
│              │               │   │  • TokenCleanupSched   04:00 │      │
└──────────────┼───────────────┘   └──────────────────────────────┘      │
               ▼                                                         │
┌────────────────────────────────────────────────────────────────────────┐
│                       MySQL  (db_bookkeeping)                          │
│  t_user • t_bill • t_category • t_recurring_bill • t_saving_goal      │
│  t_refresh_token • t_token_denylist • exchange_rate                    │
└────────────────────────────────────────────────────────────────────────┘

📂 Project Structure

Book-it-quick/
├── 📄 pom.xml                          # Spring Boot / MyBatis / Security
├── 📄 package.json                     # Vue 3 / Vite / ECharts / i18n
├── 📄 db-migration.sql                 # Idempotent schema + seed migrations
├── 📄 api-test.http                    # REST smoke tests
├── 📄 vite.config.js
│
├── 🗂️  src/main/java/.../config/       # Security, JWT, CORS, Schedulers
├── 🗂️  src/main/java/.../controller/   # REST controllers
├── 🗂️  src/main/java/.../service/      # Business logic
├── 🗂️  src/main/java/.../mapper/       # MyBatis mappers (XML in resources)
├── 🗂️  src/main/java/.../entity/       # JPA-style entities
├── 🗂️  src/main/java/.../dto/          # Request/response DTOs
├── 🗂️  src/main/java/.../security/     # Filters, UserDetails, entry points
│
├── 🗂️  src/views/                      # Vue pages
│   ├── Dashboard.vue
│   ├── Bills.vue
│   ├── Analytics.vue
│   ├── Budget.vue
│   ├── Categories.vue
│   ├── SavingGoals.vue
│   ├── Trash.vue
│   ├── Login.vue
│   └── Register.vue
│
├── 🗂️  src/components/                 # Reusable UI (ThemeToggle,
│   │                                   #           LanguageSelector, charts…)
├── 🗂️  src/composables/                # useTheme.js, useCurrency.js
├── 🗂️  src/stores/                     # Pinia stores
├── 🗂️  src/router/                     # Vue Router + auth guards
├── 🗂️  src/i18n/locales/               # en / id / ja / zh-CN / zh-TW
├── 🗂️  src/utils/                      # Axios instance, formatters
├── 🗂️  src/assets/                     # Images, fonts
└── 🗂️  src/test/                       # Vitest unit tests

💻 Installation & Setup

✅ Prerequisites

Make sure the following are installed and on your PATH:

Tool Version
JDK 25
Maven 3.9+ (or just use the bundled ./mvnw)
Node.js v18+ (LTS recommended)
npm v9+ (bundled with Node)
MySQL 5.7+ / 8.x

1️⃣ Database Setup

  1. Create the database (the migration script targets the currently selected DB, so name it however you like — the default is db_bookkeeping):

    CREATE DATABASE db_bookkeeping
        CHARACTER SET utf8mb4
        COLLATE utf8mb4_unicode_ci;
  2. Apply the migration — the file is idempotent and safe to re-run:

    mysql -u root -p db_bookkeeping < db-migration.sql

    This single script creates / patches every table the app needs: t_user, t_bill, t_category, t_recurring_bill, t_saving_goal, t_refresh_token, t_token_denylist, exchange_rate, plus the is_deleted soft-delete columns, the (user_id, bill_date) index, and the role RBAC column.

  3. Configure credentials & API keys in src/main/resources/application.yml:

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/db_bookkeeping?useSSL=false&serverTimezone=Asia/Jakarta
        username: root
        password: YOUR_DB_PASSWORD
    
    app:
      currency:
        api-key: YOUR_EXCHANGERATE_API_KEY
      security:
        jwt:
          secret: CHANGE_ME_TO_A_LONG_RANDOM_STRING

2️⃣ Backend (Spring Boot)

From the project root:

# Build once (downloads dependencies, compiles)
./mvnw clean install

# Run the API
./mvnw spring-boot:run

The backend will start on http://localhost:8080. On first boot the first user registered via /api/auth/register is automatically promoted to ADMIN by the migration's bootstrap step, so you can immediately exercise the admin-only endpoints.

🪟 Windows users: use mvnw.cmd instead of ./mvnw.


3️⃣ Frontend (Vue 3 + Vite)

Open a second terminal in the project root:

# Install dependencies
npm install

# Start the Vite dev server
npm run dev

The SPA will be served on http://localhost:5173. Vite proxies API calls to the Spring Boot backend (see vite.config.js) so no CORS workarounds are required in development.

For a production bundle:

npm run build      # Outputs static assets to dist/
npm run preview    # Locally preview the production build

🔌 API Surface

The backend exposes a clean, versioned REST API under /api. All non-/api/auth/** endpoints require a valid Authorization: Bearer <jwt> header.

Domain Endpoints Purpose
Auth POST /api/auth/register, POST /api/auth/login, POST /api/auth/refresh, POST /api/auth/logout Identity, refresh rotation, denylist writes
Bills GET /api/bills, GET /api/bills/page, POST /api/bills, PUT /api/bills/{id}, DELETE /api/bills/{id} CRUD on financial transactions
Recurring GET /api/recurring, POST /api/recurring, PUT /api/recurring/{id}, DELETE /api/recurring/{id} Monthly auto-posting templates
Budget GET /api/budget, PUT /api/budget Per-user monthly spending cap
Stats GET /api/stats/** Aggregations feeding the ECharts dashboards
Categories GET /api/categories, POST /api/categories, PUT /api/categories/{id}, DELETE /api/categories/{id} User-defined transaction categories
Saving Goals GET /api/saving-goals, POST /api/saving-goals, PUT /api/saving-goals/{id}, DELETE /api/saving-goals/{id} Wishlist / target savings tracker
Trash GET /api/trash/**, POST /api/trash/{id}/restore, DELETE /api/trash/{id} Recycle bin: list, restore, hard-delete
Exchange Rates GET /api/exchange-rates, GET /api/exchange-rates/{code} USD-based rates, refreshed by CurrencyScheduler
Admin (RBAC) GET /api/admin/users, PUT /api/admin/users/{id}/role @PreAuthorize("hasRole('ADMIN')")

📄 For concrete request/response payloads, the repository ships with an api-test.http file — open it in IntelliJ IDEA's HTTP Client or any compatible client to smoke-test every endpoint.


🧪 Testing

Layer Command What it covers
Frontend (unit) npm test Vitest single run
Frontend (watch) npm run test:watch Vitest interactive watch mode
Frontend (coverage) npm run test:coverage v8 coverage report
Backend (manual) Open api-test.http in IntelliJ End-to-end REST flows incl. auth + RBAC

✅ The project is structured for easy extension with @SpringBootTest integration tests on the service layer — see the service/ package seams for entry points.


🚀 Roadmap

  • Bank-feed / CSV import (OFX/QIF) for automatic transaction ingestion
  • Two-factor authentication (TOTP) for ADMIN accounts
  • Email + push notifications when budget thresholds are crossed
  • Predictive cash-flow forecasting using simple time-series models
  • Docker Compose for one-command stack bootstrap (MySQL + backend + frontend)
  • OpenAPI 3.1 spec auto-generated from controller signatures

👨‍💻 Author

Dio Stania Adinata Software Engineer — Game Technology & Software Engineering

Built during the Software Production Internship at Shandong University of Science and Technology.

  • 🌐 Portfolio: [add your link]
  • 💼 LinkedIn: [add your link]
  • 🐙 GitHub: github.com/Rytsia1

📄 License

This project is released under the MIT License — see LICENSE for the full text. You are free to use, modify, and distribute it for personal or commercial purposes, provided the original copyright is retained.


If you found this project useful, consider giving it a ⭐ — it helps more than you know!

Made with ☕, a lot of BigDecimal, and a deep respect for the audit trail.

About

A full-stack web application developed during a two-week software production internship, enabling users to manage personal finances through intuitive bookkeeping tools, data visualization, and budget tracking.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages