suhail
spoecs
9eafd9f
# 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`)