A self-hosted time tracking, invoicing, and expense management app built with Next.js, shadcn/ui, and Supabase.
- Time Tracking — Start/stop timer or manually log hours with per-project billable rates
- Client Management — Store client contact info, assign colors, and set automated invoice schedules
- Project Management — Create projects under clients with custom hourly rates and status tracking
- Expense Tracking — Log expenses by category with automatic invoice linking
- Invoicing — Generate invoices from tracked time and expenses, edit status/tax/notes, preview at PDF scale
- Calendar View — Monthly overview of earnings, expenses, and hours worked
- Reports — Filterable financial summaries broken down by client or project
- Email Integration — Send invoices via email using Resend
- Payout Threshold — Set minimum payout amounts with currency selection
- Dark Mode — Full dark/light theme support
- Next.js 16 (App Router + Turbopack)
- React 19
- shadcn/ui v4 (Radix primitives + Tailwind CSS v4)
- Supabase (PostgreSQL)
- Resend (transactional email — optional)
- date-fns for date formatting
- pnpm package manager
git clone https://github.com/your-username/timetracker.git
cd timetrackerpnpm install- Go to supabase.com and create a new project
- Once your project is ready, go to Settings > API and copy your:
- Project URL (looks like
https://abcdefg.supabase.co) - Anon public key (starts with
eyJ...)
- Project URL (looks like
Option A — Supabase CLI (recommended)
npx supabase login
npx supabase link --project-ref your-project-ref
npx supabase db pushYour project ref is the subdomain in your Supabase URL (e.g. abcdefg from https://abcdefg.supabase.co).
Option B — SQL Editor
- Open your project in the Supabase dashboard
- Go to SQL Editor and click New Query
- Copy the entire contents of
supabase/setup.sqland paste it in - Click Run — this creates all tables, indexes, and RLS policies in one go
cp .env.example .env.localEdit .env.local with your Supabase credentials:
NEXT_PUBLIC_DB_PROVIDER=supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-keypnpm devOpen http://localhost:3000 in your browser.
To send invoices via email:
- Create an account at resend.com
- Generate an API key (starts with
re_) - Either add it to your
.env.local:Or enter it in the app under Settings > Email IntegrationRESEND_API_KEY=re_your_api_key
You'll also need to verify a sending domain in Resend, or use their test domain for development.
timetracker/
├── app/ # Next.js App Router pages
│ ├── api/ # API routes (Resend key, email sending)
│ ├── calendar/ # Calendar view
│ ├── clients/ # Client management
│ ├── expenses/ # Expense tracking
│ ├── invoices/ # Invoice generation and management
│ ├── projects/ # Project management
│ ├── reports/ # Financial reports
│ ├── settings/ # App settings and configuration
│ └── tracker/ # Time tracking
├── components/ # Reusable UI components
│ └── ui/ # shadcn/ui primitives
├── lib/ # Core utilities
│ ├── db/ # Database providers (Supabase, future MariaDB)
│ ├── store.tsx # React context state management
│ ├── types.ts # TypeScript interfaces
│ └── format.ts # Currency/number formatting
├── supabase/
│ └── migrations/ # SQL migration files
└── .env.example # Environment variable template
TimeTracker uses a DataProvider interface that abstracts all database operations. The current implementation uses Supabase (PostgreSQL), but the architecture supports swapping to any backend (MariaDB, SQLite, REST API) by implementing the same interface. See lib/db/ for details.
pnpm build
pnpm startThis project is licensed under the GNU General Public License v3.0 — you're free to use, modify, and distribute this software as long as you:
- Give appropriate credit to the original author
- Make your modified source code available under the same license
- Include a copy of the license in any distribution