Development Guide
Guide for developers working on the Open Receipt OCR codebase.
Project Structure
open-receipt-ocr/
├── client/ # Angular frontend
│ ├── src/
│ │ ├── app/
│ │ │ ├── components/ # Reusable UI components
│ │ │ ├── layouts/ # Page layouts
│ │ │ ├── pipes/ # Custom pipes & parsers
│ │ │ └── services/ # API & utility services
│ │ └── assets/
│ └── public/ # Static assets & translations
├── server/ # NestJS backend
│ ├── src/
│ │ ├── core/ # Core modules
│ │ │ ├── database/ # TypeORM & database
│ │ │ ├── storage/ # Storage providers
│ │ │ ├── secrets/ # Secret management
│ │ │ └── types/ # Shared type definitions
│ │ ├── ocr-jobs/ # OCR job management
│ │ ├── worker/ # Background job processing
│ │ │ ├── ocr/ # OCR processor implementations
│ │ │ └── config/
│ │ └── main.ts # Server entry point
│ ├── .env.example # Environment variables template
│ └── worker.ts # Worker process entry point
├── packages/
│ ├── types/ # Shared TypeScript types
│ │ └── src/
│ │ ├── ocr-provider.enum.ts # OCR provider enum
│ │ └── ...
│ └── ...
├── docker-compose.yaml # Multi-container setup
├── Dockerfile # Docker image
└── package.json # Root package (monorepo)
Development Setup
Prerequisites
- Node.js 18+
- npm or yarn
- Git
- Docker & Docker Compose (for containerized development)
Initial Setup
# Clone repository
git clone https://github.com/iursevla/open-receipt-ocr.git
cd open-receipt-ocr
# Install dependencies
npm install
# Setup environment
cp server/.env.example server/.env
# Edit server/.env with your configuration
# Start Redis
redis-server # or: docker run -d -p 6379:6379 redis:latest
# Start development server
npm run dev
Running Individual Services
# Start backend only
npm run dev:server
# Start frontend only (in another terminal)
npm run dev:client
# Start worker only (in another terminal)
npm run dev:worker
Technology Stack
Frontend
- Framework: Angular 18+
- UI Library: PrimeNG
- Styling: CSS/SCSS
- State Management: Angular Services
- I18n: Transloco
Backend
- Framework: NestJS
- ORM: TypeORM
- Database: SQLite (development), PostgreSQL (recommended for production)
- Job Queue: BullMQ (with Redis)
- API: REST (JSON)
DevOps
- Containerization: Docker
- Orchestration: Docker Compose
- CI/CD: GitHub Actions (if configured)
Code Standards
TypeScript
- Use strict mode:
"strict": trueintsconfig.json - Prefer interfaces over types for object shapes
- Use enums for fixed sets of values
- Add JSDoc comments for public APIs
Example:
interface OcrResult {
markdown: string;
rawText: string;
}
/**
* Process a file with the specified OCR provider
*/
async function processFile(file: File, provider: OcrProvider): Promise<OcrResult> {
// implementation
}
File Naming
- Components:
*.component.ts - Services:
*.service.ts - Processors:
*.processor.ts - Modules:
*.module.ts - Enums:
*.enum.ts - Interfaces: Defined in
*.tsfiles or*.interface.ts
Angular Components
import { Component } from '@angular/core';
@Component({
selector: 'app-receipt-viewer',
templateUrl: './receipt-viewer.component.html',
styleUrls: ['./receipt-viewer.component.scss']
})
export class ReceiptViewerComponent {
// Component logic
}
NestJS Services
import { Injectable } from '@nestjs/common';
@Injectable()
export class OcrJobService {
constructor(private repository: OcrJobRepository) {}
async process(jobId: number): Promise<void> {
// Business logic
}
}
Adding Features
Add a New OCR Provider
See Extending Guide for detailed instructions.
Add a New API Endpoint
- Create a new controller or add to existing:
// server/src/ocr-jobs/ocr-jobs.controller.ts
@Controller('ocr-jobs')
export class OcrJobsController {
constructor(private service: OcrJobService) {}
@Get(':id')
async getJob(@Param('id') id: number) {
return this.service.findOne(id);
}
}
- Add corresponding service method
- Add tests for the endpoint
- Update API documentation
Add a New Angular Component
- Generate using Angular CLI:
ng generate component components/receipt-upload --skip-tests
- Add to appropriate module’s declarations
- Style with SCSS
- Add unit tests
Testing
Run All Tests
npm run test
Run Specific Test
npm run test -- --include='**/ocr.processor.spec.ts'
Test Coverage
npm run test:cov
Coverage reports are generated in the coverage/ directory.
Writing Tests
Backend example (NestJS):
describe('OcrJobService', () => {
let service: OcrJobService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [OcrJobService],
}).compile();
service = module.get<OcrJobService>(OcrJobService);
});
it('should process a job', async () => {
const result = await service.processJob(1);
expect(result).toBeDefined();
});
});
Git Workflow
Branch Naming
- Feature:
feature/short-description - Bug fix:
fix/issue-description - Documentation:
docs/topic - Chore:
chore/task-description
Example: feature/add-paddle-ocr-support
Commit Messages
Use conventional commits:
type(scope): description
[optional body]
[optional footer]
Types: feat, fix, docs, style, refactor, test, chore
Example:
feat(ocr): add support for local PaddleOCR
- Integrate paddleocr npm package
- Add configuration option PADDLE_OCR_LOCAL_ENABLED
- Implement PaddleOCR processor
Closes #42
Pull Request Checklist
- Code follows project standards
- Tests are included and passing
- Documentation is updated
- No breaking changes (or clearly documented)
- Commit messages are descriptive
Debugging
Backend
Enable debug logging:
DEBUG=open-receipt-ocr:*
Use VS Code debugger with server/.vscode/launch.json:
{
"type": "node",
"request": "launch",
"name": "NestJS Server",
"program": "${workspaceFolder}/server/dist/main.js",
"cwd": "${workspaceFolder}/server"
}
Frontend
Use Angular DevTools Chrome extension or:
// In component
constructor(private logger: Logger) {}
ngOnInit() {
this.logger.log('Component initialized', this.data);
}
Database
Query SQLite directly:
sqlite3 data/db/ocr.sqlite
sqlite> .tables
sqlite> SELECT * FROM ocr_jobs LIMIT 5;
Redis
Monitor Redis commands:
redis-cli
127.0.0.1:6379> MONITOR
Building for Production
Build Docker Image
docker build -t open-receipt-ocr:latest .
Build Frontend Only
npm run build:client
Build Backend Only
npm run build:server
Performance Optimization
Frontend
- Use
OnPushchange detection strategy - Lazy load modules
- Optimize images and assets
- Monitor bundle size:
npm run analyze
Backend
- Use connection pooling for database
- Implement caching with Redis
- Optimize database queries with indexing
- Use async/await properly
Database
Recommended indexes:
CREATE INDEX idx_ocr_jobs_status ON ocr_jobs(status);
CREATE INDEX idx_ocr_jobs_created_at ON ocr_jobs(created_at);
CREATE INDEX idx_ocr_files_job_id ON ocr_files(job_id);
Documentation
- Update
docs/folder for user-facing documentation - Add JSDoc comments for public APIs
- Include examples in README sections
- Keep architecture diagrams up to date
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Make your changes
- Run tests:
npm run test - Commit:
git commit -m "feat: description" - Push:
git push origin feature/your-feature - Open a Pull Request
Common Tasks
Migrate Database
# Generate migration
npm run typeorm:migration:generate -- -n AddNewColumn
# Run migrations
npm run typeorm:migration:run
Update Dependencies
# Check for updates
npm outdated
# Update specific package
npm update @nestjs/core
# Update all
npm update
Reset Database
rm data/db/ocr.sqlite
npm run typeorm:migration:run
Troubleshooting
“Cannot find module” errors
rm -rf node_modules package-lock.json
npm install
Port conflicts
lsof -i :3000 # Find process
kill -9 <PID>
Redis connection issues
redis-cli ping # Should return PONG
ps aux | grep redis # Check if running