Tutorials Courses Interview Prep (100 Q&A) AI Tools (50) Developer Tools (50) Tracks Pricing Plans Blog & Articles Contact Us
Open-Access Production Interview Prep

Senior & Lead Engineer Interview Mastery Hub

100 real-world, scenario-based architecture & concurrency questions designed for 5–10+ years experienced developers. Free & open for every student and engineer.

100

Real-world Q&As

100%

Scenario-Based

5-10 Yrs

Senior / Lead Depth

5 Stacks

Core Technologies

Showing 25 questions for senior interview preparation

•
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Expert Production Scenario

How does Laravel Octane handle state persistence across requests, and how do you prevent catastrophic memory leaks and data bleeding in singletons?

Incident Scenario: In a high-throughput production environment running Laravel Octane with Swoole/FrankenPHP serving 10,000 req/sec, users reported seeing other users' authenticated profiles, and worker memory consumption steadily increased until pods crashed with OOM.
106 views • Direct Permalink

Root Cause Analysis: Traditional PHP-FPM vs. Long-Running Octane

Under traditional PHP-FPM, the entire application lifecycle (memory, static variables, singletons) is instantiated on request arrival and wiped completely when the request terminates (shared-nothing architecture).

Under Laravel Octane (Swoole, RoadRunner, FrankenPHP), the PHP application boots once into memory. Worker processes persist across thousands of requests. Any state attached to a singleton, static property, or service provider persists across subsequent HTTP requests from completely different clients.

Critical Failure Vectors

  1. Data Bleeding: Storing request-scoped data (like Auth::user() or tenant IDs) inside a singleton service constructor or static class property. Subsequent requests will read the prior user's cached identity.
  2. Memory Leak: Appending items into static array caches (private static array $cache = []) or listening to events without unregistering listeners.

Architectural Solution

  1. Use bindScoped Instead of singleton: Laravel Octane resets scoped bindings between requests:

    // BAD in Octane (persists across requests)
    $this->app->singleton(TenantManager::class, fn () => new TenantManager($request->header('X-Tenant-ID')));
    
    // GOOD in Octane (purged after each request finishes)
    $this->app->scoped(TenantManager::class, fn () => new TenantManager(request()->header('X-Tenant-ID')));
    
  2. Octane Warmers & Listeners: Flush state explicitly in config/octane.php listeners:

    OperationTerminated::class => [
        FlushTemporaryCaches::class,
        ResetTenantContext::class,
    ],
    
  3. Pass Callbacks or Resolvers: Instead of caching an instantiated $user in a service, pass a Closure or resolve dynamically via Auth::user().

Tags: #Octane #Swoole #Memory Leaks #Singletons #State Bleed
Laravel Advanced & Architecture 5-8 Years (Senior) Hard Production Scenario

How do you prevent Deadlocks when processing concurrent financial transactions or inventory deductions across multiple queue workers in Laravel?

Incident Scenario: During a Flash Sale with 50 concurrent queue workers processing checkout jobs, MySQL threw repeated "Deadlock found when trying to get lock; try restarting transaction" (Error 1213), causing failed orders and duplicate inventory deductions.
294 views • Direct Permalink

Why Deadlocks Occur in Concurrent Workers

A deadlock occurs when Worker A holds a lock on Resource 1 and requests Resource 2, while Worker B holds a lock on Resource 2 and requests Resource 1. Neither can proceed.

Battle-Tested Remediation Strategy

  1. Strict Ordering of Locks: Always sort entity IDs before acquiring database row locks (lockForUpdate):

    // Sort items by ID so all workers acquire locks in the exact same sequence
    $itemIds = collect($cartItems)->pluck('product_id')->sort()->values();
    
    DB::transaction(function () use ($itemIds) {
        $products = Product::whereIn('id', $itemIds)->lockForUpdate()->get();
        // Deduct inventory safely
    }, 5); // 5 retries on deadlock
    
  2. Atomic SQL Decrements: Instead of SELECT -> calculate in PHP -> UPDATE, perform atomic database decrements:

    $affected = DB::table('products')
        ->where('id', $productId)
        ->where('stock', '>=', $quantity)
        ->decrement('stock', $quantity);
    
    if ($affected === 0) {
        throw new OutOfStockException("Insufficient inventory.");
    }
    
  3. Redis Atomic Distributed Lock (Redlock / Mutex): Prevent queue workers from touching the same wallet simultaneously:

    use Illuminate\Support\Facades\Redis;
    
    Redis::throttle("wallet-lock:{$userId}")
        ->block(10)
        ->allow(1)
        ->every(1)
        ->then(function () use ($userId, $amount) {
            // Execute transaction safely
        });
    
Tags: #Transactions #Deadlocks #Pessimistic Locking #Queues #Concurrency
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Hard Production Scenario

How does the Laravel Service Container resolve dependencies using Reflection, and what are the performance trade-offs in large applications?

Incident Scenario: A large enterprise SaaS app with 800+ service classes was experiencing high latency on cold boots. Profiling via Blackfire showed 35% of request time was spent in `Illuminate\Container\Container::resolve()`.
253 views • Direct Permalink

How Container Resolution Works

  1. When you request a class (e.g. app(PaymentService::class)), if no binding exists, the container checks isBuildable($concrete).
  2. It instantiates ReflectionClass($concrete).
  3. It inspects getConstructor() and iterates through parameters via ReflectionParameter.
  4. It recursively resolves parameter typehints from the container or defaults until the dependency graph is fully satisfied.

Optimization Strategies for Large Applications

  • Service Provider Deferral: Use \Illuminate\Contracts\Support\DeferrableProvider so large service providers are only loaded when their bound service is explicitly requested.
  • Route & Config Caching: php artisan route:cache, php artisan config:cache avoids repetitive reflection scans on routes and controllers.
  • Explicit Bindings: Direct closures ($this->app->bind(Service::class, fn () => new Service(...))) skip reflection overhead entirely.
Tags: #Service Container #Reflection #Dependency Injection #Performance
Laravel Advanced & Architecture 10+ Years (Principal / Architect) Expert Production Scenario

How do you execute Zero-Downtime database migrations on tables with 50+ million rows without locking writes in production Laravel?

Incident Scenario: Running `php artisan migrate` to add a new column and composite index on a 60-million-row `orders` table locked the table for 18 minutes, resulting in HTTP 504 Gateway Timeouts across the entire checkout funnel.
807 views • Direct Permalink

Root Cause

Standard ALTER TABLE statements in MySQL can acquire exclusive metadata locks (MDL), blocking all incoming INSERT/UPDATE operations until the table rewrite finishes.

Safe Migration Patterns

  1. Online DDL with Algorithm=INPLACE, Lock=NONE:
    ALTER TABLE orders ADD COLUMN fulfillment_status VARCHAR(30) DEFAULT 'pending',
    ALGORITHM=INPLACE, LOCK=NONE;
    
  2. The Expand/Contract (Blue-Green Schema) Pattern:
    • Step 1 (Expand): Add the new column as NULLABLE (instant operation).
    • Step 2 (Dual-Write): Write to both old and new columns via model events or repository layer.
    • Step 3 (Backfill in Background Queues): Chunk existing 60M rows with a queue worker in batches of 5,000 using ID-based cursor pagination.
    • Step 4 (Switch Reads): Deploy code pointing all read queries to the new column.
    • Step 5 (Contract): Drop the old column after zero dependencies remain.
  3. Use GitHub's gh-ost or Percona pt-online-schema-change: Creates an ghost shadow table, triggers/binlog replays changes, and performs an atomic table swap without holding locks.
Tags: #Database Migrations #Zero Downtime #MySQL Online DDL #Large Tables
Laravel Advanced & Architecture 10+ Years (Principal / Architect) Expert Production Scenario

How do you architect Multi-Tenant database isolation in Laravel (Single DB vs Multi DB vs Schema Separation)?

Incident Scenario: An enterprise B2B SaaS platform is scaling from 100 to 10,000 tenants. Enterprise clients require strict GDPR data segregation, isolated database backups, and custom billing databases.
795 views • Direct Permalink

Comparison of Multi-Tenancy Models

Strategy Pros Cons Ideal For
Single DB (Column Tenant ID) Low cost, simple migrations, aggregate reporting easy High risk of data leaks if scope missed, table bloat B2C or low-tier SaaS
Multi-DB (Isolated Databases) Complete data security, per-tenant backups, GDPR compliant Migration latency across 10k DBs, connection overhead Enterprise B2B SaaS
PostgreSQL Schemas Single DB connection pool, isolated table namespaces Migration complexity Hybrid enterprise

