ca-grow-ops-manager/frontend/README.md
fullsizemalt da7729d6e4
Some checks failed
Deploy to Production / deploy (push) Failing after 0s
Test / backend-test (push) Failing after 0s
Test / frontend-test (push) Failing after 0s
Initial commit: Spec Kit foundation complete
- Constitution and project spec (spec.yml)
- 7 comprehensive feature specs (tasks, batches, labor, compliance, inventory, integrations, comms)
- Phase 1 implementation plan (6-week roadmap)
- Week 1 task breakdown (15 concrete tasks)
- Architecture and compliance documentation
- Backend and frontend setup guides
- Deployment guide for nexus-vector
- CI/CD workflows (Forgejo Actions)
- Quick start guide for developers

Project is ready for implementation with:
- Automated testing on every push
- Automatic deployment to nexus-vector on push to main
- Database migrations handled automatically
- Health checks and monitoring

Stack: TypeScript, Fastify, React, Vite, PostgreSQL, Prisma, Docker
2025-12-08 23:54:12 -08:00

442 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CA Grow Ops Manager — Frontend
**Version**: 0.1.0
**Stack**: TypeScript, React, Vite/Next.js, Radix UI/shadcn
---
## Overview
The frontend is a **mobile-first, accessible** web application optimized for low-friction daily use in cultivation facilities. It provides intuitive interfaces for tasks, batches, labor tracking, compliance, and team communication.
---
## Tech Stack
- **Language**: TypeScript 5.x
- **Framework**: React 18.x
- **Build Tool**: Vite or Next.js (to be decided during implementation)
- **Component Library**: Radix UI or shadcn-style accessible primitives
- **Styling**: Tailwind CSS or modern CSS-in-JS
- **State Management**: React Context + hooks (Zustand or Redux Toolkit for complex state)
- **Routing**: React Router (Vite) or Next.js App Router
- **Forms**: React Hook Form + Zod validation
- **API Client**: Axios or Fetch with TypeScript types
- **Testing**: Vitest + React Testing Library
---
## Project Structure
### Vite Option
```
frontend/
├── src/
│ ├── app/ # App shell
│ │ ├── App.tsx
│ │ ├── Router.tsx
│ │ └── Layout.tsx
│ ├── pages/ # Page components
│ │ ├── Dashboard.tsx
│ │ ├── Tasks/
│ │ │ ├── TasksPage.tsx
│ │ │ ├── TaskDetail.tsx
│ │ │ └── TodayView.tsx
│ │ ├── Batches/
│ │ ├── Labor/
│ │ ├── Compliance/
│ │ └── Settings/
│ ├── components/ # Reusable components
│ │ ├── ui/ # Base UI components (buttons, inputs, etc.)
│ │ ├── tasks/ # Task-specific components
│ │ ├── batches/
│ │ └── shared/ # Shared components (nav, header, etc.)
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts
│ │ ├── useTasks.ts
│ │ └── useApi.ts
│ ├── lib/ # Utilities and helpers
│ │ ├── api.ts # API client
│ │ ├── auth.ts # Auth helpers
│ │ └── utils.ts
│ ├── types/ # TypeScript types
│ │ ├── api.ts
│ │ └── models.ts
│ ├── styles/ # Global styles
│ │ ├── index.css
│ │ └── tailwind.css
│ └── main.tsx # Entry point
├── public/ # Static assets
├── .env.example
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md
```
### Next.js Option
```
frontend/
├── app/ # Next.js App Router
│ ├── layout.tsx
│ ├── page.tsx # Dashboard
│ ├── tasks/
│ │ ├── page.tsx
│ │ └── [id]/page.tsx
│ ├── batches/
│ ├── labor/
│ └── api/ # API routes (if needed)
├── components/ # Same as Vite
├── hooks/
├── lib/
├── types/
├── styles/
└── public/
```
---
## Design System
### Component Library (Radix UI / shadcn)
Use accessible primitives for:
- **Buttons**: Primary, secondary, destructive
- **Inputs**: Text, number, date, select
- **Dialogs**: Modals, drawers, alerts
- **Dropdowns**: Menus, selects, comboboxes
- **Tabs**: Navigation, content switching
- **Cards**: Content containers
- **Badges**: Status indicators
### Styling (Tailwind CSS)
```css
/* Design tokens */
:root {
--color-primary: #10b981; /* Green for cultivation */
--color-secondary: #3b82f6; /* Blue for actions */
--color-danger: #ef4444; /* Red for alerts */
--color-warning: #f59e0b; /* Orange for warnings */
--color-success: #10b981; /* Green for success */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'Fira Code', monospace;
}
```
### Mobile-First Design
- **Big Tap Targets**: Minimum 44×44px for all interactive elements
- **Dark Mode**: Default dark theme with light mode option
- **Responsive Breakpoints**:
- Mobile: < 640px
- Tablet: 640px - 1024px
- Desktop: > 1024px
---
## Key Features
### 1. Today View (Mobile-Optimized)
```tsx
// TodayView.tsx
export const TodayView = () => {
const { tasks, loading } = useTasks({ dueToday: true });
return (
<div className="p-4 space-y-4">
<h1 className="text-2xl font-bold">Today's Tasks</h1>
{tasks.map(task => (
<TaskCard key={task.id} task={task} />
))}
</div>
);
};
```
### 2. Timeclock Widget
```tsx
// TimeclockWidget.tsx
export const TimeclockWidget = () => {
const { currentShift, clockIn, clockOut } = useTimeclock();
return (
<Card className="p-6">
{currentShift ? (
<div>
<p>Clocked in: {formatTime(currentShift.clockIn)}</p>
<Button onClick={clockOut} size="lg">Clock Out</Button>
</div>
) : (
<Button onClick={clockIn} size="lg">Clock In</Button>
)}
</Card>
);
};
```
### 3. Batch Timeline
```tsx
// BatchTimeline.tsx
export const BatchTimeline = ({ batchId }: { batchId: string }) => {
const { events } = useBatchTimeline(batchId);
return (
<div className="space-y-4">
{events.map(event => (
<TimelineEvent key={event.id} event={event} />
))}
</div>
);
};
```
---
## API Integration
### API Client
```typescript
// lib/api.ts
import axios from 'axios';
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
headers: {
'Content-Type': 'application/json',
},
});
// Add auth token to requests
api.interceptors.request.use(config => {
const token = localStorage.getItem('accessToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Handle token refresh
api.interceptors.response.use(
response => response,
async error => {
if (error.response?.status === 401) {
// Attempt token refresh
const refreshToken = localStorage.getItem('refreshToken');
if (refreshToken) {
const { data } = await axios.post('/api/auth/refresh', { refreshToken });
localStorage.setItem('accessToken', data.accessToken);
error.config.headers.Authorization = `Bearer ${data.accessToken}`;
return axios(error.config);
}
}
return Promise.reject(error);
}
);
export default api;
```
### Custom Hooks
```typescript
// hooks/useTasks.ts
export const useTasks = (filters?: TaskFilters) => {
const [tasks, setTasks] = useState<Task[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchTasks = async () => {
const { data } = await api.get('/api/tasks', { params: filters });
setTasks(data.data);
setLoading(false);
};
fetchTasks();
}, [filters]);
return { tasks, loading };
};
```
---
## Authentication
### Auth Context
```typescript
// hooks/useAuth.ts
const AuthContext = createContext<AuthContextType | null>(null);
export const AuthProvider = ({ children }: { children: ReactNode }) => {
const [user, setUser] = useState<User | null>(null);
const login = async (email: string, password: string) => {
const { data } = await api.post('/api/auth/login', { email, password });
localStorage.setItem('accessToken', data.accessToken);
localStorage.setItem('refreshToken', data.refreshToken);
setUser(data.user);
};
const logout = () => {
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) throw new Error('useAuth must be used within AuthProvider');
return context;
};
```
---
## Testing
### Component Tests (Vitest + React Testing Library)
```typescript
// TaskCard.test.tsx
import { render, screen } from '@testing-library/react';
import { TaskCard } from './TaskCard';
describe('TaskCard', () => {
it('renders task name', () => {
const task = { id: '1', name: 'Water plants', status: 'PENDING' };
render(<TaskCard task={task} />);
expect(screen.getByText('Water plants')).toBeInTheDocument();
});
});
```
---
## Environment Variables
```bash
# API
VITE_API_URL=http://localhost:3000/api
# Auth
VITE_AUTH_ENABLED=true
# Features
VITE_METRC_ENABLED=false
```
---
## Development Workflow
### Setup
```bash
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env
# Start dev server
npm run dev
```
### Scripts
```json
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"test": "vitest",
"test:ui": "vitest --ui",
"lint": "eslint src --ext .ts,.tsx",
"format": "prettier --write src"
}
}
```
---
## Accessibility
- **WCAG 2.1 AA Compliance**: All components meet accessibility standards
- **Keyboard Navigation**: All interactive elements keyboard-accessible
- **Screen Reader Support**: Proper ARIA labels and roles
- **Focus Management**: Clear focus indicators and logical tab order
- **Color Contrast**: Minimum 4.5:1 contrast ratio for text
---
## Mobile & PWA
### Progressive Web App (Stretch Goal)
```typescript
// vite.config.ts
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({
plugins: [
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'CA Grow Ops Manager',
short_name: 'Grow Ops',
theme_color: '#10b981',
icons: [
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
],
},
}),
],
});
```
---
## Next Steps
1. **Choose Build Tool**: Decide between Vite and Next.js
2. **Set Up Project**: Initialize React project with TypeScript
3. **Configure Tailwind**: Set up Tailwind CSS and design tokens
4. **Build Design System**: Implement base UI components
5. **Implement Pages**: Build page components per spec
6. **Write Tests**: Component and integration tests
7. **Deploy**: Set up CI/CD and deploy to staging
---
## Resources
- [React Documentation](https://react.dev)
- [Vite Documentation](https://vitejs.dev)
- [Next.js Documentation](https://nextjs.org/docs)
- [Radix UI Documentation](https://www.radix-ui.com)
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)
- [React Testing Library](https://testing-library.com/react)