Files
2026-09-18 12:51:16 -04:00

14 KiB
Raw Permalink Blame History

manager_employees_rust — Backend (Rust)

Assignment 4: Implementing Control Structures — Rust Backend API University of the Cumberlands — Master’s Program, Semester 4 / Week 4

Rust Axum Postgres License: MIT

Author: Carlos Gutierrez — cgutierrez44833@ucumberlands.edu

Repository: https://git.cargdev.io/CarGDev/manager_employees_rust — this repo is the Rust backend

Related Repositories (Assignment 4 — 3 implementations):

Implementation Language / Role Repository
This repo Rust — Backend API (Axum/Postgres) manager_employees_rust
Companion Python — Backend/CLI manager_employees_python
Companion GUI — Graphical Interface manager_employees_gui

📌 This Repository — Rust Backend Only

This repo contains ONLY the Rust backend for Assignment 4. The assignment requires implementing the same scheduling problem in two contrasting languages (e.g., Rust + Python) to demonstrate control flow across paradigms — with an optional GUI.

  • Scope of this repo: REST API built with Axum (src/router.rs:159), Tokio async runtime, SQLx + Postgres persistence (src/database/connection.rs:5), and a preference-aware weekly scheduling engine (src/router.rs:561, src/manager/).
  • Companion repos are not tracked here — see table above: Python implementation and GUI implementation live at git.cargdev.io/CarGDev.
  • API docs are served via utoipa + Swagger UI at /swagger-ui (src/router.rs:187).

📖 Story: Assignment 4 — Implementing Control Structures

1. Overview

You will implement, without logical errors, various control structures such as conditionals, loops, and branching, in multiple programming languages. This assignment will demonstrate your mastery of syntax and control flow in different paradigms. — Assignment 4 Prompt

For me, Carlos Gutierrez, this assignment was about proving that the same business rules can be expressed cleanly in two very different paradigms. I chose Rust for this backend because its match, if let, ownership model, and Result error handling force explicit, safe control flow — a sharp contrast to a dynamic language like Python or JavaScript. Every scheduling rule below is therefore not just business logic, but a deliberate exercise in conditionals, loops, and branching done idiomatically in Rust.

2. Application Prompt — Employee Schedule Manager

The company operates 7 days/week with 3 shifts/day (morning, afternoon, evening — src/database/types.rs:18). The app must:

  1. Input and Storage: Collect employee names and their preferred shift for each day, storing in appropriate structures. Here: users + employee_weekly_preferences + company_users tables (src/database/schema.rs:36, src/database/entities/), with requests like CreateEmployeeRequest and WeeklyPreferenceRequest (src/router.rs:32, src/router.rs:46).

  2. Scheduling Logic: Auto-assign shifts ensuring:

    • No employee works more than one shift per day (src/manager/validator.rs:5, src/router.rs:585)
    • Max 5 days per week per employee (src/manager/validator.rs:11, src/router.rs:586)
    • At least 2 employees per shift per day; if fewer are available, randomly/round-robin assign additional valid employees (src/main.rs:37, src/manager/scheduler.rs:25, src/router.rs:597)
  3. Shift Conflicts: Detect when a preferred shift is full and resolve by assigning to another available shift on the same or next day (src/manager/conflict.rs:4, src/manager/conflict.rs:10, src/manager/conflict.rs:16, src/router.rs:240).

  4. Output: Final weekly schedule in readable format indicating employee → day → shift. Here: GET /schedules/weekly and print_final_schedule() grouping by day/shift (src/manager/scheduler.rs:44, src/router.rs:542).

  5. Bonus — Priority Ranking: Employees rank shifts first > second > third (src/database/types.rs:18, src/database/schema.rs:70). The engine ranks candidates with preference_rank() (src/router.rs:240) and accommodates preferences while still meeting coverage.

3. Programming Language Choice

Suggested: Python, Java, C++, JavaScript, Go, Rust — must be contrasting paradigms.

This repo = Rust (systems, compiled, ownership + exhaustive match) at manager_employees_rust. My contrasting implementations are:

