Development Guide
This guide covers setting up your development environment and contributing to Lakra.
Prerequisites
Initial Setup
1. Clone Repository
git clone <repository-url>
cd lakra
2. Install Dependencies
npm install
# or
yarn install
# or
bun install
3. Environment Configuration
Create .env file:
cp .env.example .env
Add your Supabase credentials:
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key
4. Database Setup
In Supabase Dashboard:
Go to SQL Editor
Run table creation scripts (see Database Schema)
Set up RLS policies
Create database functions/triggers
5. Start Development Server
npm run dev
Application runs at http://localhost:5173
Project Structure
lakra/
├── .github/ # GitHub workflows
├── docs/ # Documentation (ReadtheDocs)
├── public/ # Static assets
│ ├── lakra.svg
│ ├── favicon.svg
│ └── _redirects
├── src/
│ ├── components/ # React components
│ ├── contexts/ # React contexts
│ ├── hooks/ # Custom hooks
│ ├── services/ # API services
│ ├── types/ # TypeScript types
│ ├── utils/ # Utilities
│ ├── App.tsx # Main app
│ ├── main.tsx # Entry point
│ └── index.css # Global styles
├── .env # Environment variables (gitignored)
├── .env.example # Example env file
├── .gitignore
├── package.json
├── tsconfig.json # TypeScript config
├── tailwind.config.js # Tailwind config
├── vite.config.ts # Vite config
├── eslint.config.js # ESLint config
├── README.md
└── CONTRIBUTING.md
Available Scripts
Development
npm run dev # Start dev server (HMR enabled)
npm run build # Build for production
npm run preview # Preview production build
npm run lint # Run ESLint
Vite Configuration
vite.config.ts includes:
React plugin
Console removal in production
Code splitting (vendor, router chunks)
Development Workflow
Branching Strategy
# Create feature branch from master
git checkout master
git pull
git checkout -b feature/your-feature-name
# Make changes...
git add .
git commit -m "feat: add new feature"
# Push to remote
git push origin feature/your-feature-name
Commit Message Convention
Follow Conventional Commits:
type(scope): description
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentationstyle: Formattingrefactor: Code refactoringtest: Adding testschore: Maintenance
Examples:
feat(annotations): add voice recording support
fix(auth): resolve username login issue
docs(api): update API reference
Code Style
TypeScript
Use TypeScript for all new files:
// Define types
interface User {
id: string;
email: string;
role: 'admin' | 'annotator' | 'evaluator';
}
// Type function parameters and return
function getUser(id: string): Promise<User | null> {
// implementation
}
// Type React components
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
function Button({ label, onClick, disabled = false }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{label}</button>;
}
React Best Practices
// Use functional components
function MyComponent() {
// Use hooks
const [state, setState] = useState(initialValue);
useEffect(() => {
// Side effects
return () => {
// Cleanup
};
}, [dependencies]);
// Early returns for loading/error states
if (loading) return <Loading />;
if (error) return <Error message={error} />;
// Main render
return <div>Content</div>;
}
ESLint Configuration
Project uses ESLint with:
TypeScript support
React hooks rules
React refresh plugin
Fix linting issues:
npm run lint -- --fix
Tailwind CSS
Use utility classes:
<div className="flex flex-col gap-4 p-6 bg-white rounded-lg shadow-md">
<h2 className="text-2xl font-bold text-gray-900">Title</h2>
<p className="text-gray-600">Description</p>
</div>
Use responsive modifiers:
<div className="w-full md:w-1/2 lg:w-1/3">
Responsive width
</div>
Adding New Features
1. Create Component
// src/components/features/NewFeature.tsx
import { useState } from 'react';
interface NewFeatureProps {
data: string;
}
export default function NewFeature({ data }: NewFeatureProps) {
const [state, setState] = useState('');
return (
<div>
<h2>{data}</h2>
</div>
);
}
2. Add Route (if needed)
In App.tsx:
<Route
path="/new-feature"
element={
<ProtectedRoute>
<Layout>
<NewFeature />
</Layout>
</ProtectedRoute>
}
/>
3. Add API Function (if needed)
In src/services/supabase-api.ts:
export const newFeatureAPI = {
async getData(id: string) {
const { data, error } = await supabase
.from('table_name')
.select('*')
.eq('id', id)
.single();
if (error) throw error;
return data;
},
};
4. Update Types
In src/types/index.ts:
export interface NewFeatureData {
id: string;
name: string;
// ...
}
Database Migrations
Creating Migrations
Design schema changes
Write SQL migration in Supabase SQL Editor
Test in development
Document in
database-schema.mdApply to production
Example Migration:
-- Add new column
ALTER TABLE users
ADD COLUMN preferred_language TEXT;
-- Create index
CREATE INDEX idx_users_preferred_language
ON users(preferred_language);
-- Update RLS policy
CREATE POLICY "Users can update own language"
ON users FOR UPDATE
USING (auth.uid() = id)
WITH CHECK (auth.uid() = id);
Testing
Manual Testing Checklist
Before submitting PR:
Feature works as expected
No console errors
Responsive on mobile/tablet/desktop
Works in Chrome, Firefox, Safari
No TypeScript errors (
npm run build)No linting errors (
npm run lint)Tested with different user roles
Tested error cases
Testing User Flows
1. Authentication:
Sign up new user
Login with email
Login with username
Password reset
Logout
2. Annotation:
Navigate to annotation interface
Select sentence
Add highlights
Submit annotation
View submitted annotations
3. Evaluation:
View pending evaluations
Evaluate annotation
Submit feedback
4. Admin:
Create users
Add sentences
Import CSV
View statistics
Debugging
Browser DevTools
Use React Developer Tools:
Install extension
Inspect component tree
View props/state
Profile performance
Supabase Dashboard
Check:
Database tables
RLS policies
API logs
Auth users
Storage files
Common Issues
“Failed to fetch” errors:
// Check network tab
// Verify Supabase URL/key
// Check RLS policies
// Review CORS settings
Authentication issues:
// Clear localStorage
localStorage.clear();
// Check Supabase Auth logs
// Verify user exists in database
Build errors:
# Clear cache
rm -rf node_modules
rm package-lock.json
npm install
# Clear build
rm -rf dist
npm run build
Performance Optimization
Code Splitting
// Lazy load components
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
Memoization
// Memoize expensive calculations
const expensiveValue = useMemo(() => {
return computeExpensiveValue(data);
}, [data]);
// Memoize callbacks
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
Database Query Optimization
// Select only needed fields
const { data } = await supabase
.from('table')
.select('id, name, email') // Not *
.limit(20);
// Use pagination
const { data } = await supabase
.from('table')
.select('*')
.range(0, 19);
Documentation
Update documentation when:
Adding new features
Changing API
Modifying database schema
Updating configuration
Documentation locations:
User docs:
docs/user-manual/Technical docs:
docs/technical-manual/Code comments: Inline for complex logic
README: Project overview
Contributing
See CONTRIBUTING.md for:
Code of Conduct
Pull Request process
Review criteria
Style guidelines
Resources
See Also
Architecture - System design
Components - Component documentation
API Reference - API docs
Deployment - Production deployment