We welcome contributions! This guide covers the development setup, coding standards, and contribution workflow.
- R >= 4.0.0
- RStudio (recommended)
- Git
git clone https://github.com/SumedhSankhe/PG-E-Data-Visualizer.git
cd PG-E-Data-Visualizerrenv::restore() # Install dependencies
shiny::runApp('.') # Launch the appLogs are written to logs/app-YYYY-MM-DD.log.
PG-E-Data-Visualizer/
├── ui.R # Main Shiny UI
├── server.R # Main Shiny server
├── global.R # Global variables, logging
├── config.R # Configuration constants
├── helpers.R # Utility functions
├── home.R # Home module
├── loadData.R # Data loading module
├── qc.R # Quality Control module
├── anomaly.R # Anomaly Detection module
├── pattern.R # Pattern Recognition module
├── cost.R # Cost Optimization module
├── data/ # Sample data
├── tests/ # Unit tests
├── scripts/ # Dev scripts (lint, test, coverage)
└── www/ # Custom CSS/JS
The application uses the Shiny Module pattern. Each module is self-contained:
- Home (
home.R) - Landing page - Load Data (
loadData.R) - File upload, validation, returns reactive dataset - Quality Control (
qc.R) - IQR outlier detection, quality metrics - Anomaly Detection (
anomaly.R) - Four algorithms with configurable sensitivity - Pattern Recognition (
pattern.R) - Daily/weekly patterns, k-means clustering - Cost Optimization (
cost.R) - Rate plan comparison, savings recommendations
User Upload → loadDataServer → Raw Reactive Data
↓
Global Date Filter
↓
Filtered Reactive Data
↙ ↓ ↓ ↘
qc anomaly pattern cost
Module Module Module Module
- Naming:
snake_casefor variables/functions,UPPER_SNAKE_CASEfor constants - Indentation: 2 spaces (no tabs)
- Line Length: ≤ 120 characters
- Spacing: Spaces around operators (
<-,=,+)
# Good
qcServer <- function(id, dt) {
moduleServer(id, function(input, output, session) {
req(dt()) # Guard against NULL
validate(need( # User-friendly error
nrow(dt()) > 0,
"No data available for quality control"
))
logger::log_info("Quality control analysis started")
})
}
# Bad
qcServer<-function(id,dt){
moduleServer(id,function(input,output,session){plot(dt()$value)})
}source('scripts/style.R') # Apply tidyverse style
source('scripts/lint.R') # Check for issueslinters: linters_with_defaults(
line_length_linter(120),
object_length_linter(40),
cyclocomp_linter(15),
commented_code_linter = NULL
)
exclude: "renv"source('scripts/test.R') # Run all tests
source('scripts/coverage.R') # Check coverage
# Run specific test file
testthat::test_file('tests/testthat/test_modules.R')library(testthat)
library(shiny)
test_that("loadServer returns reactive data", {
testServer(loadServer, {
expect_true(is.reactive(data))
})
})
test_that("module handles empty data gracefully", {
testServer(analyseServer, {
session$setInputs(data = data.frame())
expect_true(is.null(output$plot))
})
})- Main:
master(protected) - Features:
feature/feature-name - Bugfixes:
bugfix/issue-description - Hotfixes:
hotfix/critical-fix
-
Fork and clone the repository
-
Create a feature branch
git checkout -b feature/your-feature-name
-
Implement changes
- Follow Shiny module pattern
- Use
req()andvalidate(need())for error handling - Add logging with
logger::log_info()
-
Run quality checks
source('scripts/style.R') source('scripts/lint.R') source('scripts/test.R')
-
Commit and push
git add . git commit -m "Add feature description" git push origin feature/your-feature-name
-
Open a pull request
- Code follows style guidelines
- Tests pass and coverage is maintained
- No security vulnerabilities
- Clear commit messages
See docs/CODE_REVIEW_CHECKLIST.md for the complete checklist.
# Missing dependencies
renv::restore()
# Port already in use
shiny::runApp('.', port = 8888)- Ensure required columns:
dttm_start,hour,value,day,day2 - Use date format:
YYYY-MM-DD HH:MM:SS
dir.create("logs", showWarnings = FALSE)- Filter to specific date ranges for large datasets
- Use
bindCache()for expensive computations
- Issues: GitHub Issues
- Discussions: GitHub Discussions