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>
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>
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>
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>
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>
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>
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>
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>
- Replace raw `ANY(${array})` SQL with drizzle's inArray() in
src/lib/server/export/financial.ts; the raw form sent UUID arrays
in a malformed Postgres array literal causing 500 on download
- Add static/favicon.svg (Thai baht symbol on blue square) and point
app.html at it; remove the empty favicon.png
- Redirect /favicon.ico to /favicon.svg in hooks.server.ts so
browsers' implicit fallback request stops 404'ing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New /companies/[id]/export page with year selector and big download button
- GET /export/zip endpoint generates the financial-export-{name}-{year}.zip
by calling buildFinancialExport, then logs financial_exported in
the company audit trail
- New "Export" tab in company nav, visible to admin or accountant
- Page lists all included files and warns about sensitive PII
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Install jszip dependency (~100KB, pure JS)
- New src/lib/server/export/financial.ts builds a year-scoped ZIP
with one CSV per logical table: company, projects, parties (incl
archived), employees (incl terminated), budget_allocations, expenses,
invoices + line items, salary_history (effective on/before year end),
payslips + line items, packages (with carrier label and customs link),
external_transactions (with provider label and matched expense),
company_log
- All CSVs prefixed with UTF-8 BOM for Excel/Thai support
- Reference tables include soft-deleted rows so historical FKs resolve
- Routes and UI to follow in next commit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New 'accountant' role in companyRoleEnum (orthogonal like 'hr')
- meetsMinRole and requireCompanyRole now exclude accountant from
hierarchy along with hr
- Settings UI exposes accountant in the role checkbox lists for both
add-member and edit-member forms
- New 'financial_exported' value added to companyLogEventEnum, ready
for the upcoming export feature
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New /feature-requests route accessible to all logged-in users via sidebar nav
- feature_requests + feature_request_votes tables (one vote per user per request)
- Submit form (modal), upvote toggle, filter by status, sort by votes/newest
- System admins can change status (open / in_review / waiting_for_checks / in_progress / resolved / closed) with optional note
- Submitter auto-votes their own request on creation
- Admin or original submitter can delete a request
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Budget/expense amounts on dashboard, project view, and expenses page
now show white text in dark mode instead of black.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Theme store with localStorage persistence and system preference detection
- Inline script in app.html to prevent flash of wrong theme
- Sun/moon toggle button in top bar and auth pages
- Tailwind v4 dark mode via @custom-variant with class strategy
- Dark mode classes applied to all 20+ pages: sidebar, auth forms,
dashboard, companies, projects, expenses, budget, categories,
reports, import, settings, admin pages, and all modals
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added disabledAt column to users table
- Disabled users are blocked at login and session validation (immediate logout)
- Admin users page shows Active/Disabled status badges
- Disable/Enable toggle button per user (kills all sessions on disable)
- Permanent delete with confirmation modal (removes user, sessions, memberships)
- Self-protection: admins cannot disable or delete themselves
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added deletedAt column to companies table for soft delete
- System admins see a trash icon on each company card with confirmation modal
- Archived companies are filtered from sidebar, dashboard, company list, and direct access
- Audit log entry created on archive
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multi-company budget/project tracking tool built with SvelteKit 5,
PostgreSQL (Drizzle ORM), and Tailwind CSS v4.
Features:
- Auth: local (email/password with Argon2) + generic OIDC
- 4 roles per company: admin, manager, user, viewer
- Multi-company with per-company user membership
- Projects with budget allocation from company pool
- Expense submission with approval workflow
- Categories and tags for expense organization
- Reports with spending breakdowns (by category, project, time)
- CSV import for Actual Budget migration
- Company audit log tracking all budget and admin actions
- Remaining budget hero display on overview and budget pages
- Admin-only company creation; new users wait for invitation
- Deployment configs for systemd + nginx (bare metal/Proxmox)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>