bearny-codes/pawsome-mary
Pawsome Mary is a Laravel/PHP package from bearny-codes that offers a simple, framework-friendly way to bring its core functionality into your application, keeping integration clean and lightweight while fitting naturally into Laravel projects.
Pawsome Mary is a starter kit, not a library — you don't composer require it into an existing app. You scaffold a new project from it and then own the code outright. That distinction drives everything else below.
Minimal path:
# Via the Laravel installer (if the kit is registered) or directly:
laravel new my-app --using=pawsome-mary
# Or clone/copy the repo and:
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
npm install && npm run dev
First three places to look, in order:
routes/web.php + routes/auth.php — confirms which auth flows (OTP registration, passkey login) are wired and at what paths.app/Livewire/ — the MaryUI-driven auth screens live here. This is where you'll spend most of your customization time.config/ for passkeys and OTP — the two non-standard pieces. Confirm the relying-party ID (passkeys) and OTP expiry/length before touching anything else.First real use case: spin up an authenticated dashboard with role-gated navigation in under an hour. Register with OTP, seed a couple of roles, log in with a passkey, and confirm a permission-gated route behaves correctly. If that loop works end to end, the kit is doing its job.
Because 0.5.2 is the first release, treat it as a greenfield scaffold you'll fork and maintain, not something you'll composer update. Pin your Laravel/Livewire/MaryUI versions on day one.
MaryUI as your UI vocabulary. Every screen is composed from <x-…> MaryUI components sitting on DaisyUI/Tailwind classes. Rather than hand-rolling forms, follow the existing auth components' shape — x-form, x-input, x-button, x-card — so new screens inherit the same theming and validation display. When you need a new admin screen, copy an existing Livewire component's skeleton (property bag → rules() → save()) and swap the fields; that keeps you inside the kit's conventions instead of fighting them.
OTP registration flow. Registration is a two-phase interaction: collect identity → send code → verify. Customize it in the Livewire registration component plus the notification/Mailable that mints the code. A pattern that pays off:
// Keep issuance in one place so both resend and initial send share it
$code = $this->otpService->issue($user); // persists hash + expiry, sends notification
Store a hash of the code with an expires_at and an attempt counter, never the plaintext. Gate the "verify" step on a signed or session-scoped pending-user record so the unverified account isn't fully authenticated yet.
Permissions: seed early, gate consistently. If the kit ships Spatie's permission package, define roles/permissions in a seeder on day one and reference them via enum or constants rather than raw strings:
// database/seeders/RoleSeeder.php
Role::findOrCreate('admin');
Permission::findOrCreate('manage-users');
Then use @can in Blade, ->can() in policies, and middleware('can:manage-users') on routes — pick one primary enforcement layer (policies/middleware) and let Blade directives be cosmetic only. Don't sprinkle permission checks across controllers and views; you'll get drift.
Passkeys alongside passwords, not instead of them. The pragmatic integration is additive: leave the existing password (or OTP) login intact and register a passkey as a second credential on the profile/security screen. Feature-detect in the browser and hide the passkey button where unsupported rather than degrading the whole login form. Treat passkey registration as a post-login action so a broken WebAuthn ceremony never blocks account creation.
Composable workflow for a typical feature: Livewire component (state + validation) → action/service class (OTP issuance, passkey registration, role assignment) → policy/middleware (authorization) → Blade with MaryUI components → Pest/PHPUnit feature test hitting the route. The kit's own auth tests are your template for asserting OTP and passkey paths without real hardware (fake the WebAuthn assertion at the service boundary).
MAIL_MAILER=log means codes go to storage/logs/laravel.log, not your inbox). Consider a local escape hatch — log the code at debug level, or allow a fixed test code only when app()->isLocal(). Never let that branch survive into staging.localhost works for dev, but 127.0.0.1 vs localhost, HTTP vs HTTPS, and any proxy/APP_URL mismatch produce opaque browser errors. If passkeys fail silently, check APP_URL, session domain, and the RP config before the JS. Also remember passkeys require a secure context (HTTPS) outside local hostnames.primary, base-100) come from your Tailwind config. Overriding brand colors means editing the theme, not the components — and custom classes on MaryUI components may be merged, not replaced. Check the rendered HTML when a class "doesn't apply."php artisan permission:cache-reset or the equivalent) or tests will mysteriously fail. Use RefreshDatabase plus re-seeding in tests.@can should have a matching server-side check.How can I help you explore Laravel packages today?