The Rust side emphasizes match over if-else chains, iterator loops (for day in all_days() src/router.rs:581), and Result-based branching for DB errors (src/app.rs:29) — a direct contrast to Python’s approach in the companion repo.


✨ Features

  • 7-day × 3-shift auto-generation via POST /schedules/weekly/generate (src/router.rs:561)
  • Preference-aware ranking (first=0, second=1, third=2, fallback=3) (src/router.rs:240)
  • Validation: one-shift/day, ≤5 days/week, ≥2/shift (src/manager/validator.rs)
  • Conflict resolution: same-day fallback → next-day (src/manager/conflict.rs)
  • Clock-in/out (POST /employees/{id}/clock-in src/router.rs:627, PUT /employees/{id}/clock-out src/router.rs:652)
  • Company & employee CRUD, weekly preferences (PUT /employees/{id}/weekly-preferences src/router.rs:465)
  • Health check GET /health (src/router.rs:262), CORS permissive (src/router.rs:188), OpenAPI docs

🛠 Tech Stack

Layer Choice Version / File
Language Rust edition = "2024" (Cargo.toml:4)
Web Axum 0.8.4 (Cargo.toml:7)
Async Tokio 1.53.1 full (Cargo.toml:13)
DB Postgres + SQLx 0.9.0 chrono/postgres/runtime-tokio (Cargo.toml:12)
Validation/Types Chrono, Serde chrono 0.4.42, serde 1.0.228 (Cargo.toml:8, Cargo.toml:10)
Docs utoipa + utoipa-swagger-ui 5 / 9 (Cargo.toml:15, Cargo.toml:16)
Middleware tower-http CORS 0.6.6 (Cargo.toml:14)
Env dotenvy 0.15.7 (Cargo.toml:9)

📁 Project Structure

src/
  main.rs                 # entry, env loading, pool init, serve (src/main.rs:10)
  app.rs                  # AppState { pool }, ApiError → 404/500 (src/app.rs:10)
  router.rs               # 16 routes, OpenAPI, scheduling core (src/router.rs:159)
  database/
    connection.rs         # connect() + init_database() (src/database/connection.rs:5)
    schema.rs             # 9 DDL queries: enums + 5 tables + alters (src/database/schema.rs:94)
    types.rs              # WorkTime, DayOfWeek enums (src/database/types.rs:18)
    entities/             # Company, User, CompanyUser, Schedule, WeeklyPreference
    queries/              # company, employee, preference, schedule, user
  manager/                # business-rule stubs extracted from main.rs assignment_rules()
    scheduler.rs          # generate_weekly_schedule, fill_missing, clock-in/out
    validator.rs          # same-day, 5-day, 2-employee validations
    conflict.rs           # detect + resolve same/next day
  models/
    company/              # CreateCompanyRequest + service

🗄 Database Schema

Enums: work_time('morning','afternoon','evening') (src/database/schema.rs:1), day_of_week('sunday'..'saturday') (src/database/schema.rs:10)

Table Key Columns
companies id SERIAL PK, name TEXT UNIQUE (src/database/schema.rs:27)
users id, name, last_name, preference work_time (src/database/schema.rs:36)
company_users user_id FK→users, company_id FK→companies, UNIQUE(user_id,company_id) (src/database/schema.rs:47)
schedules user_id FK, enter_time, day_of_week, out_time, shift work_time (src/database/schema.rs:58)
employee_weekly_preferences user_id, day_of_week, first/second/third work_time, UNIQUE(user_id,day_of_week) (src/database/schema.rs:70)

Init via CREATE_SCHEMA_QUERIES loop (src/database/connection.rs:13).


📐 Business Rules in Code

  • assignment_rules() summary (src/main.rs:29-39)
  • all_days() / all_shifts() helpers (src/router.rs:224, src/router.rs:236)
  • Candidate filtering + sort_by_key(preference_rank) (src/router.rs:589-595)
  • assigned_days: HashMap<(user_id, DayOfWeek), bool> + day_count_by_user: HashMap<user_id, i32> (src/router.rs:576)

🔌 API Reference

