- Recurring invoices: schedule-based auto-generation with CRUD UI at /dashboard/invoices/recurring and POST /api/cron/generate-recurring cron endpoint
- Public invoice link: generate/revoke shareable /i/[token] page for unauthenticated clients with PDF download
- Live time tracker: localStorage-persisted timer widget in invoice editor that appends a line item on stop (rounds to nearest 0.25h)
- Partial payment tracking: record payments per invoice, auto-mark paid when fully covered, balance due display
- Send reminder: email reminder via Resend with custom message dialog and last-sent indicator
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CardContent defaults to px-5 pb-4. Tailwind's CSS cascade means pb-4
always wins over the py-0 override, leaving 16px of phantom bottom
padding on all thin toolbar cards. Replaced CardContent with plain divs
carrying the intended py-2 px-3 directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Description field now shows a fuzzy-matched dropdown of past line items
(description, hours, rate) as you type via Fuse.js — zero server cost
- Selecting a suggestion pre-fills description, hours, and rate in one click
- NL quick-add bar lets you type e.g. "3hrs web design @120" + Enter to
append a fully-parsed line item without clicking through fields
- New tRPC query `getLineItemHistory` returns deduplicated past line items
for the current user, ordered by recency
- New `parseLineItem` utility handles hours/rate extraction via regex
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove two-column hero layout. Page is now a compact centered card:
logo, "Welcome back" heading, email/password form, and footer links.
Eliminates the left panel background mismatch issue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Auto-derive trusted origin from AUTHENTIK_ISSUER URL so OAuth callbacks
are accepted without requiring a separate AUTHENTIK_ORIGIN env var
- Remove leftover ssoProvider schema mapping (no longer used with genericOAuth)
- Remove dead @better-auth/sso dependency from package.json
- Drop md:shadow-2xl/md:shadow-lg from auth cards — the downward box-shadow
was rendering as a U-shaped border (bottom+sides, no top); border +
backdrop-blur-xl provides sufficient visual separation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Implemented `AdministrationContent` component for managing account roles.
- Created `AdministrationPage` to serve as the main entry point for administration tasks.
- Added PDF preview functionality with `PdfPreviewFrame` component for invoice generation.
- Introduced `InputColor` component for advanced color selection with various formats.
- Established color conversion utilities in `color-converter.ts` for handling color formats.
- Defined appearance-related schemas and types in `appearance.ts` for consistent theme management.
- Cleaned up imports and formatted code for better readability in invoices-data-table.tsx.
- Enhanced invoice interface definitions for clarity.
- Improved toast messages for bulk delete and update actions.
- Refactored date formatting and status type retrieval for better readability.
- Simplified template management in templates page, extracting TemplateList component.
- Added registration toggle based on environment variable DISABLE_SIGNUPS.
- Updated navbar to conditionally render registration link based on allowRegistration prop.
- Enhanced error handling and validation in expenses and settings routers.
- Improved PDF export footer handling.
- Updated TRPC react integration for cleaner type imports.
- Deleted the InvoiceView component to streamline the codebase.
- Updated EmailPreview and SendEmailDialog components to include currency and notes fields.
- Enhanced invoice-form to handle default hourly rates and improved item mapping.
- Refactored email template generation to include notes and currency formatting.
- Adjusted API routers for invoices to calculate totals and handle notes and currency correctly.
- Deleted the start.sh script for container management.
- Added AGENTS.md for project guidelines and development principles.
- Introduced new SQL migration files for user appearance preferences and platform settings.
- Implemented appearance provider to manage user interface themes and preferences.
- Created branding utility to define and manage branding-related constants and types.
Co-authored-by: Copilot <copilot@github.com>
- Add taxDeductible boolean to expenses schema + migration 0002
- Update expenses router, form, and list to support tax-deductible flag
- Fix invoice-view tax calculation (was hardcoded $0.00; now uses taxRate)
- New Tax Summary tab in Reports: year selector, income/deductions breakdown,
SE tax + federal income estimates, quarterly bar chart
- CSV export for accountant with income + expense rows and tax summary
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
The previous baseline blindly recorded all migrations as applied.
Now on startup the script validates every recorded migration against
the actual schema; any entry whose schema changes don't exist is
deleted so migrate() will re-run that migration.
This unblocks the existing deployment where 0001 was recorded as done
but beenvoice_client.currency was never actually added.
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
Previously the baseline marked ALL migrations as done, causing 0001 to
be skipped even on databases that didn't have the currency column yet.
Now each migration is checked against a sentinel column/table before
being seeded into the tracking table. Migrations whose changes don't
exist yet are left out so migrate() runs them normally.
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
When switching from db:push to db:migrate on an existing database,
the migration table is empty so Drizzle tries to re-run all migrations,
failing with "relation already exists".
Detect this case (tables exist but no migration history) and seed the
__drizzle_migrations tracking table with all current migrations so
Drizzle treats them as already applied. Future migrations run normally.
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
- Remove drizzle/*.sql and drizzle/*-journal from .dockerignore so
migration files are included in the Docker build context
- Restore next/font/google imports (removed prematurely due to local
IP being 403'd by Google Fonts; production builds should work fine)
- Update CSS font fallbacks to use proper system font stacks
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
- Move EXPENSE_CATEGORIES to ~/lib/expense-categories.ts to break
server router import chain from client component
- Use inline import() types in trpc/react.tsx to prevent Turbopack
from including server modules (pg, db) in the client bundle
- Replace next/font/google with system font stacks to fix build
failures in environments without Google Fonts access
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
Migrations:
- drizzle.config.ts: add out: './drizzle' so drizzle-kit generate writes
SQL migration files instead of only supporting push
- drizzle/0000_glossy_magneto.sql: initial migration capturing all 9
current tables (users, accounts, sessions, verification_tokens,
sso_providers, clients, businesses, invoices, invoice_items)
- src/server/db/migrate.ts: programmatic runner using drizzle-orm's
migrate() — tracks applied migrations in __drizzle_migrations,
safe to run on every deploy
- package.json: db:migrate now runs the programmatic runner instead of
drizzle-kit migrate (CLI requires devDeps at runtime)
- start.sh: replace drizzle-kit push with bun src/server/db/migrate.ts
- Dockerfile: copy drizzle/ folder into the runner image so migrations
are available at container startup
Mobile fixes:
- data-table.tsx: pagination buttons grow from 32px to 40px on mobile
(h-10 w-10 md:h-8 md:w-8) to meet 44px touch-target guidelines
- floating-action-bar.tsx: stack left-content + action buttons to column
layout on narrow screens (flex-col sm:flex-row), reduce padding on
mobile (p-3 sm:p-4)
- revenue-chart.tsx: responsive chart height (h-48 md:h-64) so the chart
doesn't consume too much vertical space on small screens
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
- README: fix auth (better-auth), database (PostgreSQL), env vars,
Docker setup, and feature list to reflect actual implementation
- InvoicesDataTable: show status badge + amount inline on mobile
(previously hidden behind sm: breakpoint, leaving mobile users
with no financial or status info at a glance)
- InvoiceItemsTable: hide Date/Hours/Rate columns on mobile and
fold that info into the Description cell as secondary text
- invoice-view.tsx header card: wrap to column layout on mobile
so status/amount/button don't overflow narrow screens; also
improve item rows to show date, hours, and rate as subtext
https://claude.ai/code/session_012sqEgNQpx676isepeoX4Mi
- Add cache invalidation after invoice create/update mutations
- Properly invalidate both getById and getAll queries
- Prevents stale data from being displayed after saving
- Fixes flaky behavior where updates didn't appear immediately
- Create types.ts with proper TypeScript interfaces for dashboard data
- Replace all 'any' types in dashboard/page.tsx with DashboardStats and RecentInvoice
- Fix type safety in invoice-form.tsx:
- Replace 'any' in updateItem with proper union type
- Add generic type parameter to updateField for type safety
- Fix status type assertion (any -> proper union type)
- Replace || with ?? for safer null handling
- All TypeScript compilation errors resolved
- Lint down to 1 warning (false positive for 'loading' variable)