Multi-DB Switching Implementation in Laravel

class SwitchTenantConnection
{
    public function handle(Request $request, Closure $next): Response
    {
        $tenant = Tenant::where('domain', $request->getHost())->firstOrFail();
        
        // Dynamically purge and reconnect
        Config::set('database.connections.tenant.database', $tenant->database_name);
        DB::purge('tenant');
        DB::reconnect('tenant');
        DB::setDefaultConnection('tenant');

        return $next($request);
    }
}
Tags: #Multi-Tenancy #Database Architecture #Security #GDPR
Laravel Advanced & Architecture 5-8 Years (Senior) Medium

Explain the Pipeline pattern in Laravel and how middleware executes using Onion Architecture.

Incident Scenario: An interviewer asks you to implement a custom data sanitizer pipeline from scratch using `Illuminate\Pipeline\Pipeline`.
729 views • Direct Permalink

Onion Architecture in Laravel

In Laravel, HTTP requests pass through middleware like layers of an onion. Middleware executes in sequence going inward, reaches the core route handler, and returns outward in reverse order.

Using Pipeline for Custom Business Logic

$sanitizedOrder = app(Pipeline::class)
    ->send($rawPayload)
    ->through([
        StripHtmlTags::class,
        NormalizePhoneNumbers::class,
        ApplyTaxExemptions::class,
        ValidatePromoCodes::class,
    ])
    ->then(fn ($payload) => Order::create($payload));

Each pipe implements a handle($passable, Closure $next) method:

class NormalizePhoneNumbers
{
    public function handle($payload, Closure $next)
    {
        $payload['phone'] = preg_replace('/[^0-9+]/', '', $payload['phone']);
        return $next($payload);
    }
}
Tags: #Pipeline Pattern #Middleware #Design Patterns #Architecture
Laravel Advanced & Architecture 5-8 Years (Senior) Hard Production Scenario

How do you debug and resolve Queue Worker starvation and RabbitMQ/Redis Queue backpressure in Laravel?

Incident Scenario: A burst of 500,000 Welcome Email jobs blocked urgent Password Reset and Payment Verification jobs from processing for over 2 hours.
225 views • Direct Permalink

Solution: Strict Queue Prioritization & Dedicated Worker Pools

  1. Never dump all jobs into a single default queue.
  2. Partition queues by SLA: high, default, low, notifications:
    SendPasswordResetNotification::dispatch($user)->onQueue('high');
    SendMarketingNewsletter::dispatch($campaign)->onQueue('low');
    
  3. Configure Supervisor with weighted prioritization:
    # Dedicated High-Priority worker
    php artisan queue:work --queue=high,default,low --tries=3 --timeout=60
    
  4. Queue Rate Limiting:
    public function middleware(): array
    {
        return [(new WithoutOverlapping($this->userId))->releaseAfter(60)];
    }
    
Tags: #Queue Tuning #Worker Starvation #Redis #Supervisor #Priority Queues
Laravel Advanced & Architecture 5-8 Years (Senior) Medium Production Scenario

How does Laravel’s Eloquent ORM prevent N+1 queries during polymorphic and nested eager loading with custom constraints?

Incident Scenario: An endpoint fetching 50 posts with comments, comment authors, and polymorphic image attachments was executing 1,400 database queries, taking 4.2 seconds.
311 views • Direct Permalink

Constrained Nested & Morph Eager Loading

$posts = Post::query()
    ->with([
        'author:id,name,avatar',
        'comments' => function ($query) {
            $query->where('is_approved', true)
                  ->latest()
                  ->take(5)
                  ->with(['user:id,name']);
        },
        'imageable' => function (MorphTo $morphTo) {
            $morphTo->morphWith([
                Post::class => ['tags'],
                User::class => ['profile'],
            ]);
        }
    ])
    ->select(['id', 'user_id', 'title', 'slug', 'created_at'])
    ->paginate(20);

Prevention in Development:

Enforce strict loading in AppServiceProvider::boot():

