ls

Tulk · Laravel · React

Glassmorphism Over a Laravel API: Shipping Tulk as a React SPA

Sanctum auth, throttled logins, verification codes, and a glass UI — notes from building a bilingual social platform on Laravel 10 and React 18.

August 24, 2026 · 7 min read

Tulk is a social platform — feeds, friendships, follows, likes, messages — with a glassmorphic React interface over a Laravel 10 and MySQL API. Pretty on top, strict underneath. That combination only works if the boundary between the two is boring and predictable.

Auth is a checklist, not a feature

The API route file reads like a security checklist: login throttling, registration, verification codes, password recovery, two-factor, and Sanctum-guarded everything else:

Route::post('/login', [AuthController::class, 'login'])->middleware(ThrottleLogin::class);
Route::post('register', [AuthController::class, 'register']);
Route::post('send-verification', [VerificationController::class, 'sendVerificationCode']);
Route::post('verify-code', [VerificationController::class, 'verify-code']);
Route::post('verify-2fa', [AuthController::class, 'verify2fa']);

Route::middleware('auth:sanctum')->group(function () {
    Route::post('logout', [AuthController::class, 'logout']);
    // Posts routes
    Route::get('/posts/feed', [PostController::class, 'getFeedPosts']);

Throttle the login before anything else — brute force is the attack you will actually receive. Verification codes before trust, 2FA before sensitivity, Sanctum around all of it.

Feeds need read-state

A social feed is not a list endpoint; it is a list endpoint plus memory. Endpoints like unread-count and mark-read exist so the UI can show what is new without re-downloading the world. Design the read-state on day one — retrofitting "seen" semantics onto a feed is miserable.

Friendship is a domain, not a flag

Follows, likes, friendships (Amitie), messages, profiles — each gets its own controller because each has its own rules. A follow is one direction; a friendship is a negotiation with states. Giving each relationship its own home keeps the rules from tangling.

Glass needs contrast discipline

Glassmorphism is unforgiving: translucent panels over unpredictable content turn to mud without strict contrast rules. The React side pairs every glass surface with a scrim discipline — dark text on light glass, light text on dark, never hoping the background cooperates. Beauty is a constraint problem.

Bilingual from the first string

Tulk ships in French and English, and every user-facing string went through the language files from the start — including validation messages and emails. Retrofitting a second language means touching every string twice; starting bilingual means touching each once.

Takeaway

Social apps fail at trust boundaries: auth, read-state, relationships, languages. Put each behind its own explicit mechanism — throttle, Sanctum, dedicated controllers, language files — and the pretty glass on top stays honest.