-
Notifications
You must be signed in to change notification settings - Fork 176
docs: add modular starter kit guide #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Replace hardcoded localhost:3000 with window.location.origin - Enables auth to work on any port (3000, 3001, etc.) - Fixes issue when port 3000 is already in use - Maintains SSR compatibility with fallback env var
- Change /todos to /dashboard/todos to match actual route - Fixes 404 error when clicking Todos in navigation - Actual route is in app/dashboard/todos/page.tsx
- Fix buildSystenPrompt → buildSystemPrompt (lines 47, 76) - Fix styleInstructructions → styleInstructions (line 81, 90) - Improves code readability and professionalism
- Replace browser alert() with toast.error() for better UX - Import toast from react-hot-toast (already in dependencies) - Provides non-blocking, styled error notifications - Consistent with rest of application error handling
- Add aria-label="Delete todo" to icon-only button - Improves screen reader accessibility - Follows WCAG 2.1 guidelines for icon buttons - No visual changes
- Validate image files are under 5MB before upload
- Validate only PNG/JPG files are accepted
- Show toast error messages for validation failures
- Reset file input on validation error
- Prevents large file uploads that would fail
- Matches documented limits ("PNG, JPG up to 5MB")
The CLOUDFLARE_R2_URL environment variable already includes the protocol prefix (https://), so prepending another 'https://' results in malformed URLs like 'https://https://...'. This fix removes the hardcoded protocol prefix and uses the env var value directly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Replace hardcoded D1 database ID in drizzle.config.ts with CLOUDFLARE_D1_DATABASE_ID environment variable for better configurability across different environments. Changes: - Add CLOUDFLARE_D1_DATABASE_ID to .dev.vars.example - Update drizzle.config.ts to use env var instead of hardcoded ID - Document the new env var in README.md with instructions - Add note about copying database_id when creating D1 database This allows developers to easily switch between different databases (dev/staging/prod) without modifying code. Note: wrangler.jsonc still requires the actual database_id value as it doesn't support environment variable interpolation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Add proper handling for Next.js redirect errors in updateTodoAction to match the pattern used in createTodoAction. Without this, redirect() calls from server actions could be incorrectly logged as errors. Changes: - Check if error message is 'NEXT_REDIRECT' before error logging - Re-throw NEXT_REDIRECT errors unchanged to allow proper redirection - Prevents false error logs in console for successful operations This matches the existing pattern in create-todo.action.ts for consistency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Update createCategory action to return success/error object instead of throwing errors, making it consistent with other mutation actions like deleteTodoAction and updateTodoFieldAction.
Changes:
- create-category.action.ts: Return { success, data?, error? } instead of throwing
- add-category.tsx: Update to handle new response structure without try/catch
- Added authentication error handling for consistency
Benefits:
- Consistent error handling across all non-form mutation actions
- Cleaner client code (no try/catch needed)
- Better error propagation to UI
- Matches established pattern used by delete and update field actions
This brings all programmatic mutations to use the same response pattern, while form actions with redirect() continue to use throw pattern (as required by Next.js).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add complete API reference documentation covering all REST endpoints and server actions. Contents: - REST API Endpoints (2 endpoints) - POST /api/summarize - Text summarization with Workers AI - /api/auth/[...all] - Better Auth endpoints - Server Actions (11 actions) - Authentication: signIn, signUp, signOut - Todos: getAllTodos, getTodoById, create, update, updateField, delete - Categories: getAllCategories, createCategory - Authentication Details - Better Auth configuration - OAuth providers (Google) - Utility functions - Data Models - Todo, Category, User, Session schemas - Validation rules and constraints - Error Handling - API error formats - Server action patterns - Security considerations Each endpoint/action includes: - Purpose and description - Request/response formats with TypeScript types - Authentication requirements - Error conditions and codes - Practical usage examples - Side effects (revalidation, redirects, R2 uploads) Total: 500+ lines of comprehensive API documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Import react-hot-toast for consistent error feedback - Replace alert() with toast.error() on line 35 - Simplify error message to match other components - Consistent with PR ifindev#14 (delete-todo.tsx) Provides professional, non-blocking error notifications when toggling todo completion fails.
- Import react-hot-toast and useRouter - Use toast.promise to show loading/success/error states - Show 'Creating/Updating todo...' during operation - Show success message before redirect - Provides clear user feedback for save operations Enhances UX by confirming successful todo creation/updates before redirect happens.
- Import cookies() in create-todo and update-todo actions - Set 'todo-warning' cookie when R2 upload fails - Create WarningToast component to display cookie-based warnings - Integrate WarningToast into todo-list page - Clear warning cookie after displaying Now users see: 'Image upload failed, but todo was created/updated successfully' when R2 upload fails but todo operation succeeds. Prevents silent failures.
- Add spinning loader icon to submit button during submission - Show specific text when image is being uploaded: - 'Creating with image...' for new todos with images - 'Updating with image...' for editing todos with images - Generic 'Creating...' / 'Updating...' when no image - Disable cancel button during submission - Visual feedback improves UX during potentially slow image uploads Users now see clear indication that image upload is in progress.
Changes: - todo-card.tsx: - text-gray-500/400/600 → text-muted-foreground (with opacity variants) - text-blue-600 → text-primary (image badge) - text-red-600 → text-destructive (overdue indicators) - todo-list.page.tsx: - text-gray-600/500/400 → text-muted-foreground (with opacity variants) Benefits: - Theme-aware: Colors adapt to light/dark mode automatically - Consistent: Uses shadcn/ui semantic color system - Maintainable: Change theme by editing CSS variables - Professional: Avoids arbitrary hard-coded colors Note: Priority/status badge colors (green/yellow/red/etc) kept as-is since they're functional semantic indicators, not UI colors.
- Install next-themes package - Create ThemeProvider component with localStorage persistence - Create ModeToggle cycling button (Light → Dark → System) - Update layout.tsx: - Wrap app with ThemeProvider - Add suppressHydrationWarning to html tag - Replace bg-gray-50 with bg-background - Update navigation.tsx: - Add ModeToggle button next to LogoutButton - Replace bg-white with bg-card - Remove hard-coded text colors **Complete semantic color audit (54 violations fixed):** - dashboard.page.tsx: Replace all gray/blue/green/purple with semantic - todo-card.tsx: text-muted-foreground, text-primary, text-destructive - todo-list.page.tsx: text-muted-foreground variants - delete-todo.tsx: text/bg-destructive for delete actions - todo-form.tsx: border-border, text-primary for upload UI - edit-todo.page.tsx: text-muted-foreground - new-todo.page.tsx: text-muted-foreground Priority/status badge colors kept as-is (semantic data visualization). Dark mode now fully functional with proper theme-aware colors.
- Import dashboardRoutes and todosRoutes for type-safe navigation - Replace hardcoded paths with route constants (dashboardRoutes.dashboard, todosRoutes.list) - Fix dark mode colors: bg-white → bg-card, remove text-gray-900 - Improves maintainability and dark mode support
- Filter out NEXT_REDIRECT errors in toast.promise error handler - NEXT_REDIRECT is Next.js flow control, not an actual error - Fixes interaction issue between PR ifindev#19 and PR ifindev#23
…ry colors - Replace 24 hardcoded color violations in priority/status badges - Use semantic Tailwind colors (bg-muted, bg-accent, bg-primary, etc.) - Add categoryColor to getAllTodos query - Display category badges with actual user-defined colors - Category badges now use inline styles with color from database - Ensures proper light/dark mode support for all badges
- Remove duplicate text input that conflicted with color picker - Both inputs were bound to same form field causing DOM conflict - Now uses single color picker input - Fixes bug where categories wouldn't save with custom colors
- Radix Dialog was closing when native color picker triggered pointer events - Added onPointerDownOutside handler to DialogContent - Prevents dialog closure specifically for color input interactions - Maintains standard dialog behavior for other outside clicks - Fixes: category creation failing when selecting custom colors
- Install react-colorful library - Create custom ColorPicker component using HexColorPicker - ColorPicker uses Popover (stays within Dialog DOM) - Includes both visual picker and hex text input - Remove onPointerDownOutside handler (no longer needed) - Fixes dialog closing issue completely - Better UX with drag-based color selection
Add comprehensive documentation to make this a production-ready modular starter kit that can be forked and customized for new projects. New Documentation: - MODULES.md: Complete module system guide * Available modules (auth, todos, dashboard) * How to remove a module * How to add a new module * Module best practices and dependencies * Database integration patterns * Type safety and testing - MODULE_TEMPLATE.md: Step-by-step module creation guide * Complete "Invoices" module example * Database schema patterns * Server action patterns (CRUD operations) * Component patterns (list, form, card, delete) * Route setup * Testing checklist - README.md: Updated with modular architecture section * Quick start for new projects * Fork-and-customize workflow * Link to MODULES.md Architecture Approach: - Feature-based modules (industry standard) - Fork-and-customize pattern (same as T3 Stack) - No plugin system needed (avoids 50-100h overhead) - Each module is self-contained and reusable - Simple to copy modules between projects Benefits: - 5 minutes to fork and start new project - Clear patterns for adding features - Easy to remove unwanted modules - Low maintenance burden - Production-tested architecture Generated with Claude Code https://claude.com/claude-code Co-Authored-By: Claude <noreply@anthropic.com>
WalkthroughThis PR introduces a comprehensive modular architecture framework with extensive documentation, integrates a theme system with next-themes for dark mode support, refactors server action error handling to use structured responses with toast notifications, adds new UI components (color picker, popover, theme toggle), updates styling to use design system tokens, and adjusts configuration for environment-based database IDs. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Areas requiring extra attention:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (8)
src/lib/r2.ts (1)
76-76: Complete or document the stub function.The
listR2Filesfunction is currently empty. If this functionality is planned, consider adding a TODO comment or implementation. If it's not needed, removing it would reduce clutter.Would you like me to help implement this function following R2's listing patterns, or should it be removed?
drizzle.config.ts (1)
16-16: Consider validating environment variable before use.The non-null assertion (
!) will cause a runtime error with an unclear message ifCLOUDFLARE_D1_DATABASE_IDis missing or undefined. Consider adding explicit validation with a helpful error message.Apply this diff to add validation:
+if (!process.env.CLOUDFLARE_D1_DATABASE_ID) { + throw new Error( + "CLOUDFLARE_D1_DATABASE_ID is required. Please check your .dev.vars file." + ); +} + export default defineConfig({ schema: "./src/db/schema.ts", out: "./src/drizzle", dialect: "sqlite", driver: "d1-http", dbCredentials: { accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, - databaseId: process.env.CLOUDFLARE_D1_DATABASE_ID!, + databaseId: process.env.CLOUDFLARE_D1_DATABASE_ID, token: process.env.CLOUDFLARE_D1_TOKEN!, }, });src/modules/todos/components/warning-toast.tsx (1)
10-18: Consider preventing duplicate toasts for the same warning.The current implementation will show the toast again if the component unmounts and remounts with the same warning message. While this may be acceptable for the current use case, you might want to track shown warnings to prevent duplicates.
If duplicate prevention is desired, apply this diff:
+"use client"; + +import { useEffect, useRef } from "react"; import toast from "react-hot-toast"; interface WarningToastProps { warning: string | null; } export function WarningToast({ warning }: WarningToastProps) { + const shownRef = useRef<string | null>(null); + useEffect(() => { - if (warning) { + if (warning && warning !== shownRef.current) { toast.error(warning, { duration: 6000, // Show warning for 6 seconds icon: "⚠️", }); + shownRef.current = warning; } }, [warning]); return null; // This component doesn't render anything }However, the current implementation is acceptable for the cookie-based warning pattern where warnings are short-lived.
docs/DATABASE_SCHEMA.md (1)
750-755: Format URLs as proper markdown links.The References section contains bare URLs that should be formatted as markdown links for better readability and to resolve linting warnings.
Apply this diff:
## References -- **Drizzle ORM Docs**: https://orm.drizzle.team/docs/overview -- **SQLite Data Types**: https://www.sqlite.org/datatype3.html -- **D1 Documentation**: https://developers.cloudflare.com/d1/ -- **Better Auth Schema**: https://www.better-auth.com/docs/concepts/database +- [Drizzle ORM Docs](https://orm.drizzle.team/docs/overview) +- [SQLite Data Types](https://www.sqlite.org/datatype3.html) +- [D1 Documentation](https://developers.cloudflare.com/d1/) +- [Better Auth Schema](https://www.better-auth.com/docs/concepts/database)MODULE_TEMPLATE.md (1)
67-74: Add language identifier to fenced code block.To resolve the linting warning, add a language identifier to the fenced code block:
-``` +```text src/modules/invoices/ ├── actions/ ← Server actions (create, read, update, delete) ├── components/ ← React components ├── models/ ← Database query helpers (optional) ├── schemas/ ← Zod schemas and database tables └── utils/ ← Helper functions (optional)</blockquote></details> <details> <summary>src/components/ui/color-picker.tsx (1)</summary><blockquote> `33-38`: **Consider validating complete hex colors before calling onChange.** The regex allows partial hex values (e.g., "#f", "#ff"), and onChange is called for any partial input. This may cause issues with the HexColorPicker or parent components expecting complete 6-digit hex colors. Consider one of these approaches: 1. **Only call onChange for complete colors** (recommended): ```diff onChange={(e) => { const newColor = e.target.value; - if (/^#[0-9A-Fa-f]{0,6}$/.test(newColor)) { + // Allow typing incomplete colors, but only propagate complete ones + if (/^#[0-9A-Fa-f]{0,6}$/.test(newColor)) { + if (newColor.length === 7) { + onChange(newColor); + } + } +}} +// Alternative: allow typing and propagate all valid partial colors +onChange={(e) => { + const newColor = e.target.value; + if (/^#[0-9A-Fa-f]{0,6}$/.test(newColor)) { onChange(newColor); } }}
- Or document that partial colors are intentionally supported if this is the desired behavior for real-time preview.
src/modules/todos/components/todo-form.tsx (2)
114-129: Good client-side validation, consider extracting constants.The image validation properly enforces size (5MB) and type (PNG/JPG) constraints with clear error messages.
Consider extracting magic numbers as constants for reusability:
+const MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB +const ALLOWED_IMAGE_TYPES = ["image/png", "image/jpeg", "image/jpg"]; + const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => { const file = e.target.files?.[0]; if (file) { - const maxSize = 5 * 1024 * 1024; - if (file.size > maxSize) { + if (file.size > MAX_IMAGE_SIZE) { toast.error("Image must be less than 5MB"); e.target.value = ""; return; } - const validTypes = ["image/png", "image/jpeg", "image/jpg"]; - if (!validTypes.includes(file.type)) { + if (!ALLOWED_IMAGE_TYPES.includes(file.type)) { toast.error("Only PNG and JPG images are allowed"); e.target.value = ""; return; }
6-6: Unused import: useRouter.The
useRouteris imported and instantiated (line 77) but not used in the code. Consider removing it if navigation is handled by server action redirects.-import { useRouter } from "next/navigation"; import { useState, useTransition } from "react"; export function TodoForm({ user, categories: initialCategories, initialData, }: TodoFormProps) { - const router = useRouter(); const [isPending, startTransition] = useTransition();Also applies to: 77-77
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (34)
.dev.vars.example(1 hunks)MODULES.md(1 hunks)MODULE_TEMPLATE.md(1 hunks)PROJECT_BRIEF.md(1 hunks)README.md(5 hunks)SESSION.md(1 hunks)docs/API_ENDPOINTS.md(1 hunks)docs/DATABASE_SCHEMA.md(1 hunks)docs/IMPLEMENTATION_PHASES.md(1 hunks)drizzle.config.ts(1 hunks)package.json(2 hunks)src/app/layout.tsx(2 hunks)src/components/mode-toggle.tsx(1 hunks)src/components/navigation.tsx(1 hunks)src/components/theme-provider.tsx(1 hunks)src/components/ui/color-picker.tsx(1 hunks)src/components/ui/popover.tsx(1 hunks)src/lib/r2.ts(1 hunks)src/modules/auth/utils/auth-client.ts(1 hunks)src/modules/dashboard/dashboard.page.tsx(2 hunks)src/modules/todos/actions/create-category.action.ts(2 hunks)src/modules/todos/actions/create-todo.action.ts(2 hunks)src/modules/todos/actions/get-todos.action.ts(1 hunks)src/modules/todos/actions/update-todo.action.ts(3 hunks)src/modules/todos/components/add-category.tsx(3 hunks)src/modules/todos/components/delete-todo.tsx(4 hunks)src/modules/todos/components/todo-card.tsx(5 hunks)src/modules/todos/components/todo-form.tsx(7 hunks)src/modules/todos/components/toggle-complete.tsx(2 hunks)src/modules/todos/components/warning-toast.tsx(1 hunks)src/modules/todos/edit-todo.page.tsx(1 hunks)src/modules/todos/new-todo.page.tsx(1 hunks)src/modules/todos/todo-list.page.tsx(2 hunks)src/services/summarizer.service.ts(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
src/modules/todos/actions/get-todos.action.ts (1)
src/modules/todos/schemas/category.schema.ts (1)
categories(7-21)
src/components/ui/color-picker.tsx (3)
src/components/ui/popover.tsx (1)
Popover(48-48)src/components/ui/button.tsx (1)
Button(58-58)src/components/ui/input.tsx (1)
Input(21-21)
src/modules/todos/actions/create-category.action.ts (1)
src/modules/todos/schemas/category.schema.ts (1)
Category(39-39)
src/components/ui/popover.tsx (1)
src/lib/utils.ts (1)
cn(4-6)
src/modules/todos/components/todo-form.tsx (2)
src/modules/todos/actions/update-todo.action.ts (1)
updateTodoAction(17-114)src/modules/todos/actions/create-todo.action.ts (1)
createTodoAction(13-110)
src/modules/todos/components/todo-card.tsx (1)
src/modules/todos/models/todo.enum.ts (2)
TodoPriority(8-13)TodoStatus(1-6)
src/components/navigation.tsx (2)
src/components/mode-toggle.tsx (1)
ModeToggle(8-44)src/modules/auth/components/logout-button.tsx (1)
LogoutButton(9-31)
src/modules/todos/todo-list.page.tsx (2)
src/modules/todos/actions/get-todos.action.ts (1)
getAllTodos(8-46)src/modules/todos/components/warning-toast.tsx (1)
WarningToast(10-21)
src/modules/todos/components/add-category.tsx (2)
src/modules/todos/actions/create-category.action.ts (1)
createCategory(13-72)src/components/ui/color-picker.tsx (1)
ColorPicker(13-45)
src/app/layout.tsx (1)
src/components/theme-provider.tsx (1)
ThemeProvider(6-8)
🪛 LanguageTool
SESSION.md
[uncategorized] ~3-~3: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...Project: fullstack-next-cloudflare (Open Source Contributions) Repository: https://...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
docs/API_ENDPOINTS.md
[grammar] ~89-~89: Use a hyphen to join words.
Context: ...uth/sign-up/email- Email/password sign up -POST /api/auth/sign-in/email` - Em...
(QB_NEW_EN_HYPHEN)
[grammar] ~90-~90: Use a hyphen to join words.
Context: ...uth/sign-in/email- Email/password sign in -POST /api/auth/sign-out` - Sign ou...
(QB_NEW_EN_HYPHEN)
MODULE_TEMPLATE.md
[uncategorized] ~135-~135: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... numbers (store money in cents to avoid floating point issues) - Add .notNull() for required...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
[grammar] ~1030-~1030: Use a hyphen to join words.
Context: ...- Add sorting options - Create export to PDF feature - Add email notifications - ...
(QB_NEW_EN_HYPHEN)
docs/IMPLEMENTATION_PHASES.md
[style] ~326-~326: The double modal “requires LEFT” is nonstandard (only accepted in certain dialects). Consider “to be LEFT”.
Context: ... - Fetching contacts with tags requires LEFT JOIN on junction table - Drizzle syntax...
(NEEDS_FIXED)
🪛 markdownlint-cli2 (0.18.1)
MODULE_TEMPLATE.md
67-67: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
MODULES.md
23-23: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
32-32: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
145-145: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
150-150: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
161-161: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
167-167: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
182-182: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
194-194: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
199-199: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
220-220: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
227-227: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
233-233: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
265-265: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
290-290: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
306-306: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
368-368: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
650-650: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
660-660: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/IMPLEMENTATION_PHASES.md
40-40: Bare URL used
(MD034, no-bare-urls)
docs/DATABASE_SCHEMA.md
752-752: Bare URL used
(MD034, no-bare-urls)
753-753: Bare URL used
(MD034, no-bare-urls)
754-754: Bare URL used
(MD034, no-bare-urls)
755-755: Bare URL used
(MD034, no-bare-urls)
PROJECT_BRIEF.md
4-4: Bare URL used
(MD034, no-bare-urls)
5-5: Bare URL used
(MD034, no-bare-urls)
🔇 Additional comments (39)
src/modules/todos/actions/update-todo.action.ts (2)
56-61: Cookie-based warning pattern is well-designed.The approach of setting a short-lived cookie to communicate non-critical failures (image upload) while allowing the main operation (todo update) to succeed is a good user experience pattern. The 10-second expiry is appropriate for a post-redirect notification.
96-99: LGTM! Correct handling of Next.js redirect mechanism.Next.js 15 uses exceptions for control flow in redirects. This guard correctly distinguishes redirect "errors" from actual failures, preventing false error logs and ensuring redirects work as intended.
.dev.vars.example (1)
7-9: LGTM! Clear documentation for database ID.The comment provides helpful guidance on how to obtain the database ID, with specific wrangler commands. This aligns well with the environment variable usage in
drizzle.config.ts.src/services/summarizer.service.ts (1)
47-47: LGTM! Typo corrections improve code quality.The fixes correctly rename
buildSystenPrompttobuildSystemPromptandstyleInstructructionstostyleInstructions, with all references properly updated.Also applies to: 76-90
src/modules/todos/components/delete-todo.tsx (2)
41-43: LGTM! Toast notification improves user experience.Replacing
alert()withtoast.error()provides a more modern, less intrusive error notification that aligns with the overall application UX.
54-55: LGTM! Design tokens and accessibility improvements.The changes improve both maintainability (using semantic
destructivetokens instead of hardcodedredcolors) and accessibility (addingaria-labelto the icon-only button).docs/IMPLEMENTATION_PHASES.md (1)
1-834: Excellent comprehensive implementation guide.This documentation provides a well-structured, phase-by-phase implementation plan with clear verification criteria, data flow diagrams, and gotchas. The level of detail is appropriate for developers forking the project.
Minor suggestion: Line 40 contains a bare URL (
http://localhost:5173). Consider wrapping it in angle brackets for better Markdown rendering:<http://localhost:5173>.SESSION.md (1)
1-163: LGTM! Useful session tracking documentation.This file provides excellent context for understanding the project's evolution and current state. The organization by phases with specific PR references makes it easy to track progress and understand what has been completed.
MODULE_TEMPLATE.md (1)
883-888: LGTM! Correctly implements Next.js 15 async params.The example properly types
paramsas a Promise and awaits it before use, which is the correct pattern for Next.js 15.Based on Next.js 15 documentation.
docs/API_ENDPOINTS.md (1)
1-872: Excellent comprehensive API documentation!This documentation provides thorough coverage of the API surface including REST endpoints, server actions, authentication utilities, data models, and error handling patterns. The structure is clear with practical examples for each endpoint/action.
Minor note: The LanguageTool warnings about "sign up" and "sign in" hyphenation are style preferences and can be safely ignored.
MODULES.md (1)
1-699: Comprehensive and well-structured module system guide!This documentation effectively explains the feature-based module architecture with clear examples for adding/removing modules, best practices, and troubleshooting guidance. The progressive examples (Todos removal, Invoices addition) make it easy to follow.
Note: The static analysis warnings about fenced code blocks and emphasis-as-heading are minor formatting issues that don't impact the documentation quality.
src/modules/todos/new-todo.page.tsx (1)
23-23: LGTM! Standardized to design system tokens.The change from
text-gray-600totext-muted-foregroundaligns with the design system standardization across the codebase and improves theme compatibility.src/modules/todos/actions/create-todo.action.ts (1)
64-69: Good pattern for non-fatal warning notifications.Setting a short-lived cookie to communicate the image upload failure while preserving the successful todo creation is a good UX pattern. The 10-second expiry is appropriate for the redirect flow.
Note: The code correctly awaits
cookies()which is required in Next.js 15 where cookie access is asynchronous. Based on Next.js 15 documentation.src/modules/todos/edit-todo.page.tsx (1)
42-42: LGTM! Consistent design token usage.Matches the design system standardization applied across other pages in this PR.
package.json (1)
39-54: Dependency versions verified as current.All three dependencies are at their latest stable versions:
next-themes0.4.6 ✓react-colorful5.6.1 ✓@radix-ui/react-popover1.1.15 ✓The additions appropriately support the theme system and UI component enhancements.
src/modules/todos/components/toggle-complete.tsx (1)
4-4: LGTM! Improved error notification UX.Replacing the browser
alertwithtoast.errorprovides a better user experience with consistent, non-blocking notifications. The error message extraction with fallback is well handled.Also applies to: 35-37
src/modules/todos/actions/get-todos.action.ts (1)
20-20: LGTM! Category color support added.The addition of
categoryColorfrom thecategories.colorfield expands the Todo data shape to support visual categorization. The left join correctly handles cases where todos have no associated category, making this field nullable.src/app/layout.tsx (1)
31-31: LGTM! Theme system properly integrated.The ThemeProvider integration is well-implemented:
suppressHydrationWarningcorrectly prevents hydration mismatches with client-side theme detectionbg-backgroundreplaces hard-coded color for theme responsiveness- ThemeProvider configuration follows next-themes best practices
- Moving Toaster inside ThemeProvider ensures toast notifications respect the active theme
Also applies to: 33-33, 35-43
src/components/mode-toggle.tsx (2)
8-24: LGTM! Proper hydration handling.The mounted state pattern correctly prevents hydration mismatches by deferring theme-dependent rendering until after the client mount. The loading state with a disabled button provides good UX during initialization.
26-42: LGTM! Clean theme cycling implementation.The theme toggle implementation is well-designed:
- Clear cycling order (light → dark → system → light)
- Appropriate icons for each theme state
- Good accessibility with sr-only labels and title attribute
- Proper button sizing and styling
src/components/theme-provider.tsx (1)
1-8: LGTM! Clean provider wrapper.Simple and effective wrapper around
NextThemesProviderthat forwards all props correctly. The abstraction provides a centralized import point for the theme provider.src/modules/auth/utils/auth-client.ts (1)
6-9: LGTM! Improved SSR-aware baseURL handling.The updated baseURL logic properly handles both client and server contexts:
- Client-side auto-detects from
window.location.origin(works with any port)- Server-side uses environment variable with sensible fallback
- More robust than NODE_ENV-based branching for SSR/SSG scenarios
src/components/navigation.tsx (2)
5-7: LGTM! Improved maintainability and theme support.The changes enhance the navigation component:
- Route constants replace hard-coded paths, improving maintainability and type safety
bg-cardreplacesbg-whitefor proper theme support- Removing
text-gray-900allows theme system to control text colorAlso applies to: 11-11, 16-28
36-39: LGTM! Clean integration of theme toggle.The ModeToggle is appropriately positioned alongside the LogoutButton with proper spacing. The flex container provides good layout control.
README.md (2)
5-46: LGTM! Excellent modular architecture documentation.The new Modular Architecture section provides clear guidance for developers:
- Well-structured overview of the module system
- Practical Quick Start guide with fork-and-customize workflow
- Clear references to detailed documentation (MODULES.md)
- Benefits are clearly articulated
This aligns perfectly with the PR objectives to document the starter kit approach.
187-187: LGTM! Environment variable documentation updated.The additions of
CLOUDFLARE_D1_DATABASE_IDthroughout the documentation properly reflect the environment-based database configuration approach. The explanatory notes (especially lines 303-306) provide helpful context about where to obtain the database ID and how to use it.Also applies to: 303-306, 372-372, 447-447
src/modules/dashboard/dashboard.page.tsx (1)
16-23: LGTM - Design system token migration.The styling updates consistently migrate from hardcoded color values to design system tokens (text-muted-foreground, bg-primary/10, text-primary), improving theme consistency and maintainability.
Also applies to: 68-99
src/modules/todos/todo-list.page.tsx (2)
13-21: LGTM - Correct Next.js 15 async cookies pattern.The cookie handling correctly uses
await cookies()and conditionally deletes the cookie after reading it, following Next.js 15's async request API pattern.
25-25: LGTM - WarningToast integration.The WarningToast component is properly integrated to display server-side warnings passed via cookies, providing user feedback for image upload failures or other non-blocking issues.
src/modules/todos/components/todo-form.tsx (1)
185-201: LGTM - Proper toast notification pattern with redirect handling.The toast.promise implementation provides good user feedback, and correctly suppresses toast for Next.js redirects (line 196-198) which are flow control, not actual errors.
src/modules/todos/components/add-category.tsx (2)
61-77: LGTM - Cleaner structured error handling.The refactored submission handler uses structured result objects instead of try/catch, making error paths explicit and aligning with the updated server action pattern. The success path correctly checks for
result.databefore proceeding.
132-135: LGTM - ColorPicker integration.The ColorPicker component properly integrates with React Hook Form, using
field.value || "#6366f1"as a fallback for the initial color value.src/modules/todos/actions/create-category.action.ts (1)
13-71: LGTM - Improved structured error handling pattern.The refactored return type provides explicit success/error/data paths, eliminating the need for try/catch in callers and making error handling more predictable and type-safe. All error cases return descriptive messages, and revalidation occurs correctly before the success response.
src/components/ui/popover.tsx (1)
1-48: LGTM - Solid Radix UI wrapper implementation.The Popover components properly wrap Radix UI primitives with consistent styling, data-slot attributes, and type-safe prop forwarding. The Portal usage ensures proper positioning, and default props (align="center", sideOffset={4}) are sensible.
Minor style note: Consider adding a semicolon after "use client" on line 1 for consistency with other files, though this doesn't affect functionality.
src/modules/todos/components/todo-card.tsx (5)
19-19: LGTM!The addition of
categoryColoras an optional, nullable field is consistent with the existing pattern for category properties.
31-41: LGTM!The migration from explicit color values to design system tokens improves theming support and maintains consistency across priority and status badges.
72-82: LGTM!The completed state styling appropriately uses
text-muted-foregroundtokens for consistency with the design system, and the line-through decoration clearly indicates the completed status.
134-138: LGTM!The migration from an explicit color to the
text-primarytoken maintains consistency with the design system migration.
141-153: LGTM!The due date styling appropriately uses semantic color tokens (
text-destructivefor overdue,text-muted-foregroundfor normal) to clearly communicate the todo's status.
| # Database Schema: Fullstack Next.js + Cloudflare CRM | ||
|
|
||
| **Database**: Cloudflare D1 (distributed SQLite) | ||
| **Migrations**: Located in `drizzle/` | ||
| **ORM**: Drizzle ORM | ||
| **Schema Files**: `src/modules/*/schemas/*.schema.ts` | ||
|
|
||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| The CRM extends the existing template database (users, sessions, todos, categories) with 4 new tables for contacts and deals management. | ||
|
|
||
| **Existing Tables** (from template): | ||
| - `user` - User accounts (Better Auth) | ||
| - `session` - Active sessions (Better Auth) | ||
| - `account` - OAuth provider accounts (Better Auth) | ||
| - `verification` - Email verification tokens (Better Auth) | ||
| - `todos` - Task management | ||
| - `categories` - Todo categories | ||
|
|
||
| **New CRM Tables** (added in Phase 2): | ||
| - `contacts` - Contact profiles | ||
| - `contact_tags` - User-defined tags | ||
| - `contacts_to_tags` - Many-to-many junction table | ||
| - `deals` - Sales pipeline deals | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify documentation scope: CRM schema vs. current implementation.
The PR objectives describe documenting the existing modular architecture (auth, todos, dashboard), but this file documents a "Phase 2 CRM" with contacts, deals, and tags tables. This appears to be aspirational/future-work documentation rather than documenting the current codebase.
If this is intended as example documentation for the module template, consider:
- Adding a clear note at the top stating this is example/future documentation
- Renaming to reflect it's a template (e.g.,
docs/examples/CRM_SCHEMA.md) - Ensuring consistency between the PR description and documentation scope
If this CRM schema is already implemented, please disregard this comment.
| // CLOUDFLARE_R2_URL already includes the protocol (https://) | ||
| const publicUrl = `${(env as any).CLOUDFLARE_R2_URL}/${key}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add type safety and validate the environment variable.
The (env as any) type assertion bypasses type checking and could mask a missing or undefined CLOUDFLARE_R2_URL at compile time. If the environment variable is not defined, the URL becomes "undefined/${key}", leading to a malformed URL.
Consider this approach:
// Return public URL of R2 (should be using custom domain)
// CLOUDFLARE_R2_URL already includes the protocol (https://)
- const publicUrl = `${(env as any).CLOUDFLARE_R2_URL}/${key}`;
+ const r2BaseUrl = (env as any).CLOUDFLARE_R2_URL as string | undefined;
+ if (!r2BaseUrl) {
+ return {
+ success: false,
+ error: "CLOUDFLARE_R2_URL environment variable is not configured",
+ };
+ }
+ const publicUrl = `${r2BaseUrl}/${key}`;Additionally, consider extending the environment type definitions to include CLOUDFLARE_R2_URL to avoid the any cast entirely.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // CLOUDFLARE_R2_URL already includes the protocol (https://) | |
| const publicUrl = `${(env as any).CLOUDFLARE_R2_URL}/${key}`; | |
| // Return public URL of R2 (should be using custom domain) | |
| // CLOUDFLARE_R2_URL already includes the protocol (https://) | |
| const r2BaseUrl = (env as any).CLOUDFLARE_R2_URL as string | undefined; | |
| if (!r2BaseUrl) { | |
| return { | |
| success: false, | |
| error: "CLOUDFLARE_R2_URL environment variable is not configured", | |
| }; | |
| } | |
| const publicUrl = `${r2BaseUrl}/${key}`; |
🤖 Prompt for AI Agents
In src/lib/r2.ts around lines 49-50, the code uses (env as
any).CLOUDFLARE_R2_URL which bypasses type checking and can produce
"undefined/${key}" at runtime; update the code to (1) add CLOUDFLARE_R2_URL to
your environment/Env type so you no longer need the any cast, (2) perform a
runtime validation that env.CLOUDFLARE_R2_URL is a non-empty string and throw or
return an explicit error if missing, and (3) construct publicUrl only after
validation (optionally normalizing/trimming slashes) so malformed URLs cannot be
generated.
| <Badge | ||
| variant="outline" | ||
| className="border-2" | ||
| style={todo.categoryColor ? { | ||
| backgroundColor: `${todo.categoryColor}15`, | ||
| borderColor: todo.categoryColor, | ||
| color: todo.categoryColor | ||
| } : undefined} | ||
| > | ||
| {todo.categoryName} | ||
| </Badge> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add color format validation and consider accessibility.
The dynamic category badge styling has two concerns:
-
Color format assumption: The code assumes hex format (
${todo.categoryColor}15), which will break if users provide colors inrgb(),hsl(), or named color formats. -
Accessibility risk: Using the category color directly for text without contrast validation could result in insufficient contrast ratios, especially problematic for users with low vision. WCAG AA requires at least 4.5:1 contrast for normal text.
Consider adding:
- Color format validation/normalization before rendering
- Contrast ratio checking, or use the color only for the border while keeping text/background theme-aware
- Fallback styling when contrast is insufficient
Example approach:
// In a utility file
function isValidHexColor(color: string): boolean {
return /^#([0-9A-F]{3}){1,2}$/i.test(color);
}
function addAlphaToHex(hex: string, alpha: string): string {
return isValidHexColor(hex) ? `${hex}${alpha}` : undefined;
}Then in the component:
{todo.categoryName && (
<Badge
variant="outline"
className="border-2"
- style={todo.categoryColor ? {
- backgroundColor: `${todo.categoryColor}15`,
- borderColor: todo.categoryColor,
- color: todo.categoryColor
- } : undefined}
+ style={todo.categoryColor && isValidHexColor(todo.categoryColor) ? {
+ backgroundColor: addAlphaToHex(todo.categoryColor, '15'),
+ borderColor: todo.categoryColor,
+ color: todo.categoryColor
+ } : undefined}
>
{todo.categoryName}
</Badge>
)}Alternatively, for better accessibility, consider using the color only for the border and keeping text theme-aware:
style={todo.categoryColor ? {
borderColor: todo.categoryColor,
borderWidth: '2px'
} : undefined}🤖 Prompt for AI Agents
In src/modules/todos/components/todo-card.tsx around lines 121 to 131, the Badge
style assumes a hex color and uses `${todo.categoryColor}15` which breaks for
non-hex color formats and can cause poor text contrast; fix by
validating/normalizing the color before using it (create/consume utility
functions isValidHexColor and addAlphaToHex), only append the alpha when the
color is a valid hex, otherwise avoid creating a concatenated color string and
instead apply the color only to the border (e.g., set borderColor and
borderWidth) while keeping text and background theme-aware; additionally run a
contrast check (utility that computes contrast ratio) and if contrast is
insufficient fall back to a safe text color or switch to border-only styling so
the badge text always meets accessibility contrast requirements.
…ev#20 **Phase 1: Remove CRM Content Leak** - Delete docs/DATABASE_SCHEMA.md (CRM contacts/deals/tags from separate project) - Delete docs/IMPLEMENTATION_PHASES.md (CRM implementation phases) **Phase 2: Critical Accessibility Fixes (PR ifindev#28)** - Add ref forwarding to Popover components (PopoverTrigger, PopoverContent, PopoverAnchor) - Prevents accessibility issues with asChild pattern - Follows shadcn/ui standards with React.forwardRef + displayName **Phase 3: UX Improvements (PR ifindev#28)** - Add visual validation feedback to color picker input - Show red border when hex color is invalid - Allow partial input while typing - Remove redundant backgroundColor from button (keep only on inner div) **Phase 4: Markdown Fixes (PR ifindev#29)** - Add 'plaintext' language identifier to code block (line 67) - Fix hyphenation: "export to PDF" → "export-to-PDF" (line 1030) **Note on PR ifindev#20:** - createCategory already uses correct discriminated union pattern - No changes needed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Overview
Adds comprehensive documentation to help developers fork and customize this template for new projects.
What's Added
MODULES.md - Complete guide to the module system
MODULE_TEMPLATE.md - Step-by-step tutorial for creating new modules
README.md - Updated with "Modular Architecture" section
Why This Helps
The project is already structured with feature modules (
src/modules/auth,src/modules/todos,src/modules/dashboard), but there's no documentation explaining:This documentation makes it significantly easier for developers to use this as a production starter kit.
Examples Included
The MODULE_TEMPLATE.md includes a complete, copy-paste-ready example:
todosmoduleArchitecture Approach
Documents the fork-and-customize pattern (same approach as T3 Stack):
This is simpler and lower-maintenance than a plugin system, while still providing excellent reusability.
Benefits
Testing
Documentation has been reviewed for:
Happy to make any adjustments if you'd like different formatting or content!
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
UI Updates
Documentation
Dependencies