Model::preventLazyLoading(! app()->isProduction());
Tags: #Eloquent #N+1 Query #Eager Loading #Polymorphism #Optimization
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Hard Production Scenario

How do you handle Cache Stampede (Dog-Piling) in Laravel when high-traffic cache keys expire simultaneously?

Incident Scenario: When the home page top banner cache expired at midnight, 5,000 concurrent requests simultaneously hammered MySQL with the exact same complex aggregation query, bringing the primary database server CPU to 100%.
257 views • Direct Permalink

The Cache Stampede Problem

When a hot cache item expires, hundreds of incoming concurrent threads miss the cache at the exact same millisecond and all attempt to compute the expensive query and write back to cache simultaneously.

Solution 1: Cache::flexible() in Modern Laravel

Laravel provides stale-while-revalidate out of the box:

$stats = Cache::flexible('homepage_stats', [300, 600], function () {
    return DB::table('orders')->selectRaw('count(*), sum(amount)')->first();
});
// Serves stale cache instantly while dispatching background regeneration after 300s

Solution 2: Atomic Cache Locking (Cache::lock)

$data = Cache::get('homepage_stats');

if (! $data) {
    $lock = Cache::lock('lock:homepage_stats', 10);
    if ($lock->get()) {
        try {
            $data = ComputeExpensiveStats();
            Cache::put('homepage_stats', $data, now()->addMinutes(10));
        } finally {
            $lock->release();
        }
    } else {
        // Sleep briefly and read cache populated by the winning thread
        usleep(200000);
        $data = Cache::get('homepage_stats');
    }
}
Tags: #Cache Stampede #Redis #Atomic Locks #Dog-Piling #High Traffic
Laravel Advanced & Architecture 5-8 Years (Senior) Medium Production Scenario

Explain the architectural differences between Laravel Events vs. Model Observers vs. Action Classes.

Incident Scenario: In a team of 15 engineers, business logic was scattered between Eloquent observers, listeners, and fat controllers, causing unintended side effects during seeding and batch imports.
797 views • Direct Permalink

Comparison Matrix

Pattern Best Used For Warning / Anti-Pattern
Model Observers Passive lifecycle tracking (Audit logs, cache clearing, slug auto-generation) Calling external APIs or triggering billing inside observers. Observers fire during seeders/batch updates and are hard to trace.
Events & Listeners Asynchronous, cross-boundary side effects (Sending email after order placed, push notifications) Synchronous coupling where the caller expects immediate return value.
Action Classes (Single Responsibility) Core domain business operations (e.g. RegisterUserAction, ProcessRefundAction) Keep business logic testable and explicit with typed parameters.
Tags: #Domain Architecture #Events #Observers #Action Classes #Clean Code
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Hard Production Scenario

How do you safely scale Laravel Horizon with Redis Clusters when handling 50,000 jobs per minute?

Incident Scenario: Redis memory was saturated and Horizon workers threw "MOVED" cluster errors because queue keys were not mapped to the same hash slot in a multi-node Redis cluster.
432 views • Direct Permalink

Redis Cluster Hash Tag Pinning

In Redis Cluster, commands operating on multiple keys (like atomic queue pops) require all keys to reside on the same cluster node. Use Redis Hash Tags {horizon}:

'prefix' => '{horizon}:',

This forces all related Horizon state keys into the same hash slot, eliminating MOVED cluster exceptions while scaling workers seamlessly across nodes.

Tags: #Horizon #Redis Cluster #Hash Tags #DevOps #Scaling
Laravel Advanced & Architecture 5-8 Years (Senior) Hard Production Scenario

How do you implement Idempotent API endpoints in Laravel to prevent duplicate charges upon client network retries?

Incident Scenario: A mobile client with poor connectivity sent 3 consecutive `POST /api/v1/payments` requests with the same card payload when the network timed out, causing the customer to be billed 3 times.
371 views • Direct Permalink

Idempotency Key Middleware Implementation

