Commit Graph

65 Commits

Author SHA1 Message Date
grabowski bbfab9faaa Add expense invoice fields, sales tables, and Paperless env vars
Expenses now have invoiceFileUrl, invoiceFileName, paperlessUrl,
paperlessDocumentId for supplier invoice attachment.

New expense_packages junction links expenses to multiple packages.

New sales + sale_line_items + sale_packages tables for income tracking
with per-line tax rate and per-sale withholding rate.

Added saleStatusEnum and 4 audit events: expense_invoice_uploaded,
sale_created, sale_confirmed, sale_voided.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 11:51:18 +07:00
grabowski 84c8beca15 Auto-refresh FX rates daily from fawazahmed0/exchange-api
Deploy to LXC / deploy (push) Successful in 1m56s
Validate / validate (push) Successful in 33s
Scheduler checks every 15min; if 24h since last FX refresh, fetches
rates for all foreign-currency accounts and updates fxRateToBase.
Uses CDN primary + Cloudflare fallback with 10s timeout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:36:17 +07:00
grabowski 34b1524d3a Add FX rate per account, convert foreign balances to base currency in budget
Deploy to LXC / deploy (push) Successful in 1m55s
Validate / validate (push) Successful in 34s
Accounts now have fxRateToBase (default 1.0). The budget total query
multiplies each transaction by the account's rate, so a USD account
with rate 34.5 contributes correctly to the THB-denominated budget.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:24:00 +07:00
grabowski bc0699a992 Derive total budget from account balances instead of manual field
Deploy to LXC / deploy (push) Successful in 1m55s
Validate / validate (push) Successful in 38s
Total budget is now sum(account transaction amounts) across all
non-deleted accounts. Removed the manual 'Add Budget' action and form.
Budget page is now read-only for the total; allocations still work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:16:05 +07:00
grabowski 283f0d4dd1 Add invoice linking on expenses: optional FK, dropdown on add form, clickable chip
Deploy to LXC / deploy (push) Successful in 1m56s
Validate / validate (push) Successful in 32s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:46:20 +07:00
grabowski 0710d63cc1 Add inline expense form on expenses tab with company-wide (General) option
Deploy to LXC / deploy (push) Successful in 1m56s
Validate / validate (push) Successful in 37s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:26:18 +07:00
grabowski 5ff4f07ff4 Add invoice void with ledger reversal, required reason, and voided badge
Deploy to LXC / deploy (push) Successful in 1m56s
Validate / validate (push) Successful in 48s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 15:18:35 +07:00
grabowski 0906a448b3 Add procedure instance detail with step completion and auto-complete
Deploy to LXC / deploy (push) Successful in 1m55s
Validate / validate (push) Successful in 33s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:58:10 +07:00
grabowski 65cee9855c Add procedures templates, step management, and nav tab
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:51:29 +07:00
grabowski f1dd6877f6 Add procedures schema: templates, steps, instances, 7 audit events
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:47:36 +07:00
grabowski 8a23a849da Fix CSP: allow unsafe-inline scripts for SvelteKit hydration
Deploy to LXC / deploy (push) Successful in 1m56s
Validate / validate (push) Successful in 38s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:32:12 +07:00
grabowski b4eda2d553 Fix security audit findings: auth scoping, OIDC hardening, CSP, file download
Deploy to LXC / deploy (push) Successful in 1m56s
Validate / validate (push) Successful in 33s
C3: Budget allocation now verifies project belongs to company
M4: Expense approve/reject scoped by company via project join
H2: OIDC cookies get secure flag on HTTPS
H3: OIDC auto-link only when email_verified by provider
H4: Content-Security-Policy + X-Content-Type-Options in hooks
M7: SSRF favicon redirect depth capped at 3
M2: File downloads use attachment disposition (not inline)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:18:28 +07:00
grabowski dbfd229ba8 Link service accounts to recurring bills with dropdown and display chip
Deploy to LXC / deploy (push) Successful in 2m1s
Validate / validate (push) Successful in 35s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 13:58:43 +07:00
grabowski 1ce614186d Add service accounts page with CRUD, filter pills, and nav tab
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 13:52:33 +07:00
grabowski 493ffa4097 Add service accounts schema, enum, audit events, recurringBills FK
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 13:49:16 +07:00
grabowski a1fffebbf6 Add CI/CD deploy setup doc
Validate / validate (push) Successful in 31s
Deploy to LXC / deploy (push) Successful in 1m55s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:52:46 +07:00
grabowski 1fed8ee920 Add Gitea Actions deploy workflow
Mirrors the buildfor_life_repair workflow: SSH into LXC, reset working
tree, pull, npm ci, build, db:push, restart the buildfor-life-budget
systemd service, health-check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:49:33 +07:00
grabowski 639c261995 Regenerate deployment architecture diagram via beautiful-mermaid
Validate / validate (push) Successful in 30s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:42:08 +07:00
grabowski 5451a591ad Add deployment doc: Caddy + Tor + Yggdrasil + NetBird + external TLS proxy
Validate / validate (push) Successful in 32s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:36:49 +07:00
grabowski fef69b653c Add inline rename/edit on project detail page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:09:52 +07:00
grabowski 57f3d42133 Redesign company overview: 4 compact KPIs, side-by-side projects + recent expenses
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:06:19 +07:00
grabowski f51e156539 Restructure company nav: 8 primary tabs + HR/Ops/Admin dropdowns with active highlight
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:59:25 +07:00
grabowski 03526ff3b9 Restore pointer cursor on buttons (Tailwind v4 Preflight reset)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:35:46 +07:00
grabowski b43924f527 Add recurring bills UI with full CRUD, filters, overdue highlight, amount override
Validate / validate (push) Successful in 33s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:23:53 +07:00
grabowski b611207d25 Add recurring bills poster, scheduler boot, and manual run stub
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:17:38 +07:00
grabowski bd87cd09f5 Add recurring bills schema and cycle math helper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:13:38 +07:00
grabowski 70bb5954a0 Make entire account card clickable to open detail
Stretched-link pattern: absolute-positioned overlay anchor covers the
card; action controls (edit/archive/delete + inline forms) get
`relative z-10` so they float above and stay clickable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:25:03 +07:00
grabowski c1a575241f Fix zero balance on accounts list page
The correlated subquery in the SELECT was returning 0 for every row.
Replaced with a separate grouped-sum query joined in JS — same data, more
reliable SQL generation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:17:33 +07:00
grabowski 77c5d72e43 Reconciliation link, account CSVs in export, drop legacy bank/card tables
Validate / validate (push) Successful in 31s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:06:53 +07:00
grabowski 0d4fdb6fd7 Add account detail page with transaction history, filters, and CSV export
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 13:58:44 +07:00
grabowski 3a095851e9 Auto-post expenses and invoice payments to accounts ledger
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 12:04:15 +07:00
grabowski d75fe6ed95 Add opening balance, manual transactions, and cross-currency transfers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:54:10 +07:00
grabowski aea6dbc06e Add accounts list page with CRUD, Accounts nav tab, profile deprecation banner
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:50:40 +07:00
grabowski 57e72e5b6c Add companyAccounts schema, ledger helper, legacy migration script
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:34:57 +07:00
grabowski 2c2353e2e7 Wire favicon fetch and refresh action into links page
Validate / validate (push) Successful in 27s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:56:31 +07:00
grabowski 1ef68a4d0d Add personal bookmarks CRUD on links page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:54:11 +07:00
grabowski ca0335671c Add company links page with CRUD and Links nav tab
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:49:04 +07:00
grabowski 84a98efd6e Add companyLinks schema, favicon helper with SSRF guard, URL validator
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:45:08 +07:00
grabowski 5d9c0f0249 Add Documents tab and include document metadata in financial export
Validate / validate (push) Successful in 26s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:11:54 +07:00
grabowski 2489b092af Add document detail page with versions and download endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:10:41 +07:00
grabowski a198bae9be Add company documents list and upload page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:59:50 +07:00
grabowski f69313bf33 Add company documents schema, uploads helper, and env wiring
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:52:06 +07:00
grabowski eceda5f007 Add company bank/cards/addresses to financial export ZIP
Validate / validate (push) Successful in 24s
Three new CSVs in the export bundle, with matching README entries:
- company_bank_accounts.csv
- company_cards.csv (last4 only, joined with linked bank account name)
- company_addresses.csv

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:34:52 +07:00
grabowski 504fbadec4 Add Profile tab to company nav
Visible to admin, manager, and accountant. Placed between
Integrations and Export so the broader-audience tab appears first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:32:44 +07:00
grabowski 7d58a1a1c6 Add company Profile page with bank accounts, cards, and addresses
New /companies/[id]/profile route. Single page, three sections:

