Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Demo Mode Laravel Package

spatie/laravel-demo-mode

Protect work-in-progress Laravel apps from prying eyes with a demo-mode middleware. Redirects visitors (including unknown routes) to an “under construction” URL until they visit a configurable access URL (e.g. /demo) to unlock protected routes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-demo-mode
    

    Publish the config file:

    php artisan vendor:publish --provider="Spatie\DemoMode\DemoModeServiceProvider"
    
  2. Configure Routes:

    • Add the demo middleware to routes you want to protect in routes/web.php:
      Route::middleware(['demo'])->group(function () {
          Route::get('/dashboard', [DashboardController::class, 'index']);
      });
      
    • Define the "unlock" route (e.g., /demo) in config/demomode.php:
      'unlock_url' => '/demo',
      'redirect_url' => '/under-construction',
      
  3. First Use Case:

    • Visit /demo to "unlock" the app.
    • All protected routes (e.g., /dashboard) will now be accessible until the session expires or the browser is closed.
    • Unauthorized users will be redirected to /under-construction.

Implementation Patterns

Workflows

  1. Temporary Access for Clients/Stakeholders:

    • Use the demo middleware for client demos or internal previews.
    • Example: Protect all frontend routes during development:
      Route::middleware(['demo'])->group(function () {
          Route::get('/', [HomeController::class, 'index']);
          Route::get('/products', [ProductController::class, 'index']);
      });
      
  2. Environment-Specific Activation:

    • Enable demo mode only in local or staging environments by checking the config:
      if (app()->environment('local')) {
          Route::middleware(['demo'])->group(...);
      }
      
  3. Custom Unlock Logic:

    • Extend the unlock URL to require a password or token:
      Route::get('/demo', function () {
          if (request()->input('password') === config('demomode.unlock_password')) {
              session()->put('demo_mode_unlocked', true);
              return redirect()->intended('/');
          }
          return back()->withErrors(['password' => 'Incorrect password']);
      });
      
  4. Integration with Authentication:

    • Combine with Laravel's auth middleware for layered protection:
      Route::middleware(['auth', 'demo'])->group(function () {
          Route::get('/admin', [AdminController::class, 'index']);
      });
      

Integration Tips

  • Session Storage: Demo mode relies on session storage. Ensure your app uses a session driver (e.g., file, database, or redis).
  • API Routes: Exclude API routes from demo mode unless intentional:
    Route::middleware(['demo', 'api'])->group(function () {
        Route::get('/api/preview', [ApiController::class, 'preview']);
    });
    
  • Testing: Mock the demo mode middleware in tests:
    $this->actingAs($user)->withSession(['demo_mode_unlocked' => true]);
    

Gotchas and Tips

Pitfalls

  1. Session Expiry:

    • Demo mode is session-based. If the session expires (e.g., due to inactivity or cookie deletion), users will be locked out until they revisit the unlock URL.
    • Fix: Use session()->put('demo_mode_unlocked', true) with a longer session.lifetime in .env.
  2. Caching Issues:

    • Aggressive caching (e.g., Varnish, Cloudflare) may bypass the middleware. Exclude demo routes from cache or use a cache-busting query string (e.g., ?demo=1).
  3. CSRF Token Conflicts:

    • If the unlock URL (/demo) uses a form, ensure CSRF protection is disabled or handled:
      Route::post('/demo', [DemoController::class, 'unlock'])->middleware('throttle:10,1');
      
  4. Middleware Order:

    • Place demo middleware after web but before route-specific middleware (e.g., auth). Incorrect ordering may cause unintended redirects.

Debugging

  • Check Session Data:
    dd(session()->all()); // Verify 'demo_mode_unlocked' exists.
    
  • Log Redirects: Add temporary logging to the handle method in app/Http/Middleware/DemoMode.php:
    \Log::debug('Demo mode redirect triggered for: ' . $request->path());
    

Config Quirks

  • Custom Redirect URL: Override the redirect URL dynamically:
    config(['demomode.redirect_url' => '/maintenance']);
    
  • Multiple Unlock URLs: Extend the unlock logic to support multiple paths:
    if (request()->is('demo') || request()->is('preview')) {
        session()->put('demo_mode_unlocked', true);
    }
    

Extension Points

  1. Custom Unlock Conditions: Override the unlock logic in a custom middleware:

    public function handle($request, Closure $next)
    {
        if ($this->isUnlocked($request)) {
            return $next($request);
        }
        return redirect(config('demomode.redirect_url'));
    }
    
    protected function isUnlocked($request)
    {
        return session()->has('demo_mode_unlocked') ||
               $request->ip() === config('demomode.trusted_ip');
    }
    
  2. Event-Based Unlocking: Trigger unlock via events (e.g., after user registration):

    event(new DemoModeUnlocked($user));
    

    Listen for the event in a service provider:

    DemoModeUnlocked::class => function ($event) {
        session()->put('demo_mode_unlocked', true);
    },
    
  3. Database-Backed Unlocks: Store unlock status in the database for persistence across sessions:

    if (DemoUnlock::where('ip', $request->ip())->exists()) {
        session()->put('demo_mode_unlocked', true);
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport