# Adding New Configurations to Master LMS This guide outlines the standard end-to-end workflow for introducing a new configuration field (like the "Park Advance Collection" feature) into the Master LMS system. The architecture requires updates across the Database schema, Pydantic validation, API routers, and the Frontend React UI. --- ## 1. Update SQLAlchemy Models **File:** `app/models/configuration.py` Begin by adding the new column to the relevant database model (e.g., `AllocationConfiguration`, `InterestConfiguration`). ```python class AllocationConfiguration(TemporalConfigBase): __tablename__ = "allocation_configurations" # ... existing fields park_advance_collection = Column(Boolean, nullable=False, default=False) ``` ## 2. Generate and Apply Database Migrations **Folder:** `alembic/versions/` Use Alembic to auto-generate the SQL migration script for the new column. 1. **Generate script:** Run `alembic revision --autogenerate -m "Add park advance collection"` 2. **CRITICAL - Manually Review Script:** Because Master LMS shares a database with other services (which are not defined in its SQLAlchemy models), Alembic may incorrectly generate `op.drop_table()` commands for tables like `loans` or `payments`. * **You MUST manually delete all `drop_table` and `drop_index` commands from the generated script.** * Keep only the `op.add_column()` instruction in `upgrade()` and `op.drop_column()` in `downgrade()`. 3. **Apply migration:** Run `alembic upgrade head`. ## 3. Update Pydantic Schemas **File:** `app/schemas/configuration.py` Update the corresponding `*Create` schema so the FastAPI backend knows how to validate the incoming payload from the frontend. ```python class AllocationConfigCreate(TemporalConfigBase): # ... existing fields park_advance_collection: bool = Field(default=False) ``` *Note: If you are introducing a new enum or category type (e.g., adding `ADVANCE_COLLECTION` to `sequence_type`), ensure you update the associated `@field_validator` methods to prevent 422 Validation Errors.* ## 4. Update API Routers **File:** `app/routers/configuration.py` When the API receives a POST/PUT request, it maps the Pydantic schema object to the SQLAlchemy model object. You must explicitly pass your new field into the SQLAlchemy instantiation. ```python @router.post("/allocation") async def save_allocation_config(config: AllocationConfigCreate, db: AsyncSession = Depends(get_db)): db_config = AllocationConfiguration( # ... existing fields park_advance_collection=config.park_advance_collection, # ... existing fields ) # ... save logic ``` *(Data returned via `GET` endpoints usually maps automatically because of Pydantic's `from_attributes=True` or manual column iteration, but verify if a specific `Out` schema is used.)* ## 5. Frontend React State Management **File:** `frontend/src/views/ProductConfig.jsx` Update the React component to handle loading and saving the new configuration. 1. **Add State:** ```javascript const [parkAdvanceCollection, setParkAdvanceCollection] = useState(false); ``` 2. **Ingest Data on Load (`loadConfigs`):** ```javascript if (matchingAllocation) { setParkAdvanceCollection(matchingAllocation.park_advance_collection || false); } ``` 3. **Include Data on Save (`saveAllocation`):** ```javascript await api.saveAllocationConfig({ // ... existing fields park_advance_collection: parkAdvanceCollection }); ``` ## 6. Frontend UI Rendering **File:** `frontend/src/views/ProductConfig.jsx` Finally, render the new UI elements (dropdowns, toggles, text inputs) and bind them to your state setter methods (`onChange={() => setParkAdvanceCollection(...)}`). Use conditional rendering (e.g., `{selectedSeqType === 'ADVANCE_COLLECTION' && ( ... )}`) to ensure the UI is only displayed in the correct context.