feat: Sprint 2.5 - Mobile-First Foundation

 Implemented:
- Mobile-first Tailwind breakpoints (xs: 375px → 2xl: 1536px)
- Tablet-optimized for cultivation floor (md: 768px primary target)
- Touch-friendly spacing (44px minimum tap targets)
- Mobile-optimized font sizes (16px minimum to prevent iOS zoom)
- Touch-friendly base styles (smooth scrolling, tap highlights)
- Added 777 Wolfpack team logo for splash screen

�� Mobile-First Features:
- Responsive container padding (1rem mobile → 3rem desktop)
- Touch target utilities (touch: 44px, touch-lg: 56px)
- iOS-optimized inputs (prevent zoom, smooth scrolling)
- Webkit touch improvements

🎨 Branding:
- Added 777 Wolfpack logo to /frontend/public/assets/
- Team name: 777 Wolfpack (initial cultivation team users)

⏭️ Next: Mobile navigation + responsive page layouts
This commit is contained in:
fullsizemalt 2025-12-09 13:55:53 -08:00
parent 9dc0586d67
commit 4c0aad0e06
5 changed files with 488 additions and 2 deletions

149
docs/SPRINT-2-PROGRESS.md Normal file
View file

@ -0,0 +1,149 @@
# Sprint 2 Progress Update
**Date**: 2025-12-09
**Time**: ~1 hour elapsed
**Status**: Phase 1 Complete ✅
---
## ✅ Completed (Phase 1: Backend Auth Core)
### Task 2.1: Password Hashing ✅
- ✅ Installed bcrypt + types
- ✅ Created `backend/src/utils/password.ts`
- ✅ Implemented `hashPassword()` and `comparePassword()`
- ✅ Updated seed script to hash all passwords
- ✅ Added 4 test users (one per role)
### Task 2.2: JWT Token Generation ✅
- ✅ Installed jsonwebtoken + types
- ✅ Created `backend/src/utils/jwt.ts`
- ✅ Implemented `generateAccessToken()` (15min expiry)
- ✅ Implemented `generateRefreshToken()` (7d expiry)
- ✅ Implemented `verifyToken()`
### Task 2.3: Updated Auth Controller ✅
- ✅ Updated login to use bcrypt password comparison
- ✅ Updated login to return access + refresh tokens
- ✅ Added `refresh` endpoint
- ✅ Added `logout` endpoint (placeholder for Redis)
- ✅ Proper error handling
### Task 2.4: Updated Routes ✅
- ✅ Added `/api/auth/refresh` route
- ✅ Added `/api/auth/logout` route
- ✅ Existing `/api/auth/login` and `/api/auth/me` routes
---
## 🧪 What Can Be Tested Now
### Login with New Token Format
```bash
curl -X POST https://777wolfpack.runfoo.run/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@runfoo.run",
"password": "password123"
}'
```
**Expected Response:**
```json
{
"accessToken": "eyJhbGc...",
"refreshToken": "eyJhbGc...",
"user": {
"id": "...",
"email": "admin@runfoo.run",
"name": "Facility Owner",
"role": "OWNER"
}
}
```
### Test All User Roles
- `admin@runfoo.run` - OWNER
- `manager@runfoo.run` - MANAGER
- `grower@runfoo.run` - GROWER
- `staff@runfoo.run` - STAFF
All passwords: `password123`
---
## ⏭️ Next Steps (Phase 2: Protected Routes)
### Task 2.5: Auth Middleware (30-45 min)
- [ ] Create `backend/src/middleware/auth.ts`
- [ ] Implement `authenticate` middleware
- [ ] Implement `authorize(...roles)` middleware
- [ ] Add TypeScript types for request.user
### Task 2.6: Apply Auth to Routes (30 min)
- [ ] Protect `/api/rooms` routes
- [ ] Protect `/api/batches` routes
- [ ] Protect `/api/timeclock` routes
- [ ] Test protected routes without token (should 401)
- [ ] Test protected routes with token (should work)
### Task 2.7: Frontend Integration (1-2 hours)
- [ ] Update AuthContext to use new token format
- [ ] Create axios instance with interceptors
- [ ] Store tokens in localStorage
- [ ] Add Authorization header to requests
- [ ] Handle token refresh on 401
---
## 📊 Sprint 2 Progress
**Overall**: ~25% Complete
**Time Spent**: ~1 hour
**Time Remaining**: ~7-9 hours
| Phase | Status | Time |
|-------|--------|------|
| Phase 1: Backend Auth Core | ✅ Complete | 1h |
| Phase 2: Protected Routes | ⏭️ Next | 1-1.5h |
| Phase 3: Frontend Integration | 📋 Planned | 2-3h |
| Phase 4: Testing & Polish | 📋 Planned | 1-2h |
---
## 🔐 Security Notes
### What's Secure Now
- ✅ Passwords hashed with bcrypt (salt rounds = 10)
- ✅ JWT tokens with expiry (15m access, 7d refresh)
- ✅ No plaintext passwords in database
- ✅ Password comparison using bcrypt.compare
### What's Still TODO
- ⏳ Store refresh tokens in Redis for revocation
- ⏳ Implement actual logout (invalidate refresh token)
- ⏳ Add rate limiting to login endpoint
- ⏳ Add CORS configuration
- ⏳ Use httpOnly cookies for refresh tokens (more secure than localStorage)
---
## 🚀 Ready to Continue?
The backend auth core is solid! Next up is creating the middleware to protect routes and enforce RBAC.
**Estimated time for Phase 2**: 1-1.5 hours
Let me know when you're ready to proceed! 🎯

