Project Management Tool
STATUS = BUILDING
A flexible, multi-user project management tool inspired by Notionβs dynamic collections. Manage tasks and GitHub PRs with a block-based structure, custom properties, and optimized client-side caching.
π Features
Tasks & PR Management β Organize and track work efficiently.
Custom Properties β Define dynamic fields per task or PR.
Optimized Client Caching β React Query ensures fast updates with minimal refetching.
CMD + K Navigation β Quick actions for an efficient workflow.
Multi-User Workspaces β Collaborative and scalable.
π§ Architecture
Data Model
The current data model uses three main PostgreSQL tables: BLOCK
, PROPERTY
, and PROPERTY_VALUES
.
-
Blocks are the actual tasks or PR entries that users create. These blocks are responsible for holding the property values and the associated properties together.
-
Properties are much like the columns of a table, but they are dynamic, allowing you to change their type.
-
Property values are the value entries for a block and a property.
Why Not NoSQL?
Using a NoSQL database may seem flexible at first, but when we need to think about deleting properties and enforcing relations ourselves, it becomes a harder system to maintain. These are some reasons why NoSQL is not suitable for this project:
-
Deletes are the worst β Removing a property requires modifying all related documents. If you have 100+ task rows, each document needs an update, and large-scale writes are expensive. In SQL, cascading deletes handle this automatically.
-
Query inefficiency β Properties and tasks are stored separately, leading to multiple fetches instead of a simple JOIN.
-
Bulk operations are costly β Updating thousands of documents vs. running a single SQL query.
-
Data integrity challenges β No built-in constraints like foreign keys to enforce relationships.
-
Aggregations are harder β Though not needed now, complex calculations (like sum, count, or averages) are much trickier in NoSQL.
Why SQL?
-
Cascading updates & deletes β Modify properties efficiently without touching every row.
-
Efficient queries β JOINs are better than manually fetching multiple documents.
-
Better indexing β Structured queries scale better with large data.
-
Stronger consistency β Every property value is strongly linked to its block and property.
-
Simpler property management β The server doesnβt need to check or enforce property existence manually. π
As a software developer, Iβve always been amazed by how Notion implements its dynamic data model. Fortunately, I landed a job at a company that builds websites using Notion as a CMS, which gave me deeper insights into its structured data model.
After reading this blog about notionβs data model and addtionaly, this post led me to explore Notionβs SQLite file structure, which played a crucial role in shaping my current block-based model.
Backend
-
Built on a unified action-based architecture, keeping the backend, frontend, and cache updates in sync.
-
Unified Action Handler β Strongly typed, routing all block, property, and value operations.
-
Single-Source API Design β Reduces redundancy and improves maintainability.
Frontend
Refer: collection hook for more information For the frontend, we used Next.js 15 and React Query.
The unified action handler is responsible for handling all block, property, and value mutations and instead of refetching we just update the cache with new values.
Demo Images
Tech Stack
- Frontend: Next.js 15, React Query, shadcn
- Backend: Next.js API Routes, Drizzle ORM, PostgreSQL
- Auth: BetterAuth
- Hosting: Vercel,Neon(PG)
π¦ Installation
# Clone the repository
git clone https://github.com/lakshmanshankar/project-2.git && cd project-2
# Install dependencies
pnpm install
# Start development server
pnpm dev
π License
MIT License. Check out the repo π GitHub.