Files
lego-instructions-manager/docs/MOC_AUTO_GENERATION.md

8.7 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.

Features

🤖 Automatic Number Generation

  • Sequential Numbering: Automatically generates MOC numbers in sequence (MOC-10000, MOC-10001, MOC-10002, etc.)
  • Conflict-Free: Ensures no duplicate MOC numbers
  • Customizable Prefix: Default is "MOC" but can be changed
  • User-Scoped Option: Can scope MOC numbers per user or globally

🔌 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 'true'

Response:

{
  "success": true,
  "moc_number": "MOC-10001",
  "prefix": "MOC",
  "user_scoped": true
}

Example Usage:

fetch('/api/moc/generate')
  .then(response => response.json())
  .then(data => {
    console.log('Next MOC number:', data.moc_number);
  });

2. Validate MOC Number

POST /api/moc/validate

Request Body:

{
  "set_number": "MOC-12345",
  "user_scoped": true
}

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
        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 MOC number
moc_number = MOCNumberGenerator.generate_next_number(
    prefix='MOC',
    user_id=current_user.id  # Optional: scope to user
)

# Validate MOC number availability
is_available = MOCNumberGenerator.validate_moc_number(
    'MOC-12345',
    user_id=current_user.id
)

# 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():
    moc_number = MOCNumberGenerator.generate_next_number(
        user_id=current_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

Per-User vs Global Numbering

Per-User Numbering (default):

  • Each user has their own MOC number sequence
  • MOC-10000 can exist for multiple users
  • API: user_scoped=true

Global Numbering:

  • All users share the same MOC number sequence
  • Ensures unique MOC numbers across the entire system
  • API: user_scoped=false

Use Cases

Creating a New MOC

  1. User clicks "Add New Set"
  2. User toggles "This is a MOC" checkbox
  3. System automatically generates MOC-10000 (or next available)
  4. User fills in MOC designer, description, and other details
  5. System saves set with is_moc=True

Importing Multiple MOCs

from app.services.moc_generator import MOCNumberGenerator

for moc_data in moc_import_list:
    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:

  1. Check that user is logged in (endpoint requires authentication)
  2. Verify database connection
  3. Check browser console for JavaScript errors
  4. Ensure moc_bp is registered in app/__init__.py

Duplicate MOC Numbers

Issue: Same MOC number assigned to multiple sets

Solutions:

  1. Check database constraints on set_number field
  2. Verify user_scoped parameter matches your use case
  3. Run database migration to add unique constraint if missing

MOC Toggle Not Working

Issue: Toggle switch doesn't show/hide sections

Solutions:

  1. Check JavaScript console for errors
  2. Verify element IDs match between HTML and JavaScript
  3. 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

Support

For issues or questions about MOC auto-generation:

  1. Check existing issues on Gitea
  2. Review this documentation
  3. Check application logs for errors
  4. 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.0
Compatibility: LEGO Instructions Manager v1.3.0+