Architecture Overview
Sunday is built with a modern, scalable architecture using Next.js App Router and React.
Technology Stack
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 16 | Full-stack React framework with App Router |
| UI Library | React 19 | Component-based UI |
| UI Components | Radix UI | Accessible, unstyled primitives |
| Styling | Tailwind CSS 4 | Utility-first CSS |
| Animations | Framer Motion | Smooth animations |
| State | Zustand | Lightweight state management |
| Database | MongoDB | Document database |
| Auth | JWT + bcrypt | Secure authentication |
| Validation | Zod | Runtime type validation |
| DnD | dnd-kit | Drag and drop |
Project Structure
dhdflow/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ │ ├── auth/ # Authentication endpoints
│ │ ├── boards/ # Board CRUD
│ │ ├── tasks/ # Task CRUD
│ │ ├── workspaces/ # Workspace CRUD
│ │ └── ...
│ ├── boards/[id]/ # Board page
│ ├── dashboard/ # Dashboard page
│ ├── signin/ # Sign in page
│ ├── signup/ # Sign up page
│ ├── layout.tsx # Root layout
│ └── page.tsx # Landing page
│
├── components/ # React components
│ ├── board/ # Board views & controls
│ │ ├── table-view.tsx
│ │ ├── kanban-view.tsx
│ │ ├── timeline-view.tsx
│ │ └── ...
│ ├── ui/ # Base UI components
│ ├── layout/ # Layout components
│ ├── automations/ # Automation panel
│ ├── filters/ # Filter components
│ └── ...
│
├── lib/ # Utilities & helpers
│ ├── store.ts # Zustand store (1500+ lines)
│ ├── types.ts # TypeScript types
│ ├── auth.ts # Auth utilities
│ ├── mongodb.ts # DB connection
│ ├── validation.ts # Zod schemas
│ ├── filter-utils.ts # Filter helpers
│ └── email.tsx # Email templates
│
├── middleware.ts # Rate limiting middleware
├── tailwind.config.ts # Tailwind configuration
└── public/ # Static assetsRequest Flow
Authentication Flow
Key Design Patterns
Zustand Store Pattern
The application uses a single Zustand store with all state and actions:
const useAppStore = create<AppState>((set, get) => ({
// UI State
sidebarCollapsed: false,
currentView: "table",
// Data
workspaces: [],
boards: [],
tasks: [],
// Actions
addTask: (task) => set((state) => ({
tasks: [...state.tasks, task]
})),
updateTask: (taskId, updates) => { /* ... */ },
}))API Route Pattern
API routes follow a consistent pattern with Zod validation:
export async function POST(request: Request) {
try {
const body = await request.json()
const validated = mySchema.parse(body) // Zod validation
const db = await getDatabase()
const result = await db.collection('items').insertOne(validated)
return Response.json({ success: true, id: result.insertedId })
} catch (error) {
if (error instanceof z.ZodError) {
return Response.json({ error: error.errors }, { status: 400 })
}
return Response.json({ error: 'Server error' }, { status: 500 })
}
}Component Composition
UI components use Radix primitives with Tailwind styling:
import * as Dialog from '@radix-ui/react-dialog'
export function MyDialog({ children, title }) {
return (
<Dialog.Root>
<Dialog.Trigger asChild>{children}</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/50" />
<Dialog.Content className="fixed left-1/2 top-1/2 ...">
<Dialog.Title>{title}</Dialog.Title>
{/* Content */}
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
)
}