A modern, intelligent scheduling system for Colby College student workers
MuleScheduler is a full-stack web application designed to streamline the scheduling process for student workers at Colby College. It empowers students to set their availability preferences while giving administrators powerful tools to manage locations, time slots, and automatically generate optimized weekly schedules.
- π Smart Auto-Scheduling - Automatically assigns workers based on availability, preferences, and constraints
- π₯ Multi-Location Support - Manage shifts across multiple campus locations
- β° Flexible Time Slots - Define custom time slots for each day of the week
- π― Preference-Based Matching - Workers can mark preferred shifts, and the scheduler prioritizes accordingly
- π Admin Dashboard - Comprehensive tools for managing users, locations, and schedules
- π Real-Time Updates - View and modify schedules with instant feedback
- π¨ Modern UI - Beautiful, responsive interface built with React and Bootstrap 5
- Backend: Python Flask (REST API) π
- Frontend: React with TypeScript βοΈ
- UI Framework: Bootstrap 5 + React-Bootstrap π¨
- Calendar: FullCalendar React with Bootstrap 5 theme π
- Database: SQLite (easily switchable to PostgreSQL) ποΈ
- Testing: pytest (Backend) + Jest (Frontend) β
MuleScheduler/
βββ backend/ # Flask API
β βββ app.py # Main Flask application
β βββ models.py # SQLAlchemy models
β βββ routes/ # API route handlers
β βββ services/ # Business logic (scheduler)
β βββ tests/ # Backend tests (pytest)
β βββ requirements.txt # Python dependencies
β βββ seed_data.py # Database seeding script
βββ frontend/ # React application
β βββ src/
β β βββ components/ # Reusable components
β β βββ contexts/ # React contexts (Auth)
β β βββ pages/ # Page components
β β βββ __tests__/ # Frontend tests (Jest)
β β βββ services/ # API client
β βββ package.json
β βββ vite.config.ts
βββ README.md
-
Navigate to backend directory:
cd backend -
Create and activate virtual environment:
python -m venv venv # Windows venv\Scripts\activate # macOS/Linux source venv/bin/activate
-
Install dependencies:
pip install -r requirements.txt
-
Initialize the database:
python app.py
This creates the SQLite database and initializes all tables.
-
Seed sample data (recommended):
python seed_data.py
Creates:
- 1 admin user (
admin@colby.edu) - ~30 student worker users
- 5 sample locations
- Time slots for Monday-Friday, 9am-5pm (hourly)
- Default global settings
- 1 admin user (
-
Run the Flask server:
python app.py
API available at
http://localhost:5000π
-
Navigate to frontend directory:
cd frontend -
Install dependencies:
npm install
-
Start the development server:
npm run dev
App available at
http://localhost:5173π
MuleScheduler now uses Google OAuth 2.0. Emails must end with @colby.edu; non-Colby emails are rejected.
-
Create a Google OAuth client (Web application):
- Go to Google Cloud Console β APIs & Services β Credentials.
- Create OAuth client ID (type: Web application).
- Add authorized redirect URI:
http://localhost:5000/api/auth/google/callback(and your production URL). - Copy the Client ID and Client Secret.
-
Backend env vars (required):
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETGOOGLE_REDIRECT_URI(optional; defaults tohttp://localhost:5000/api/auth/google/callback)FRONTEND_ORIGIN(optional; defaults tohttp://localhost:5173)
-
Frontend env vars:
VITE_GOOGLE_CLIENT_ID(not currently required for the flow, but keep for future use)
- User clicks βSign In with Colbyβ on the login page.
- Browser is redirected to Google OAuth; user signs in with
@colby.edu. - Backend validates the ID token, enforces
@colby.edu, creates the user if needed, and issues an app token. - Backend redirects back to the frontend with
?token=...; the SPA stores it and uses it for API calls. - User roles (admin/user) remain in the database.
-
Set Availability:
- Navigate to "Availability" from the navbar
- Select a week starting date
- Mark yourself as available for each location and time slot
- Optionally mark shifts as "Preferred" vs "Neutral"
- Click "Save Availability"
-
View Schedule:
- Navigate to "My Schedule"
- View your assigned shifts in a beautiful weekly calendar view
- Use the date picker or navigation buttons to change weeks
-
Configure Settings:
- Navigate to "Settings"
- Locations: Add, edit, or delete locations
- Time Slots: Define time slots (day of week + start/end time)
- Global Settings: Set max workers per shift and max hours per user per week
-
Set Shift Requirements:
- Navigate to "Requirements"
- Select a week starting date
- For each location and time slot, specify how many workers are needed
- Click "Save Requirements"
-
Generate Schedule:
- Navigate to "Schedule"
- Select the week you want to schedule
- Click "Run Auto-Scheduler"
- The system automatically assigns workers based on:
- Their availability preferences
- Shift requirements
- Global constraints (max workers per shift, max hours per user)
- Priority: workers with fewer assigned hours get assigned first
-
Manual Adjustments:
- Click on any shift in the calendar
- View assigned worker
- Reassign to a different available worker
- Remove assignments
The backend uses pytest for comprehensive testing with a 95% branch coverage requirement.
Directory Structure:
backend/tests/
βββ unit/ # Unit tests for individual functions
β βββ test_models.py
β βββ test_scheduler.py
β βββ test_slot_generator.py
βββ functional/ # Integration tests for API endpoints
βββ test_auth.py
βββ test_assignments.py
βββ test_availability.py
βββ test_locations.py
βββ test_settings.py
βββ test_shift_requirements.py
βββ test_time_slots.py
βββ test_users.py
βββ test_weekly_overrides.py
Running Tests:
cd backend
pytest # Run all tests (coverage enforced, min 95% branch)
pytest -v # Verbose output
pytest tests/unit/ # Run only unit tests
pytest tests/functional/ # Run only functional tests
pytest --cov=. --cov-branch # With branch coverage report
pytest --cov=. --cov-report=html # Generate HTML report (open htmlcov/index.html)Coverage Requirement:
- Branch Coverage: β₯ 95% (enforced in CI)
- Tests will fail if branch coverage is below 95%. This is enforced both locally and in CI.
Viewing Coverage Reports:
- GitHub Actions: Check the "Backend Tests" job summary for a detailed coverage table showing branch and line coverage percentages
- Coverage Artifacts: Download
coverage.xmlfrom the Actions run artifacts for detailed analysis - Local HTML Report: Run
pytest --cov=. --cov-branch --cov-report=htmland openhtmlcov/index.htmlin your browser
Key Test Files:
test_scheduler.py- Unit tests for scheduler service functions (calculate_hours, get_user_total_hours, has_overlapping_assignment, run_auto_scheduler, etc.)test_assignments.py- Functional tests for assignment API endpoints (run-scheduler, create assignment, validation)
The frontend uses Jest with React Testing Library for component testing.
Directory Structure:
frontend/src/__tests__/
βββ App.test.tsx
βββ LoginPage.test.tsx
βββ SignupPage.test.tsx
βββ Navbar.test.tsx
Running Tests:
cd frontend
npm test # Run tests in watch mode
npm run test:ci # Run tests once (CI mode)Testing Approach:
- Uses React Testing Library for user-centric testing
- Mocks API calls with
jest.mock() - Tests component rendering, user interactions, and error handling
- Aim for 60%+ coverage on components and pages
Key Test Files:
SignupPage.test.tsx- Tests for signup form rendering, validation, and submissionLoginPage.test.tsx- Tests for login functionalityNavbar.test.tsx- Tests for navigation component
GitHub Actions automatically runs tests on:
- Every push to
mainordevelop - Every pull request to
mainordevelop
CI Jobs:
-
Backend Tests
- Installs Python dependencies
- Runs flake8 linting
- Runs pytest with branch coverage (95% minimum)
- Extracts and displays coverage percentages in job summary
- Uploads coverage.xml as artifact for detailed analysis
-
Frontend Tests
- Installs Node.js dependencies
- Runs ESLint
- Runs Jest tests
Branch Protection: All tests must pass before merging to main β
POST /api/auth/login- Login (stub)GET /api/auth/me- Get current user
GET /api/users/me- Get current user infoGET /api/users- List all users (admin only)
GET /api/locations- List all active locationsPOST /api/locations- Create location (admin)PUT /api/locations/:id- Update location (admin)DELETE /api/locations/:id- Delete location (admin)
GET /api/time-slots- List all time slotsPOST /api/time-slots- Create time slot (admin)PUT /api/time-slots/:id- Update time slot (admin)DELETE /api/time-slots/:id- Delete time slot (admin)
GET /api/settings- Get global settings (admin)PUT /api/settings- Update global settings (admin)
GET /api/shift-requirements?week_start=YYYY-MM-DD- Get requirements for a weekPOST /api/shift-requirements- Create/update requirement (admin)PUT /api/shift-requirements/:id- Update requirement (admin)DELETE /api/shift-requirements/:id- Delete requirement (admin)
GET /api/availability?week_start=YYYY-MM-DD- Get current user's availabilityPOST /api/availability- Create/update availability entryPOST /api/availability/batch- Create/update multiple availability entries
GET /api/assignments?week_start=YYYY-MM-DD- Get assignments (user sees only their own, admin sees all)POST /api/assignments/run-scheduler- Run auto-scheduler for a week (admin)POST /api/assignments- Create assignment (admin)PUT /api/assignments/:id- Update assignment (admin)DELETE /api/assignments/:id- Delete assignment (admin)GET /api/assignments/available-workers- Get available workers for a shift (admin)
The intelligent auto-scheduler assigns workers to shifts based on:
- Availability - Only assigns workers who marked themselves as available β
- No Overlaps - Skips workers already assigned to overlapping time slots β°
- Max Hours Constraint - Respects
max_hours_per_user_per_weekif set π - Priority System:
- Workers with fewer assigned hours in the week are prioritized first π―
- Workers who marked a shift as "preferred" get slight priority over "neutral" β
- Capacity Management - Assigns up to
min(required_workers, max_workers_per_shift)per shift π₯
- The backend uses SQLite by default. To switch to PostgreSQL, update the
DATABASE_URLinapp.pyor set it as an environment variable. - The frontend uses Vite for fast development. The proxy is configured to forward
/apirequests to the Flask backend. - Authentication tokens are stored in localStorage. In production, use secure HTTP-only cookies.
- The calendar view uses FullCalendar with Bootstrap 5 theme for consistent styling.
- π Replace stub authentication with Google OAuth
- π§ Add email notifications for schedule assignments
- π Add shift swap/request functionality
- π Add reporting and analytics
- π± Add mobile app support
- π Add shift templates for recurring requirements
See LICENSE file for details.