diff --git a/CLAUDE.md b/CLAUDE.md
index d2086efa..444aa374 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,74 +1,89 @@
# CLAUDE.md
-Factory Inventory Management System Demo with GitHub integration - Full-stack application with Vue 3 frontend, Python FastAPI backend, and in-memory mock data (no database).
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
-## Critical Tool Usage Rules
+Factory Inventory Management System — full-stack demo app with Vue 3 frontend, Python FastAPI backend, and in-memory mock data (no database).
-### Subagents
-Use the Task tool with these specialized subagents for appropriate tasks:
+## Commands
-- **vue-expert**: Use for Vue 3 frontend features, UI components, styling, and client-side functionality
- - Examples: Creating components, fixing reactivity issues, performance optimization, complex state management
- - **MANDATORY RULE: ANY time you need to create or significantly modify a .vue file, you MUST delegate to vue-expert**
-- **code-reviewer**: Use after writing significant code to review quality and best practices
-- **Explore**: Use for understanding codebase structure, searching for patterns, or answering questions about how components work
-- **general-purpose**: Use for complex multi-step tasks or when other agents don't fit
-
-### Skills
-- **backend-api-test** skill: Use when writing or modifying tests in `tests/backend` directory with pytest and FastAPI TestClient
+**Backend** (from `server/`):
+```bash
+uv sync # Install dependencies
+uv run python main.py # Start server on http://localhost:8001
+```
-### MCP Tools
-- **ALWAYS use GitHub MCP tools** (`mcp__github__*`) for ALL GitHub operations
- - Exception: Local branches only - use `git checkout -b` instead of `mcp__github__create_branch`
-- **ALWAYS use Playwright MCP tools** (`mcp__playwright__*`) for browser testing
- - Test against: `http://localhost:3000` (frontend), `http://localhost:8001` (API)
+**Frontend** (from `client/`):
+```bash
+npm install && npm run dev # Start dev server on http://localhost:3000
+npm run build # Production build to client/dist/
+```
-## Stack
-- **Frontend**: Vue 3 + Composition API + Vite (port 3000)
-- **Backend**: Python FastAPI (port 8001)
-- **Data**: JSON files in `server/data/` loaded via `server/mock_data.py`
+**Tests** (from `tests/`):
+```bash
+uv run pytest backend/ -v # All 51 tests
+uv run pytest backend/test_inventory.py -v # Single file
+uv run pytest --cov=../server --cov-report=html # With coverage
+```
-## Quick Start
+**Windows note:** `scripts/start.sh` is macOS/Linux only. Start backend and frontend in separate terminals manually.
-```bash
-# Backend
-cd server
-uv run python main.py
+## Architecture
-# Frontend
-cd client
-npm install && npm run dev
```
+client/src/
+ api.js # Centralized Axios client — all HTTP calls go here
+ composables/ # Shared state: useFilters.js (4-filter system), useAuth.js, useI18n.js
+ views/ # Page components (Dashboard, Inventory, Orders, Spending, Demand, Reports)
+ components/ # Reusable UI (FilterBar, *DetailModal, TasksModal, ProfileMenu)
+
+server/
+ main.py # All FastAPI endpoints + apply_filters() + filter_by_month()
+ mock_data.py # Loads server/data/*.json into memory at startup
+ data/*.json # Source of truth — inventory, orders, spending, demand_forecasts, backlog_items
+```
+
+Data flow: Vue filter composable → `api.js` query params → FastAPI → in-memory filtering → Pydantic response → Vue computed properties.
+
+## Critical Tool Usage
+
+- **vue-expert subagent**: MANDATORY for any `.vue` file creation or significant modification
+- **code-reviewer subagent**: Use after writing significant code
+- **backend-api-test skill**: Use when writing/modifying tests in `tests/backend/`
+- **GitHub MCP** (`mcp__github__*`): Use for ALL GitHub operations (exception: local branch creation with `git checkout -b`)
+- **Playwright MCP** (`mcp__playwright__*`): Use for browser testing against `http://localhost:3000` / `http://localhost:8001`
## Key Patterns
-**Filter System**: 4 filters (Time Period, Warehouse, Category, Order Status) apply to all data via query params
-**Data Flow**: Vue filters → `client/src/api.js` → FastAPI → In-memory filtering → Pydantic validation → Computed properties
-**Reactivity**: Raw data in refs (`allOrders`, `inventoryItems`), derived data in computed properties
-
-## API Endpoints
-- `GET /api/inventory` - Filters: warehouse, category
-- `GET /api/orders` - Filters: warehouse, category, status, month
-- `GET /api/dashboard/summary` - All filters
-- `GET /api/demand`, `/api/backlog` - No filters
-- `GET /api/spending/*` - Summary, monthly, categories, transactions
-
-## Common Issues
-1. Use unique keys in v-for (not `index`) - use `sku`, `month`, etc.
-2. Validate dates before `.getMonth()` calls
-3. Update Pydantic models when changing JSON data structure
-4. Inventory filters don't support month (no time dimension)
-5. Revenue goals: $800K/month single, $9.6M YTD all months
-
-## File Locations
-- Views: `client/src/views/*.vue`
-- API Client: `client/src/api.js`
-- Backend: `server/main.py`, `server/mock_data.py`
-- Data: `server/data/*.json`
-- Styles: `client/src/App.vue`
+**Filter system**: 4 filters — Time Period, Warehouse, Category, Order Status — passed as query params to every endpoint. Filter values of `'all'` are skipped. Inventory endpoints do **not** support month filtering (no time dimension on inventory data).
+
+**Backend filtering**:
+```python
+# Never mutate global data — filter on copies
+if warehouse and warehouse != 'all':
+ results = [r for r in results if r.get('warehouse') == warehouse]
+```
+
+**Date/quarter filtering**: Supports `2025-01` (month) and `Q1-2025` (quarter) formats. Parse safely and handle null dates.
+
+**Frontend reactivity**:
+- Raw data in `ref()`, derived data in `computed()` — never the reverse
+- Always use unique IDs (not array index) as `v-for` keys
+- Validate dates before calling `.getMonth()`: `if (!isNaN(date.getTime()))`
+- In `
-
-
-```
-
-**Why Composition API:**
-- Better code organization by feature
-- Easier to extract and reuse logic
-- TypeScript support
-- Smaller bundle size
-- More flexible than Options API
-
-### Reactive Data Best Practices
-
-**refs vs computed:**
-- Use `ref()` for values that change via assignment
-- Use `computed()` for values derived from other reactive data
-- computed properties are cached until dependencies change
-- Never mutate computed properties
-
-**Example:**
-```javascript
-// refs - mutable state
-const searchQuery = ref('')
-const items = ref([])
-
-// computed - derived from refs
-const filteredItems = computed(() => {
- if (!searchQuery.value) return items.value
- return items.value.filter(item =>
- item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
- )
-})
-```
-
-**Accessing ref values:**
-- In `
+
+
diff --git a/server/CLAUDE.md b/server/CLAUDE.md
index bca8f787..2037f679 100644
--- a/server/CLAUDE.md
+++ b/server/CLAUDE.md
@@ -2,285 +2,30 @@
This file provides guidance to Claude Code (claude.ai/code) when working with the FastAPI backend.
-## Running the Server
+## Commands
```bash
-# From server directory
-uv run python main.py
-# Server runs on http://localhost:8001
-# API docs at http://localhost:8001/docs
+uv sync # Install dependencies
+uv run python main.py # Start on http://localhost:8001 (API docs at /docs)
```
-## Development Best Practices
+## Architecture
-### API Design Principles
+- `main.py` — all FastAPI endpoints plus `apply_filters()` and `filter_by_month()` helpers. Everything lives here (no separate modules).
+- `mock_data.py` — loads `data/*.json` into module-level globals at startup. Data is in-memory; restart to reload.
+- `data/*.json` — source of truth: `inventory.json`, `orders.json`, `spending.json`, `demand_forecasts.json`, `backlog_items.json`, `purchase_orders.json`, `transactions.json`.
-**RESTful Design:**
-- Use appropriate HTTP methods (GET for retrieval, POST for creation, etc.)
-- Return proper status codes (200, 201, 404, 400, 500)
-- Use plural nouns for resource endpoints (`/api/orders`, not `/api/order`)
-- Keep URLs simple and predictable
+## Key Patterns
-**Request/Response:**
-- Always validate input with Pydantic models
-- Return consistent response structure
-- Include error details in error responses
-- Use ISO 8601 for dates (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS)
+**Never mutate globals**: Always filter on a copy — `results = [r for r in all_items if ...]`.
-### Adding New Endpoints
+**Filter params**: All endpoints accept `warehouse`, `category`, `status`, `month` as optional query params. Skip filter when value is `'all'` or `None`. Inventory endpoints do **not** support `month` (no time dimension on inventory data).
-**Process:**
-1. Define Pydantic model for data validation
-2. Create endpoint function with clear name
-3. Add route decorator with explicit path
-4. Implement business logic
-5. Handle errors appropriately
-6. Write tests in `tests/backend/`
+**Date/quarter formats**: `apply_filters` handles both `2025-01` (month) and `Q1-2025` (quarter). Parse safely and skip records with null dates.
-**Example Pattern:**
-```python
-class MyModel(BaseModel):
- id: str
- name: str
- value: float
+**Adding an endpoint**:
+1. Define Pydantic response model
+2. Add `@app.get` route, filter on copy of data, return typed response
+3. Write tests in `tests/backend/`
-@app.get("/api/resource", response_model=List[MyModel])
-def get_resources(
- filter_param: Optional[str] = None,
- category: Optional[str] = None
-):
- """Get resources with optional filtering."""
- results = all_resources
-
- if filter_param and filter_param != 'all':
- results = [r for r in results if r['field'] == filter_param]
-
- if category and category != 'all':
- results = [r for r in results if r['category'].lower() == category.lower()]
-
- return results
-```
-
-### Data Model Best Practices
-
-**Pydantic Models:**
-- Define once, use everywhere
-- Make optional fields explicitly `Optional[Type]`
-- Use descriptive field names
-- Add default values where appropriate
-- Keep models close to their usage
-
-**Model Updates:**
-- When adding fields to JSON data, update Pydantic models
-- When removing fields, mark as Optional first, then remove
-- Consider backwards compatibility
-- Update tests when models change
-
-### Filtering Best Practices
-
-**Standard Pattern:**
-- Accept filter parameters as optional query params
-- Check for 'all' value and skip that filter
-- Use lowercase comparison for case-insensitive matching
-- Apply filters sequentially for code clarity
-- Don't mutate original data - filter on copies
-
-**Filter Implementation:**
-```python
-def filter_data(data, warehouse=None, category=None):
- """Filter data by multiple criteria."""
- filtered = data
-
- if warehouse and warehouse != 'all':
- filtered = [item for item in filtered
- if item.get('warehouse') == warehouse]
-
- if category and category != 'all':
- filtered = [item for item in filtered
- if item.get('category', '').lower() == category.lower()]
-
- return filtered
-```
-
-**Date/Time Filtering:**
-- Support both direct month match (2025-01) and quarters (Q1-2025)
-- Parse date strings safely
-- Handle missing/null dates gracefully
-- Consider timezone if adding real database
-
-### Error Handling
-
-**Use HTTPException:**
-```python
-from fastapi import HTTPException
-
-@app.get("/api/item/{item_id}")
-def get_item(item_id: str):
- item = find_item(item_id)
- if not item:
- raise HTTPException(
- status_code=404,
- detail=f"Item {item_id} not found"
- )
- return item
-```
-
-**Best Practices:**
-- Return 404 for "not found" errors
-- Return 400 for bad input/validation errors
-- Return 500 for server errors (let FastAPI handle these)
-- Include helpful error messages
-- Log errors for debugging
-
-### Mock Data Management
-
-**Pattern:**
-- Load all data from JSON files at startup
-- Data lives in memory during server runtime
-- Changes don't persist (restart reloads from files)
-- Keep JSON files well-formatted and validated
-
-**Adding New Data:**
-1. Update JSON file in `server/data/`
-2. Update Pydantic model if structure changed
-3. Restart server to reload data
-4. Verify with API docs (/docs endpoint)
-
-**Data Consistency:**
-- Ensure SKUs in orders reference valid inventory items
-- Keep category names consistent across data files
-- Use same date format everywhere
-- Validate JSON structure before committing
-
-### CORS Configuration
-
-**Development:**
-- Allow all origins during development (`allow_origins=["*"]`)
-- Useful for frontend dev server on different port
-
-**Production:**
-- Restrict to specific origins only
-- Example: `allow_origins=["https://yourdomain.com"]`
-- Never use wildcard (*) in production
-- Configure based on deployment environment
-
-### Testing API Endpoints
-
-**Using FastAPI Docs:**
-1. Start server
-2. Navigate to http://localhost:8001/docs
-3. Click endpoint to expand
-4. Click "Try it out"
-5. Fill in parameters
-6. Execute and verify response
-
-**Using pytest:**
-```python
-def test_endpoint(client):
- response = client.get("/api/endpoint?param=value")
- assert response.status_code == 200
- data = response.json()
- assert isinstance(data, list)
- assert len(data) > 0
-```
-
-**What to Test:**
-- Successful requests return 200
-- Invalid IDs return 404
-- Filters work correctly
-- Response structure matches model
-- Calculations are accurate
-- Edge cases (empty results, invalid input)
-
-### Performance Considerations
-
-**In-Memory Data:**
-- Fast reads (no database queries)
-- No indexing needed for demo
-- All filtering happens in Python
-- Reasonable for small datasets (<10K items)
-
-**If Scaling:**
-- Add database (PostgreSQL, MongoDB)
-- Implement pagination
-- Add caching layer (Redis)
-- Use database indexes for common filters
-- Consider async database queries
-
-### Code Organization
-
-**When to Extract:**
-- Filtering logic used in multiple endpoints → Extract to utility function
-- Complex business logic → Move to separate module
-- Data validation beyond Pydantic → Create custom validators
-- Repeated calculations → Extract to helper functions
-
-**Module Structure for Growth:**
-```
-server/
-├── main.py # API endpoints only
-├── models.py # Pydantic models
-├── services/ # Business logic
-│ ├── inventory.py
-│ └── orders.py
-├── utils/ # Helper functions
-│ └── filters.py
-└── data/ # JSON data files
-```
-
-### Common Pitfalls
-
-**Avoid:**
-- ❌ Mutating global data (filter on copies)
-- ❌ Missing Pydantic model updates when JSON changes
-- ❌ Inconsistent filter parameter names across endpoints
-- ❌ Returning raw dict instead of Pydantic model
-- ❌ Not handling None/null values in data
-
-**Do:**
-- ✅ Validate all input with Pydantic
-- ✅ Return typed responses (response_model)
-- ✅ Handle optional parameters gracefully
-- ✅ Keep endpoints focused and simple
-- ✅ Write tests for new endpoints
-
-### Debugging
-
-**Techniques:**
-- Use FastAPI's automatic docs for quick testing
-- Print statements in endpoint functions (shows in terminal)
-- Check Pydantic validation errors in response
-- Use Python debugger (`import pdb; pdb.set_trace()`)
-- Review JSON data files for structure issues
-
-**Common Issues:**
-- Data not loading → Check JSON file path
-- Validation errors → Verify Pydantic model matches data
-- Empty results → Check filter logic and data
-- 404 errors → Verify route path and HTTP method
-
-### Security Notes
-
-**For Production:**
-- Add authentication/authorization
-- Validate and sanitize all input
-- Use HTTPS only
-- Implement rate limiting
-- Add input size limits
-- Use environment variables for sensitive config
-- Never commit secrets to git
-
-**Current State:**
-- No authentication (demo only)
-- CORS allows all origins
-- No rate limiting
-- No input validation beyond types
-- Suitable for local development only
-
-## Quick Reference
-
-**Start server:** `uv run python main.py`
-**API docs:** http://localhost:8001/docs
-**Run tests:** `cd ../tests && uv run pytest backend/ -v`
-**Add endpoint:** Define model → Add route → Write tests
-**Add filter:** Add query param → Check 'all' value → Filter data
+**Adding data**: Update JSON in `server/data/` → update Pydantic model if structure changed → restart server.
diff --git a/server/main.py b/server/main.py
index a0c2d8c5..86cb042b 100644
--- a/server/main.py
+++ b/server/main.py
@@ -2,6 +2,7 @@
from fastapi.middleware.cors import CORSMiddleware
from typing import List, Optional
from pydantic import BaseModel
+from datetime import datetime, timedelta
from mock_data import inventory_items, orders, demand_forecasts, backlog_items, spending_summary, monthly_spending, category_spending, recent_transactions, purchase_orders
app = FastAPI(title="Factory Inventory Management System")
@@ -120,6 +121,12 @@ class CreatePurchaseOrderRequest(BaseModel):
expected_delivery_date: str
notes: Optional[str] = None
+class CreateOrderRequest(BaseModel):
+ customer: str
+ items: List[dict]
+ warehouse: Optional[str] = None
+ category: Optional[str] = None
+
# API endpoints
@app.get("/")
def root():
@@ -153,6 +160,29 @@ def get_orders(
filtered_orders = filter_by_month(filtered_orders, month)
return filtered_orders
+@app.post("/api/orders", response_model=Order)
+def create_order(request: CreateOrderRequest):
+ """Create a new restocking order"""
+ new_id = str(len(orders) + 1)
+ order_date = datetime.utcnow().isoformat()
+ expected_delivery = (datetime.utcnow() + timedelta(days=14)).isoformat()
+ total_value = sum(i.get("quantity", 0) * i.get("unit_price", 0) for i in request.items)
+ order = {
+ "id": new_id,
+ "order_number": f"ORD-RESTOCK-{new_id.zfill(4)}",
+ "customer": request.customer,
+ "items": request.items,
+ "status": "Submitted",
+ "warehouse": request.warehouse,
+ "category": request.category,
+ "order_date": order_date,
+ "expected_delivery": expected_delivery,
+ "total_value": round(total_value, 2),
+ "actual_delivery": None
+ }
+ orders.append(order)
+ return order
+
@app.get("/api/orders/{order_id}", response_model=Order)
def get_order(order_id: str):
"""Get a specific order"""