class EnsureIdempotency
{
    public function handle(Request $request, Closure $next): Response
    {
        $idempotencyKey = $request->header('Idempotency-Key');
        if (! $idempotencyKey) {
            return response()->json(['error' => 'Idempotency-Key header is required'], 400);
        }

        $cacheKey = "idempotency:{$request->user()->id}:{$idempotencyKey}";
        $lock = Cache::lock("lock:{$cacheKey}", 15);

        if (! $lock->get()) {
            return response()->json(['error' => 'Concurrent request in progress'], 409);
        }

        if ($cachedResponse = Cache::get($cacheKey)) {
            $lock->release();
            return response()->json($cachedResponse['data'], $cachedResponse['status']);
        }

        $response = $next($request);

        if ($response->isSuccessful()) {
            Cache::put($cacheKey, [
                'data' => json_decode($response->getContent(), true),
                'status' => $response->getStatusCode(),
            ], now()->addHours(24));
        }

        $lock->release();
        return $response;
    }
}
Tags: #API Design #Idempotency #Payments #Security #Resilience
Laravel Advanced & Architecture 10+ Years (Principal / Architect) Expert Production Scenario

How do you configure and optimize Laravel for High-Concurrency Microservices using gRPC and HTTP/2?

Incident Scenario: Microservices communicating via JSON over HTTP/1.1 experienced serialization bottlenecks and TCP connection exhaustion under 15,000 RPS internal traffic.
791 views • Direct Permalink

gRPC with Protocol Buffers in PHP

  1. Binary Serialization vs JSON: Protocol Buffers serialize payloads into compact binary format, reducing payload size by 70% and CPU deserialization time by 80%.
  2. HTTP/2 Multiplexing: Multiple bidirectional gRPC RPC calls share a single persistent TCP connection, preventing ephemeral port exhaustion.
  3. RoadRunner gRPC Plugin: Run Laravel worker processes through Spiral RoadRunner gRPC server for native C-level gRPC transport.
Tags: #Microservices #gRPC #HTTP/2 #Protobuf #High Throughput
Laravel Advanced & Architecture 5-8 Years (Senior) Hard Production Scenario

How do you handle Dynamic Database Connection Routing (Read/Write Splitting) and Replica Lag in Laravel?

Incident Scenario: After a user updated their profile, they were redirected back to the profile page and saw their old data because the read query hit a MySQL replica with 400ms replication lag.
448 views • Direct Permalink

Sticky Connections in Laravel config/database.php

Enable the sticky option:

'mysql' => [
    'read' => [
        'host' => ['192.168.1.10', '192.168.1.11'],
    ],
    'write' => [
        'host' => ['192.168.1.5'],
    ],
    'sticky' => true, // Reads in the same request/lifecycle immediately route to Write DB
],

Force Primary Read on Critical Reads:

$user = User::onWriteConnection()->find($id);
Tags: #Read Write Splitting #Replication Lag #Database #High Availability
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Hard Production Scenario

Explain the internal architecture of Laravel Broadcast Channels, Pusher, and Laravel Reverb WebSockets.

Incident Scenario: Scaling live chat and notifications to 100,000 concurrent socket connections without dropping messages or overwhelming backend servers.
691 views • Direct Permalink

Laravel Reverb Architecture

Laravel Reverb is a first-party, high-performance WebSocket server written directly in PHP using asynchronous event loops.

  • Epoll Event Loop: Capable of sustaining tens of thousands of open TCP sockets on a single server.
  • Horizontal Scaling via Redis Pub/Sub: When server A broadcasts an event, it publishes to Redis; Server B, C, and D receive the pub/sub notification and relay the frame to their local connected client sockets.
  • Zero Third-Party Billing: Direct drop-in replacement for Pusher.
Tags: #Reverb #WebSockets #Broadcasting #Realtime #Pusher
Laravel Advanced & Architecture 10+ Years (Principal / Architect) Expert Production Scenario

How do you design a robust Event-Sourced audit trail with CQRS in Laravel without third-party monolith packages?

Incident Scenario: A healthcare management system requires immutable historical state recreation so auditors can view the exact state of a medical record at any millisecond in the past 5 years.
363 views • Direct Permalink

Event Sourcing Core Principles

  1. Append-Only Event Store: State changes are stored as immutable past-tense events (PatientDiagnosed, PrescriptionIssued). The database table has NO UPDATE or DELETE permissions.
  2. Replaying State:
    $record = new MedicalRecord();
    foreach ($eventStream as $event) {
        $record->apply($event);
    }
    
  3. Projections (Read Models): Asynchronous queue listeners consume domain events and project denormalized read-optimized views into Elasticsearch or Postgres for fast querying.