Base: http://127.0.0.1:5005 (configurable via APP_ADDRESS)

Method Path Tag Description
GET /health health {"status":"ok"} (src/router.rs:254)
POST /companies companies create (src/router.rs:276)
GET /companies companies list (src/router.rs:284)
GET /companies/{id} companies get (src/router.rs:310)
DELETE /companies/{id} companies delete (src/router.rs:319)
POST /employees employees create + assign to company (src/router.rs:350)
GET /employees employees list (src/router.rs:375)
POST /companies/{company_id}/employees/{employee_id} employees assign (src/router.rs:394)
DELETE /employees/{id} employees delete (src/router.rs:418)
PUT /employees/{id}/preference employees single pref (src/router.rs:441)
PUT /employees/{id}/weekly-preferences employees 7-day prefs (src/router.rs:465)
GET /companies/{company_name}/employees/names employees names by company (src/router.rs:499)
POST /schedules schedules create (src/router.rs:518)
GET /schedules/weekly schedules list all (src/router.rs:542)
POST /schedules/weekly/generate schedules auto-generate (src/router.rs:561)
POST /employees/{id}/clock-in schedules clock-in now (src/router.rs:627)
PUT /employees/{id}/clock-out schedules clock-out (src/router.rs:652)

Swagger: GET /swagger-ui + GET /api-docs/openapi.json (src/router.rs:187).


🚀 Getting Started

Prerequisites

  • Rust stable (with cargo)
  • Postgres ≥14 running locally
  • sqlx-cli optional (schema is auto-created on boot)

1. Clone & Configure

git clone https://git.cargdev.io/CarGDev/manager_employees_rust
cd manager_employees_rust
cp .env.example .env  # or create .env

See also companions: manager_employees_python and manager_employees_gui.

.env (src/main.rs:11 loads via dotenvy):

DATABASE_URL=postgres://carlos:password@localhost/rust_manager_employees
APP_ADDRESS=127.0.0.1:5005

.env is gitignored ( .gitignore:7). Example URL from .env:1.

2. Create Database

createdb rust_manager_employees
# or: psql -c "CREATE DATABASE rust_manager_employees;"

Tables/enums are created automatically on first run via init_database() (src/database/connection.rs:12).

3. Run

cargo run
# → listening on 127.0.0.1:5005
curl http://127.0.0.1:5005/health
# {"status":"ok"}

4. Try the Flow

# 1. Create company
curl -X POST http://127.0.0.1:5005/companies \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme"}'

# 2. Create employees (company_id from above)
curl -X POST http://127.0.0.1:5005/employees \
  -H "Content-Type: application/json" \
  -d '{"company_id":1,"name":"Ana","last_name":"Lopez","preference":"morning"}'

# 3. Set weekly preferences
curl -X PUT http://127.0.0.1:5005/employees/1/weekly-preferences \
  -H "Content-Type: application/json" \
  -d '{"preferences":[{"day_of_week":"monday","first":"morning","second":"afternoon","third":"evening"}]}'

# 4. Generate weekly schedule
curl -X POST http://127.0.0.1:5005/schedules/weekly/generate \
  -H "Content-Type: application/json" \
  -d '{"company_id":1}'

# 5. View schedule
curl http://127.0.0.1:5005/schedules/weekly
# Swagger UI: http://127.0.0.1:5005/swagger-ui

⚙️ Configuration

Var Required Default Description
DATABASE_URL yes — Postgres URL (src/main.rs:13)
APP_ADDRESS no 127.0.0.1:5005 Bind addr (src/main.rs:19)

👨‍💻 Development

cargo fmt
cargo clippy
cargo check
cargo test

Error handling: ApiError(sqlx::Error) → RowNotFound→404, else 500 with JSON {"error": "..."} (src/app.rs:29).


📄 License

MIT — Copyright (c) 2026 Carlos Gutierrez. See LICENSE.


📬 Contact

Carlos Gutierrez — University of the Cumberlands
Email: cgutierrez44833@ucumberlands.edu
Project: manager_employees_rust — Rust backend for Assignment 4: Implementing Control Structures
Repositories: