Zero-cost, globally accessible task manager with smart prioritisation, recurrence rules, and full authentication.
| Layer | Tool | Cost |
|---|---|---|
| Frontend | React 18 + Vite + TypeScript | Free |
| Styling | CSS (DM Sans / DM Mono) | Free |
| Auth + DB | Supabase (Postgres + RLS) | Free tier |
| Hosting | Vercel | Free tier |
| State | Zustand | Free |
| Recurrence | rrule.js + date-fns | Free |
git clone https://github.com/YOUR_USERNAME/taskflow.git
cd taskflow
npm install- Go to supabase.com → New project
- Copy your Project URL and anon public key from
Project Settings → API
cp .env.example .env.local
# Edit .env.local with your Supabase URL and anon key# Option A: Supabase CLI (recommended)
npx supabase login
npx supabase db push
# Option B: Paste manually
# Open Supabase Dashboard → SQL Editor
# Run: supabase/migrations/001_init.sql
# Run: supabase/migrations/002_rls.sqlIn Supabase Dashboard → Authentication → Providers:
- Email — enabled by default
- Google — add your OAuth client ID + secret
(Google Cloud Console → APIs & Services → Credentials)
npm run dev
# → http://localhost:5173- Push your repo to GitHub
- Go to vercel.com → Import project → select your repo
- Add environment variables in Vercel:
VITE_SUPABASE_URLVITE_SUPABASE_ANON_KEY
- Add your Vercel domain to Supabase:
Authentication → URL Configuration → Site URL & Redirect URLs - Deploy — every
git push mainauto-deploys ✓
taskflow/
├── supabase/migrations/
│ ├── 001_init.sql # Tables, triggers, indexes
│ ├── 002_rls.sql # Row Level Security policies
│ └── seed.sql # Dev seed data
├── src/
│ ├── components/
│ │ ├── auth/
│ │ ├── tasks/
│ │ │ ├── TaskCard.tsx
│ │ │ └── TaskForm.tsx # Priority + recurrence form
│ │ └── layout/
│ │ └── PrivateRoute.tsx
│ ├── pages/
│ │ ├── Login.tsx
│ │ ├── Signup.tsx
│ │ └── Dashboard.tsx
│ ├── hooks/
│ │ ├── useAuth.ts # Session listener
│ │ └── useTasks.ts # Task CRUD
│ ├── store/
│ │ ├── authStore.ts # Zustand auth state
│ │ └── taskStore.ts # Zustand task state
│ ├── lib/
│ │ ├── supabase.ts # Client singleton
│ │ ├── priority.ts # Scoring algorithm
│ │ └── rrule.ts # Recurrence helpers
│ ├── types/index.ts
│ └── styles/global.css
├── .env.example
├── vercel.json
└── package.json
Each task gets a computed score at render time (no DB call):
score = base_priority (high=100, medium=50, low=10)
+ time_of_day_bonus (+10 if preferred_time is within 2h of now)
+ day_of_week_bonus (+20 if today is in task's active days)
+ overdue_bump (+30 if past due date)
+ due_soon_bonus (+15 if due within 24h)
+ recurring_boost (+5 if task repeats)
Tasks are sorted descending by score — the most contextually relevant task always surfaces first.
MIT