DailyTM
Project and task management for teams that ship — sold as source code you own and run yourself.
Board, list, and calendar views · configurable statuses · subtasks · labels · comments with @mentions · notifications · file attachments · full-text search — on multi-tenant authorization enforced by the architecture rather than by remembering to check.
What this is
A complete, production-shaped project and task manager, and the codebase behind it. You get every file: the Next.js application, the Prisma schema and its committed migrations, every service and its authorization tests, the CI workflow, the seed script, and the documentation you are reading.
It is not open source. See LICENSE — you may run, modify, rebrand, and deploy it for your own organization, commercially and without limit. You may not redistribute the source or publish it as a template.
About "v2"
If DailyTM is new to you, ignore the number and read on — this is the product.
There was a v1. This is not an upgrade of it; it is a rebuild that shares no code, and four of its five load-bearing dependencies were replaced. v1 is frozen on the legacy/v1 branch at tag v1.0.0, still deploys, and still receives patches.
If you run v1 today: there is no migration script, on purpose. UPGRADING.md is the only other place this comes up — it explains why, what changed, and what a manual move looks like. Everywhere else in this documentation, v2 is simply the product.
What it does
| Projects and views | Board with optimistic drag, sortable list, month calendar. Filters, search, and the active view all live in the URL, so any arrangement is a shareable link |
| Task modelling | Per-project statuses you rename, recolour, and reorder. One level of subtasks with a completed/total rollup. Organization-scoped labels |
| Collaboration | Rich-text descriptions and comments, @mentions resolved on the server, an inbox with unread state, email notifications, due-date reminders, and an organization audit timeline |
| Files | Attachments straight from the browser to any S3-compatible bucket. Private by default, signed on demand |
| People | Organizations, email invitations and shareable links, four roles defined once and read by both the interface and the server |
| Search | Postgres full-text over tasks and projects, wired into a ⌘K command menu, and filtered by the same visibility rule as everything else |
| Billing | Optional. Polar checkout, portal, and idempotent webhooks — or leave it out and every limit is unlimited |
Requirements
- Node 20+ and pnpm
- PostgreSQL 14+ — Neon, Supabase, RDS, or a container
That is the whole list. Email, OAuth, object storage, billing, and scheduled jobs are all optional.
Quickstart
cp .env.example .env.local
# set DATABASE_URL and BETTER_AUTH_SECRET (openssl rand -hex 32)
pnpm install
pnpm db:generate
pnpm exec prisma migrate deploy
pnpm db:seed # optional — a populated demo workspace
pnpm dev
Open http://localhost:3000/status to confirm the app, the API, and the wire format are wired up.
Then sign up. With no email provider configured the verification link is printed to your terminal, so a fresh clone completes the whole sign-up flow with no third-party account at all.
If you ran the seed, sign in as ada@dailytm.demo with the password the script printed — six people, six projects, seventy-odd tasks, subtasks, labels, and threaded comments, so nothing you open is an empty state.
The promise about configuration
The app boots with exactly three variables: DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL. Every other variable in .env.example is optional, and its absence hides a feature rather than breaking the app:
| Unset | Effect |
|---|---|
RESEND_API_KEY |
Emails are logged to the console instead of sent |
GOOGLE_* / GITHUB_* |
That provider's sign-in button is not rendered |
S3_* |
The Files tab and avatar uploader are absent, not disabled |
POLAR_* |
Every organization is unlimited; the billing interface is absent |
CRON_SECRET |
/api/cron/* returns 404; reminders are off |
A missing required variable fails at startup with a named error listing all of them at once — not a stack trace three layers down at runtime.
Documentation
| SETUP.md | Every provider account, required or optional, with exact steps — and the production security checklist |
| EXTENDING.md | Start here after it runs. One feature end to end: schema → migration → service → authz test → router → page → component |
| ARCHITECTURE.md | Normative. The layer rule, the import matrix, the enforced invariants, the procedure ladder |
| CODE_STANDARDS.md | Naming, TypeScript, React, Prisma, tRPC, tests, definition of done |
| DEPLOYMENT.md | Production, the public demo, rollbacks |
| UPGRADING.md | v1 → v2 is a fresh install, and why |
| ROADMAP.md | What is coming, what is deliberately not, and what was rejected — each with the reason |
| THIRD-PARTY-LICENSES.md | The dependency licence review |
Architecture, in one screen
Dependencies point downward only, and three rules are enforced by ESLint rather than by review:
src/app/ routing, layouts, server components
↓
src/components/ presentational and interactive UI
↓
src/trpc/ routers: validate input, check a permission, call one service
↓
src/server/ services: all business logic, all database access
↓
src/lib/ db, auth, authz, permissions, s3, email
- Every file under
src/server/importsserver-only— a leaked database call becomes a build failure, not a shipped credential. findUniqueis banned insidesrc/server/services/— usefindFirstwithorganizationId. A lookup by id alone returns another tenant's row.- Services never read the request; routers never touch the database; components never import server code.
Two more that lint cannot catch, and which are checked at review:
- The tenant comes from the session's active organization, never from a route parameter. A
projectIdin an input is a filter, never a source of authority. - Every service ships an
.authz.test.tsproving a member of organization B receivesNOT_FOUNDfor an organization A resource, on read and on write. No service merges without one.
Scripts
pnpm dev / pnpm build / pnpm start |
The usual three |
pnpm lint / pnpm typecheck / pnpm test |
Three of the four release gates |
pnpm test:e2e |
Playwright; boots its own dev server |
pnpm format / pnpm format:check |
Prettier |
pnpm db:generate / pnpm db:studio / pnpm db:seed |
Prisma |
pnpm screenshots |
Regenerate the marketing screenshots from the running, seeded app |
The four release gates are pnpm lint && pnpm typecheck && pnpm test && pnpm build. CI runs all four on every push and pull request, against a Postgres service container — no account and no API key, so a fork runs green on the first try.
pnpm db:pushexists for local iteration only. It cannot create the partial indexes, generatedtsvectorcolumns, andCHECKconstraints that ship inside migration files, so never use it to prepare a database that matters.
Use
pnpm dlx, nevernpx— npm's arborist crashes on pnpm's symlinkednode_modulesin this repository.
Running the tests against a database
The suites truncate every table, so they need their own. Set DATABASE_URL_TEST to something that is not DATABASE_URL — the app refuses to start if the two match. Leave it unset and the database-backed suites skip themselves by name rather than failing.
DATABASE_URL="<your test url>" pnpm exec prisma migrate deploy
Stack
Next.js 16 (App Router) · React 19 · TypeScript 5 strict · tRPC 11 · TanStack Query 5 · Prisma 7 + PostgreSQL · Better Auth 1.7 with the organization plugin · Tailwind 4 · shadcn/ui · TipTap 3 · Resend · any S3-compatible storage · optional Polar.
No Server Actions — tRPC only. Route handlers exist for Better Auth, tRPC, avatars, and the cron entry point, and nothing else.
Licence
Commercial. One purchase covers your organization: unlimited deployments, unlimited users, commercial use, and the right to modify and rebrand. Redistribution of the source is not permitted.
Read LICENSE — it is written in plain English and is shorter than this README. If you need terms it does not grant — an agency licence covering multiple clients, OEM redistribution, source escrow — those are available; the contact address is in package.json.
© 2026 Nyansa Studio.