A multi-workspace project and task management app built on the Next.js App Router. Teams sign in with Kinde, create workspaces, invite members by email or link, and track work across projects with a dashboard, table, and drag-and-drop Kanban board.
- Auth & onboarding — Kinde-hosted login/registration, a first-run profile form, and an automatic redirect chain (onboarding → create workspace → workspace).
- Workspaces — unique invite codes, email invites over SMTP, and
OWNER/MEMBER/VIEWERroles for settings, role changes, and removals. - Projects — three views per project selected via
?view=: a dashboard (progress stats, task distribution chart, activity feed, comments), a sortable table, and a Kanban board. - Tasks — six statuses, four priorities, start/due dates, assignees, comments, and image/PDF attachments via UploadThing. Drag-and-drop across Kanban columns persists status and ordering.
- My Tasks — every task assigned to the signed-in user across the workspace.
- UI — shadcn/ui on Radix, light/dark/system theming, responsive sidebar, and a 5-minute client-side cache (
contexts/app-state-context.tsx) to avoid refetching on every navigation.
Next.js 15.5 (App Router, Server Actions, Turbopack) · React 19 · TypeScript · Tailwind CSS 3 + shadcn/ui · Prisma 6 + PostgreSQL · Kinde auth · UploadThing · Nodemailer · Zod + React Hook Form · Recharts · @hello-pangea/dnd
Requires Node 18.18+, a PostgreSQL database, a Kinde app, an UploadThing app, and SMTP credentials for invites.
git clone https://github.com/zohaibfast99/Trackly.git
cd Trackly
npm install
# create .env (see below)
npx prisma migrate dev
npm run devOpen http://localhost:3000. In the Kinde dashboard, set the callback URL to http://localhost:3000/api/auth/kinde_callback and the logout redirect to http://localhost:3000.
# Kinde
KINDE_CLIENT_ID=
KINDE_CLIENT_SECRET=
KINDE_ISSUER_URL=https://<your-subdomain>.kinde.com
KINDE_SITE_URL=http://localhost:3000
KINDE_POST_LOGOUT_REDIRECT_URL=http://localhost:3000
KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000/workspace
DATABASE_URL=postgresql://user:password@host:5432/trackly
UPLOADTHING_TOKEN=
UPLOADTHING_SECRET_KEY=
NEXT_PUBLIC_BASE_URL=http://localhost:3000 # used to build invite links
# SMTP for invite emails
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_SECURE=false
MAIL_FROM=Without SMTP, invite emails fail gracefully and the invite link is still generated for manual sharing. LemonSqueezy keys live in .env.lemonsqueezy.example and are only needed if the subscription code is re-enabled.
| Command | Description |
|---|---|
npm run dev |
Dev server (Turbopack) |
npm run build / npm run start |
Production build and serve |
npx prisma migrate dev |
Apply migrations |
npx prisma studio |
Browse the database |
No lint or test scripts are defined yet.
app/
(protected)/ # Authenticated area
onboarding/ create-workspace/
workspace/[workspaceId]/ # Sidebar layout + dashboard
members/ my-tasks/ settings/
projects/[projectId]/ # Dashboard | Table | Kanban, plus [taskId]
pricing/ billing/ # Static placeholders (see notes)
actions/ # "use server" mutations
data/ # Server-side read queries
api/ # Kinde auth, uploadthing, lemonsqueezy webhook
workspace-invite/[workspaceId]/join/[inviteCode]/
page.tsx # Public landing page
components/ # ui/ (shadcn) + sidebar, workspace, project, task
contexts/ hooks/ lib/ utils/ prisma/
Pages under app/(protected) are Server Components that read through app/data/**; mutations go through "use server" functions in app/actions/**, validated with Zod schemas from lib/schema.ts and written via the shared Prisma client in lib/db.ts.
Data model (prisma/schema.prisma): User, Workspace, WorkspaceMember (carries the access level), Project, ProjectAccess, Task, Comment, Activity, File, Subscription, and an as-yet-unused Documentation.
Deploys to Vercel or any Node host supporting Next.js 15. Set every variable above with production URLs, run npx prisma migrate deploy, then build and start. next.config.ts allows remote images from utfs.io — add your host to images.remotePatterns if uploads are served elsewhere.
- Subscriptions are disabled. The LemonSqueezy system (plan limits, actions, webhook, provider, pricing/billing components) exists but is commented out in
app/layout.tsxand in thecheckPlanLimitscalls inworkspace.tsandproject.ts, so no limits are enforced./pricingand/billingrender static pages. SeeSUBSCRIPTION_SYSTEM.mdfor the intended design. - No tests or ESLint config are checked in, despite ESLint dev dependencies being present.
hooks/use-mobile.tsandhooks/use-mobile.tsxare duplicates, andapp/actions/workspace.tshas a strayeffect/src/Listimport that should be removed.- Route protection is per page/action via
userRequired()rather than amiddleware.ts.
Feature work happens on per-developer branches that merge into main via pull request. Keep new UI on the shadcn/ui primitives in components/ui, put mutations in app/actions, reads in app/data, and validate action input with a Zod schema in lib/schema.ts.