Releases: genes3e7/Duty-Planner
v4.2.0: Multi-Team Scaling & Planner Flexibility
This release introduces major architectural upgrades to support scaling operations with multiple teams, enhances the planner with manual adjustment capabilities, and refactors the UI for better usability.
🚀 New Features
👥 Multi-Team Support
- Scalable Operations: You can now configure the number of Active Teams (AM/PM/24H) and Standby Teams independently in the Rules tab.
- Dynamic Shift Generation: The system automatically generates and schedules slots for additional teams (e.g.,
AM_2,PM_2,S/B_2). - Inheritance: "Team 2" shifts automatically inherit point values and public holiday multipliers from their base shift types.
🎛️ Planner Enhancements
- Manual Point Adjustments: Added a "Manual Adj" column to the Statistics table. You can now apply ad-hoc penalties (e.g.,
-5) or bonuses (+5) directly in the planner. - Editable "Brought Fwd": Starting balances can now be edited directly in the grid, making it easier to correct carry-over errors without re-uploading files.
- Negative Balance Support: The solver's logic has been upgraded to support negative point domains. This ensures that staff with a negative "Brought Fwd" balance (debt) can still be scheduled effectively to "catch up."
🎨 UI/UX Improvements
- Rules Tab Overhaul: The Rules page has been reorganized into two tabs:
- 📋 Configuration: For defining team structures, staff counts, and global limits.
- 🔄 Transitions: For configuring the shift transition matrix (Hard/Soft Bans).
- Settings Page Refactor: Simplified to focus purely on Global Configuration (Personnel, Country) and Point Values.
- Standardized Labels: Widget labels have been unified across the app for consistency (e.g., changed "Needed" to "Staff", unified "Is Multiplier?" checkboxes).
🛠️ Logic & Quality
- Robust Solver: Refactored the core scheduling engine to remove magic numbers and improve input validation for shift strings.
- Compatibility: Config files now use aliased keys (e.g.,
S/B) to ensure seamless save/load operations between versions. - Documentation: Updated README with comprehensive details on the new Hard/Soft constraint logic and Multi-Team architecture.
What's Changed
- Support for additional active and standby teams by @genes3e7 in #21
- chore(deps): Bump streamlit from 1.53.0 to 1.53.1 by @dependabot[bot] in #18
- chore(deps): Bump ruff from 0.14.13 to 0.14.14 by @dependabot[bot] in #20
- chore(deps): Bump holidays from 0.88 to 0.89 by @dependabot[bot] in #19
- Update README with multi-team logic and manual adjustments by @genes3e7 in #22
Full Changelog: v4.1.0...v4.2.0
v4.1.0: Catch Up Limits & Dynamic Transition Rules
This release introduces significant improvements to the scheduling engine, offering granular control over staff workload limits and shift transition rules. It empowers administrators to prevent burnout for staff with point deficits and fully customize shift sequences (e.g., AM → PM) directly from the UI.
🚀 New Features
1. Relative Catch Up Limit
- What it is: A fairness mechanism to prevent staff who are "catching up" on points from being assigned an excessive number of duties in a single month.
- How it works: Administrators can set a "limit" in Settings. The solver ensures no single person is assigned more than
Average Monthly Points + Limit. - Configuration:
- 0: Unlimited catch-up (Standard behavior).
- > 0: Caps the workload relative to the team average.
- Logic Update: Includes a smart floor (
max(1, limit)) to ensure that even with small limits or low averages, the constraint remains mathematically feasible and does not unintentionally ban all work.
2. Dynamic Rules Configuration
- New UI Tab: A dedicated Rules page has been added to the application sidebar.
- Customizable Transitions: Users can now define the relationship between any pair of consecutive shifts (e.g., AM → PM). The solver no longer relies on hardcoded transition logic.
- ✅ Allowed: Standard transition.
⚠️ Soft Ban: Discouraged; the solver avoids it unless necessary (incurs penalty).- ⛔ Hard Ban: Strictly forbidden; the solver will never assign this sequence.
🛠 Improvements & Technical Changes
- Logic (
app/core/scheduler.py):- Updated the constraint programming model to support dynamic transition lookups from the configuration.
- Implemented the "Relative Catch Up" constraint logic in the fairness objective.
- Config (
app/models/config.py):- Added
RulesConfigmodel to store the transition matrix. - Added
catch_up_limitfield toConstraintsConfig. - Validation: Added robust Pydantic validators to ensure rule statuses are valid, defaulting to "Allowed" if malformed data is encountered.
- Added
- UI:
- Added tooltips to the Settings page to explain complex point constraints.
- New
app/ui/rules.pymodule for the Rules matrix editor.
- Testing:
- Added
tests/test_catch_up_limit.pyto verify capping logic and edge cases (e.g., minimal rosters). - Added
tests/test_scheduling_rules.pyto verify Hard/Soft ban enforcement.
- Added
📦 Documentation
- Updated
README.mdwith detailed explanations of the new constraints and architecture. - Achieved 100% docstring coverage for all modified files.
What's Changed
- chore(deps): Bump ortools from 9.14.6206 to 9.15.6755 by @dependabot[bot] in #16
- chore(deps): Bump ruff from 0.14.11 to 0.14.13 by @dependabot[bot] in #15
- chore(deps): Bump pydantic from 2.12.3 to 2.12.5 by @dependabot[bot] in #14
- chore(deps): Bump streamlit from 1.52.2 to 1.53.0 by @dependabot[bot] in #13
- Add catch up limit and dynamic scheduling rules by @genes3e7 in #17
Full Changelog: v4.0.0...v4.1.0
v4.0.0 - The Web Architecture Update
Release Notes: v4.0.0 - The Web Architecture Update
🚀 Major Release
We are excited to announce a complete re-architecture of the Duty Planner! This release marks the transition from a local desktop executable (customtkinter) to a modern, responsive web application built on Streamlit. This shift allows for easier deployment, better cross-platform compatibility, and a more robust user experience.
✨ Key Highlights
🖥️ Complete UI Overhaul (Streamlit Port)
- Web-Based Interface: The application now runs in the browser, eliminating the need for
.exebuilds or platform-specific GUI dependencies. - Interactive Data Grid: Replaced the static button grid with
st.data_editor, allowing for intuitive, Excel-like inline editing of the roster. - Responsive Sidebar: Centralized navigation, configuration, and file imports in a collapsible sidebar.
- Toast Notifications: Real-time feedback for actions like saving settings, solving schedules, or importing data.
⚙️ Enhanced Configuration Engine
- Granular Multipliers: Point calculations are now significantly more flexible. You can now configure separate multipliers for:
- Fridays: Split controls for AM, PM, and 24H shifts.
- Public Holiday Eves: Specific settings distinct from standard Public Holidays.
- Toggleable Logic: New boolean flags (e.g.,
ph_is_multiplier) allow you to choose between multiplying points (e.g., "2x points") or adding flat bonuses (e.g., "+2 points"). - Pydantic Validation: We have replaced standard data classes with Pydantic models. This ensures that configuration files are strictly validated, with automatic error recovery and safe fallbacks if a file is partially corrupt.
🧠 Solver & Logic Improvements
- Refactored Core Scheduler: The OR-Tools integration has been modularized into a dedicated
DutySchedulerEnginewith a cleaner separation of concerns. - Soft vs. Hard Bans: The logic now explicitly differentiates between "Hard Constraints" (impossible moves) and "Soft Bans" (discouraged moves with penalties), improving the solver's ability to find solutions in tight schedules.
- Improved 24H Logic: The "24H Mode" toggle is now integrated directly into the day configuration dataframe, allowing mixed-mode months (some days Shift, some days 24H) to be handled seamlessly.
🛠️ DevOps & Engineering
- CI/CD Pipeline: Added GitHub Actions workflows (
ci.yml) to automatically run tests and linting on every push. - Testing Suite: Introduced a comprehensive test suite using
pytestandAppTest(Streamlit's headless browser testing), covering:- Unit tests for logic and data parsing.
- Integration tests for the solver engine.
- Headless UI tests for the Streamlit frontend.
- Modern Tooling: Adopted
rufffor linting/formatting andpip-toolsfor deterministic dependency management. - Dev Containers: Added
.devcontainerconfiguration for instant, reproducible development environments in VS Code or GitHub Codespaces.
🔄 Migration Guide (v3.0.0 to v4.0.0)
Due to the change in architecture, previous config.json files from v3.0.0 are not directly compatible due to the new nested structure for point multipliers.
- Config: We recommend generating a fresh config using the new "Download Config JSON" button in the sidebar.
- Rosters: Excel exports from v3.0.0 can still be imported via the "Import Previous Month" feature to carry over points, as the logic relies on column name matching which remains consistent.
📦 Dependency Changes
- Removed:
customtkinter,pyinstaller,tk - Added:
streamlit,pydantic,holidays,ruff,pytest
Thank you to all contributors who helped test the transition to the web architecture!
What's Changed
- Refactor code to satisfy linting standards by @genes3e7 in #2
- CI Integrations for Python compatibility testing and Code base restructuring by @genes3e7 in #3
- Build(deps): Bump ruff from 0.14.10 to 0.14.11 by @dependabot[bot] in #7
- Build(deps): Bump holidays from 0.87 to 0.88 by @dependabot[bot] in #6
- Refactor app to Streamlit, update CI and config by @genes3e7 in #5
- Remove data leak vulnerability by @genes3e7 in #10
- Add multi-country holiday support and soft ban scheduling logic by @genes3e7 in #11
- chore(deps): Bump ruff from 0.14.10 to 0.14.11 by @dependabot[bot] in #9
- chore(deps): Bump pydantic from 2.12.3 to 2.12.5 by @dependabot[bot] in #8
- Documentation and Code Cleanup by @genes3e7 in #12
New Contributors
- @genes3e7 made their first contribution in #2
- @dependabot[bot] made their first contribution in #7
Full Changelog: v3.0.0...v4.0.0
The Architecture & UX Update
This release brings a massive under-the-hood improvement to code stability, along with high-value workflow improvements for the end user.
✨ New Features & Logic
- Smart Import: When importing a previous month's balance file, the app now detects new names and offers to overwrite your current personnel list entirely. This keeps your settings in perfect sync with your Excel data.
- Smarter Defaults: The "Check All 24H" logic has been refined.
- Previously: All Weekends & Holidays defaulted to 24H mode.
- Now: Only Public Holidays default to 24H mode. Saturdays/Sundays remain in Shift mode (AM/PM) unless manually toggled.
- Enhanced Feedback: The status bar now explicitly states the loaded Year (e.g.,
Loaded January 2026) to prevent confusion during end-of-year planning.
🎨 UI Improvements
- Clearer Controls: Buttons have been renamed to be self-explanatory:
Reset->Reset TableClear->Clear DutiesImport->Import Previous Month
- Workflow Optimization: Swapped the positions of the Generate and Export buttons to prevent accidental clicks.
🛠 Technical Overhaul
- Modular Architecture: The application has been split into a Controller/View structure (
planner_tab.py,settings_tab.py), making the code significantly easier to maintain. - Strict Typing: Replaced loose dictionaries with Python Data Classes (
AppConfig,ConstraintsConfig) and Enums (ShiftType). This eliminates typo-related bugs. - Decoupled Solver: The scheduling engine no longer knows about the UI. It receives a clean Data Transfer Object (
SolverRequest), making it testable and robust. - Documentation: 100% docstring coverage added across the codebase.
🐞 Bug Fixes
- Fixed a bug where the grid would not visually refresh after importing a file if the month hadn't changed.
- Fixed the Settings tab displaying stale personnel data after an import occurred in the Planner tab.
Full Changelog: v2.0.0...v3.0.0
The Flexibility Update
We are excited to ship Duty Scheduler Pro v2.0.0. This major update focuses on real-world flexibility, allowing planners to handle office closures, holidays, and dynamic team changes with zero friction.
🌟 New Features
Duty Toggle (Day Disable):
What it is: A new "Duty?" checkbox row has been added to the top of the grid.
How it works: Unchecking a box instantly disables that entire day column, turning it grey.
Impact: The solver effectively "skips" this day. No manpower constraints are enforced, and no points are accrued. Perfect for weekends, public holidays, or office closures where no duty personnel are required.
Dynamic Personnel Import:
Smart Onboarding: When importing a balance file (.xlsx) from a previous month, the system now detects names that are not in your current configuration.
Action: It prompts you to automatically add these new staff members to your settings, preventing data loss and manual entry errors.
⚡ Improvements & Changes
UI Streamlining:
Removed "Unit" Field: The "Workplace/Unit Name" field has been removed from the top bar to declutter the interface, as it was decorative and not used in logic or exports.
Enhanced Solver Logic:
The constraint engine now explicitly handles "Inactive Days." It mathematically ensures zero shifts are assigned on disabled days, preventing "ghost" assignments.
Robust Testing:
Added a comprehensive unit test suite covering 6 critical scenarios, including strict gap rules, impossible manpower demands, and point accumulation accuracy.
🐞 Fixes
Defensive State Management: Fixed an edge case where toggling a day off didn't immediately clear visual data. The column now wipes clean immediately upon disabling.
Constraint Handling: Fixed potential crash when manpower requirements were set to 0 for specific shifts.
📦 Upgrading
No database migration is required. Your existing config.json is compatible, though we recommend reviewing your "Daily Requirements" in the Settings tab after upgrading.
Download the latest source or executable.
Run gui.py (or the .exe).
Tip: Try the new "Duty?" toggle on the first weekend of the month to see it in action!
Full Changelog: v1.0.0...v2.0.0
Initial Production Release
We are pleased to announce the first stable production release of Duty Scheduler Pro. This application is a specialized automated rostering tool designed to handle complex 24/7 scheduling requirements. It utilizes advanced Constraint Satisfaction Programming (CSP) to generate fair, rule-compliant rosters while optimizing for equitable workload distribution.
🚀 Key Features
Intelligent Solver Engine: Built on Google OR-Tools, the engine automatically solves for:
Strict Gap Rules: Enforces mandatory rest periods (no back-to-back active duties).
Manpower Constraints: Adheres to daily requirements for AM, PM, 24H, and Standby shifts.
Fairness Optimization: Mathematically minimizes the variance in duty points across all personnel.
Interactive Planner Interface:
Excel-like grid with horizontal scrolling for monthly views.
Manual overrides: Click-to-cycle logic for pre-assigning Leaves (X), Duties, or Standby shifts.
24H Toggle: Global and daily controls to switch specific days between Shift mode (AM/PM) and 24-hour duty mode.
Dynamic Configuration:
Smart Import: Automatically detects and onboards new personnel when importing balance files from previous months.
Customizable Scoring: Fully editable point values and multipliers (Weekends/Public Holidays) via the Settings GUI.
Data Integrity: Supports "Brought Forward" balances to ensure long-term fairness across consecutive rostering periods.
Export: Generates formatted .xlsx reports containing the final roster and detailed point summaries.
🛠 Technical Specifications
Language: Python 3.10+
UI Framework: CustomTkinter (Material Design Light Theme)
Solver: Google OR-Tools (CP-SAT)
Data Handling: Pandas & OpenPyXL
📄 Licensing
This project is released under the Creative Commons Attribution-NonCommercial 4.0 International License (CC BY-NC 4.0).
Usage: Free for personal and non-commercial organizational use.
Commercial Use: Prohibited without express permission.
Full Changelog: https://github.com/genes3e7/Duty-Planner/commits/v1.0.0