{"id":33631751,"url":"https://github.com/jsnmrs/aggro","last_synced_at":"2026-05-09T17:04:23.483Z","repository":{"id":37082815,"uuid":"258379647","full_name":"jsnmrs/aggro","owner":"jsnmrs","description":"Aggro is the codebase that powers BMXfeed.com.","archived":false,"fork":false,"pushed_at":"2026-02-10T23:50:14.000Z","size":2326,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-11T02:25:16.002Z","etag":null,"topics":["aggregator","bmx","rss"],"latest_commit_sha":null,"homepage":"https://bmxfeed.com","language":"PHP","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/jsnmrs.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-04-24T02:03:09.000Z","updated_at":"2026-02-10T23:50:01.000Z","dependencies_parsed_at":"2023-02-10T00:01:00.936Z","dependency_job_id":"c9c6f844-37d8-4a47-9448-db8b5ac7ab16","html_url":"https://github.com/jsnmrs/aggro","commit_stats":null,"previous_names":[],"tags_count":78,"template":false,"template_full_name":null,"purl":"pkg:github/jsnmrs/aggro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnmrs%2Faggro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnmrs%2Faggro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnmrs%2Faggro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnmrs%2Faggro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jsnmrs","download_url":"https://codeload.github.com/jsnmrs/aggro/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnmrs%2Faggro/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29600746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T00:59:38.239Z","status":"ssl_error","status_checked_at":"2026-02-19T00:59:36.936Z","response_time":162,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["aggregator","bmx","rss"],"created_at":"2025-12-02T05:01:50.946Z","updated_at":"2026-04-02T22:47:45.479Z","avatar_url":"https://github.com/jsnmrs.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Aggro\n\nAggro is the codebase that powers [BMXfeed](https://bmxfeed.com), a BMX news aggregator and video discovery platform. Running continuously since 2006, BMXfeed collects and curates BMX-related content from across the web.\n\n![BMXfeed Screenshot](https://user-images.githubusercontent.com/1215760/98826155-4a15c100-242d-11eb-81fa-cdbe68a3e872.jpg)\n\n## Features\n\n- News aggregation — automatically collects and displays BMX news from various sources\n- Video integration — aggregates BMX videos from YouTube and Vimeo\n- RSS feed directory — maintains a curated directory of BMX-related RSS feeds\n- Content curation — automatically archives old content and manages content quality\n- API support — integrates with YouTube and Vimeo APIs for video metadata\n- Feed generation — provides RSS/OPML feeds of aggregated content\n- Responsive design — mobile-first, responsive web interface\n- Error monitoring — integrated Sentry for real-time error tracking and performance monitoring\n- Enhanced security — parameterized database queries, secure configuration management, input validation, CSRF protection, security headers\n\n## Tech stack\n\n- Back-end — PHP 8.4+ with CodeIgniter 4 framework\n- Front-end — vanilla CSS with PostCSS processing and no JavaScript!\n- Database — MySQL/MariaDB (SQLite for testing)\n- Testing — PHPUnit 11.5 for unit testing with coverage reporting\n- Debugging — Xdebug available for local development (off by default)\n- Error monitoring — Sentry for application monitoring and error tracking\n- Code quality — PHP CS Fixer, PHP CodeSniffer, PHPMD, PHPStan for static analysis and code standards\n- Dependencies — SimplePie for feed parsing, Composer for PHP package management, npm for front-end build tooling\n\n## Architecture\n\nAggro follows a clean architecture pattern with separation of concerns:\n\n- Controllers — Handle HTTP requests and coordinate responses\n- Models — Core business logic and data structures\n- Repositories — Data access layer for database operations\n- Services — Domain-specific business logic (archiving, thumbnails)\n- Helpers — Utility functions for common operations\n- Libraries — Third-party integrations and custom components\n\nThis architecture improves code maintainability, testability, and follows SOLID principles. The clean separation of concerns enables unit testing with 464 tests achieving 46.22% line coverage across all architectural layers.\n\n## Local development setup\n\nAggro uses [DDEV](https://ddev.com) for local development. This ensures a consistent development environment across machines.\n\n### Prerequisites\n\n1. Install [DDEV](https://ddev.com/get-started/)\n2. Docker compatible host system\n\n### Installation\n\n1. Clone the repository and enter directory:\n   ```bash\n   git clone https://github.com/jsnmrs/aggro.git\n   cd aggro\n   ```\n\n2. Initialize the project:\n   ```bash\n   ddev init\n   ```\n\n3. View the site:\n   - Open https://aggro.ddev.site in your browser\n   - The init process creates a local database from aggro-db.sql\n\n### Debugging with Xdebug\n\nXdebug is available in the DDEV environment but disabled by default for better performance. Enable it when you need debugging or profiling:\n\n```bash\nddev xdebug on\n```\n\nWhen enabled, the configuration is:\n\n- Server name — `aggro.ddev.site`\n- Port — `9003`\n- IDE key — `VSCODE`\n- Coverage — Enabled for test coverage reports\n\nConfigure VS Code to listen for Xdebug connections on port 9003. The debugger will automatically connect when triggered.\n\nWhen you're done debugging, disable Xdebug to restore performance:\n\n```bash\nddev xdebug off\n```\n\n### Development commands\n\nAggro includes several custom DDEV commands to help with development:\n\n- `ddev check` — Check local URL responses for errors\n- `ddev clicheck` — Run application maintenance tasks\n- `ddev cron` — Manage crontab (sync or clear)\n- `ddev fire` — Run a controller method from the CLI\n- `ddev frontend` — Run front-end build process\n- `ddev shellcheck` — Run ShellCheck on custom commands\n- `ddev tunnel` — Run a controller method on the remote server\n- `ddev upgrade` — Update Composer packages\n\n### CLI maintenance commands\n\nMaintenance tasks can be run via CLI using `ddev fire` for local or `ddev tunnel` for remote:\n\n- `aggro log` — View application log\n- `aggro log-error` — View error log\n- `aggro log-clean` — Clean old log entries\n- `aggro log-error-clean` — Clean old error log entries\n- `aggro news` — Fetch news feeds\n- `aggro news-cache` — Clear news feed cache\n- `aggro news-clean` — Archive old news items\n- `aggro sweep` — Run all maintenance tasks\n- `aggro vimeo/VIDEO_ID` — Fetch a Vimeo video\n- `aggro youtube/VIDEO_ID` — Fetch a YouTube video\n\n## Configuration\n\n### Environment variables\n\nCopy `.env-sample` to `.env` for your local environment. Key configurations:\n\n- `CI_ENVIRONMENT` — set to \"development\" for local work\n- `app.baseURL` — your local URL (default: https://aggro.ddev.site)\n- Database credentials — configured through DDEV\n- API keys — for video services\n\n### Sentry configuration\n\n- `SENTRY_DSN` — your Sentry Data Source Name for error tracking\n- `SENTRY_ENVIRONMENT` — environment name (development/production)\n- `SENTRY_RELEASE` — application release version\n- `SENTRY_SAMPLE_RATE` — error sampling rate (0.0 to 1.0)\n- `SENTRY_TRACES_SAMPLE_RATE` — performance monitoring sample rate\n- `SENTRY_SEND_DEFAULT_PII` — whether to send personally identifiable information\n\n### Storage configuration\n\nThe `app/Config/Storage.php` file centralizes all file paths and storage-related settings:\n\n- Thumbnail storage — path, dimensions, and quality settings\n- Archive periods — content archival and cleanup timeframes\n- Cache durations — default cache times for various operations\n- Network timeouts — connection and request timeout settings\n\n### 1Password CLI (optional)\n\nIf you use [1Password CLI](https://developer.1password.com/docs/cli/), you can manage deployment secrets through 1Password instead of an on-disk `.env-production` file.\n\n1. Create items in your 1Password vault matching the `op://` references in `.env-1p` (production) and `.env-1p-dev` (development)\n2. Add an `SSH_PRIVATE_KEY` field to each item containing the full SSH private key (including `-----BEGIN/END-----` markers, with no leading spaces)\n3. Customize the `op://Vault/Item/Field` paths to match your vault structure\n4. Deploy with `ddev deploy prod` or `ddev deploy dev` — it automatically loads the SSH key, injects secrets from 1Password, deploys, and cleans up\n\nThis is entirely optional — local development still uses the standard `.env-sample` to `.env` workflow, and CI/CD uses its own secret store (`secrets.DOT_ENV` and `secrets.SSH_PRIVATE_KEY`).\n\n### Cron jobs\n\nThe `.crontab` file defines scheduled tasks for:\n\n- News feed updates — every 6 minutes\n- YouTube video checks — every 5 minutes\n- Vimeo video checks — every 7 minutes\n- Archive management — daily\n- Feed cache clearing — monthly\n\n## Testing\n\nThe project includes 464 tests achieving 46.22% line coverage using PHPUnit for unit testing and multiple code quality tools.\n\n### Test Suite Overview\n\n- Total Tests — 464 unit tests\n- Coverage — 46.22% line coverage across all components\n- Assertions — 741 test assertions ensuring thorough validation\n- External Dependencies — 86 tests appropriately skipped for external services (YouTube/Vimeo APIs, Sentry, file system)\n- Test Files — 28 test files covering all major components\n\n### Unit Testing with PHPUnit\n\nThe test suite covers:\n\n- Controllers — HTTP request handling, response coordination, and validation (Feed: 100%, Home: 100%, BaseController: 100%)\n- Models — Core business logic and data structures (AggroModels: 100%, NewsModels: 37.59%, UtilityModels: 55.88%)\n- Helpers — Utility functions and common operations with parameter validation\n- Services — Domain-specific business logic (ArchiveService: 96.30%, ThumbnailService: 68.63%, ValidationService: 100%)\n- Repositories — Data access layer operations (ChannelRepository: 100%, VideoRepository: 82.47%)\n- Libraries — Third-party integrations (SentryService: 12.84%, SentryLogHandler: 19.44%)\n- Filters — Request/response filtering (SecurityFilter: 100%, CustomCSRF: 100%, SentryPerformance: 12.90%)\n- Security — SQL injection prevention, input validation, CSRF protection\n\nTests use an in-memory SQLite database for fast, isolated testing without affecting your development database. External services are properly mocked or skipped to ensure reliable test execution.\n\n### Running Tests\n\n```bash\n# Run all tests (includes PHPUnit + linting)\nddev test\n\n# Run only PHPUnit unit tests\ncomposer test:unit\n\n# Run tests with coverage report (requires Xdebug: ddev xdebug on)\nXDEBUG_MODE=coverage composer test:coverage\n\n# Run all Composer test scripts\ncomposer test\n```\n\n### Test Coverage Reports\n\nWhen running tests with coverage, detailed HTML reports are generated in:\n\n- Coverage reports — `build/logs/html/index.html`\n- Raw coverage data — `build/logs/coverage.xml`\n- Current baseline — 46.22% line coverage, 42.52% method coverage\n\nOpen the HTML report in your browser to view detailed coverage metrics by file and function.\n\nNote — Coverage reporting requires Xdebug to be enabled (`ddev xdebug on`). Use `XDEBUG_MODE=coverage` when running coverage commands.\n\n### Code Quality Checks\n\n```bash\n# Run specific checks\nddev composer lint # PHP linting, static analysis\nddev composer test # PHP unit tests\nddev shellcheck # Shell script linting\n\n# Individual quality tools\nddev exec vendor/bin/php-cs-fixer fix  # Auto-fix PHP code style issues\nddev exec vendor/bin/phpstan analyse   # Run PHPStan static analysis\n```\n\n### Testing Best Practices\n\nThe test suite follows TDD principles and best practices:\n\n- Proper Isolation — External dependencies (APIs, file system, network) are mocked or skipped\n- Fast Execution — In-memory SQLite database for rapid test runs\n- Coverage — Tests cover success paths, error conditions, and edge cases\n- Clean Architecture — Testable design with dependency injection\n- External Service Handling — 86 tests appropriately skipped for YouTube/Vimeo APIs, Sentry, and file operations\n\n### Continuous Integration\n\nGitHub Actions automatically runs the full test suite (464 tests) on all pull requests, including:\n\n- PHPUnit unit tests with coverage validation\n- Code style checks (PHP CS Fixer, CodeSniffer)\n- Static analysis (PHPStan, PHPMD)\n- Shell script linting\n\nAll tests must pass before code can be merged, ensuring code quality and preventing regressions.\n\n### Security Features\n\nThe application includes the following security measures:\n\n- CSRF Protection — Custom CSRF filter for all state-changing operations\n- Input Validation — ValidationService provides sanitization for slugs, video IDs, gate keys, and integers\n- SQL Injection Prevention — All database queries use parameterized statements\n- Security Headers — Automatic security headers via SecurityFilter\n- Null Byte Protection — Automatic null byte removal from all input\n- Timing-Safe Comparisons — Used for sensitive string comparisons like gate keys\n\n## Deployment\n\nDeployment is handled through GitHub Actions and Deployer with automated testing:\n\n1. Pull Request Testing — All PRs automatically run the complete test suite (464 tests) including PHPUnit tests, code quality checks, and static analysis\n2. Automated deployment — Deployment to production occurs on merge to main branch (only after all tests pass)\n3. Front-end assets — Assets are built and included in deployment\n4. Environment files — Securely transferred during deployment\n5. Crontab updates — Scheduled tasks are updated on deployment\n\nThe CI/CD pipeline ensures code quality by requiring all tests to pass before any code reaches production.\n\n### Manual deployment\n\n```bash\n# Deploy to development\nddev deploy dev\n\n# Deploy to production\nddev deploy prod\n```\n\n## Error monitoring\n\nAggro uses Sentry for application monitoring:\n\n- Real-time error tracking and alerting\n- Performance monitoring for slow requests\n- Automatic error grouping and deduplication\n- Integration with deployment tracking\n\nConfigure Sentry by setting the appropriate environment variables in your `.env` file.\n\n## License\n\nAggro is open-source software licensed under the MIT license. See the [LICENSE](LICENSE) file for details.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Run tests (`ddev test`)\n5. Submit a pull request\n\n## Credits\n\n- Developed and maintained by [Jason Morris](https://jasonmorris.com)\n- Built with [CodeIgniter 4](https://github.com/codeigniter4/CodeIgniter4)\n- Uses [SimplePie](https://github.com/simplepie/simplepie) for feed parsing\n- [DDEV](https://ddev.com) for development environment\n\n## Support\n\n- Issues — [GitHub Issues](https://github.com/jsnmrs/aggro/issues)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsnmrs%2Faggro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjsnmrs%2Faggro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsnmrs%2Faggro/lists"}