Commit graph

28 commits

Author SHA1 Message Date
Claude
a5b4ed8389
style: redesign UI to GitHub-esque aesthetic
Replaces the dark-navy nav and blue-tinted palette with GitHub's
design language: #24292f header, canvas-subtle body (#f6f8fa),
d0d7de borders, GitHub's font stack, green primary buttons, blue
accents, uppercase muted table headers, and focus rings.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 17:33:58 +00:00
Claude
4054667b38
Merge feature branch: store-credit webapp 2026-05-30 17:31:39 +00:00
Claude
7b4e33254c
feat: admin-configurable default paper size for receipts/statements
Adds a Paper Size setting (A4/A5) to the General section of Admin
settings. Receipts and statements pre-select the configured size and
apply the correct @page margins; staff can still override per-print.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 17:29:59 +00:00
Claude
6aa4c45616
docs: update all four guides to reflect new features
Covers timezone settings, business address/branding/logo upload,
transfer types, transaction reference prefix, receipt label
localisation, separate charge/cashier footers, three-role system
(POS Staff / Cashier / Admin), five-option overdraft policy,
per-member overdraft override, withdrawal transaction type,
and manage.py CLI (reset-admin, reset-db).

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 17:12:09 +00:00
Claude
ea03355743
Add manage.py CLI for password reset and database wipe
Two commands, run from the server terminal:

  python manage.py reset-admin
    Interactively select an admin account and set a new password.
    The app does not need to be stopped first (SQLite WAL handles
    concurrent access safely). Existing sessions remain valid until
    they expire (8 h); restart the app to invalidate them immediately.

  python manage.py reset-db
    Deletes clubledger.db plus any -wal/-shm sidecar files.
    Requires the app to be stopped first. After restart the app
    recreates a fresh database with the default admin/admin account.
    Asks the user to type RESET to confirm before deleting anything.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 17:02:40 +00:00
Claude
b1fcc3dbe9
Add configurable display timezone; default to server's local timezone
- _server_timezone(): detects IANA timezone from /etc/timezone or
  /etc/localtime symlink at startup; used as the CONFIG default
- CONFIG: new "timezone" key set to server's detected timezone
- AppSettingsUpdate: new optional timezone field
- _display_tz(), _fmt_dt(), _now_display() helpers: convert stored UTC
  datetimes to the configured timezone for display; falls back to server
  local if the setting is empty or the zone name is invalid
- receipt(): transaction timestamp uses _fmt_dt() instead of raw UTC slice
- statement(): row timestamps and "Generated" line use _fmt_dt()/_now_display()
- Admin settings: Timezone text input (IANA name) in General section
- app.js: loadAdminSettings/saveSettings handle timezone field

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 16:59:54 +00:00
Claude
09df5efb07
Redesign receipts/statement to match spec; add logo upload
Receipts:
- Font size raised to 11pt base (labels 9pt, amounts 13pt bold)
- Each field now shows LABEL (small, uppercase, gray) above VALUE —
  two cells per row in a 1fr/1fr CSS grid, matching the provided samples
- Business header: left column = address lines, right column = Tel/Email/Web
- Charge receipt: STAFF+TRANSACTION / CHARGE+TIME / AMOUNT+BALANCE
- Top-up/Withdrawal receipt: STAFF+TXN / TRANSFER_TYPE+TIME /
  AMOUNT+BALANCE / TRANSFER_TYPE+TRANSFER_REF
- Print button moved into the paper-size controls bar

Statement:
- Reduced from 9 to 7 columns: Date, Reference, Type, Venue, Staff,
  Amount (+/-), Balance — removes the separate Charge/Credit split
- Amount shown as "+ £X.XX" (green) or "- £X.XX" (red)
- Sub-row shows "Transfer type: X — Ref" for top-ups/withdrawals,
  or the note text for charges

Logo:
- New POST /admin/logo endpoint: accepts image upload, saves to
  static/logo.{ext}, auto-updates logo_url setting
