Modern personal productivity workspace — fast, organized, and built for real-world task management
Tasks, tags, subtasks, smart views, Google sign-in, soft-delete trash, stats, and keyboard shortcuts.
Features · Stack · Run locally · Structure · Brief & rubric · Deploy
- Features
- Tech stack
- Architecture
- Prerequisites
- Local setup
- Environment variables
- Scripts
- Testing
- Project structure
- Deployment notes
Core
- List tasks with title, description, status, priorities, due dates, and timestamps
- Create, edit, and delete tasks with confirmation where destructive actions warrant it
- Toggle completion / status with optimistic updates
- Filter and search tasks; sort and URL-synced explorer state
- Client and server validation (empty titles and invalid payloads rejected with clear feedback)
Beyond the brief
- Google OAuth via Better Auth; data scoped per user in PostgreSQL
- Soft delete with trash, restore, and bulk actions
- Tags, subtasks, drag-to-reorder, Today / Upcoming / Completed views
- Stats and keyboard shortcuts (see
FEATURES.mdfor the full product spec)
| Layer | Choice |
|---|---|
| App framework | TanStack Start (React 19, Vite 7) |
| Routing | TanStack Router |
| Server / data access | TanStack createServerFn, Prisma 7 |
| Database | PostgreSQL (NeonDB) |
| Auth | Better Auth + Google OAuth |
| Validation | Zod (shared schemas for server and forms) |
| Server state | TanStack Query |
| Forms | React Hook Form + Zod resolver |
| Styling | Tailwind CSS 4 |
| Tests | Vitest (unit), Playwright (E2E) |
- Full-stack in one repo: the browser calls server functions defined in
src/lib/*.functions.tsinstead of hand-writtenfetchto ad-hoc REST paths. Each function runs on the server, checks the session, validates input with Zod, and calls the Prisma layer insrc/lib/tasks.repo.ts(and related modules). - Auth: Better Auth exposes
/api/auth/*(seesrc/routes/api/auth/$.ts). All task operations require a signed-in user; data is always filtered byuserId. - Persistence: Prisma migrations live in
prisma/migrations/; the schema isprisma/schema.prisma.
The original assignment specified a minimal REST shape (GET/POST /api/tasks, etc.). This project fulfills the same behaviors through authenticated server functions and a richer domain model (soft delete, tags, and multi-status tasks). See the mapping table in Assignment alignment.
- Node.js 22.x (LTS) or newer — nodejs.org
- PostgreSQL — local instance or a hosted URL (Neon recommended for quick setup)
- Bun (optional but recommended) — bun.sh — used by some npm scripts (
bunx). If you prefer not to install Bun, use the alternatives in Local setup. - Google Cloud OAuth credentials (OAuth client ID + secret) with authorized redirect URI:
{BETTER_AUTH_URL}/api/auth/callback/google
(for local dev,BETTER_AUTH_URLis typicallyhttp://localhost:5173).
Goal: clone, configure env, migrate, seed, run — under ~10 minutes on a typical machine with Postgres and Node already available.
-
Clone the repository
git clone <your-repo-url> task-flow cd task-flow
-
Install dependencies
npm install
-
Configure environment
cp .env.example .env
Edit
.env: setDATABASE_URL,BETTER_AUTH_SECRET(≥ 32 random characters),BETTER_AUTH_URL(e.g.http://localhost:5173), and Google OAuth keys. See Environment variables. -
Create the database schema
npm run db:migrate
Applies Prisma migrations to your database.
-
Seed demo data (optional)
npm run db:seed
The script uses
bunxinternally. If the command fails, install Bun or run the seed directly:npx tsx --tsconfig tsconfig.json prisma/seed.ts
Seeding creates a synthetic user (
dev@taskflow.local) with sample tasks for database inspection (e.g. Prisma Studio). Signing in with Google creates or loads your real user, which is separate—expect an empty list until you add tasks in the UI. -
Start the dev server
npm run dev
Open the URL printed in the terminal (defaults to
http://localhost:5173when following Playwright/local conventions). -
Sign in
Open Sign in with Google on the login page. After authentication you are redirected into the dashboard at
/tasks.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string (sslmode=require for Neon). |
BETTER_AUTH_URL |
Yes | Public origin of the app (e.g. http://localhost:5173). |
BETTER_AUTH_SECRET |
Yes | Secret for session signing (≥ 32 chars). |
GOOGLE_CLIENT_ID |
Yes (for Google login) | OAuth 2.0 client ID. |
GOOGLE_CLIENT_SECRET |
Yes (for Google login) | OAuth 2.0 client secret. |
OAuth: set Google redirect to {BETTER_AUTH_URL}/api/auth/callback/google. During vite build, the app exposes that same canonical origin to the browser client (VITE_* substitution from vite.config.ts)—use https:// in production.
All placeholders are listed in .env.example. Never commit a real .env file.
| Command | Purpose |
|---|---|
npm run dev |
Start Vite dev server (TanStack Start). |
npm run build |
Production build. |
npm run preview |
Preview production build locally. |
npm run lint |
ESLint. |
npm run format |
Prettier write. |
npm run db:generate |
Regenerate Prisma client. |
npm run db:migrate |
Run migrations (dev). |
npm run db:migrate:deploy |
Apply migrations (deploy/CI). |
npm run db:seed |
Seed the database (requires Bun for bunx or use npx tsx fallback above). |
npm run db:studio |
Open Prisma Studio. |
npm test |
Vitest unit tests. |
npm run test:e2e |
Playwright E2E (starts dev server on 127.0.0.1:5173 unless PLAYWRIGHT_BASE_URL is set). |
- Unit:
npm test— validation and repository-level tests undertests/unit/. - E2E:
npm run test:e2e— requires a runnable app and appropriate env for auth/database where tests need it.
├── docs/
│ └── taskflow-mark.svg # README / branding mark
├── prisma/
│ ├── schema.prisma # Database schema
│ ├── migrations/ # SQL migrations (source of truth for schema history)
│ └── seed.ts # Sample tasks/tags
├── src/
│ ├── routes/ # File-based routes (TanStack Router)
│ ├── components/ # UI (dashboard, primitives)
│ ├── hooks/ # React Query hooks, UX hooks
│ ├── lib/
│ │ ├── auth.ts # Better Auth server config
│ │ ├── *.functions.ts # Server functions (tasks, auth, …)
│ │ ├── *.repo.ts # Prisma data access
│ │ └── validations/ # Zod schemas
│ └── generated/prisma/ # Generated client (after `prisma generate`)
├── tests/
│ ├── unit/
│ └── e2e/
├── .env.example # Documented env template (copy to .env)
├── AGENTS.md # Contributor / agent conventions
├── FEATURES.md # Detailed product specification
└── README.md # This file
- Configure the same environment variables on the host as in
.env.example; setBETTER_AUTH_URLto the public origin users hit in the browser (must match your Vercel domain, e.g.https://your-app.vercel.app). - Run
npm run db:migrate:deployagainst productionDATABASE_URLbefore serving traffic. - Google OAuth console must list the production callback URL:
{BETTER_AUTH_URL}/api/auth/callback/google.
This app uses nitro in vite.config.ts and cloudflare: false on the @lovable.dev/vite-tanstack-config preset so builds emit Vercel’s expected .vercel/output during CI (VERCEL=1). Without Nitro and with the default Cloudflare plugin enabled on vite build, the bundle targets Cloudflare Workers, which Vercel does not consume—typically resulting in 404 NOT_FOUND at /.
Deploy with default build npm run build without overriding Output Directory manually. Run migrations against prod DB (see Prisma deploy migrations).
wrangler.jsoncreferencessrc/server.tsfor Workers. Use Wrangler/deploy to Cloudflare if you prefer that path instead of Vercel.