Bank Accounts:
- Table view with masked account numbers (••••1234)
- Add form (always-on inline) with bank, account holder, number,
  type, branch, SWIFT/BIC, IBAN, currency, primary toggle, notes
- Inline edit row (admin only) and Set Primary / Remove actions
- Audit log: bank_account_added/updated/removed

Cards:
- Add form gates input to last 4 digits (maxlength=4 + regex)
- Amber warning: "Last 4 digits only — never enter full PAN"
- Optional link to a bank account
- Brand select (Visa/Mastercard/Amex/JCB/UnionPay/Discover/Other)
- Audit log: card_added/removed (no edit — remove + re-add)

Addresses:
- Type enum (Legal/Shipping/Billing/Other) with type-coloured badges
- Grouped by type, default flag scoped per type
- Full Thai address fields plus contact person/phone
- Inline edit per row, Set Default per type, Remove
- Audit log: address_added/updated/removed

Read access: admin/manager/accountant. Edit: admin only.
All forms use enhance with reset:false to preserve state on error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:31:24 +07:00
grabowski 92a07685b0 Add company profile schema (bank accounts, cards, addresses)
Three new per-company tables backing the upcoming Profile page:

- company_bank_accounts: bank/account name, account number, type,
  branch, SWIFT/BIC, IBAN, currency (default THB), isPrimary,
  isActive, notes
