{"id":20866500,"url":"https://github.com/ericboehs/sprintosaurus-sinatra","last_synced_at":"2026-03-19T17:55:34.074Z","repository":{"id":253139403,"uuid":"823832173","full_name":"ericboehs/sprintosaurus-sinatra","owner":"ericboehs","description":null,"archived":false,"fork":false,"pushed_at":"2025-01-16T19:03:06.000Z","size":667,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-16T20:22:30.744Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ericboehs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-03T20:14:56.000Z","updated_at":"2025-01-16T19:03:07.000Z","dependencies_parsed_at":"2024-08-19T23:43:07.133Z","dependency_job_id":"7ce6eb3c-979c-4dd5-beda-45be3028cadd","html_url":"https://github.com/ericboehs/sprintosaurus-sinatra","commit_stats":null,"previous_names":["ericboehs/gh-projects-sprint-report","ericboehs/sprintosaurus-sinatra"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fsprintosaurus-sinatra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fsprintosaurus-sinatra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fsprintosaurus-sinatra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericboehs%2Fsprintosaurus-sinatra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericboehs","download_url":"https://codeload.github.com/ericboehs/sprintosaurus-sinatra/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243240493,"owners_count":20259432,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T05:58:20.585Z","updated_at":"2025-12-25T22:21:19.057Z","avatar_url":"https://github.com/ericboehs.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sprintosaurus\n\n\u003cimg src=\"public/sunset.png\" alt=\"Sunset\" width=\"80\" align=\"right\"\u003e\n\n\u003e [!IMPORTANT]  \n\u003e Sprintosaurus is sunsetting on Sept 30th, 2025. This README will help you self-host it if you still need it.\n\nSprintosaurus is a Ruby/Sinatra web application that generates comprehensive sprint reports for GitHub Projects. It integrates with the GitHub API to fetch project data, track issues across sprints with point estimates, and provides reporting capabilities including CSV exports and visual charts.\n\n## Features\n\n- **Sprint Tracking**: Monitor GitHub Project iterations with start dates and durations\n- **Issue Management**: Track issues, points, status changes across sprints\n- **Soft Deletion**: Issues can be moved between sprints with full audit trail\n- **Visual Reports**: Charts showing sprint progress and completion\n- **CSV Export**: Download sprint data for external analysis\n- **Real-time Sync**: Background job continuously syncs with GitHub\n- **Responsive Design**: Works on desktop and mobile devices\n\n## Architecture\n\n### Core Components\n\n- **Web Application** (`app.rb`): Sinatra-based web server with ActionView helpers\n- **Background Job** (`job.rb`): Continuous GitHub API synchronization\n- **Models**: ActiveRecord models for Projects, Sprints, Issues, and relationships\n- **GitHub Integration** (`lib/github/project.rb`): GraphQL API client with rate limiting\n\n### Database Schema\n\n- `projects`: GitHub project containers (number, title, URL)\n- `sprints`: Time-boxed iterations (start_date, duration, iteration_id)\n- `issues`: GitHub issues (points, status, sprint associations)\n- `issues_sprints`: Join table with soft deletion using `removed_at` pattern\n\n## Deployment on Fly.io\n\n### Prerequisites\n\n1. **Fly.io CLI**: Install from https://fly.io/docs/hands-on/install-flyctl/\n2. **GitHub Personal Access Token**: Classic token with these scopes:\n   - `repo` (Full control of private repositories)\n   - `read:org` (Read org and team membership)\n   - `read:project` (Read access to projects)\n\n### Step 1: Clone and Setup\n\n```bash\ngit clone https://github.com/ericboehs/sprintosaurus-sinatra.git\ncd sprintosaurus-sinatra\n```\n\n### Step 2: Configure Fly Application\n\n```bash\n# Login to Fly.io\nfly auth login\n\n# Create a new Fly application\nfly apps create your-sprintosaurus-app\n\n# Update fly.toml with your app name\n```\n\nEdit `fly.toml`:\n```toml\napp = \"your-sprintosaurus-app\"  # Change this to your app name\n\n[build]\n  dockerfile = \"./Dockerfile\"\n\n[experimental]\n  allowed_public_ports = [9292]\n  auto_rollback = true\n\n[processes]\n  web = \"bundle exec rackup config.ru -o 0.0.0.0\"\n  job = \"ruby job.rb\"\n\n[[services]]\n  processes = [\"web\"]\n  internal_port = 9292\n  protocol = \"tcp\"\n\n  [[services.ports]]\n    port = 80\n\n  [[services.ports]]\n    handlers = [\"tls\", \"http\"]\n    port = 443\n\n  [[services.tcp_checks]]\n    interval = 10000\n    timeout = 2000\n    grace_period = \"5s\"\n    restart_limit = 0\n```\n\n### Step 3: Set Up PostgreSQL Database\n\n```bash\n# Create a PostgreSQL database\nfly postgres create --name your-sprintosaurus-db --region ord\n\n# Attach database to your app\nfly postgres attach --app your-sprintosaurus-app your-sprintosaurus-db\n```\n\n### Step 4: Configure Environment Variables\n\n```bash\n# Set GitHub token (REQUIRED)\nfly secrets set GH_TOKEN=your_github_personal_access_token\n\n# Set initial project URLs to sync (OPTIONAL)\n# Format: comma-separated GitHub project URLs\nfly secrets set SEED_GH_PROJECT_URLS=\"https://github.com/orgs/your-org/projects/123,https://github.com/orgs/your-org/projects/456\"\n\n# Production environment\nfly secrets set RACK_ENV=production\n\n# Redirect all routes to sunset page (OPTIONAL - for service retirement)\nfly secrets set SUNSET=true\n\n# Show sunset banner (OPTIONAL - defaults to false for self-hosting)\nfly secrets set SHOW_SUNSET_BANNER=true\n```\n\n### Step 5: Deploy\n\n```bash\n# Deploy the application\nfly deploy\n\n# Check deployment status\nfly status\n\n# View logs\nfly logs\n```\n\n### Step 6: Run Database Migrations\n\n```bash\n# SSH into your app instance\nfly ssh console\n\n# Run migrations\ndbmate up\n\n# Exit SSH session\nexit\n```\n\n## Local Development\n\n### Prerequisites\n\n- Ruby 3.3+\n- PostgreSQL\n- dbmate (database migration tool)\n- Tailwind CSS standalone binary\n\n### Setup\n\n```bash\n# Install dependencies\nbundle install\n\n# Install dbmate (if not already installed)\n# Download from: https://github.com/amacneil/dbmate/releases\n# Or install via your package manager, e.g.: brew install dbmate\n\n# Set up environment variables\ncp .env.local.example .env.local\n# Edit .env.local with your values\n\n# Create database\ncreatedb sprintosaurus_development\ncreatedb sprintosaurus_test\n\n# Run migrations\ndbmate up\n\n# Install Tailwind CSS standalone binary (if not already installed)\n# Download from: https://github.com/tailwindlabs/tailwindcss/releases\n# Or install via your package manager, e.g.: brew install tailwindcss\n\n# Build Tailwind CSS\ntailwindcss -i input.css -o public/tailwind.css --config tailwind.config.js\n\n# Start development server\nbundle exec rerun 'rackup config.ru -o 0.0.0.0'\n\n# In another terminal, start background job\nruby job.rb\n```\n\n### Environment Variables\n\nCreate `.env.local` with:\n\n```bash\n# Database connections\nDATABASE_URL=\"postgres://localhost/sprintosaurus_development?sslmode=disable\"\nTEST_DATABASE_URL=\"postgres://localhost/sprintosaurus_test?sslmode=disable\"\n\n# GitHub integration (REQUIRED)\nGH_TOKEN=\"your_github_personal_access_token\"\n\n# Initial projects to sync (OPTIONAL)\nSEED_GH_PROJECT_URLS=\"https://github.com/orgs/your-org/projects/123\"\n\n# Development settings (OPTIONAL)\nRACK_ENV=\"development\"\nENABLE_CSP=\"false\"\nDEBUG=\"false\"\n\n# Redirect all routes to sunset page (OPTIONAL - for service retirement)\nSUNSET=\"false\"\n\n# Sunset banner (OPTIONAL - set to \"true\" to show the banner)\nSHOW_SUNSET_BANNER=\"false\"\n```\n\n### Running Tests\n\n```bash\n# Run all tests\nruby test/job_test.rb\n\n# Run with minitest\nbundle exec ruby -Itest test/job_test.rb\n```\n\n## GitHub Setup\n\n### Creating a Personal Access Token\n\n1. Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)\n2. Click \"Generate new token (classic)\"\n3. Select these scopes:\n   - `repo` - Full control of private repositories\n   - `read:org` - Read org and team membership\n   - `read:project` - Read access to projects\n4. Copy the token and use it as `GH_TOKEN`\n\n### Project Requirements\n\nYour GitHub Projects must have:\n\n- **Sprint/Iteration field**: Used to track sprint iterations\n- **Points/Estimate field**: Used for story point tracking (optional)\n- **Status field**: Used for issue status tracking (optional)\n\nThe application automatically detects these field names and adapts to your project structure.\n\n## Adding Projects\n\n### Via Environment Variable\n\nSet `SEED_GH_PROJECT_URLS` with comma-separated project URLs:\n\n```bash\nfly secrets set SEED_GH_PROJECT_URLS=\"https://github.com/orgs/my-org/projects/123\"\n```\n\n### Via Web Interface\n\n1. Navigate to your deployed application\n2. Click \"Add Project\"\n3. Enter the GitHub project URL\n4. The background job will automatically sync the project\n\n## Monitoring and Maintenance\n\n### Logs\n\n```bash\n# View application logs\nfly logs\n\n# Follow logs in real-time\nfly logs -f\n\n# Filter by process\nfly logs --app your-app-name job\n```\n\n### Updates\n\n```bash\n# Deploy new version\ngit pull origin main\nfly deploy\n\n# Check deployment\nfly status\n```\n\n## Security Considerations\n\n### Content Security Policy\n\nWhen `ENABLE_CSP=true`, the application enforces strict CSP headers:\n\n- Only self-hosted resources allowed\n- Nonces required for inline scripts/styles\n- HTTPS upgrade enforced in production\n\nThis is the default for production but is useful for testing locally.\n\n### Environment Variables\n\n- Never commit `.env.local` or actual tokens to version control\n- Use Fly secrets for sensitive data\n- Rotate GitHub tokens periodically\n\n### Database Security\n\n- Database is encrypted at rest on Fly.io\n- Use SSL connections in production\n- Regular backups are handled by Fly Postgres\n\n## Troubleshooting\n\n### Common Issues\n\n**Database Connection Errors**\n```bash\n# Check database status\nfly postgres list\n\n# View database logs\nfly logs --app your-db-name\n```\n\n**GitHub API Rate Limits**\n- The application automatically handles rate limits\n- Monitor logs for rate limit messages\n- Consider using multiple tokens for high-volume usage\n\n**Build Failures**\n```bash\n# Check build logs\nfly logs --app your-app-name\n\n# Rebuild from scratch\nfly deploy --no-cache\n```\n\n**Background Job Not Running**\n```bash\n# Check process status\nfly status\n\n# View job logs specifically\nfly logs job\n```\n\n### Performance Optimization\n\n- Background job runs every 10 minutes by default\n- Adjust sync frequency in `job.rb` if needed\n- Use database indexing for large datasets\n- Monitor memory usage and scale accordingly\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Support\n\nThis project is being sunset and will not receive active support after September 30th, 2025. This README provides comprehensive self-hosting instructions. For issues specific to self-hosting, please open a GitHub issue.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericboehs%2Fsprintosaurus-sinatra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericboehs%2Fsprintosaurus-sinatra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericboehs%2Fsprintosaurus-sinatra/lists"}