- New logo_max_width / logo_max_height config fields (default 200×80px)
- Admin branding section: file upload input + max-width/height fields
- python-multipart added to requirements.txt (needed for file upload)

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 16:55:23 +00:00
Claude
79ae833fa9
Replace literal em-dashes with — HTML entities
Fixes garbled display ("â€"") on Windows where the UTF-8 bytes for U+2014
were being misread as Windows-1252. All em-dash occurrences in index.html,
app.js, and common.js are now expressed as HTML entities.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 16:42:46 +00:00
Claude
4125972b67
Ignore runtime data files (clubledger.db, staff.json)
https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 15:44:56 +00:00
Claude
8616ff1d49
Add business branding, transaction references, and redesigned receipts
- CONFIG: add business address/contact, logo URL+alignment, venue names,
  transaction ref prefix, transfer types list, and 14 localizable receipt
  labels plus per-receipt-type footer fields
- DB: add transfer_type and transfer_ref columns to ledger_entries
  (init_db + migrate_db); fix duplicate return in pos_user
- Pydantic: extend AppSettingsUpdate with all new settings;
  add transfer_type/transfer_ref to TopupRequest and WithdrawalRequest
- /topup and /withdrawal: persist transfer_type and transfer_ref
- /config: return transfer_types as parsed array for frontend dropdowns
- New helpers: _txn_ref(), _logo_html(), _biz_header_html()
- New RECEIPT_CSS with 2-column grid layout; receipt() fully redesigned
  with business header, auto-generated TXN reference, separate charge vs
  top-up/withdrawal layouts; statement() adds Reference column and
  transfer-detail sub-rows
- index.html: Transfer Type + Transfer Reference fields on cashier/
  withdrawal panels; admin settings expanded into organized sections
  (General, Business Address, Branding, Transactions, Receipt Labels,
  Receipt Footers)
- app.js: populateTransferTypes() called on startup and after settings
  save; doTopup/doWithdrawal send transfer fields; clearCashierSelection
  clears new fields; loadAdminSettings/saveSettings handle all new fields

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 15:44:27 +00:00
Claude
21b6791f4c
Move overdraft override to per-member setting on member record
Instead of a per-transaction checkbox at point of sale, the overdraft
override is now a persistent flag on each member, set via the Edit Member
modal by the appropriate role.

Schema:
- members.overdraft_override INTEGER DEFAULT NULL
  (NULL = follow global policy, 1 = explicitly allowed, 0 = explicitly blocked)
- migrate_db(): ALTER TABLE members ADD COLUMN ... for existing databases

Charge logic (combining global policy + member flag):
- never:          always block (member flag ignored)
- always:         always allow (member flag ignored)
- staff_override: allow only if member flag = 1
- admin_override: allow only if member flag = 1 (only admin can set it via UI)
- staff_block:    allow unless member flag = 0 (explicitly blocked)

Edit Member modal:
- Shows "Allow overdraft for this member" for staff_override / admin_override
  (admin_override hidden from non-admins)
- Shows "Block overdraft for this member" for staff_block
- Hidden for never / always policies
- Checkbox state pre-populated from current member.overdraft_override value

Removed the per-transaction barOverrideRow that was added in the previous
commit — it has been superseded by this per-member approach.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 15:08:19 +00:00
Claude
7fa74963b0
Replace overdraft checkbox with 5-option policy dropdown
Policies:
- never            – not allowed (default)
- always           – allowed for all charges
- staff_override   – default no; staff sees checkbox to allow per charge
- admin_override   – default no; only admins see the allow-per-charge checkbox
- staff_block      – default yes; staff sees checkbox to block per charge

Backend:
- CONFIG: allow_negative_balance → overdraft_policy: "never"
- migrate_db(): converts old allow_negative_balance setting in app_settings
  to the equivalent overdraft_policy value on first startup after upgrade
- ChargeRequest: new optional overdraft_override: bool = False
- POST /charge: full policy logic; admin_override enforced server-side
  so a non-admin can't bypass it by sending override=true
- POST /admin/settings: validates policy value before saving

Frontend:
- Admin settings: checkbox replaced by <select> with five options
- Bar form: barOverrideRow (hidden by default); selectBarMember() shows
  it with the right label when policy is staff_override / admin_override
  (admin only) / staff_block; hidden for never and always
- clearBarSelection() resets the override checkbox and hides the row

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 14:39:43 +00:00
Claude
acd8ff3fd0
Add withdrawal feature to cashier tab
Cashiers can process credit withdrawals (cash-back) for members:
- Requires member PIN to authorize
- Always checks sufficient balance (overdraft not allowed for withdrawals)
- Appears as 'withdrawal' type in ledger, statement, and on receipt
- Receipt opens automatically, same as top-up/charge

Backend:
- migrate_db() now also recreates ledger_entries with type constraint
  extended to include 'withdrawal' (existing rows preserved)
- POST /withdrawal endpoint (cashier_user required)
- Receipt label map updated to include Withdrawal

Frontend:
- Cashier tab now shows two panels side-by-side: Top Up and Withdrawal
- Each panel has its own message area so they don't overwrite each other
- Withdrawal panel includes PIN field; top-up panel unchanged

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 14:31:16 +00:00
Claude
68a35e5bff
Split staff role into cashier/pos-staff; fix admin tab visibility
Roles:
- cashier: Members + Cashier (top-up) tabs; POST /topup enforced at API level
- pos-staff: Members + Bar (charge) tabs; POST /charge enforced at API level
- admin: all tabs including Admin panel

Changes:
- migrate_db() recreates staff_accounts with new CHECK constraint and
  converts any existing 'staff' rows to 'pos-staff' on startup
- cashier_user / pos_user FastAPI dependencies added; applied to /topup and /charge
- Role dropdowns in admin panel updated to the three new values
- startApp() hides irrelevant tabs per role on login
- doLogout() resets all tab visibility so the next login starts clean
- fmtRole() formats role names ('pos-staff' → 'POS Staff') in the accounts table

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 14:19:41 +00:00
Claude
803d157d25
Fix login overlay visible on reopen when session is still active
The login overlay lacked the `hidden` class by default, so on every page
load it was visible and blocking the app. On fresh load with a valid session,
boot() skips showLogin() (no submit handler added), leaving the overlay
covering the screen with a non-functional form. Adding `hidden` to the HTML
and explicitly hiding the overlay in startApp() fixes both paths.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 13:42:41 +00:00
4ad77f450c
WINDOWS ONLY
Add batch script to set up virtual environment

Delete if not using Windows.
2026-05-30 20:30:03 +07:00
Claude
4cdfddac38
deployment.md: add Part 7 explaining internet isolation and NAT protection
Explains why NAT already blocks external access by default, what never
to do (port forwarding, reverse proxy, cloud VPS), how to verify from
outside the network, optional binding to local IP only, and Linux ufw
firewall rules. Renumbers old security notes to Part 8.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 12:15:46 +00:00
Claude
034c882425
Add documentation: user, admin, developer, and deployment guides
docs/user-guide.md    – sign-in, Members/Cashier/Bar tabs, receipts, FAQ
docs/admin-guide.md   – everything in user guide plus Admin tab, settings
                        reference, correcting transactions, DB backup/queries
docs/developer-guide.md – stack, project layout, DB schema, settings system,
                        auth system, full API reference, extension guide
docs/deployment.md    – internal network setup for Linux/Mac/Windows:
                        prerequisites, running the server, finding the IP,
                        connecting other devices, auto-start (systemd /
                        launchd / Task Scheduler), static IP, port change,
                        security notes

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 12:10:49 +00:00
Claude
45e10422c8
run.sh: remove --quiet from pip so install errors are visible
https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 11:47:23 +00:00
Claude
e3af023582
Fix run.sh: always run pip install, not only on venv creation
Existing .venv without packages caused ModuleNotFoundError. pip install
is a no-op when everything is already up to date, so always running it
is safe and ensures deps are present.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 11:45:45 +00:00
Claude
8fa3aca85d
Add run.sh to handle venv setup automatically
Creates .venv on first run, installs dependencies, then starts the server.
Subsequent runs skip straight to starting. Avoids externally-managed-environment
errors on Debian/Ubuntu 12+.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 11:42:48 +00:00
Claude
a5c9af1ca6
Add staff auth, admin area, currency decimal input
Auth system
- staff_accounts table: name, username, bcrypt password, role (staff|admin)
- Session tokens in memory (8-hour TTL), httpOnly cookie
- POST /auth/login, /auth/logout, GET /auth/me
- All API endpoints now require a valid session
- Default admin account seeded on first run (admin/admin), printed to console
- Staff name for transactions comes from the session, no more dropdown

Currency input fix
- Amount inputs are now decimal (step=0.01); users enter 1.00 not 100
- Frontend multiplies by cfg.currency_divisor before POSTing
- TopupRequest/ChargeRequest no longer include staff_name (from session)

Admin area (4th tab, admin role only)
- App Settings: club name, currency symbol, major/minor unit names,
  divisor, min/max topup, max charge, receipt footer, allow overdraft
- Settings persisted in app_settings DB table; merged with CONFIG defaults
  at startup and refreshed after each save
- Staff Accounts: list with edit modal (name, username, password, role,
  active flag) and delete; Add Account inline form
- /admin/settings GET/POST, /admin/staff-accounts CRUD
- /config endpoint exposes live settings to frontend on every page load

receipt_footer field rendered on both receipt and statement print views

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 09:19:07 +00:00
Claude
79d51973cd
Remove product search from bar tab
Removed product search field, results list, barProductLookup(),
and selectProduct() from the bar view in index.html, bar.html,
app.js, and bar.js. Backend /products endpoints are unchanged.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 08:52:18 +00:00
Claude
6c155d00bb
Restore three-view SPA; add member edit and delete
- / now serves index.html (three-view SPA: Members, Cashier, Bar)
- /cashier and /bar remain as standalone pages (unchanged)
- Members view: Edit button on every row opens a modal to update
  name, member number, and optionally PIN. Delete button only appears
  when balance is exactly 0; confirmation dialog before deletion removes
  the member and their ledger entries.
- PUT /members/{id}: updates any combination of name/member_number/pin;
  guards against duplicate member numbers.
- DELETE /members/{id}: rejects with 400 if balance != 0, otherwise
  deletes ledger entries then member row.
- Modal styles added to style.css; app.js rebuilt as combined SPA script
  (loads common.js for shared helpers).

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 08:33:44 +00:00
Claude
34b3e88fe2
Fix 1-4: staff dropdown, split pages, print size toggle, receipts
Fix 1: Replace free-text staff name with a dropdown populated from staff.json
  via GET/POST/DELETE /staff endpoints. Staff management panel on cashier page
  (type name, Add button, chip list with × remove). Dropdown remembers last
  selection per session via sessionStorage.

Fix 2: Split single-page app into /cashier (register + top-up + member list +
  staff management) and /bar (charge only). Each page is its own HTML file
  with two plain <a> nav links; / redirects to /cashier. Shared helpers
  extracted to common.js; page logic in cashier.js and bar.js.

Fix 3: Statement view gains an A4/A5 radio toggle that rewrites a dynamic
  <style> @page rule before the browser print dialog opens. Defaults to A4.

Fix 4: POST /topup and POST /charge now return entry_id. Each successful
  transaction opens /receipt/{entry_id} in a new tab — server-rendered HTML
  showing member name/number, type, amount, balance-after (computed as running
  sum up to that entry), staff, note, timestamp. Same A4/A5 print toggle.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 06:28:54 +00:00
Claude
7af0dd0496
Fix on_event deprecation, use lifespan handler
FastAPI 0.93+ deprecates @app.on_event; replaced with @asynccontextmanager
lifespan pattern. Also cleaned up unused stdlib imports.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 06:00:34 +00:00
Claude
fa4884bdb4
Add store-credit web app (FastAPI + SQLite)
- main.py: single-file backend with Member, LedgerEntry, Product models;
  endpoints for register, list/search members, topup (cashier), charge (bar,
  PIN-verified), transaction history, printable HTML statement, product CRUD.
  All monetary values stored as integers (pence). bcrypt PIN hashing.
  Admin-tunable CONFIG dict at top of file.
- static/index.html + style.css + app.js: three-view SPA (Members, Cashier,
  Bar) with member search, product search with member-price support, and
  XSS-safe rendering throughout.
- requirements.txt: fastapi, uvicorn, bcrypt only.

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 05:21:01 +00:00
68f3ae1538
Initial commit 2026-05-30 12:01:08 +07:00