achyutn/flirt-kit
Flirt Kit is a Laravel/PHP package that provides a playful toolkit for adding flirtation-inspired features to your app, with ready-to-use helpers for managing lighthearted messages and interactions. It is lightweight and designed for quick integration.
flirt-kit is not a Composer library you require — it's a skeleton application (a starter kit) built on Laravel + Inertia + React + Tailwind + Filament v4. The first step is therefore to create a project from it rather than add it as a dependency:
composer create-project achyutn/flirt-kit my-app
# or
git clone https://github.com/achyutkneupane/flirt-kit.git my-app && cd my-app
composer install && npm install
cp .env.example .env && php artisan key:generate
php artisan migrate
php artisan make:filament-user # create your first admin
npm run dev
Where to look first, in order:
app/Providers/Filament/*PanelProvider.php — this is the heart of the admin panel. Panel path (/admin), auth guard, colors, middleware, and registered resources/pages/widgets all live here. Read this before anything else.routes/web.php and routes/auth.php — the Inertia/React surface area, typically split from the Filament panel routes (which are auto-registered by the panel provider).resources/js/Pages — your React/Inertia pages; resources/js/app.tsx is the Inertia + Vite entry point.app/Filament/Resources — generated CRUD resources. These are the day-one files you'll be editing.HandleInertiaRequests middleware — where shared props (auth user, flash, ziggy routes) are defined.The first real use case is almost always: model → Filament resource → Inertia page for one entity. Confirm the whole loop works end-to-end (create via admin, display via React) before touching anything else, because a broken Filament panel or broken Vite build masks everything downstream.
Two front doors, one model layer. The core pattern is that Eloquent models, policies, and form requests are shared between the Filament panel (admin) and the Inertia/React frontend (your product). Put authorization in Policies and both surfaces pick them up — Filament respects policies for resource visibility/actions, and Gate::authorize in your controllers keeps the React side honest. Don't duplicate logic in Filament's ->visible() closures and then again in controllers.
Generate, then refine. Day-to-day CRUD work is:
php artisan make:filament-resource Post --generate
php artisan make:filament-relation-manager PostResource comments comment
php artisan make:filament-widget StatsOverview --stats-overview
The --generate flag infers form/table schema from the model. Treat the output as a draft: reorder columns, add ->searchable(), ->sortable(), ->toggleable(isToggledHiddenByDefault: true). Filament's fluent API is where most dev time goes.
Split admin and product routes cleanly. Keep routes/web.php for Inertia pages and let the panel provider own /admin/*. If you need custom Filament pages (dashboards, settings), register them on the panel, not in web.php.
Inertia data flow. Share only what every page needs in HandleInertiaRequests::share() — the authenticated user, flash messages, and route helpers. Everything else should come from page props in controllers. On the React side, use the typed PageProps interface and the usePage<T>() hook; keep a single resources/js/types/index.d.ts that mirrors your shared props so TypeScript catches drift.
Forms on both sides. Filament uses its schema builder (TextInput, Select, Repeater) for admin forms; the React side typically uses useForm from @inertiajs/react (or React Hook Form + an Inertia adapter). Don't try to share form components between the two — the abstraction cost is higher than the duplication. Do share validation rules by centralizing them in Form Requests, or in the model's rules() if the codebase already does that.
Assets and two builds. Vite builds your Inertia entry (resources/js/app.tsx); Filament ships its own compiled assets. Keep the vite.config.ts input list scoped to your app (typically app.tsx and a CSS entry) — do not add Filament source paths to it. Run php artisan filament:assets if you customize a published Filament theme.
Testing. Feature-test the Inertia endpoints with $this->get('/posts')->assertInertia(fn ($page) => $page->component('Posts/Index')->has('posts.data', 10)) and test the Filament panel with Livewire-style tests (livewire(ListPosts::class)->assertCanSeeTableRecords(...)). The Filament resource is worth testing because it bypasses your controllers entirely.
Local dev loop. Two dev servers are the standard posture: npm run dev (Vite) and php artisan serve (or Sail/Valet/Herd). If you use SSR (php artisan inertia:start-ssr in a third terminal), remember the Node SSR server needs restarting after React changes in some setups — this is the #1 source of "my page looks stale" reports.
composer update to pull new upstream features; you merge them. If you care about tracking upstream, keep a .git remote pointing at the skeleton repo and cherry-pick fixes, or plan for periodic manual diffs. This is the biggest long-term cost of any starter kit, and doubly so for one with ~12 stars and no dependents — expect to be your own maintainer.composer.json before copying snippets.@tailwindcss/vite. If your Inertia frontend uses Tailwind v3 config (tailwind.config.js + PostCSS), you'll get silent style mismatches between admin and frontend. Decide early: run Tailwind v4 on both sides, or keep the Filament build isolated and don't touch its config.web guard, so an admin logged in via /login is also authenticated on /admin. If you want separate admin accounts, set a distinct guard in the panel provider — but then you'll need a separate admin provider, migration, and a canAccessPanel() implementation. Half-migrating this is a classic footgun that leads to "I can log in but see a 403."FileUpload and SpatieMediaLibraryFileUpload write to the public disk. php artisan storage:link is not run for you; on fresh deploys you'll get broken images. Add it to your deploy script.php artisan filament:clear-cached-components (or php artisan optimize:clear). Same for php artisan config:clear after touching the panel provider.getRouteKeyName() returning slug in the model so both surfaces agree.useForm behavior, deferred props, history encryption). Confirm the installed version in package.json before following any tutorial.php artisan about (verify the panel is registered) and Laravel Telescope — Filament actions fire Livewire requests, so tracing them without Telescope is painful. In production, avoid APP_DEBUG=true; Filament will leak schema information in error pages.getNavigationGroup(), getNavigationBadge(), or a policy can express your requirement. Most "I need to customize X" cases are covered by the panel provider or the policy contract, and those survive regeneration.->tenant() support is excellent but assumes a tenant_id column and a tenant model with the HasTenants contract across every resource. Don't half-enable it — enable it on day one or not at all.composer outdated and npm outdated pass, and don't assume upstream will.How can I help you explore Laravel packages today?