View file

@ -0,0 +1,265 @@
# Sprint 2.5: Mobile-First UI Refactor (URGENT)
**Date**: 2025-12-09
**Status**: 🔴 Critical Priority
**Duration**: 2-3 hours
**Reason**: Cultivation floor workers use tablets/phones - desktop-first won't work
---
## 🎯 Objective
Refactor the entire frontend to be **mobile-first** with proper responsive breakpoints for tablet and desktop use.
---
## 📱 Mobile-First Principles
### Target Devices
1. **Primary**: Tablets (iPad, Android tablets) - 768px-1024px
2. **Secondary**: Large phones - 375px-767px
3. **Tertiary**: Desktop - 1024px+
### Design Requirements
- **Minimum tap target**: 44×44px (Apple HIG standard)
- **Font sizes**: Minimum 16px for body text (prevents zoom on iOS)
- **Spacing**: Generous padding/margins for fat-finger taps
- **Dark mode**: Default (easier on eyes in grow rooms)
- **Landscape support**: Tablets often used in landscape
---
## 🔧 Implementation Plan
### Phase 1: Tailwind Configuration (30 min)
#### Task 2.5.1: Update Tailwind Config
- [ ] Add custom breakpoints optimized for tablets
- [ ] Set mobile-first defaults
- [ ] Add touch-friendly spacing scale
- [ ] Configure larger tap targets
```javascript
// Proposed breakpoints
screens: {
'xs': '375px', // Large phones
'sm': '640px', // Small tablets portrait
'md': '768px', // Tablets portrait
'lg': '1024px', // Tablets landscape / small desktop
'xl': '1280px', // Desktop
'2xl': '1536px', // Large desktop
}
```
#### Task 2.5.2: Update Base Styles
- [ ] Increase base font size to 16px
- [ ] Add touch-friendly button styles
- [ ] Increase form input sizes
- [ ] Add mobile-optimized spacing utilities
---
### Phase 2: Component Refactor (1-1.5 hours)
#### Task 2.5.3: Update Layout Components
- [ ] **App.tsx**: Mobile-first layout structure
- [ ] **Navigation**: Bottom nav for mobile, side nav for tablet+
- [ ] **Header**: Compact mobile header with hamburger menu
- [ ] **Cards**: Stack on mobile, grid on tablet+
#### Task 2.5.4: Update Page Components
- [ ] **LoginPage**: Full-screen on mobile, centered card on tablet+
- [ ] **DashboardPage**: Single column mobile, 2-col tablet, 3-col desktop
- [ ] **RoomsPage**: List view mobile, grid tablet+
- [ ] **BatchesPage**: List view mobile, grid tablet+
- [ ] **TimeclockPage**: Large buttons for easy tapping
#### Task 2.5.5: Update UI Components
- [ ] **Buttons**: Minimum 44px height, generous padding
- [ ] **Forms**: Large inputs (min 44px height)
- [ ] **Tables**: Horizontal scroll on mobile, full on tablet+
- [ ] **Modals**: Full-screen on mobile, centered on tablet+
---
### Phase 3: Touch Optimization (30-45 min)
#### Task 2.5.6: Touch-Friendly Interactions
- [ ] Increase all clickable areas to 44×44px minimum
- [ ] Add active states for touch feedback
- [ ] Remove hover-only interactions
- [ ] Add swipe gestures where appropriate
#### Task 2.5.7: Performance Optimization
- [ ] Lazy load images
- [ ] Optimize bundle size
- [ ] Add loading skeletons
- [ ] Test on actual devices
---
## 📐 Responsive Patterns
### Stack to Grid
```jsx
// Mobile: Stack
// Tablet+: Grid
<div className="flex flex-col md:grid md:grid-cols-2 lg:grid-cols-3 gap-4">
```
### Hide/Show Elements
```jsx
// Mobile: Hidden
// Tablet+: Visible
<div className="hidden md:block">Desktop content</div>
// Mobile: Visible
// Tablet+: Hidden
<div className="block md:hidden">Mobile content</div>
```
### Responsive Text
```jsx
<h1 className="text-2xl md:text-3xl lg:text-4xl">
```
### Responsive Spacing
```jsx
<div className="p-4 md:p-6 lg:p-8">
```
---
## 🎨 Mobile-First Component Examples
### Button Component
```tsx
// Minimum 44px height, large text, generous padding
<button className="
min-h-[44px]
px-6 py-3
text-base md:text-sm
font-medium
rounded-lg
active:scale-95
transition-transform
">
Tap Me
</button>
```
### Card Component
```tsx
// Full width mobile, constrained tablet+
<div className="
w-full
md:max-w-md
p-4 md:p-6
rounded-lg
shadow-lg
">
```
### Navigation
```tsx
// Bottom nav mobile, side nav tablet+
<nav className="
fixed bottom-0 left-0 right-0
md:static md:w-64
bg-card border-t md:border-r
">
```
---
## ✅ Success Criteria
- [ ] All pages render correctly on 375px width (iPhone SE)
- [ ] All tap targets are minimum 44×44px
- [ ] No horizontal scroll on any screen size
- [ ] Text is readable without zooming (16px minimum)
- [ ] Navigation works on mobile, tablet, and desktop
- [ ] Forms are easy to fill on touch devices
- [ ] Dark mode works across all breakpoints
- [ ] Tested on actual iPad and iPhone
---
## 🧪 Testing Checklist
### Devices to Test
- [ ] iPhone SE (375px)
- [ ] iPhone 14 Pro (393px)
- [ ] iPad Mini (768px)
- [ ] iPad Pro (1024px)
- [ ] Desktop (1280px+)
### Orientations
- [ ] Portrait (all devices)
- [ ] Landscape (tablets)
### Features to Test
- [ ] Login flow
- [ ] Dashboard navigation
- [ ] Room/Batch CRUD
- [ ] Timeclock buttons
- [ ] Forms (add/edit)
- [ ] Modals/dialogs
---
## 📝 Files to Modify
### Configuration
- `frontend/tailwind.config.js` - Update breakpoints
- `frontend/src/index.css` - Update base styles
### Layout
- `frontend/src/App.tsx` - Mobile-first layout
- `frontend/src/components/Layout.tsx` - NEW (if needed)
- `frontend/src/components/Navigation.tsx` - NEW (mobile nav)
### Pages
- `frontend/src/pages/LoginPage.tsx`
- `frontend/src/pages/DashboardPage.tsx`
- `frontend/src/pages/RoomsPage.tsx`
- `frontend/src/pages/BatchesPage.tsx`
- `frontend/src/pages/TimeclockPage.tsx`
### Components
- `frontend/src/components/ui/Button.tsx` - Touch-friendly
- `frontend/src/components/ui/Input.tsx` - Larger inputs
- `frontend/src/components/ui/Card.tsx` - Responsive
---
## 🚀 Let's Begin
**Priority**: This is critical for actual floor use. Pausing Sprint 2 (Auth) to tackle this first.
**Estimated Time**: 2-3 hours
**Next Action**: Update Tailwind config with mobile-first breakpoints...

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 KiB

