# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project status

**No application code exists yet.** This repository currently contains only planning documents:

- `monthly_ledger_blueprint.md` — the complete, approved-pending-review project specification (requirements, DB schema, architecture, security, phased roadmap). This is the source of truth for all design decisions.
- `phases.md` — a condensed cheat-sheet of files created/modified per phase, for quick reference without re-reading the full blueprint.
- `sample.html` — a static, standalone HTML/CSS/JS design mock of the dashboard (Phase 3's target UI). It has no backend; all interactions just show a toast. Useful as the visual/markup reference when building the real `index.php`, but it is a throwaway mockup, not a file to build on top of directly.

There is no `.git` repository, no `composer.json`, no build tooling, and no test suite yet — all of that gets created as part of Phase 1 onward, per the blueprint.

## How work proceeds in this repo

Development is explicitly phased and gated by the user (see blueprint Section 25):

- **Only build one phase at a time, and only when asked** (e.g. "build Phase 1"). Never generate a future phase unprompted.
- Each phase must end with a fully working app — earlier phases must keep working after later ones are added.
- Database changes are **additive only**: later phases never alter or drop tables/columns created by earlier phases, so the user's real test data survives every upgrade.
- If a mid-project design change is needed, reflect it back into `monthly_ledger_blueprint.md` first, so the blueprint stays the single source of truth — don't let code and blueprint drift apart.
- The 11 phases (summarized in `phases.md`, detailed in blueprint Section 25.3) build in this order: Foundation & DB → Auth → Dashboard Core (add/summary/chart) → Edit & Delete → Month Navigation → Search & Filters → Manage & Settings → Budgets → Income & Savings → Reports & Charts → Export/Backup/Go-Live.

## Stack and environment

PHP 8.2+ (no framework), MySQL 8 / MariaDB 10.6+, HTML5/CSS3, vanilla JavaScript, Bootstrap 5.3 (CDN) + Bootstrap Icons (CDN). Runs on local XAMPP (`htdocs/monthly_ledger/` is the web root) and must be portable as-is to typical shared hosting later — no build step, no shell access assumed at runtime, only `includes/config.php` values change between environments.

There is deliberately no framework (see blueprint Section 10.1): two users, ~10 pages, one developer — plain PHP with disciplined conventions instead of a framework's build/update treadmill.

## Planned architecture (once code exists)

**Pattern: page controllers + shared includes + JSON API endpoints**, PHP includes/require-based, no autoloader/router:

- **Page controllers** (`index.php`, `expenses.php`, `reports.php`, …): one file per page. Each file (1) requires auth via `includes/auth.php`, (2) gathers data through helper functions, (3) renders HTML between shared `includes/layout/header.php` / `nav.php` / `footer.php`. Top of file = logic, bottom = template — same shape everywhere.
- **API endpoints** (`api/expense_save.php`, `api/expense_delete.php`, …): small handlers called via `fetch()` so the add/edit/delete loop never reloads the page. Every response is a consistent JSON envelope (success flag + data or error message). Every endpoint independently re-checks auth and CSRF — never trust the browser.
- **Progressive enhancement:** the add-expense form is a real HTML form; with JS it submits via fetch and updates in place, but the same endpoint also accepts a plain POST and does post/redirect/get if JS fails.
- **Core includes** (all under `includes/`, blocked from direct web access by `.htaccess`): `config.php` (credentials + dev/prod flag), `db.php` (one shared PDO connection, exceptions on, prepared statements only — no string-built SQL anywhere), `auth.php` (session + remember-me + login guard), `csrf.php` (token issue/verify), `validation.php` (server-side rules — the real gatekeeper; client-side HTML5/JS validation is just for UX), `helpers.php` (money/date formatting, HTML-escaping shortcut, month math, settings access).

### The core database design decision

**There is no "month" table and no per-month rows for expenses/income.** Every expense/income row carries a real calendar `DATE`; a "month" is just a query filter on that date. This is what eliminates the old Excel "copy file, rename, clear" ritual — months exist because they're on the calendar, not because anything created them. The only genuinely per-month data is the planned `budgets` row (keyed by category + year + month), which auto-copies forward from the previous month on first visit to a new month (idempotent, one-time).

Other standing decisions (blueprint Section 9.1) that any new table/feature should follow:
- Money is always `DECIMAL(10,2)`, never float.
- Categories and payment methods are never hard-deleted, only `is_active`-deactivated, so historical entries keep their labels forever.
- Expenses and income are separate tables (different categories, income has no payment method) but share one `categories` table distinguished by a `type` enum.
- `utf8mb4` + InnoDB throughout.

Full ER diagram and table specs: blueprint Section 9.2–9.3. `database/schema.sql` will always hold the full current schema for fresh installs; each phase that touches the DB also ships an incremental file in `database/migrations/`.

### Planned folder structure

See blueprint Section 11 for the complete annotated tree. Key points: `api/` holds JSON endpoints only; `includes/` (including `includes/layout/`) is never browsed directly (`.htaccess`-blocked); `assets/css/app.css` and `assets/js/app.js` are each a single file, no build step; `database/` holds `schema.sql`, `seed.sql`, and `migrations/`; `logs/` and `backups/` are web-blocked and git-ignored.

## Conventions to follow when writing code here

- Files: lowercase snake_case, one purpose per file.
- Functions: verb-first snake_case (`get_month_expenses`, `format_money`).
- Database access: PDO prepared statements only, always.
- Output: every dynamic value goes through the shared HTML-escaping helper — no exceptions, no raw user input ever rendered as HTML.
- Dates stored as SQL `DATE`, formatted only through one shared helper. Money stored as `DECIMAL`, formatted only through one shared helper that reads the currency symbol from `settings`.
- URLs address months as `?month=YYYY-MM` everywhere (bookmarkable); invalid/malformed values silently fall back to the current month rather than erroring.
- Security is not deferred to a later hardening pass: CSRF tokens on every state-changing form/fetch, password hashing via PHP's standard password hashing API, session ID regeneration at login, split selector/validator remember-me tokens — build these in from Phase 1–2 onward, per blueprint Section 14.
- Currency/locale: this app runs in China — CNY (¥) is the default currency, and category/payment-method seed data, defaults, and copy should assume a Chinese household context (e.g. Alipay/WeChat Pay as default payment methods, Food as the default category) unless the user says otherwise.
