* Increase coverage * Add comprehensive LLM development documentation - Add CLAUDE.md as main documentation index - Create 8 detailed documentation files in docs/: - architecture.md: Tech stack, data models, auth system - directory-structure.md: Complete file tree with paths - backend-patterns.md: Module architecture and patterns - database.md: Models, migrations, and workflows - development-workflow.md: Setup and daily development - code-conventions.md: Style guide and best practices - testing.md: Test organization and patterns - common-tasks.md: How-to guides for frequent tasks - Update .gitignore to allow project-level CLAUDE.md - 4,285 lines of comprehensive documentation - Organized for easy navigation with cross-links - LLM-optimized with absolute paths and code examples * fixup! Add comprehensive LLM development documentation
580 lines
10 KiB
Markdown
580 lines
10 KiB
Markdown
# Development Workflow
|
|
|
|
[← Back to Index](../CLAUDE.md)
|
|
|
|
---
|
|
|
|
## Initial Setup
|
|
|
|
### Prerequisites
|
|
|
|
- **Node.js** v22+ (recommended - check package.json engines field)
|
|
- **npm** (comes with Node.js)
|
|
- **Git**
|
|
|
|
### Clone and Install
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone https://github.com/chrisvel/tududi.git
|
|
cd tududi
|
|
|
|
# Install all dependencies
|
|
# This installs both frontend and backend dependencies (monorepo setup)
|
|
npm install
|
|
```
|
|
|
|
### Initialize Database
|
|
|
|
```bash
|
|
# Create database and run all migrations
|
|
npm run db:init
|
|
|
|
# This command:
|
|
# 1. Creates /backend/database.sqlite
|
|
# 2. Runs all migrations from /backend/migrations/
|
|
# 3. Sets up tables and relationships
|
|
```
|
|
|
|
### Create Test User (Optional)
|
|
|
|
```bash
|
|
npm run user:create
|
|
|
|
# Interactive prompts:
|
|
# - Email address
|
|
# - Password
|
|
# - Timezone (defaults to system timezone)
|
|
```
|
|
|
|
---
|
|
|
|
## Daily Development
|
|
|
|
Tududi runs two separate processes during development:
|
|
|
|
### Two-Server Development
|
|
|
|
**Terminal 1 - Backend (Express):**
|
|
```bash
|
|
npm run backend:dev
|
|
|
|
# Details:
|
|
# - Runs: nodemon backend/app.js
|
|
# - Server: http://localhost:3002
|
|
# - Auto-reloads: Yes (on file changes)
|
|
# - API endpoints: /api/v1/*
|
|
# - Swagger docs: /api-docs (after login)
|
|
```
|
|
|
|
**Terminal 2 - Frontend (Webpack Dev Server):**
|
|
```bash
|
|
npm run frontend:dev
|
|
|
|
# Details:
|
|
# - Runs: webpack serve --mode development
|
|
# - Server: http://localhost:8080
|
|
# - Hot reload: Yes (React Fast Refresh)
|
|
# - Proxies /api/* to backend:3002
|
|
# - Proxies /locales/* to backend:3002
|
|
```
|
|
|
|
**Or run both simultaneously:**
|
|
```bash
|
|
npm start
|
|
|
|
# Runs both backend:dev and frontend:dev in parallel
|
|
# Uses 'concurrently' package
|
|
# Logs from both processes interleaved
|
|
```
|
|
|
|
### Accessing the Application
|
|
|
|
Open http://localhost:8080 in your browser.
|
|
|
|
**Login with:**
|
|
- Email: The email you set during db:init or user:create
|
|
- Password: The password you set
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
Create `/backend/.env` file (not tracked in git):
|
|
|
|
```bash
|
|
# Required
|
|
TUDUDI_SESSION_SECRET=your-random-secret-here-use-openssl-rand-hex-64
|
|
TUDUDI_USER_EMAIL=admin@example.com
|
|
TUDUDI_USER_PASSWORD=your-secure-password
|
|
|
|
# Optional - Server config
|
|
NODE_ENV=development
|
|
DB_FILE=database.sqlite
|
|
FRONTEND_URL=http://localhost:8080
|
|
BACKEND_URL=http://localhost:3002
|
|
PORT=3002
|
|
HOST=0.0.0.0
|
|
|
|
# Optional - Email
|
|
ENABLE_EMAIL=false
|
|
EMAIL_SMTP_HOST=smtp.example.com
|
|
EMAIL_SMTP_PORT=587
|
|
EMAIL_SMTP_SECURE=false
|
|
EMAIL_SMTP_USERNAME=user
|
|
EMAIL_SMTP_PASSWORD=pass
|
|
EMAIL_FROM_ADDRESS=noreply@example.com
|
|
EMAIL_FROM_NAME=Tududi
|
|
|
|
# Optional - Integrations
|
|
DISABLE_TELEGRAM=false
|
|
GOOGLE_CLIENT_ID=your-google-oauth-client-id
|
|
GOOGLE_CLIENT_SECRET=your-google-oauth-secret
|
|
GOOGLE_REDIRECT_URI=http://localhost:8080/auth/google/callback
|
|
|
|
# Optional - Features
|
|
DISABLE_SCHEDULER=false
|
|
SWAGGER_ENABLED=true
|
|
RATE_LIMITING_ENABLED=true
|
|
|
|
# Optional - Proxy (if behind reverse proxy)
|
|
TUDUDI_TRUST_PROXY=false
|
|
TUDUDI_ALLOWED_ORIGINS=http://localhost:8080
|
|
|
|
# Optional - Registration
|
|
REGISTRATION_TOKEN_EXPIRY_HOURS=24
|
|
```
|
|
|
|
**Generate secure session secret:**
|
|
```bash
|
|
openssl rand -hex 64
|
|
```
|
|
|
|
---
|
|
|
|
## Adding a New Feature (Complete Example)
|
|
|
|
**Example: Add "estimated_time" field to tasks**
|
|
|
|
This walkthrough shows all files to touch when adding a new field to an existing model.
|
|
|
|
### Step 1: Create Database Migration
|
|
|
|
```bash
|
|
npm run migration:create -- --name add-estimated-time-to-tasks
|
|
```
|
|
|
|
Edit the created file `/backend/migrations/YYYYMMDDHHMMSS-add-estimated-time-to-tasks.js`:
|
|
|
|
```javascript
|
|
'use strict';
|
|
|
|
module.exports = {
|
|
async up(queryInterface, Sequelize) {
|
|
await queryInterface.addColumn('Tasks', 'estimated_time', {
|
|
type: Sequelize.INTEGER, // minutes
|
|
allowNull: true,
|
|
defaultValue: null
|
|
});
|
|
},
|
|
|
|
async down(queryInterface, Sequelize) {
|
|
await queryInterface.removeColumn('Tasks', 'estimated_time');
|
|
}
|
|
};
|
|
```
|
|
|
|
**Run migration:**
|
|
```bash
|
|
npm run migration:run
|
|
```
|
|
|
|
### Step 2: Update Sequelize Model
|
|
|
|
Edit `/backend/models/task.js`:
|
|
|
|
```javascript
|
|
Task.init({
|
|
// ... existing fields ...
|
|
estimated_time: {
|
|
type: DataTypes.INTEGER,
|
|
allowNull: true,
|
|
comment: 'Estimated time in minutes'
|
|
},
|
|
// ... rest of fields ...
|
|
}, {
|
|
sequelize,
|
|
modelName: 'Task',
|
|
tableName: 'Tasks'
|
|
});
|
|
```
|
|
|
|
### Step 3: Update Serializer (API Response)
|
|
|
|
Edit `/backend/modules/tasks/core/serializers.js`:
|
|
|
|
```javascript
|
|
function serializeTask(task) {
|
|
return {
|
|
// ... existing fields ...
|
|
estimated_time: task.estimated_time,
|
|
// ... rest of fields ...
|
|
};
|
|
}
|
|
```
|
|
|
|
### Step 4: Update Builder (API Input)
|
|
|
|
Edit `/backend/modules/tasks/core/builders.js`:
|
|
|
|
```javascript
|
|
function buildTaskAttributes(data, userId) {
|
|
const attributes = {
|
|
// ... existing fields ...
|
|
estimated_time: data.estimated_time ? parseInt(data.estimated_time, 10) : null,
|
|
// ... rest of fields ...
|
|
};
|
|
|
|
return attributes;
|
|
}
|
|
```
|
|
|
|
### Step 5: Add Validation (Optional)
|
|
|
|
If validation needed, edit `/backend/modules/tasks/routes.js`:
|
|
|
|
```javascript
|
|
router.put('/task/:id', async (req, res, next) => {
|
|
try {
|
|
// Validate estimated_time
|
|
if (req.body.estimated_time !== undefined) {
|
|
const time = parseInt(req.body.estimated_time, 10);
|
|
if (isNaN(time) || time < 0) {
|
|
return res.status(400).json({
|
|
error: 'Estimated time must be a positive number'
|
|
});
|
|
}
|
|
}
|
|
|
|
// ... rest of route handler ...
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
```
|
|
|
|
### Step 6: Update Swagger Documentation
|
|
|
|
Edit `/backend/config/swagger.js`:
|
|
|
|
```javascript
|
|
// Find Task schema
|
|
components: {
|
|
schemas: {
|
|
Task: {
|
|
type: 'object',
|
|
properties: {
|
|
// ... existing properties ...
|
|
estimated_time: {
|
|
type: 'integer',
|
|
description: 'Estimated time in minutes',
|
|
nullable: true,
|
|
example: 30
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 7: Update Frontend TypeScript Interface
|
|
|
|
If TypeScript interface exists, edit `/frontend/entities/Task.ts`:
|
|
|
|
```typescript
|
|
export interface Task {
|
|
// ... existing fields ...
|
|
estimated_time: number | null;
|
|
// ... rest of fields ...
|
|
}
|
|
```
|
|
|
|
### Step 8: Update Frontend Component
|
|
|
|
Edit `/frontend/components/Task/TaskForm.tsx`:
|
|
|
|
```typescript
|
|
// Add input field
|
|
<div className="mb-4">
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
Estimated Time (minutes)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
min="0"
|
|
value={task.estimated_time || ''}
|
|
onChange={(e) => updateTask({
|
|
...task,
|
|
estimated_time: e.target.value ? parseInt(e.target.value) : null
|
|
})}
|
|
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
|
|
/>
|
|
</div>
|
|
```
|
|
|
|
### Step 9: Write Tests
|
|
|
|
Add tests in `/backend/tests/integration/tasks/tasks.test.js`:
|
|
|
|
```javascript
|
|
it('should create task with estimated_time', async () => {
|
|
const response = await request(app)
|
|
.post('/api/v1/task')
|
|
.set('Cookie', authCookie)
|
|
.send({
|
|
name: 'Task with estimate',
|
|
estimated_time: 60
|
|
});
|
|
|
|
expect(response.status).toBe(201);
|
|
expect(response.body.estimated_time).toBe(60);
|
|
});
|
|
|
|
it('should reject negative estimated_time', async () => {
|
|
const response = await request(app)
|
|
.post('/api/v1/task')
|
|
.set('Cookie', authCookie)
|
|
.send({
|
|
name: 'Invalid task',
|
|
estimated_time: -10
|
|
});
|
|
|
|
expect(response.status).toBe(400);
|
|
});
|
|
```
|
|
|
|
### Step 10: Run Tests and Checks
|
|
|
|
```bash
|
|
# Run backend tests
|
|
npm run backend:test
|
|
|
|
# Run linting
|
|
npm run lint:fix
|
|
|
|
# Format code
|
|
npm run format:fix
|
|
|
|
# Run all pre-push checks
|
|
npm run pre-push
|
|
```
|
|
|
|
### Step 11: Commit Changes
|
|
|
|
```bash
|
|
git add .
|
|
git commit -m "Add estimated_time field to tasks
|
|
|
|
- Add database migration for estimated_time
|
|
- Update Task model and serializers
|
|
- Update Swagger documentation
|
|
- Add validation for positive values
|
|
- Add UI field in TaskForm component
|
|
- Add integration tests"
|
|
```
|
|
|
|
---
|
|
|
|
## Database Management
|
|
|
|
```bash
|
|
# Reset database (WIPES ALL DATA!)
|
|
npm run db:reset
|
|
|
|
# Seed development data
|
|
npm run db:seed
|
|
|
|
# Check migration status
|
|
npm run db:status
|
|
|
|
# Create new migration
|
|
npm run migration:create -- --name description
|
|
|
|
# Run pending migrations
|
|
npm run migration:run
|
|
|
|
# Rollback last migration
|
|
npm run migration:undo
|
|
```
|
|
|
|
---
|
|
|
|
## Code Quality
|
|
|
|
```bash
|
|
# Check linting
|
|
npm run lint
|
|
|
|
# Auto-fix linting issues
|
|
npm run lint:fix
|
|
|
|
# Format code with Prettier
|
|
npm run format:fix
|
|
|
|
# Run all pre-push checks
|
|
# (lint + format + tests)
|
|
npm run pre-push
|
|
```
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
# Backend tests
|
|
npm test
|
|
# or
|
|
npm run backend:test
|
|
|
|
# Frontend tests
|
|
npm run frontend:test
|
|
|
|
# E2E tests
|
|
npm run test:ui # Headless
|
|
npm run test:ui:headed # With browser visible
|
|
|
|
# Coverage report
|
|
npm run test:coverage
|
|
|
|
# Watch mode (during development)
|
|
npm run test:watch
|
|
```
|
|
|
|
---
|
|
|
|
## Branch Strategy
|
|
|
|
From CONTRIBUTING.md conventions:
|
|
|
|
```bash
|
|
# Feature branches
|
|
git checkout -b feature/description
|
|
|
|
# Bug fix branches
|
|
git checkout -b fix/description
|
|
|
|
# Refactoring branches
|
|
git checkout -b refactor/description
|
|
|
|
# Documentation branches
|
|
git checkout -b docs/description
|
|
|
|
# Test branches
|
|
git checkout -b test/description
|
|
```
|
|
|
|
### Example Workflow
|
|
|
|
```bash
|
|
# Create feature branch from main
|
|
git checkout main
|
|
git pull origin main
|
|
git checkout -b feature/estimated-time
|
|
|
|
# Make changes, run tests
|
|
npm run pre-push
|
|
|
|
# Commit changes
|
|
git add .
|
|
git commit -m "Add estimated time feature"
|
|
|
|
# Before PR: rebase on main
|
|
git checkout main
|
|
git pull origin main
|
|
git checkout feature/estimated-time
|
|
git rebase main
|
|
|
|
# Push and create PR
|
|
git push origin feature/estimated-time
|
|
```
|
|
|
|
---
|
|
|
|
## Build for Production
|
|
|
|
```bash
|
|
# Build frontend
|
|
npm run build
|
|
|
|
# Builds to: /dist/
|
|
# - Minified JavaScript
|
|
# - Optimized CSS
|
|
# - Hashed filenames for cache busting
|
|
```
|
|
|
|
### Docker Production
|
|
|
|
```bash
|
|
# Build Docker image
|
|
docker build -t tududi:latest .
|
|
|
|
# Run container
|
|
docker run \
|
|
-e TUDUDI_USER_EMAIL=admin@example.com \
|
|
-e TUDUDI_USER_PASSWORD=secure-password \
|
|
-e TUDUDI_SESSION_SECRET=$(openssl rand -hex 64) \
|
|
-v ~/tududi_db:/app/backend/db \
|
|
-v ~/tududi_uploads:/app/backend/uploads \
|
|
-p 3002:3002 \
|
|
-d tududi:latest
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Port Already in Use
|
|
|
|
```bash
|
|
# Find process using port 3002
|
|
lsof -ti:3002
|
|
|
|
# Kill process
|
|
kill -9 $(lsof -ti:3002)
|
|
|
|
# Or use different port
|
|
PORT=3003 npm run backend:dev
|
|
```
|
|
|
|
### Database Locked
|
|
|
|
```bash
|
|
# Stop all servers
|
|
# Delete database file
|
|
rm backend/database.sqlite
|
|
|
|
# Reinitialize
|
|
npm run db:init
|
|
```
|
|
|
|
### Module Not Found
|
|
|
|
```bash
|
|
# Clean install
|
|
rm -rf node_modules package-lock.json
|
|
npm install
|
|
```
|
|
|
|
### Webpack Build Errors
|
|
|
|
```bash
|
|
# Clear webpack cache
|
|
rm -rf node_modules/.cache
|
|
|
|
# Rebuild
|
|
npm run frontend:dev
|
|
```
|
|
|
|
---
|
|
|
|
[← Back to Index](../CLAUDE.md)
|