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:
parent
9dc0586d67
commit
4c0aad0e06
5 changed files with 488 additions and 2 deletions
149
docs/SPRINT-2-PROGRESS.md
Normal file
149
docs/SPRINT-2-PROGRESS.md
Normal 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! 🎯
|
||||
265
docs/SPRINT-2.5-MOBILE-FIRST.md
Normal file
265
docs/SPRINT-2.5-MOBILE-FIRST.md
Normal 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...
|
||||
BIN
frontend/public/assets/logo-777-wolfpack.jpg
Normal file
BIN
frontend/public/assets/logo-777-wolfpack.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 463 KiB |
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: [],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue