A web application for managing aquarium society Breeder Awards Programs (BAP), tracking breeding achievements, managing member submissions, and handling species data.
Production: https://bap.basny.org
- Member Management: User registration, authentication, and profile management
- Submission System: Track breeding achievements with photos and detailed information
- Witness Verification: Multi-stage verification process for submissions
- Waiting Period Tracking: Automatic calculation of species-specific waiting periods
- Awards & Standings: Real-time leaderboards and award progression tracking
- Species Database: Comprehensive fish, coral, plant, and invertebrate species catalog
- Admin Tools: Approval queue, witness management, member administration
- Image Processing: Automatic image optimization and multiple size variants
- Activity Feed: Real-time updates on submissions, approvals, and achievements
- Runtime: Node.js with TypeScript
- Framework: Express.js
- Database: SQLite with migrations
- Session Management: Cookie-based sessions
- Authentication: OAuth integration (Google)
- Email: Nodemailer for notifications
- Image Processing: Sharp for image optimization
- Storage: Cloudflare R2 for image storage
- Template Engine: Pug templates
- Interactivity: HTMX for dynamic updates
- Styling: Tailwind CSS with PostCSS
- Build Tools: esbuild for bundling
- Hosting: AWS EC2 (t3.micro)
- Reverse Proxy: nginx with Let's Encrypt SSL
- Deployment: Docker Compose
- IaC: AWS CDK (TypeScript)
- CI/CD: GitHub Actions
- Node.js 20.x or higher
- npm or yarn
- SQLite3
# Clone the repository
git clone https://github.com/jra3/mulm.git
cd mulm
# Install dependencies
npm install
# Create configuration file
cp src/config.example.json src/config.json
# Edit src/config.json with your settings
Create src/config.json
with the following structure:
{
"databaseFile": "./database/database.db",
"sessionSecret": "your-session-secret-here",
"smtp": {
"host": "smtp.example.com",
"port": 587,
"secure": false,
"auth": {
"user": "[email protected]",
"pass": "your-password"
}
},
"oauth": {
"google": {
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"redirectUri": "http://localhost:4200/auth/google/callback"
}
},
"r2": {
"accountId": "your-r2-account-id",
"accessKeyId": "your-access-key",
"secretAccessKey": "your-secret-key",
"bucketName": "your-bucket-name",
"publicUrl": "https://your-bucket.r2.dev"
}
}
The database is automatically initialized with migrations on first run:
npm run dev
Migrations are located in db/migrations/
and run automatically at startup.
npm run dev # Start development server with hot reload
npm run build # Build TypeScript and PostCSS assets
npm test # Run test suite
npm test -- --watch # Run tests in watch mode
npm run lint # Run ESLint
npm run lint:fix # Fix ESLint issues
npm run script # Run scripts with ts-node (e.g., npm run script scripts/example.ts)
npm start # Start production server (requires build first)
npm run dev
The server will start on http://localhost:4200 with:
- Hot reload for TypeScript changes (Nodemon)
- Automatic CSS rebuilding (PostCSS watch)
- Source maps for debugging
mulm/
├── db/
│ └── migrations/ # Database migration files
├── infrastructure/ # AWS CDK infrastructure code
├── nginx/ # nginx configuration for production
├── scripts/ # Utility scripts
├── src/
│ ├── __tests__/ # Test files
│ ├── db/ # Database layer (queries, models)
│ ├── forms/ # Zod form validation schemas
│ ├── routes/ # Express route handlers
│ ├── utils/ # Utility functions
│ ├── views/ # Pug templates
│ ├── config.json # Configuration (git-ignored)
│ └── index.ts # Application entry point
├── docker-compose.prod.yml # Production Docker Compose
└── package.json
The project uses Node.js native test runner (migrated from Jest):
# Run all tests
npm test
# Run specific test file
npm test -- src/__tests__/image-processor.test.ts
# Run tests in watch mode
npm test -- --watch
Test Coverage:
- Unit tests for image processing, validation, and utilities
- Integration tests for witness workflow and database operations
- Template rendering tests for all Pug templates
- Rate limiter middleware tests
Current Status: 153/153 tests passing (100%)
members
- User accounts and profilessubmissions
- Breeding achievement recordsspecies_name
- Species catalog with classificationstank_presets
- User-saved tank configurationsawards
- Award definitions and point thresholdssessions
- Cookie-based session storageactivity_feed
- Activity log for member dashboard
Migrations run automatically on startup. To create a new migration:
# Create migration file in db/migrations/
# Format: YYYY-description.sql
Comprehensive documentation is available in the GitHub Wiki:
- Security Overview - Security posture, audits, and active initiatives
- Production Deployment - Deploy code changes, troubleshooting, SSL management
- Infrastructure Guide - AWS resources, critical resource protection, CDK deployment
# Deploy latest code from main branch
ssh BAP "cd /opt/basny && git pull && sudo docker-compose -f docker-compose.prod.yml up -d --build"
For detailed deployment procedures, troubleshooting, and infrastructure management, see the Production Deployment and Infrastructure Guide wiki pages.
- Config file:
src/config.json
(git-ignored) - Contains database path, OAuth credentials, SMTP settings, R2 storage keys
- Config file:
/mnt/basny-data/app/config/config.production.json
- Mounted read-only into container at
/app/src/config.json
- Permissions: Must be 600 (owner-only) and owned by UID 1001 (nodejs user)
The application uses RESTful conventions:
GET /submissions/:id
- View submission detailsPOST /submissions
- Create new submissionPATCH /submissions/:id
- Update submissionDELETE /submissions/:id
- Delete submission
GET /admin/queue
- Approval queueGET /admin/witness-queue
- Witness verification queuePOST /admin/submissions/:id/approve
- Approve submissionPOST /admin/submissions/:id/deny
- Deny submission
See CLAUDE.md
for complete route documentation.
- TypeScript with strict type checking
- ESLint for code quality
- Prettier for formatting (via ESLint)
- Pug templates with specific Tailwind conventions
- Create a feature branch from
main
- Make your changes with tests
- Run
npm run lint
andnpm test
- Push and create a pull request
- CI will automatically run tests and linting
Critical Rules:
- Use double quotes for attributes
- Break long Tailwind class chains across lines
- Use class attribute for modifiers (hover:, md:, focus:)
- Simple utilities only with dot notation
See CLAUDE.md
for detailed Pug best practices.
MIT License - see package.json for details
For issues or questions, please open an issue on GitHub.