9.8 KiB
MOC Auto-Generation Feature
Overview
The LEGO Instructions Manager now includes automatic MOC (My Own Creation) set number generation, making it easier to track and organize your custom LEGO builds without manually managing set numbers.
Default Behavior: Global Numbering - All users share the same MOC number sequence, ensuring system-wide unique MOC numbers.
Features
🤖 Automatic Number Generation
- Sequential Numbering: Automatically generates MOC numbers in sequence (MOC-10000, MOC-10001, MOC-10002, etc.)
- Global by Default: All users share the same sequence for system-wide uniqueness
- Conflict-Free: Ensures no duplicate MOC numbers across the entire system
- Customizable Prefix: Default is "MOC" but can be changed
- Optional User-Scoping: Can scope to individual users if needed
🔌 API Endpoints
1. Generate Next MOC Number
GET /api/moc/generate
Query Parameters:
prefix(optional): MOC prefix, default is 'MOC'user_scoped(optional): Scope to current user, default is 'false' (GLOBAL)
Response:
{
"success": true,
"moc_number": "MOC-10001",
"prefix": "MOC",
"user_scoped": false
}
Example Usage:
// Get next global MOC number (default)
fetch('/api/moc/generate')
.then(response => response.json())
.then(data => {
console.log('Next MOC number:', data.moc_number);
});
// Get next user-scoped MOC number (optional)
fetch('/api/moc/generate?user_scoped=true')
.then(response => response.json())
.then(data => {
console.log('Next user MOC number:', data.moc_number);
});
2. Validate MOC Number
POST /api/moc/validate
Request Body:
{
"set_number": "MOC-12345",
"user_scoped": false
}
Response:
{
"success": true,
"available": true,
"set_number": "MOC-12345"
}
3. Check MOC Format
GET /api/moc/check-format?set_number=MOC-10001&prefix=MOC
Response:
{
"is_moc": true,
"set_number": "MOC-10001",
"prefix": "MOC"
}
Database Schema
The Set model includes MOC support fields:
is_moc = db.Column(db.Boolean, default=False, nullable=False, index=True)
moc_designer = db.Column(db.String(100), nullable=True) # Designer/creator name
moc_description = db.Column(db.Text, nullable=True) # Detailed description
Frontend Integration
HTML Form Example
When creating a new set, users can toggle MOC mode:
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" id="is_moc" name="is_moc">
<label class="form-check-label" for="is_moc">
<strong>This is a MOC (My Own Creation)</strong>
</label>
</div>
<div id="mocSection" style="display: none;">
<div class="alert alert-success">
<i class="bi bi-lightbulb"></i>
MOC set number will be auto-generated:
<strong id="mocNumberPreview">Loading...</strong>
</div>
</div>
<div id="officialSection">
<label for="set_number">Set Number</label>
<input type="text" id="set_number" name="set_number" required>
</div>
JavaScript Integration
// Handle MOC toggle
document.getElementById('is_moc').addEventListener('change', function() {
const mocSection = document.getElementById('mocSection');
const officialSection = document.getElementById('officialSection');
const setNumberInput = document.getElementById('set_number');
if (this.checked) {
// Show MOC section, hide official section
mocSection.style.display = 'block';
officialSection.style.display = 'none';
setNumberInput.removeAttribute('required');
// Fetch next MOC number (global by default)
fetchNextMocNumber();
} else {
// Show official section, hide MOC section
mocSection.style.display = 'none';
officialSection.style.display = 'block';
setNumberInput.setAttribute('required', 'required');
}
});
// Fetch next MOC number from API
function fetchNextMocNumber() {
fetch('/api/moc/generate')
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('mocNumberPreview').textContent = data.moc_number;
// Optionally store in hidden field
document.getElementById('moc_number_hidden').value = data.moc_number;
}
})
.catch(error => {
console.error('Error fetching MOC number:', error);
document.getElementById('mocNumberPreview').textContent = 'Error generating number';
});
}
Backend Implementation
Service Layer
The MOCNumberGenerator service handles all MOC number logic:
from app.services.moc_generator import MOCNumberGenerator
# Generate next GLOBAL MOC number (default)
moc_number = MOCNumberGenerator.generate_next_number(
prefix='MOC',
user_id=None # None = global numbering
)
# Generate next USER-SCOPED MOC number (optional)
moc_number = MOCNumberGenerator.generate_next_number(
prefix='MOC',
user_id=current_user.id # Scope to specific user
)
# Validate MOC number availability (global)
is_available = MOCNumberGenerator.validate_moc_number(
'MOC-12345',
user_id=None # Check globally
)
# Check if number follows MOC format
is_moc = MOCNumberGenerator.is_moc_number('MOC-10001')
Route Layer
MOC routes are organized in app/routes/moc.py:
from flask import Blueprint, jsonify
from flask_login import login_required, current_user
from app.services.moc_generator import MOCNumberGenerator
bp = Blueprint('moc', __name__, url_prefix='/api/moc')
@bp.route('/generate', methods=['GET'])
@login_required
def generate_moc_number():
# Default: user_scoped=false (global numbering)
user_scoped = request.args.get('user_scoped', 'false').lower() == 'true'
user_id = current_user.id if user_scoped else None
moc_number = MOCNumberGenerator.generate_next_number(
user_id=user_id
)
return jsonify({
'success': True,
'moc_number': moc_number
})
Configuration
Customizing MOC Prefix
Edit app/services/moc_generator.py:
class MOCNumberGenerator:
DEFAULT_PREFIX = 'MOC' # Change to 'CUSTOM' or any prefix
DEFAULT_START = 10000 # Starting number for MOCs
Numbering Modes
Global Numbering (Default - RECOMMENDED):
- All users share the same MOC number sequence
- Ensures system-wide unique MOC numbers
- MOC-10000 is unique across the entire system
- API:
user_scoped=falseor omit parameter - Use Case: Single household, organization, or when you want guaranteed unique IDs
Per-User Numbering (Optional):
- Each user has their own MOC number sequence
- MOC-10000 can exist for multiple users
- API:
user_scoped=true - Use Case: Multi-tenant systems where users want isolated numbering
Use Cases
Creating a New MOC
- User clicks "Add New Set"
- User toggles "This is a MOC" checkbox
- System automatically generates next global MOC number (e.g., MOC-10000)
- User fills in MOC designer, description, and other details
- System saves set with is_moc=True
Importing Multiple MOCs
from app.services.moc_generator import MOCNumberGenerator
for moc_data in moc_import_list:
# Global numbering - user_id=None
moc_number = MOCNumberGenerator.generate_next_number()
new_set = Set(
set_number=moc_number,
set_name=moc_data['name'],
is_moc=True,
moc_designer=moc_data['designer'],
theme='MOC',
year_released=moc_data['year']
)
db.session.add(new_set)
db.session.commit()
Filtering MOCs
# Get all MOCs
mocs = Set.query.filter_by(is_moc=True).all()
# Get MOCs by designer
designer_mocs = Set.query.filter_by(
is_moc=True,
moc_designer='John Doe'
).all()
# Get MOCs by number range
mocs_range = Set.query.filter(
Set.is_moc == True,
Set.set_number.like('MOC-10%')
).all()
Troubleshooting
MOC Number Not Generating
Issue: API returns error or "Error generating number"
Solutions:
- Check that user is logged in (endpoint requires authentication)
- Verify database connection
- Check browser console for JavaScript errors
- Ensure
moc_bpis registered inapp/__init__.py
Duplicate MOC Numbers
Issue: Same MOC number assigned to multiple sets
Solutions:
- Verify you're using global numbering (default
user_scoped=false) - Check database constraints on
set_numberfield (should be unique) - Run database migration to add unique constraint if missing
MOC Toggle Not Working
Issue: Toggle switch doesn't show/hide sections
Solutions:
- Check JavaScript console for errors
- Verify element IDs match between HTML and JavaScript
- Ensure Bootstrap JavaScript is loaded (for styling)
Future Enhancements
Potential improvements for the MOC feature:
- Bulk MOC number generation API
- MOC number recycling (reuse deleted MOC numbers)
- Custom number formats (e.g., MOC-YYYY-NNNN for year-based)
- MOC templates for common builds
- MOC sharing/export functionality
- Integration with MOC platforms like Rebrickable
Related Documentation
- Main README - General application documentation
- Setup Guide - Installation and configuration
- Feature Update Summary - Recent changes
Support
For issues or questions about MOC auto-generation:
- Check existing issues on Gitea
- Review this documentation
- Check application logs for errors
- Create a new issue with:
- Steps to reproduce
- Expected vs actual behavior
- Browser console logs
- Server logs (if applicable)
Last Updated: December 2024
Feature Version: 1.1 (Global Numbering Default)
Compatibility: LEGO Instructions Manager v1.3.0+