- Updated README and documentation to reflect the transition from MinIO to Garage for S3-compatible storage.
- Removed the MinIO-specific docker-compose files and replaced them with Garage configurations.
- Adjusted environment variables and service dependencies in docker-compose files to accommodate Garage.
- Modified application code to log hints for Garage instead of MinIO.
- Ensured all references to MinIO in the codebase and documentation are replaced with Garage.
Link clocked time to invoice items with bidirectional sync, add entry editing on web, broaden session cookie detection for Expo clients, and handle API rate limits without signing users out.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show a disabled-registration state on the register page when DISABLE_SIGNUPS is true (default), document docker-deploy.sh with git-SHA image tags, and align onboarding progress circles and labels on a shared grid.
Co-authored-by: Cursor <cursoragent@cursor.com>
Move invoice import configuration into settings, redesign the import flow with shared components and sample templates, document the demo account in README, and polish upload and button styling.
Co-authored-by: Cursor <cursoragent@cursor.com>
Drop file fetches and embedded fonts that fail during static OG generation; use default ImageResponse typography instead.
Co-authored-by: Cursor <cursoragent@cursor.com>
Refresh onboarding wizard and shell, tighten invoice edit/detail flows, align timer widgets with the redesigned clock panel, and assign admin role on first signup.
Co-authored-by: Cursor <cursoragent@cursor.com>
Shared layout, tabs, and sidebar timer; user onboarding and registration polish; settings danger zone and data export; chart and tRPC perf fixes; migrations for onboarding and dropped appearance columns.
Co-authored-by: Cursor <cursoragent@cursor.com>
Give the landing, legal, and sign-in flows a consistent product shell while keeping marketing pages free of tRPC/session calls, fixing dev auth URL handling, and refreshing env and deploy docs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Use FormData and server-side sign-in after register, trust proxy origins for reverse-proxy deploys, pass public URL build args in Docker, and clarify that git pull plus up -d --build is required to ship code and run pending migrations.
Co-authored-by: Cursor <cursoragent@cursor.com>
Route web registration through authClient.signUp.email, set explicit better-auth baseURL/secret for Docker, and harden the mobile register API with safeParse and readable validation messages.
Co-authored-by: Cursor <cursoragent@cursor.com>
Parse DISABLE_SIGNUPS and related env booleans correctly for Compose string values, and derive auth trustedOrigins from BETTER_AUTH_URL. Rewrite README and architecture docs with the git.soconnor.dev remote and accurate deployment guidance. Allow zero-line-item draft invoices with validation when sending email.
Co-authored-by: Cursor <cursoragent@cursor.com>
Combine clients and businesses under entities, polish the web time clock,
and show live invoice PDF preview with tighter line-item editing.
Co-authored-by: Cursor <cursoragent@cursor.com>
0015 was already marked applied with the wrong column name, so redeploys
skipped it; 0016 drops send_reminder_at and adds sendReminderAt.
Co-authored-by: Cursor <cursoragent@cursor.com>
Use camelCase sendReminderAt to match existing invoice columns; the
snake_case name caused dashboard queries to fail after deploy.
Co-authored-by: Cursor <cursoragent@cursor.com>
Restrict line item edits to draft invoices, auto-create drafts on clock-out,
and add sendReminderAt scheduling with dashboard due reminders.
Co-authored-by: Cursor <cursoragent@cursor.com>
Privacy Policy and Terms now share a document layout with table of contents,
plain-paragraph copy, and beenvoice.soconnor.dev contact details for App Store review.
Co-authored-by: Cursor <cursoragent@cursor.com>
Returns whether Authentik and signups are enabled so the app can show the right
sign-in options per instance at runtime.
Co-authored-by: Cursor <cursoragent@cursor.com>
Extract privacy and terms content into reusable components, replace auth modals with links to /privacy and /terms, add settings legal section, and remove duplicate legal-modal markup.
Co-authored-by: Cursor <cursoragent@cursor.com>
Enable session-based auth from the Expo companion app via SecureStore cookies and trusted deep-link origins.
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary cards now include the in-progress session's hours and earnings,
rounded up to the nearest 15-min increment (matching clock-out billing
logic). A secondary "+Xh est." line appears below each stat when a timer
is active, updating every second as the elapsed counter ticks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add time_entries_update, time_entries_delete, time_entries_get_summary tools
- Fix textResult to use `data ?? null` so JSON.stringify always returns a
string — procedures returning undefined (e.g. getRunning with no timer,
businesses.getById not found) were dropping the text field from the MCP
content item, causing client SDK validation failures
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
next build with output:standalone does not automatically copy
.next/static or public into .next/standalone/. The standalone
server.js looks for them at __dirname/.next/static and
__dirname/public, so they must be copied there post-build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Turbopack disallows ssr:false in Server Components. Extracted the three
recharts dynamic imports into charts-client.tsx ("use client"), which
page.tsx now imports from directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dynamically import recharts components with ssr:false to prevent
server-side rendering of DOM-dependent charts, eliminating the
width/height -1 warnings and redacted SSR errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The baseline/bogus-entry logic was a one-time workaround for a db:push
→ migration transition that is long past. It required a per-migration
isMigrationApplied case — missing cases caused today's invoiceId bug.
Now both db:migrate (dev) and Docker startup use the same standard
migrate() call. Drizzle's own tracking table handles idempotency.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Baseline logic was falling through to false for all migrations after
0008, causing incorrect behaviour on fresh deploys. Now correctly
detects api_keys table, time_entry table, invoiceId column, and
verification token value column type.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a banner below the page header when a timer is running: shows
description, client, elapsed time (live), a Stop button that auto-links
to the latest invoice, and a Details link to the time clock page.
Query is prefetched server-side so the widget is instant on load.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Clock out and manual entry creation now auto-add a line item to the
client's latest draft/sent invoice and return invoice info
- Time clock page shows invoice badge on each entry with a link
- Toast after clock-out/create includes "View Invoice" action when linked
- MCP time_clock_in now accepts optional startedAt for backdating
- MCP time_clock_out description updated to document invoice linking
- Migration 0012: widen beenvoice_verification_token.value to text to
fix varchar(255) overflow during Authentik PKCE OAuth flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
drizzle-kit migrate exits 0 even when migrations fail, so the server
would start on a broken schema. The custom migrate.ts uses drizzle-orm's
programmatic migrator and calls process.exit(1) on failure, which
prevents the server from starting and makes failures visible in Coolify.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Migration now runs at container start (when DB is available) rather than
during the build stage (when no DB is reachable). The release image now
includes node_modules, drizzle.config.ts, and the drizzle/ folder so
drizzle-kit can apply pending migrations on each deploy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NEXT_PUBLIC_ vars are baked in at build time, so NEXT_PUBLIC_APP_URL=localhost
was being embedded in the bundle. Removing baseURL lets better-auth use
window.location.origin automatically, which works correctly on any domain.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PostgreSQL does not support IF NOT EXISTS for ADD CONSTRAINT. Use PL/pgSQL
DO blocks to guard constraint creation idempotently instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds invoice_payment, recurring_invoice, recurring_invoice_item tables and
publicToken/lastReminderSentAt/invoicePrefix columns to invoice. Uses
IF NOT EXISTS guards since invoicePrefix may have been applied via db:push.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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 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)
- Remove unused imports from page.tsx, clients/page.tsx, invoices/page.tsx
- Remove unused imports from invoice-form.tsx, invoice-workspace.tsx
- Move CustomTooltip outside component in revenue-chart.tsx (fixes react-hooks/static-components)
- Fix type safety in umami.ts (any -> unknown)
- Fix type safety in sidebar-provider.tsx (add type assertion)
- Add no-op comments to empty fallback functions in animation-preferences-provider.tsx
- Fix type safety in invoice-workspace.tsx (any[] -> typed array)
Note: dashboard/page.tsx still has ~55 type safety warnings related to 'any' types
in stats/invoice data. These are pre-existing and would require significant refactoring
of the dashboard data flow to properly type. TypeScript compilation passes.
- Remove unused imports from invoice-form.tsx, sidebar.tsx, dashboard-shell.tsx
- Remove unused imports from dashboard.ts and calendar.tsx
- Fix unused parameter in invoice-calendar-view.tsx with underscore prefix
- Fix type-only import for DayButton in calendar.tsx
- All typecheck errors resolved
- Remaining lint errors are in unmodified files (pre-existing)
- Remove clock icons and hour text from calendar month view, show only activity bars
- Fix calendar week view mobile layout (2-column grid instead of vertical stack)
- Update invoice form skeleton to match actual layout structure
- Add client-side validation for empty invoice item descriptions with auto-scroll to error
- Fix hourly rate defaulting logic with proper type guards
- Update invoice details skeleton to match page structure with PageHeader
- Fix hydration error in sidebar (div inside button -> span)
- Improve dashboard chart color consistency (draft status now matches monthly metrics)
- Fix mobile header layout to prevent text squishing (vertical stack on mobile)
- Add IDs to invoice line items for scroll-into-view functionality