Tags: #Event Sourcing #CQRS #Audit Trail #Immutability #Healthcare
Laravel Advanced & Architecture 5-8 Years (Senior) Medium Production Scenario

How does Laravel Sanctum issue and validate SPA cookies vs Mobile Personal Access Tokens?

Incident Scenario: A developer configured Sanctum for a Vue.js SPA and an iOS app, but the SPA kept receiving 419 CSRF Token Mismatch errors in cross-domain staging environments.
642 views • Direct Permalink

Sanctum Dual-Mode Authentication

  1. SPA (Cookie-Based Stateful Auth):
    • Client calls GET /sanctum/csrf-cookie to set XSRF-TOKEN cookie.
    • Client includes X-XSRF-TOKEN header and withCredentials: true.
    • Domain must match SANCTUM_STATEFUL_DOMAINS in .env.
  2. Mobile Apps (Bearer Tokens):
    • Issue token via $user->createToken('iphone')->plainTextToken.
    • Stored in hashed format in personal_access_tokens table.
    • Included as Authorization: Bearer <token> header without CSRF requirements.
Tags: #Sanctum #Authentication #SPA #CORS #CSRF #Security
Laravel Advanced & Architecture 5-8 Years (Senior) Hard Production Scenario

How do you optimize Laravel Eloquent Subqueries and Window Functions for enterprise analytics dashboards?

Incident Scenario: Generating a monthly leaderboard ranking top 100 students by quiz completion speed and course score required grouping across 2 million rows.
452 views • Direct Permalink

Utilizing selectSub and addSelect with Window Functions

$rankedStudents = User::query()
    ->select('id', 'name', 'email')
    ->addSelect([
        'last_quiz_score' => QuizAttempt::select('score')
            ->whereColumn('user_id', 'users.id')
            ->latest('completed_at')
            ->limit(1),
        'rank' => DB::table('quiz_attempts')
            ->selectRaw('DENSE_RANK() OVER (ORDER BY SUM(score) DESC)')
            ->whereColumn('user_id', 'users.id')
    ])
    ->orderByDesc('rank')
    ->take(100)
    ->get();

Avoids loading intermediate Eloquent collections in memory.

Tags: #Eloquent #Subqueries #Window Functions #Analytics #SQL
Laravel Advanced & Architecture 5-8 Years (Senior) Medium Production Scenario

How do you securely implement dynamic custom validation rules in Laravel that query external Microservice APIs?

Incident Scenario: Validating VAT numbers and enterprise business tax IDs against European VIES SOAP/REST APIs during user registration without hanging requests if the external service is slow.
647 views • Direct Permalink

Implementing Invokable Rule with Circuit Breaker & Timeout

class ValidEnterpriseTaxNumber implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        try {
            $response = Http::timeout(2)
                ->retry(2, 100)
                ->get("https://api.taxservice.com/validate/{$value}");

            if (! $response->successful() || ! $response->json('is_valid')) {
                $fail("The {$attribute} is not a verified business tax entity.");
            }
        } catch (\Throwable $e) {
            // Log warning and fail gracefully or flag for manual review
            Log::warning("Tax API unavailable: " . $e->getMessage());
        }
    }
}
Tags: #Validation #Custom Rules #External APIs #Timeouts #Resilience
Laravel Advanced & Architecture 8-10 Years (Tech Lead) Hard Production Scenario

How do you implement Dynamic Multi-Factor Authentication (MFA/TOTP) with backup recovery codes in Laravel 11/12/13?

Incident Scenario: Enterprise compliance SOC2 demands time-based one-time password (TOTP RFC 6238) support with cryptographically secure single-use recovery codes.
712 views • Direct Permalink

TOTP Implementation Workflow

  1. Secret Generation: Generate 32-character base32 secret and store encrypted in database (Crypt::encryptString($secret)).
  2. QR Code Provisioning: Generate otpauth://totp/App:user@email?secret=...&issuer=App.
  3. Verification: Validate code within drift window (+/- 30 seconds).
  4. Hashed Recovery Codes: Generate 8 random recovery codes, hash them with Hash::make() before saving, and burn upon single use.
Tags: #Security #MFA #TOTP #Cryptography #SOC2