Responsive PHP 8 + MySQL scheduling app for a multi-location Brazilian Jiu-Jitsu academy. It includes an admin calendar, instructor check-ins, class coverage queue, monthly hour tracking, notification preferences, OAuth hooks, and per-instructor iCal feeds.
- PHP 8 front controller with REST-style JSON endpoints
- MySQL or MariaDB via PDO
- FullCalendar.js for schedule views
- Tailwind CDN plus local CSS for the dashboard UI
- Firebase Cloud Messaging service hook for push notifications
- Google and Facebook OAuth redirect/callback flow
- Copy
.env.exampleto.env. - Create a MySQL database named
rta_scheduler. - Run the schema and demo seed:
SOURCE www/database/migrations/001_create_scheduler_schema.sql;
SOURCE www/database/seeders/demo_seed.sql;- Point your web server document root at
www. - Open
/in the browser.
If no database credentials are configured, the app falls back to session-backed demo mode. Demo email login is admin@example.com with password password.
GET /dashboard UIGET /index.php/api/bootstrapapp bootstrap dataGET /index.php/api/classescalendar events and class dataPOST /index.php/api/classescreate a classPUT /index.php/api/classes/{id}update a classDELETE /index.php/api/classes/{id}soft-delete a classPOST /index.php/api/classes/{id}/checkininstructor check-inPOST /index.php/api/classes/{id}/unavailablecreate coverage requestPOST /index.php/api/classes/{id}/claimclaim an open classGET /index.php/api/coverage-requestscoverage queuePOST /index.php/api/coverage-requests/{id}/claimclaim coveragePOST /index.php/api/users,PUT /index.php/api/users/{id},DELETE /index.php/api/users/{id}admin user CRUDPUT /index.php/api/users/{id}/goalconfigure monthly instructor goalPOST /index.php/api/schools,PUT /index.php/api/schools/{id},DELETE /index.php/api/schools/{id}admin school CRUDGET /index.php/ical/{calendar_token}unique instructor iCal feedGET /index.php/auth/googleand/index.php/auth/facebookOAuth start URLs
Apache and Azure/IIS rewrite configs are included in www/.htaccess and www/web.config. The frontend uses index.php/... URLs, so it also works without rewrites.
- Instructor: schedule view, check-ins, history, hours, preferences, unavailable/claim actions
- Location Manager: instructor features plus schedule management for assigned schools and staffing alerts
- Super User: global schedule management and conflict override surface
- Admin: full access to users, schools, roles, goals, notifications, and entities
Each user has a unique calendar_token. The Settings view exposes the iCal URL and a Google Calendar add-by-URL button. Rotate a feed by changing the user’s calendar_token.
In-app notifications are stored in notifications with the in_app channel. Mail and browser-push deliveries are queued in notification_jobs so schedule saves, check-ins, and coverage updates do not wait on external delivery providers. Browser push subscriptions are stored per user/device in push_subscriptions, and user category preferences are stored in user_notification_preferences.
Create OAuth apps with redirect URIs:
- Google:
https://your-domain/index.php/auth/callback/google - Facebook:
https://your-domain/index.php/auth/callback/facebook
Then set the matching client IDs/secrets in .env.
www/index.phpfront controllerwww/app/Corerequest, response, auth, config, database, application wiringwww/app/Controllerspage, API, and OAuth controllerswww/app/RepositoriesMySQL repository plus session demo repositorywww/app/ServicesiCal, OAuth, and notification serviceswww/views/dashboard.phpmain UI templatewww/app.jsdashboard/calendar interactionswww/styles.cssresponsive dashboard stylingwww/databasemigrations and seed data
The main dashboard and post-login path are intentionally split between critical and non-critical work:
/index.php/api/bootstrapreturns only the near-term dashboard window, recent/unread notifications, cached school/class type lists, and cached instructor monthly summaries. It no longer requires loading all historical classes before the dashboard can render.- Calendar requests must include the visible
startandendrange. The frontend sends FullCalendar's visible range and asks for compact event payloads withcompact=calendarso the server does not hydrate unused instructor profile details for every event. - Large list endpoints accept
pageandper_page; defaults are capped server-side to keep accidental unbounded loads from slowing login or updates. - Dashboard summaries are cached for 30 seconds. Instructor monthly summaries are cached for 5 minutes and invalidated after class, check-in, goal, school, class type, user, preference, coverage, and notification mutations.
- Local/dev timing logs are emitted as
[perf] METHOD path Nms queries=N. Slow production endpoints over 500 ms are also logged. SetAPP_ENV=localorAPP_DEBUG=trueto log query counts for every endpoint while profiling. - Run
www/database/migrations/002_add_performance_indexes.sqlafter the base schema to add indexes used by dashboard, schedule, check-in, calendar, coverage, and notification queries.
dashboard()loaded a broad class list, then filtered it in PHP for today/upcoming/understaffed cards.- Instructor monthly totals were recalculated by calling
classes()once per instructor, and each class hydration queried schools, class types, assignments, assigned users, check-ins, coverage, and recurrence separately. coverageRequests()andrecentActivity()hydrated classes one row at a time.- Rendering the initial dashboard immediately initialized the calendar and instructor/month panels, which caused duplicate
/classescalls while the user was still waiting for the overview. - Notification and calendar calls had no explicit pagination or compact payload mode.
- Move file-cache storage to Redis or APCu if the app is deployed across multiple PHP workers/servers.
- Add a dedicated
/api/dashboardendpoint if the bootstrap payload grows again. - Add a dedicated
/api/instructor-month-statsaggregate endpoint so the instructor table never needs to inspect class payloads client-side. - Add database-level generated columns or summary tables if historical check-in volume becomes very large.