An accessibility monitoring dashboard that tracks website accessibility scores over time using the Google PageSpeed Insights API. Built with PHP 8.4 and SQLite.
- Automated Audits — Schedule daily, weekly, biweekly, or monthly accessibility scans via the PageSpeed Insights API
- Dashboard — Overview of all projects with average scores, trends (improving/stable/degrading), and score history graphs
- Project Organisation — Group URLs into projects for logical monitoring boundaries
- URL Management — Add URLs individually or bulk import via paste list or CSV upload
- Historical Tracking — View score history, audit-to-audit comparisons, and trend analysis per URL
- Issue Tracking — Detailed accessibility issues logged per audit with descriptions and selectors
- PDF Reports — Downloadable per-project PDF reports with executive summary, score distribution, and full issue breakdown by category
- Email Notifications — Subscribe to projects and receive PDF audit reports by email (via AWS SES) after each audit completes
- CSV Export — Export audit data per URL or as a full summary across all monitored URLs
- User Management — Role-based access (admin/viewer) with session authentication and CSRF protection
- Cron Scheduling — CLI runner that automatically audits URLs when they're due based on their frequency
| Layer | Technology |
|---|---|
| Language | PHP 8.4 |
| Database | SQLite |
| Templating | Twig 3.x |
| HTTP | Symfony HttpFoundation + Routing |
| Styling | Tailwind CSS 4 |
| Interactivity | Alpine.js |
| Charts | Chart.js |
| DOMPDF | |
| AWS SES (via aws-sdk-php) | |
| API | Google PageSpeed Insights v5 |
| Testing | PHPUnit 11.x |
| Static Analysis | PHPStan Level 9 + strict-rules |
| Code Style | PHP-CS-Fixer (PSR-12) |
- PHP 8.4+ with extensions:
pdo_sqlite,mbstring,xml,curl,zip - Composer
- Node.js 18+ (for building CSS)
git clone https://github.com/your-username/beaconaudit.git
cd beaconaudit
composer install
npm ci
npm run buildCreate the environment file:
cp .env.example .envEdit .env with your settings:
APP_ENV=local
APP_DEBUG=true
DB_PATH=storage/database.sqlite
PAGESPEED_API_KEY=your-api-key-hereGet a PageSpeed Insights API key from the Google Cloud Console.
| Variable | Description | Default |
|---|---|---|
APP_ENV |
Environment (local, production) |
production |
APP_DEBUG |
Enable debug mode (true/false) |
false |
DB_PATH |
Path to SQLite database file | storage/database.sqlite |
PAGESPEED_API_KEY |
Google PageSpeed Insights API key | (required) |
AWS_SES_REGION |
AWS SES region | us-west-2 |
AWS_SES_ACCESS_KEY |
AWS IAM access key for SES | (optional) |
AWS_SES_SECRET_KEY |
AWS IAM secret key for SES | (optional) |
AWS_SES_FROM_ADDRESS |
Verified sender email address | (optional) |
Note: The
.envfile is excluded from Git. On a fresh clone (e.g. on a server), you must create it manually — see the Deployment Guide.
Create the database and an admin user:
touch storage/database.sqlite
php cli/create-user.php [email protected] --password=your-password --role=adminDatabase migrations run automatically on the first request.
With Laravel Herd (or any PHP dev server):
# Herd will automatically serve from the public/ directory
# Watch CSS for changes
npm run devOr use the built-in PHP server:
php -S localhost:8000 -t publicLog in as an admin and click "Run Audit Now" on any URL's detail page in the dashboard.
The scheduled audit runner checks all enabled URLs and runs audits for any that are due based on their configured frequency:
| Frequency | Interval |
|---|---|
| Daily | Every 24 hours |
| Weekly | Every 7 days |
| Biweekly | Every 14 days |
| Monthly | Every 30 days |
Run it manually:
php cron/run-scheduled-audits.phpFor automated monitoring, add to crontab (runs every 15 minutes, the runner decides which URLs are due):
*/15 * * * * cd /path/to/beaconaudit && /usr/bin/php cron/run-scheduled-audits.php >> storage/logs/cron.log 2>&1URLs that have never been audited are considered immediately due, so newly added or imported URLs will be picked up on the next cron run. The audit engine includes automatic retry with exponential backoff (up to 3 retries) for failed API calls, and generates comparisons between consecutive audits to track score changes.
Admin users can import multiple URLs at once from the URLs > Bulk Import page.
Enter one URL per line in the textarea. Each URL is used as both the URL and the display name.
Upload a CSV file with a header row. The url column is required; name and frequency are optional:
url,name,frequency
https://example.com,Example Site,weekly
https://test.com,Test Site,daily
https://other.com,,- If
nameis empty or missing, it defaults to the URL value - If
frequencyis empty or missing, it uses the frequency selected on the form - Duplicate URLs (already in the database or within the same batch) are skipped
- Invalid URLs are reported with line numbers and error messages
- Newly imported URLs are considered immediately due and will be picked up by the next scheduled cron run (within 15 minutes)
php cli/create-user.php [email protected] --password=secret --role=adminRoles: admin (full access) or viewer (dashboard read-only). This also runs any pending database migrations.
php cron/run-scheduled-audits.phpChecks all enabled URLs and runs audits for any that are due. Outputs a summary of completed audits with scores and statuses.
# Run all checks (CS, PHPStan, tests)
composer quality
# Individual commands
composer test # PHPUnit (310 tests)
composer phpstan # PHPStan level 9
composer cs-check # Code style dry-run
composer cs-fix # Auto-fix code styleThe application uses a modular, layered architecture:
src/
Modules/
Url/ URL & project management
Audit/ PageSpeed API client, audit engine, comparisons
Dashboard/ Statistics aggregation
Reporting/ CSV export, PDF reports
Auth/ Authentication & user management
Notification/ Email subscriptions & SES notifications
Shared/ Exceptions, base classes
Http/ Controllers, router
Views/ Twig templates
Database/ Migrations, connection
Each module follows Domain-Driven Design layers:
- Domain — Models, Value Objects, Repository Interfaces, Events
- Application — Services, Use Cases
- Infrastructure — SQLite Repositories, API Clients
See DEPLOYMENT.md for a step-by-step guide to deploying on a DigitalOcean LEMP droplet, including SSL setup, cron scheduling, SQLite backups, and log rotation.
This project is licensed under the MIT License.