Skip to content

feat: add Sunsama Clone task management app - #2

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1777910354-sunsama-clone
Open

feat: add Sunsama Clone task management app#2
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1777910354-sunsama-clone

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented May 4, 2026

Copy link
Copy Markdown

Summary

Adds a full-featured Sunsama Clone task management application as two new artifacts in the monorepo, based on welch5788/sunsama-clone.

What's included

Database schema (lib/db/src/schema/)

  • sunsama_users — user accounts for the task app
  • sunsama_tasks — tasks with scheduling, time tracking, and recurring task support

Backend (artifacts/sunsama-api/)

  • Express server on port 3002
  • Full CRUD for tasks (create, read, update, delete)
  • Toggle completion, plan tasks for specific dates
  • Schedule tasks to specific time slots
  • Recurring task support (daily, weekdays, weekly, custom interval) with instance generation
  • Drizzle ORM integration with shared @workspace/db

Frontend (artifacts/sunsama-web/)

  • React 19 + Vite + Tailwind CSS v4
  • Today view — drag-and-drop scheduling onto an hourly timeline, daily time summary
  • Week view — 7-day calendar grid with drag-and-drop task planning across days
  • All Tasks view — full task list with inline create form
  • Pomodoro Timer — 25-minute sessions with pause/resume/save progress
  • Create/Edit Task modals — full recurring task configuration
  • Settings — configurable timeline start/end hours (persisted to localStorage)
  • Keyboard shortcuts — N (new task), T (today), W (week), A (all tasks), Escape (close)
  • State management: Zustand (UI) + React Query (server state)
  • Drag & drop: @dnd-kit

Tech stack alignment

  • Uses catalog: versions from pnpm-workspace.yaml for shared deps
  • Follows existing monorepo patterns (@workspace/ naming, esbuild bundling, tsconfig references)
  • Both artifacts typecheck and build successfully

Review & Testing Checklist for Human

  • Run pnpm --filter @workspace/sunsama-web dev and verify the frontend loads at localhost:5173
  • Run pnpm --filter @workspace/sunsama-api dev with DATABASE_URL set and verify API responds at localhost:3002/health
  • Create a task via the UI and confirm it appears in the task list
  • Drag a task to a timeline slot in Today view and verify scheduling works
  • Test the Week view drag-and-drop to move tasks between days

Notes

  • The API requires a PostgreSQL database with DATABASE_URL environment variable set
  • Run pnpm --filter @workspace/db push to create the new sunsama_users and sunsama_tasks tables
  • Set VITE_API_URL in the frontend if the API runs on a different port/host than default (localhost:3002)

Link to Devin session: https://app.devin.ai/sessions/79e1e9b181824f3aa1cf7b8efd8ca55a
Requested by: @TanUIUX


Open in Devin Review

- Add Drizzle schema for sunsama_users and sunsama_tasks tables
- Create sunsama-api Express backend with task CRUD, scheduling, and recurring tasks
- Create sunsama-web React frontend with Today/Week/All Tasks views
- Features: drag-drop scheduling, Pomodoro timer, recurring tasks, timeline view
- Uses @dnd-kit, @tanstack/react-query, Zustand, Tailwind CSS v4
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@devin-ai-integration

Copy link
Copy Markdown
Author

End-to-End Test Results

Ran frontend (localhost:5173) and backend (localhost:3002) locally against a local PostgreSQL database. Tested all core task management flows via browser GUI.

All 5 test scenarios passed.

Core Feature Tests
Test Result
Task CRUD (create/toggle/delete) in All Tasks view PASSED
Plan for Today + Today view display with Daily Summary PASSED
Drag-drop scheduling onto timeline (10AM slot) PASSED
Week view navigation (Previous/Today/Next) with task in today's column PASSED
Keyboard shortcut (N) modal creation PASSED
Settings modal — change timeline start hour (8AM→9AM) PASSED
Evidence Screenshots

Task Created — All Tasks (1)

Task created

Toggle Completion — Strikethrough Styling

Toggle

Drag-Drop — Task Scheduled at 10AM

Drag-drop

Week View — Task in Mon Column

Week view

Create Task Modal via N Key

Modal

Settings Applied — Timeline Starts at 9AM

Settings

Not Tested
  • Pomodoro Timer — Component is present but requires real-time interaction (25-minute session)
  • Recurring task creation — Checkbox and config form present in modal but not exercised end-to-end
  • Edit task modal — Not tested in this session

Devin session

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines +30 to +41
const isToday = (dateString: string | null) => {
if (!dateString) return false;
const taskDate = dateString.split("T")[0];

const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const todayDate = `${year}-${month}-${day}`;

return taskDate === todayDate;
};

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Today view isToday compares UTC date from ISO string against local date, breaking task display in UTC+ timezones

The isToday function extracts the date portion from the server's UTC ISO string via dateString.split("T")[0] (yielding a UTC date like "2026-05-03"), but constructs todayDate from local date components (getFullYear(), getMonth(), getDate()), yielding a local date like "2026-05-04". In any UTC+ timezone (Europe, Asia, Africa, Oceania), these will differ when the UTC representation of local midnight falls on the previous UTC day. This means tasks planned for today won't appear in the Today view for roughly half the world's timezones.

Trace example for UTC+5
  1. User plans task for today (May 4 local) via handlePlanForToday in artifacts/sunsama-web/src/pages/Tasks.tsx:66-69
  2. today.toISOString() sends "2026-05-03T19:00:00.000Z" to server
  3. Server stores this timestamp, returns it as ISO string in API response
  4. isToday splits: taskDate = "2026-05-03" (UTC), todayDate = "2026-05-04" (local)
  5. No match → task disappears from Today view
Suggested change
const isToday = (dateString: string | null) => {
if (!dateString) return false;
const taskDate = dateString.split("T")[0];
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const todayDate = `${year}-${month}-${day}`;
return taskDate === todayDate;
};
const isToday = (dateString: string | null) => {
if (!dateString) return false;
const taskDate = new Date(dateString);
const today = new Date();
return (
taskDate.getFullYear() === today.getFullYear() &&
taskDate.getMonth() === today.getMonth() &&
taskDate.getDate() === today.getDate()
);
};
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

},
}
);
setShowTimerModal(false);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 handleTimerComplete closes modal synchronously before mutation resolves, leaking timer state on error

setShowTimerModal(false) at line 137 runs synchronously right after updateMutation.mutate(), before the async mutation completes. This causes two issues: (1) the PomodoroTimer unmounts immediately, causing the floating timer button (artifacts/sunsama-web/src/pages/Today.tsx:213-234) to flash briefly until onSuccess calls stopAndClear(), and (2) on mutation failure, the onError handler at line 132 only sets setShowTimerModal(false) (already false) but never calls stopAndClear(), so activeTask persists in the zustand store indefinitely. The floating button remains visible with no recovery, and clicking it reopens the timer in a stale state.

Prompt for agents
The handleTimerComplete function in artifacts/sunsama-web/src/pages/Today.tsx:120-138 has a premature setShowTimerModal(false) call at line 137 that runs synchronously before the mutation resolves. This line should be removed entirely since modal closure is already handled in both the onSuccess and onError callbacks. Additionally, the onError callback at line 132-134 should call stopAndClear() to clean up the timer state when the mutation fails, preventing the stale floating timer button from persisting.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant