Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions .github/workflows/worker.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
name: Bi-Weekly Work Generator
name: Work Assignment Generator

# Default to manual/API triggering for efficiency.
# See README.md for scheduling options (external scheduler, cron, etc.)
on:
schedule:
- cron: '0 9 * * *' # Run every day to check eligibility
workflow_dispatch: # Allow manual trigger
workflow_dispatch: # Manual trigger
# Uncomment for daily automated checks (less efficient):
# schedule:
# - cron: '0 9 * * *' # Daily at 9 AM UTC

jobs:
run-generator:
Expand All @@ -28,9 +31,10 @@ jobs:
- name: Build and Run
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
APP__ASSIGNMENT_INTERVAL_DAYS: ${{ secrets.ASSIGNMENT_INTERVAL_DAYS || '14' }}
run: |
# The Rust app itself will handle the "check date" logic.
# It will also set SHOULD_NOTIFY=true/false in GITHUB_ENV.
# The app checks if scheduled interval has passed.
# It sets SHOULD_NOTIFY=true/false in GITHUB_ENV.
cargo run --release > output.txt
cat output.txt

Expand Down
90 changes: 90 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
anyhow = "1.0"
thiserror = "1.0"
toml = "0.8"

[dev-dependencies]
serial_test = "3.2.0"
56 changes: 48 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A Rust-based application that automatically distributes household chores among r

## Features

- **Automated Scheduling**: Runs daily via GitHub Actions but only generates assignments every 14 days
- **Configurable Scheduling**: Assignment interval fully configurable (1-365 days, defaults to 14)
- **Fair Rotation**: Tracks assignment history to ensure people don't get the same tasks repeatedly
- **Group-Based Constraints**: Enforces rules based on group membership (Group A vs Group B)
- **Discord Integration**: Automatically posts new assignments to Discord when generated
Expand Down Expand Up @@ -46,7 +46,30 @@ DATABASE_URL=postgresql://user:password@host/dbname?sslmode=require
RUST_LOG=info
```

### 3. Run Migrations
### 3. Configure Assignment Interval (Optional)

The default interval is 14 days. To customize:

**Option 1: Edit configuration file**

Edit `config/default.toml`:
```toml
# Assignment interval in days (1-365)
assignment_interval_days = 7 # Weekly
# assignment_interval_days = 14 # Bi-weekly (default)
# assignment_interval_days = 30 # Monthly
```

**Option 2: Use environment variable**

Add to `.env`:
```bash
APP__ASSIGNMENT_INTERVAL_DAYS=7 # Weekly assignments
```

> **Note**: Environment variables override file configuration. Valid range: 1-365 days.

### 4. Run Migrations

```bash
diesel migration run
Expand All @@ -56,7 +79,7 @@ This will:
- Create the `people` and `assignments` tables
- Seed initial data from legacy files (if present)

### 4. Run the Application
### 5. Run the Application

```bash
cargo run
Expand Down Expand Up @@ -92,17 +115,34 @@ Configure these in your GitHub repository settings:

- `DATABASE_URL`: Your Neon PostgreSQL connection string
- `DISCORD_WEBHOOK`: Discord webhook URL for notifications
- `ASSIGNMENT_INTERVAL_DAYS` (optional): Override assignment interval (defaults to 14)

### Workflow
### Workflow Scheduling Options

The workflow runs daily but only sends notifications when new assignments are generated:
By default, the workflow uses **manual triggering** (`workflow_dispatch`) for efficiency:

```yaml
schedule:
- cron: '0 9 * * *' # Daily at 9 AM UTC
on:
workflow_dispatch: # Trigger manually or via API
```

The Rust application enforces the 14-day interval internally.
**Scheduling Strategies:**

1. **Manual Trigger** (Default)
- Run from GitHub Actions UI when needed
- Most efficient - no unnecessary workflow runs

2. **External Scheduler** (Recommended for automation)
- Use GitHub API with cron service (cron-job.org, etc.)
- Trigger only when needed based on interval
- Example: Weekly API call triggers workflow

3. **Daily Cron** (Less efficient but simpler)
- Uncomment cron schedule in `.github/workflows/worker.yml`
- Runs daily but only generates assignments when interval passes
- Can waste Actions minutes on unnecessary checks

The Rust application enforces the configured interval regardless of trigger method.

## Customization

Expand Down
7 changes: 7 additions & 0 deletions config/default.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# VividShift Default Configuration

# Assignment interval: How many days between shuffling work assignments
# Valid range: 1-365 days
# Common values: 7 (weekly), 14 (bi-weekly), 30 (monthly)
assignment_interval_days = 14

[work_assignments]
"Parlor" = 5
"Frontyard" = 3
Expand Down
2 changes: 2 additions & 0 deletions docs/PEOPLE_DATA.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Structured TOML configuration for managing resident data, replacing legacy `file
- **Module**: `src/people_config.rs`
- **Tests**: `tests/people_config_test.rs`

> **Related**: See [README.md](../README.md#3-configure-assignment-interval-optional) for scheduling interval configuration.

### Extending Metadata

To add new fields (e.g., email, preferences):
Expand Down
31 changes: 31 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pub struct Settings {
pub database_url: String,
pub work_assignments: HashMap<String, usize>,
pub github_env_path: Option<String>,
/// Configurable interval in days between assignment shuffles
/// Defaults to 14 if not specified
pub assignment_interval_days: Option<i64>,
}

impl Settings {
Expand All @@ -27,4 +30,32 @@ impl Settings {

s.try_deserialize()
}

/// Returns the configured assignment interval in days with validation
/// - Defaults to 14 days if not specified
/// - Validates range: 1-365 days
/// - Invalid values are clamped to valid range
pub fn assignment_interval_days(&self) -> i64 {
match self.assignment_interval_days {
Some(interval) => {
// Validate and clamp to reasonable range
if interval < 1 {
tracing::warn!(
"Invalid assignment_interval_days: {}. Defaulting to 14.",
interval
);
14
} else if interval > 365 {
tracing::warn!(
"Assignment interval {} exceeds maximum (365 days). Using 365.",
interval
);
365
} else {
interval
}
}
None => 14, // Default to 14 days
}
}
}
9 changes: 5 additions & 4 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ pub fn fetch_history(
Ok(history_map)
}

/// Checks if it has been 14 days since the last assignment run.
pub fn should_run(conn: &mut PgConnection) -> QueryResult<bool> {
/// Checks if enough time has passed since the last assignment run.
/// Uses the configured interval_days instead of a hardcoded value.
pub fn should_run(conn: &mut PgConnection, interval_days: i64) -> QueryResult<bool> {
use diesel::dsl::max;

let last_run: Option<NaiveDateTime> = assignments_dsl::assignments
Expand All @@ -128,8 +129,8 @@ pub fn should_run(conn: &mut PgConnection) -> QueryResult<bool> {
let days_diff = (now - date).num_days();
info!("Days Now: {} ", now);
info!("Days Date: {} ", date);
info!("Days Left: {} ", days_diff);
Ok(days_diff >= 14)
info!("Days since last run: {} (interval: {})", days_diff, interval_days);
Ok(days_diff >= interval_days)
}
None => Ok(true), // No history, so we should run
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
//!
//! This library provides modules for managing work group assignments.

pub mod config;
pub mod db;
pub mod models;
pub mod people_config;
pub mod schema;
11 changes: 7 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,14 @@ fn main() -> anyhow::Result<()> {
let pool = db::establish_connection(&settings.database_url);
let mut conn = pool.get().context("Failed to get DB connection")?;

// 4. Check Schedule (14 day rule)
match db::should_run(&mut conn) {
Ok(true) => info!("✅ It has been 14+ days (or first run). Proceeding."),
// 4. Check Schedule (configurable interval)
let interval = settings.assignment_interval_days();
info!("⏱️ Assignment interval configured: {} days", interval);

match db::should_run(&mut conn, interval) {
Ok(true) => info!("✅ It has been {}+ days (or first run). Proceeding.", interval),
Ok(false) => {
info!("⏳ It has NOT been 14 days since the last run. Skipping.");
info!("⏳ It has NOT been {} days since the last run. Skipping.", interval);
set_github_output(false, settings.github_env_path.as_deref());
return Ok(());
}
Expand Down
Loading