View file

@ -70,7 +70,49 @@
* {
@apply border-border;
}
html {
/* Prevent text size adjustment on orientation change (iOS) */
-webkit-text-size-adjust: 100%;
/* Enable smooth scrolling */
scroll-behavior: smooth;
}
body {
@apply bg-background text-foreground;
/* Minimum font size for mobile (prevents zoom on iOS) */
font-size: 16px;
/* Improve font rendering */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Touch-friendly button defaults */
button,
[role="button"],
input[type="submit"],
input[type="button"] {
/* Minimum touch target size */
min-height: 44px;
min-width: 44px;
/* Remove tap highlight on mobile */
-webkit-tap-highlight-color: transparent;
/* Improve touch response */
touch-action: manipulation;
}
/* Touch-friendly form inputs */
input,
select,
textarea {
/* Minimum height for easy tapping */
min-height: 44px;
/* Prevent zoom on focus (iOS) */
font-size: 16px;
}
/* Improve touch scrolling */
* {
-webkit-overflow-scrolling: touch;
}
}

View file

@ -6,9 +6,23 @@ export default {
],
darkMode: 'class',
theme: {
// Mobile-first breakpoints optimized for cultivation floor tablets
screens: {
'xs': '375px', // Large phones
'sm': '640px', // Small tablets portrait
'md': '768px', // Tablets portrait (iPad)
'lg': '1024px', // Tablets landscape / small desktop
'xl': '1280px', // Desktop
'2xl': '1536px', // Large desktop
},
container: {
center: true,
padding: "2rem",
padding: {
DEFAULT: '1rem',
sm: '1.5rem',
md: '2rem',
lg: '3rem',
},
screens: {
"2xl": "1400px",
},
@ -21,7 +35,7 @@ export default {
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "#10b981", // Emerald 500
DEFAULT: "#10b981", // Emerald 500 (cannabis green)
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
@ -54,6 +68,22 @@ export default {
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
// Touch-friendly spacing
spacing: {
'touch': '44px', // Minimum touch target size
'touch-lg': '56px', // Large touch target
},
// Mobile-optimized font sizes
fontSize: {
'xs': ['0.75rem', { lineHeight: '1rem' }],
'sm': ['0.875rem', { lineHeight: '1.25rem' }],
'base': ['1rem', { lineHeight: '1.5rem' }], // 16px minimum
'lg': ['1.125rem', { lineHeight: '1.75rem' }],
'xl': ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
},
},
},
plugins: [],