Skip to main content

Authentication

The API uses a hand-rolled Redis token guard (app/Services/Redis/RedisGuard.php). Don’t expect standard Laravel auth packages to work. Auth tokens are MD5(uniqid()) stored in Redis with ~1 year expiry. Sessions are also stored in the sessions database table.
The WebAPI middleware (app/Http/Middleware/WebAPI.php) accepts an encrypted secret parameter that it decrypts to a user ID and uses to authenticate the request. This is how email action links (booking management, reschedule accept/decline) work without requiring login.
guest() returns $this->check() instead of !$this->check(). This appears to be a bug — but may be intentionally ignored since the method isn’t called anywhere critical. Confirm with team.

Code bugs

File: app/Listeners/SendNewAccountCreatedEmail.phpChecks config('env') instead of config('app.env'). This likely returns null, meaning the production-only check may silently fail and the email may never send.
File: app/Http/Controllers/TutorController.php (around line 33)References an undefined $modelId variable. May cause errors on the tutor show endpoint.
File: buildspec-production.ymlDownloads APNS-Key.p8 and AAACertificateServices.crt from the staging config path, not production. May be intentional (shared certs) or a copy-paste bug.

Business logic gotchas

In app/Models/v1/Address.php, when a tutor adds a new address, the existing address is deleted (not soft-deleted). Tutors are limited to one address. Students can have multiple.
Commission::addNewModel() disables ALL existing commissions before inserting a new one. If you need to change commission rates, add a new model — don’t edit existing ones.
The PaymentReceipt model’s boot() method runs CommissionService calculations on every model load. This can cause performance issues on bulk queries (N+1 problem). Be careful with PaymentReceipt::all() or eager loading receipts on large collections.
The 72-hour advance notice for rescheduling is enforced in Lesson::reschedule(), not in middleware or a form request. If you bypass the model method, the rule won’t apply.
profiles.tutoring_experience is stored in months, not years. Profile::getTutoringExperience() formats it as “X years Y months” for display. Don’t store years directly.
Every query through Tutor:: automatically includes WHERE role_id = 1. If you need all users, query User:: instead. This is via the HasParent trait from calebporzio/parental.
The files table uses UUID string primary keys, not auto-increment integers. When creating files, generate the UUID yourself.

Deployment gotchas

The Dockerfile entrypoint runs php artisan migrate --force before starting PHP-FPM. If a migration fails, the container fails to start. Test migrations thoroughly before deploying.
Only staging runs PHPUnit. Production builds assume staging passed. There’s no gate between staging passing and production deploying.
QUEUE_DRIVER=sync means all jobs run inline during HTTP requests. In production, this should be redis with a queue worker process. If you see slow API responses, check if the queue driver is set correctly.

Legacy code

/api/v1/* (legacy controllers in Http/Controllers/v1/) and /api/* (current, header-versioned). Many v1 controllers have TODO comments for missing validators. Both are actively used.
Files in app/Http/Requests/v1/RequestValidators/ have empty rules() methods. Validation is done inline in controllers with $request->validate().
The job in app/Jobs/CheckVerificationStatusOfPendingApplicants.php has all its code commented out. Status updates come via webhooks instead.
SendClaimUsernameEmail has a 2-second sleep between emails. ValidateZoomTokens has a 1-second sleep in its loop. These are for rate limiting but could cause issues with queue timeouts.
Several mail classes send directly to hello@tutorbloc.com rather than using a config value. If this email changes, multiple files need updating.

Caching behavior

DataCache durationImpact of stale cache
Tutor review summariesUntil end of dayReviews won’t show until cache expires
Postcode coordinates3 monthsIncorrect coordinates until cache expires
BlackBox distance results2 daysStale travel time estimates
To clear all cache:
php artisan cache:clear