- company_cards: brand (visa/mastercard/amex/jcb/unionpay/discover/
  other), last4 (varchar(4)), cardholder, expiry month/year,
  nickname, optional FK to a bank account. Stores ONLY last 4
  digits — never the full PAN, to avoid PCI-DSS scope.
- company_addresses: type enum (legal/shipping/billing/other),
  label, recipient, full Thai address fields (subdistrict/district/
  province/postal code), country defaulting to Thailand, contact
  person + phone, isDefault, notes

Eight new audit events in companyLogEventEnum cover add/update/
remove operations on each. Page UI and export integration follow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:15:56 +07:00
grabowski 51e8cfc536 Include personal/address/emergency columns in financial export employees.csv
Validate / validate (push) Successful in 25s
Extends the employees.csv builder to include all 14 new fields
(DOB, gender, nationality, marital status, full Thai address,
emergency contact). Order matches the on-screen detail page so
auditors and accountants get the complete record.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:02:17 +07:00
grabowski f12c901a97 Show personal/address/emergency on employee detail and in edit modal
Detail page now has three new cards beneath the main employee block:
- Personal: DOB (with computed age), gender, nationality, marital status
- Address: combined one-line address plus a labelled grid for the
  Thai-specific subdistrict/district/province/postal code parts
- Emergency Contact: name, phone, relationship

Edit modal extends with matching sections so HR/admin can update
all 14 new fields. updateEmployee server action passes the new
fields through to the employees table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:01:09 +07:00
grabowski f222ac3989 Add personal/address/emergency sections to new-employee form
Three new form blocks slot in between Tax & Bank and Salary:

- Personal: date of birth, gender (select), nationality (defaults
  to Thai), marital status (select)
- Address: line 1/2, subdistrict (Tambon), district (Amphoe),
  province (Changwat), postal code, country (defaults to Thailand)
- Emergency Contact: name, phone, relationship

Server action pulls each new field from formData (all optional)
and includes them in the employees insert.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:58:38 +07:00
grabowski ed98aefecd Add personal, Thai address, and emergency contact columns to employees
14 new nullable columns on the employees table:

Personal:
- dateOfBirth, gender, nationality, maritalStatus

Address (Thai-specific):
- addressLine1, addressLine2, subdistrict (Tambon),
  district (Amphoe), province (Changwat), postalCode, country

Emergency contact:
- emergencyContactName, emergencyContactPhone,
  emergencyContactRelationship

All nullable to leave existing rows intact. Constrained sets
(gender, marital status) live in the UI selects rather than
pgEnums for flexibility. Form/UI/export updates follow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:56:48 +07:00