Spaces:
Sleeping
Sleeping
| # Research: Full-Stack Integration & UI Experience | |
| **Feature**: 002-fullstack-ui-integration | |
| **Date**: 2026-01-09 | |
| **Status**: Complete | |
| ## Overview | |
| This research document captures technical decisions, patterns, and best practices for integrating existing functionality (Specs 1 & 2) into a cohesive user experience. Since this is a polish/integration feature rather than new functionality, most decisions reference existing implementations. | |
| ## Research Areas | |
| ### 1. UI State Management Patterns | |
| **Decision**: Use React hooks (useState, useEffect) with loading/error/data states | |
| **Rationale**: | |
| - Already established pattern in existing components (TaskList, TaskForm) | |
| - Simple and effective for component-level state | |
| - No need for global state management (Redux, Zustand) for this scope | |
| - Aligns with Next.js App Router best practices | |
| **Pattern**: | |
| ```typescript | |
| const [isLoading, setIsLoading] = useState(false); | |
| const [error, setError] = useState<string | null>(null); | |
| const [data, setData] = useState<T | null>(null); | |
| ``` | |
| **Alternatives Considered**: | |
| - React Query / TanStack Query: Overkill for current scope, adds dependency | |
| - Redux: Too complex for simple loading/error states | |
| - Context API: Not needed - state is component-local | |
| **References**: | |
| - Existing: `frontend/src/components/tasks/TaskList.tsx` (lines 10-15) | |
| - Next.js Data Fetching: https://nextjs.org/docs/app/building-your-application/data-fetching | |
| --- | |
| ### 2. Loading State Indicators | |
| **Decision**: Use Tailwind CSS spinner with descriptive text | |
| **Rationale**: | |
| - Consistent with existing Tailwind-only styling constraint | |
| - Accessible (includes text for screen readers) | |
| - Lightweight (no external animation libraries) | |
| - Fast to implement and customize | |
| **Pattern**: | |
| ```tsx | |
| {isLoading && ( | |
| <div className="flex items-center justify-center p-8"> | |
| <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div> | |
| <span className="ml-3 text-gray-600">Loading tasks...</span> | |
| </div> | |
| )} | |
| ``` | |
| **Alternatives Considered**: | |
| - Skeleton screens: More complex, better for content-heavy pages | |
| - Progress bars: Not suitable for indeterminate loading | |
| - Third-party libraries (react-spinners): Adds dependency, unnecessary | |
| **References**: | |
| - Tailwind Animation: https://tailwindcss.com/docs/animation | |
| - Accessibility: Include aria-live="polite" for screen readers | |
| --- | |
| ### 3. Empty State Design | |
| **Decision**: Centered message with icon and call-to-action | |
| **Rationale**: | |
| - Guides users toward next action (create first task) | |
| - Reduces confusion when no data exists | |
| - Industry standard pattern (GitHub, Notion, Linear) | |
| - Improves onboarding experience | |
| **Pattern**: | |
| ```tsx | |
| {tasks.length === 0 && !isLoading && ( | |
| <div className="text-center py-12"> | |
| <p className="text-gray-500 text-lg mb-4">No tasks yet</p> | |
| <p className="text-gray-400 mb-6">Create your first task to get started</p> | |
| <button className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"> | |
| Create Task | |
| </button> | |
| </div> | |
| )} | |
| ``` | |
| **Alternatives Considered**: | |
| - Blank screen: Poor UX, users don't know what to do | |
| - Tutorial overlay: Too intrusive for simple app | |
| - Animated illustrations: Adds complexity, not needed | |
| **References**: | |
| - Empty States Best Practices: https://www.nngroup.com/articles/empty-state-design/ | |
| - Material Design Empty States: https://m2.material.io/design/communication/empty-states.html | |
| --- | |
| ### 4. Error Handling & Display | |
| **Decision**: Inline error messages with retry button | |
| **Rationale**: | |
| - Keeps user in context (no modal dialogs) | |
| - Provides actionable recovery (retry button) | |
| - Consistent with existing API error handling | |
| - Follows progressive disclosure principle | |
| **Pattern**: | |
| ```tsx | |
| {error && ( | |
| <div className="bg-red-50 border border-red-200 rounded-md p-4 mb-4"> | |
| <div className="flex items-start"> | |
| <div className="flex-1"> | |
| <h3 className="text-sm font-medium text-red-800">Error</h3> | |
| <p className="text-sm text-red-700 mt-1">{error}</p> | |
| </div> | |
| <button | |
| onClick={handleRetry} | |
| className="ml-3 text-sm font-medium text-red-600 hover:text-red-500" | |
| > | |
| Retry | |
| </button> | |
| </div> | |
| </div> | |
| )} | |
| ``` | |
| **Alternatives Considered**: | |
| - Toast notifications: Disappear too quickly, users miss them | |
| - Modal dialogs: Disruptive, blocks entire UI | |
| - Console.error only: Not user-facing, poor UX | |
| **References**: | |
| - Existing: `frontend/src/lib/api.ts` APIError class | |
| - Error Message Guidelines: https://www.nngroup.com/articles/error-message-guidelines/ | |
| --- | |
| ### 5. Responsive Design Breakpoints | |
| **Decision**: Use Tailwind's default breakpoints (sm: 640px, md: 768px, lg: 1024px) | |
| **Rationale**: | |
| - Already configured in existing tailwind.config.ts | |
| - Industry-standard breakpoints | |
| - Covers mobile (320px-767px), tablet (768px-1023px), desktop (1024px+) | |
| - No custom breakpoints needed for this scope | |
| **Pattern**: | |
| ```tsx | |
| <div className="grid gap-6 lg:grid-cols-3 md:grid-cols-2 grid-cols-1"> | |
| {/* Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns */} | |
| </div> | |
| ``` | |
| **Breakpoint Strategy**: | |
| - **Mobile (<768px)**: Single column, stacked layout | |
| - **Tablet (768px-1023px)**: Two columns where appropriate | |
| - **Desktop (≥1024px)**: Three columns, full layout | |
| **Alternatives Considered**: | |
| - Custom breakpoints: Unnecessary complexity | |
| - Container queries: Not widely supported yet | |
| - Fixed pixel widths: Not responsive | |
| **References**: | |
| - Existing: `frontend/tailwind.config.ts` | |
| - Tailwind Responsive Design: https://tailwindcss.com/docs/responsive-design | |
| --- | |
| ### 6. Touch Target Sizing | |
| **Decision**: Minimum 44x44px for all interactive elements | |
| **Rationale**: | |
| - WCAG 2.1 Level AAA guideline (44x44px) | |
| - Apple Human Interface Guidelines (44x44pt) | |
| - Material Design (48x48dp) | |
| - Prevents accidental taps on mobile devices | |
| **Pattern**: | |
| ```tsx | |
| <button className="min-h-[44px] min-w-[44px] px-4 py-2"> | |
| Click Me | |
| </button> | |
| ``` | |
| **Implementation**: | |
| - Buttons: `min-h-[44px]` class | |
| - Links: Adequate padding (py-2 px-3 minimum) | |
| - Form inputs: `h-11` or `h-12` classes | |
| - Checkboxes: `w-5 h-5` (20px) with larger clickable area via padding | |
| **Alternatives Considered**: | |
| - 48x48px: More generous but takes more space | |
| - 40x40px: Below accessibility guidelines | |
| - Variable sizing: Inconsistent, harder to maintain | |
| **References**: | |
| - WCAG 2.1 Success Criterion 2.5.5: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html | |
| - Apple HIG: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/ | |
| --- | |
| ### 7. API Client Error Handling | |
| **Decision**: Centralized error handling in fetchAPI with typed errors | |
| **Rationale**: | |
| - Already implemented in `frontend/src/lib/api.ts` | |
| - Consistent error structure across all API calls | |
| - TypeScript types for error responses | |
| - Automatic 401 handling with signin redirect | |
| **Existing Implementation**: | |
| ```typescript | |
| class APIError extends Error { | |
| constructor( | |
| message: string, | |
| public status: number, | |
| public errorCode?: string, | |
| public fieldErrors?: Record<string, string[]> | |
| ) { | |
| super(message); | |
| this.name = 'APIError'; | |
| } | |
| } | |
| ``` | |
| **Enhancement Needed**: None - existing implementation is sufficient | |
| **Alternatives Considered**: | |
| - Per-component error handling: Inconsistent, duplicated code | |
| - Global error boundary: Too coarse-grained, loses context | |
| - Axios interceptors: Adds dependency, fetch is sufficient | |
| **References**: | |
| - Existing: `frontend/src/lib/api.ts` (lines 6-16, 18-59) | |
| --- | |
| ### 8. Form Validation Patterns | |
| **Decision**: Client-side validation with inline error messages | |
| **Rationale**: | |
| - Already implemented in SignUpForm and SignInForm | |
| - Immediate feedback improves UX | |
| - Reduces unnecessary API calls | |
| - Backend validation still enforced (defense in depth) | |
| **Existing Pattern**: | |
| ```typescript | |
| const [errors, setErrors] = useState<Record<string, string>>({}); | |
| const validateEmail = (email: string): boolean => { | |
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | |
| return emailRegex.test(email); | |
| }; | |
| // Display errors inline | |
| {errors.email && ( | |
| <p className="text-red-600 text-sm mt-1">{errors.email}</p> | |
| )} | |
| ``` | |
| **Enhancement Needed**: None - existing validation is sufficient | |
| **Alternatives Considered**: | |
| - Form libraries (React Hook Form, Formik): Overkill for simple forms | |
| - Schema validation (Zod, Yup): Adds complexity, not needed | |
| - Server-side only: Poor UX, slow feedback | |
| **References**: | |
| - Existing: `frontend/src/components/auth/SignUpForm.tsx` (lines 20-40) | |
| - Existing: `frontend/src/components/auth/SignInForm.tsx` | |
| --- | |
| ### 9. Optimistic UI Updates | |
| **Decision**: Update UI immediately, rollback on error | |
| **Rationale**: | |
| - Improves perceived performance | |
| - Makes app feel responsive | |
| - Standard pattern for modern web apps | |
| - Easy to implement with React state | |
| **Pattern**: | |
| ```typescript | |
| const handleToggleComplete = async (taskId: number) => { | |
| // Optimistic update | |
| setTasks(tasks.map(t => | |
| t.id === taskId ? { ...t, completed: !t.completed } : t | |
| )); | |
| try { | |
| await patchTask(taskId, { completed: !task.completed }); | |
| } catch (error) { | |
| // Rollback on error | |
| setTasks(tasks.map(t => | |
| t.id === taskId ? { ...t, completed: task.completed } : t | |
| )); | |
| setError('Failed to update task'); | |
| } | |
| }; | |
| ``` | |
| **Alternatives Considered**: | |
| - Wait for server response: Slower, less responsive | |
| - No rollback: Inconsistent state on errors | |
| - Pessimistic updates: Poor UX | |
| **References**: | |
| - React Optimistic Updates: https://react.dev/reference/react/useOptimistic | |
| - Existing: Partially implemented in TaskItem component | |
| --- | |
| ### 10. Environment Configuration | |
| **Decision**: Use .env files with clear documentation | |
| **Rationale**: | |
| - Already established in Specs 1 & 2 | |
| - Standard practice for web applications | |
| - Keeps secrets out of source code | |
| - Easy to configure for different environments | |
| **Existing Configuration**: | |
| - Backend: `backend/.env` (DATABASE_URL, BETTER_AUTH_SECRET, JWT_ALGORITHM, JWT_EXPIRATION_DAYS) | |
| - Frontend: `frontend/.env.local` (NEXT_PUBLIC_API_URL, BETTER_AUTH_SECRET) | |
| **Enhancement Needed**: Document in README files and quickstart.md | |
| **Alternatives Considered**: | |
| - Hardcoded values: Security risk, not flexible | |
| - Config files: Less standard than .env | |
| - Cloud secret managers: Overkill for local development | |
| **References**: | |
| - Existing: `backend/.env`, `frontend/.env.local` | |
| - Next.js Environment Variables: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables | |
| --- | |
| ## Summary of Decisions | |
| | Area | Decision | Status | | |
| |------|----------|--------| | |
| | UI State Management | React hooks (useState, useEffect) | ✅ Existing | | |
| | Loading Indicators | Tailwind CSS spinner with text | 🔄 To implement | | |
| | Empty States | Centered message with CTA | 🔄 To implement | | |
| | Error Display | Inline errors with retry button | 🔄 To implement | | |
| | Responsive Design | Tailwind default breakpoints | ✅ Existing | | |
| | Touch Targets | Minimum 44x44px | 🔄 To verify | | |
| | API Error Handling | Centralized fetchAPI with typed errors | ✅ Existing | | |
| | Form Validation | Client-side with inline errors | ✅ Existing | | |
| | Optimistic Updates | Immediate UI update with rollback | 🔄 To implement | | |
| | Environment Config | .env files with documentation | ✅ Existing | | |
| **Legend**: | |
| - ✅ Existing: Already implemented in Specs 1 & 2 | |
| - 🔄 To implement: Needs to be added in this feature | |
| - 🔄 To verify: Needs to be checked/refined | |
| ## Implementation Priorities | |
| Based on user story priorities (P1-P5): | |
| 1. **P1 (Authentication Flow)**: Verify existing implementation works end-to-end | |
| 2. **P2 (UI States)**: Implement loading, empty, and error states | |
| 3. **P3 (Responsive Design)**: Verify and refine responsive layouts | |
| 4. **P4 (API Communication)**: Verify centralized API client works correctly | |
| 5. **P5 (Environment Setup)**: Document configuration in README files | |
| ## Next Steps | |
| 1. Generate `data-model.md` (reference existing User and Task entities) | |
| 2. Generate `contracts/` (document existing API endpoints) | |
| 3. Generate `quickstart.md` (testing and setup guide) | |
| 4. Proceed to task generation (`/sp.tasks`) | |