LaravelStarter

ezehstart — Laravel Starter Template

By ezehky

Ezeh Start is a Laravel and Livewire starter kit with built-in authentication, image and video libraries, a blog, a transaction ledger, role-based workspaces, data tables, an admin panel, email marketing, and legal pages, plus a written set of code style conventions.

Explore the design

Compare the page layouts and mobile experience. Open any screenshot for a closer look.

2 previews
Desktop homepage1 / 2
Desktop captureTop of page

Actual screenshot captured by the server browser.

All pages & views 2

Screenshots show visual appearance; interactive behavior may differ.

Recorded 2026-10-05View source

What stands out

A quick read of the recorded project description.

01

Built-in authentication flows including password login, code-based reset, email verification, passwordless login, TOTP two-factor, recovery codes, social login, and passkeys

02

The image and video libraries share the same management shape; image deletion is protected by foreign keys from a usage table, and videos are limited to a whitelist of providers

03

The blog uses the tiptap editor, supports inserting content from the media library, polymorphic categories and tags, scheduled publishing, and HTML sanitization

04

The transaction ledger stores integer minor currency units; balances are derived from confirmed records under row locks, and administrators can review and make manual adjustments

05

Roles are data rows creatable in the admin panel, assigned in any number via a pivot table, with permissions merged by taking the highest value

06

Account deletion uses a scheduled window mechanism with reminder emails, a signed cancellation link, and a daily cleanup task

Template Details

Ezeh Start is a Laravel + Livewire starter kit aimed at projects that need a complete admin and account system from day one. It pre-builds common modules such as authentication, account security, content management, transaction records, and site configuration, and constrains how new code is written with a written "house style".

Authentication includes password login, registration, password reset via email code, six-digit email verification, and passwordless code-based registration and login flows. Email codes have a two-attempt limit and a 60-second resend interval. Login rate limiting is based on both email and IP address, and supports configurable password strength, password history checks, TOTP two-factor authentication, recovery codes, remember-device tokens, Socialite social login, and Cloudflare Turnstile captcha, all controlled by site configuration switches that determine whether routes are open.

For content and media, the image library supports bulk upload, a folder tree, search by name, title renaming without changing the storage URL, and three visibility levels: private, role-visible, or public; deletion is protected by foreign key constraints from the image_usages table. The video library stores references as "provider + provider id", rebuilds the player URL on each render, and only allows YouTube and Vimeo. The blog uses the tiptap editor, can insert images and videos from the media library, has polymorphic categories and tags, supports scheduled publishing, featured and archived posts, and sanitizes HTML on write.

For accounts and permissions, roles are data rows created by administrators in the admin panel rather than enums; any number of roles can be assigned via the role_user pivot table, and permissions merge by taking the highest permission. users.user_type is a fixed login workspace (Admin and Member), each with its own middleware and route files. The transaction ledger uses integer minor currency units; balances are derived from confirmed records under row locks rather than stored directly, and administrators can review and make manual adjustments.

Admin features include a dashboard, admin and member lists, a roles page, a searchable activity log, a single-account view, a deleted accounts page, blog management, the transaction ledger and review queue, and site configuration across four screens. The member workspace includes a dashboard, profile, preferences, security settings, personal media library, transaction history, data download, and account deletion.

For account lifecycle, deletion requests are first scheduled and emailed, with five-day and one-day reminders, and a signed link in the email can cancel deletion; after the window ends, a daily task performs anonymization or permanent deletion. Unverified accounts are warned and then removed, and long-inactive members receive re-engagement emails, both with independent switches and day configurations.

Other cross-cutting features include audit trails, database notification types stored as data rows, seed data for 250 countries, confirmation modals before destructive actions, WebAuthn passkeys based on spatie/laravel-passkeys, a block-based email template builder and marketing campaigns, an announcement mechanism that uses user notification switches instead of a subscription table, currency exchange rates and display conversion, and multilingual support based on LocaleEnum and lang/{code}.json.

On limitations, the template's full documentation lives on a separate ezehstart-doc site; the legal policies in the demo seed data are boilerplate text and do not constitute legal advice; published policy versions can only be superseded by a new version and cannot be edited directly; scheduled tasks require a running scheduler; and Turnstile captcha requires both a site key and a secret key to take effect.

LaravelStarter kit

Is it right for your project?

Use Cases

  • Building a Laravel project quickly with a complete admin panel, account system, and content management features
  • Applications that need image and video libraries, a blog, a transaction ledger, and email marketing modules in place at the same time
  • Platforms that need a multi-role admin panel, a member workspace, and fine-grained permission control
  • Projects that need automated lifecycle management such as scheduled account deletion, unverified account cleanup, and re-engagement emails
  • International-facing applications that need multiple languages, multiple currencies, and configurable site settings

Suitable For

  • Teams familiar with Laravel and Livewire who want to start from a mature starter kit
  • Projects that need built-in common modules such as authentication, media libraries, a blog, and transaction records
  • Platforms that need dual admin and member workspaces plus a role and permission system
  • Applications that need account lifecycle automation and email marketing capabilities

Getting started & customization

Use these recorded setup notes alongside the repository instructions for your chosen version.

  1. 1

    Run composer setup to complete installation, key generation, migrations, npm install, and build, then use composer dev to start the server, queue, and Vite together

  2. 2

    Run php artisan db:seed to generate roles, notification types, countries, site configuration, and an administrator account; the default admin is [email protected] / password and must be changed before production use

  3. 3

    For demo data, run php artisan db:seed --class=DemoSeeder separately; its legal policies are boilerplate text, not legal advice

  4. 4

    Seven commands depend on the scheduler, including account deletion reminders and cleanup, unverified account cleanup, re-engagement emails, scheduled posts and email campaigns, and activity log cleanup

  5. 5

    Turnstile captcha requires both TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY; LARAVEL_PDF_DRIVER defaults to dompdf and requires no extra installation

Read repository instructions

License & source material

Usage conditions & limitations

Free to use · keep license notice

This entry covers the free version under the MIT license in the public repository; the free scope is the code of that version and does not mean external services or third-party assets are free.

Must comply with when using

  • You may use, modify, commercialize, and distribute the code of this version for free.
  • When distributing copies or substantial portions of the code, retain the original author's copyright notice and the full MIT license notice.
  • The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.

Additional costs & items to verify

  • Demo images, fonts, icons, and other third-party assets must be checked against their own licenses and cannot be judged solely by the code's MIT license.
  • External services such as domains, hosting, databases, payments, or AI may incur separate charges.
  • Full documentation lives on a separate ezehstart-doc site; that companion documentation site must be obtained separately to consult installation, configuration, extension, and deployment instructions.
  • The legal policies published by DemoSeeder are boilerplate text that only demonstrates the shape of a policy; they do not constitute legal advice and cannot be used directly as a compliance basis.
  • Published policy versions cannot be edited directly; they can only be superseded by drafting and publishing a new version (such as v2.0) in the admin panel.
  • Seven commands depend on the scheduler; production deployments must keep the scheduler running, otherwise account cleanup, scheduled publishing, and email campaigns will not execute.
  • Cloudflare Turnstile captcha requires both TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY environment variables; if either is missing, the switch has no effect.
  • Social login depends on Laravel Socialite and requires configuring application credentials for each third-party provider before use.
  • Image upload optimization depends on spatie/laravel-image-optimizer and only takes effect in environments where its binaries are installed.
  • Machine translation via lang:translate is for development environments only and must never be run at runtime.
  • The "Ezeh Start" name and logo are trademarks, and the MIT license does not grant trademark rights; naming a product, branch, company, domain, or paid service with this name requires authorization, while only the phrase "Built with Ezeh Start" may be used directly.
  • The copyright notice must be retained when distributing copies of the kit's source code.
View Original Text Basis

Permission is hereby granted, free of charge

Original License Text

The full documentation (installation, configuration, every feature, extending the kit and going to production) is the companion `ezehstart-doc` site.

Original README

The policies it publishes are boilerplate showing the *shape* of a policy, **not legal advice**

Original README

a published version is superseded rather than edited, so replacing it means drafting v2.0 from Admin → Site configuration → Policies and publishing that.

Original README

Seven commands run on the schedule, so a live install needs the scheduler running:

Original README

Two optional environment keys: `TURNSTILE_SITE_KEY` and `TURNSTILE_SECRET_KEY` for the captcha — the switch does nothing without both

Original README

Social sign-in through Socialite,

Original README

Uploads run through `spatie/laravel-image-optimizer` where its binaries are installed.

Original README

`lang:translate` machine-translates them in development — never at runtime.

Original README

"Ezeh Start" and its logo are trademarks of Kingsley Uchenna Ezeh, and the MIT License doesn't grant them. "Built with Ezeh Start" is always fine; naming your product, fork, company, domain or paid service after the kit needs permission.

Original README

Keep the copyright notice in copies of the kit's source.

Original README
https://github.com/ezehky/ezehstart/blob/main/LICENSEhttps://github.com/ezehky/ezehstart/blob/main/README.md

Compiled by DeepSeek based on repository license and README ·2026-10-05. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.

Project checks & description sources

Template Information

Source platforms
GitHub
Documentation and maintenance reference score
More documented · 83 / 100
Technologies
Laravel
Website type
Starter
How this score is calculated

Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.

What to verify for this project

Repository update recorded
2026-10-05
Screenshot last checked
2026-10-05

A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.

The catalog identifies Laravel as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.

Use a selection guide →

How this description was prepared

AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.

Review declaration: [email protected] · 2026-10-06

Inspect the recorded source material

SHA-256: 65afb764aa5566532ef0417b0d8d285f11c6d068237e2694196eff47d91ce993

2026-10-05T18:39:01.864Z

Source file / repository
# Ezeh Start

A Laravel 13 + Livewire 4 starter kit with the batteries a project actually needs on
day one, and a written house style that keeps everything added after day one looking
like it was there from the start.

## What ships

**Authentication** — password sign-in, registration, password reset by emailed code,
email verification by six-digit code, and a passwordless flow that both registers and
signs in from a code. Every emailed code carries the same two bounds: five wrong
guesses destroy it, and another cannot be asked for inside 60 seconds. An expiry alone
is not a bound — six digits is a million guesses wide, and at an unlimited guess rate
the whole space fits inside the window. Password reset never says whether an address is
registered: every well-formed address gets the same reply, and only a real account gets
a code.

**Sign-in hardening** — a login throttle keyed on the email *and* the address together,
so nobody can lock out an address they know. Configurable password strength and a
password-history check that refuses one this account has already used. TOTP two-factor
with a QR code rendered locally, single-use recovery codes that download as a file, and
a "remember this device" token stored only as a hash. Social sign-in through Socialite,
matching on the provider id first so somebody who changes their Google email is not
stranded with a second account, and refusing to disconnect the last way into an account.
A Cloudflare Turnstile captcha on the guest forms, per form rather than in front of the
whole site. Every one of these is a site-config switch that closes its route, not just
its button.

**Image library** — upload several at once into a folder tree, search by name, rename
the title without ever changing the stored URL, and set who can see each image: private,
a role, or everybody. Deletion is guarded by an `image_usages` table with a restricting
foreign key, so an image on a published post refuses to go rather than leaving a broken
picture behind. Members have a configurable quota; administrators do not. Uploads run
through `spatie/laravel-image-optimizer` where its binaries are installed.

**Video library** — the same again for embeds, and deliberately the same shape. A row is
a *reference* — a provider and the provider's own id — never a file and never a URL, and
the player URL is rebuilt from the pair on every render. `VideoProviderEnum` is an
allowlist (YouTube, Vimeo); an iframe pointing anywhere else is dropped rather than
cleaned, because there is no version of it we can vouch for.

**Blog** — posts written in a tiptap editor that inserts images and videos straight from
the libraries, with polymorphic categories and tags: one `categories` table serves every
kind of category, separated by `CategoryGroupEnum`, so products can reuse it later
without a second table and a second admin screen. Posts can be scheduled, featured and
archived, and the scheduler publishes them to the minute and tells the subscribers. The
HTML is sanitised on the way in. A seeded **Author** role narrows an account to the
posts it wrote and gives it a public byline. Public index and post pages with related
reading.

**Transaction ledger** — `transactions` with gateway, meta, evidence, balance and charge
rows alongside. Balances are derived from confirmed rows rather than stored, under a row
lock, so a balance can never silently disagree with the ledger that explains it. Money
is integer minor units throughout. Administrators get a review queue and a manual
adjustment that records who moved what and why.

**Roles and workspaces** — a role is a row an administrator creates from the dashboard,
not an enum case, and it divides up the admin workspace only. An admin carries **any
number** of them through the `role_user` pivot, and their gate maps merge with the
highest access winning each key — so a second role only ever widens what somebody
reaches, and the personal override on top is the only thing that can narrow it.

**Type is not role.** `users.user_type` is the workspace an account signs in to, fixed
in code. Two of them, each behind its own middleware:

| Workspace | URL prefix | Route name | Route file |
| --- | --- | --- | --- |
| Admin | `/app-splash` | `admin.` | `routes/admin.php` |
| Member | `/app` | `user.` | `routes/user.php` |
| Public + auth | `/` | *(none)* | `routes/web.php` |

**Data tables** — one trait behind every listing: row selection, a bulk bar, a column
manager each account keeps for itself, sorting, a date range, and the whole listing as
CSV, XLSX or PDF. Imports read the same two spreadsheet formats, one row at a time, and
a bad row is reported rather than allowed to abandon the run. What can leave is what the
account can already see — the gate and the column list decide the file.

**Admin workspace** — dashboard with live metrics, sparklines and a "waiting on you"
queue; admin and member listings with search, filters and exports; a roles page; a
searchable activity log with an optional retention window; a single-account view; a
deleted-accounts screen; and a manage-roles modal with guards (you cannot revoke your
own admin role, or the last one). Blog posts, categories and tags. The transaction
ledger and its review queue. Site configuration across four screens — branding, security
switches, preferences, social handles, the legal pages, the FAQs and notification types
— plus a raw JSON editor for the key no screen has grown a field for yet.

**Member workspace** — dashboard with a next-steps checklist, profile, preferences,
security settings (password, email, sessions, two-factor, connected accounts), their own
image and video libraries, their transaction statement, a download of everything held
about them, and account deletion.

**Account deletion is a window, not an event** — asking to be deleted schedules the
account and mails the date. Reminders go at five days and one day, a signed link in the
email cancels without signing in, and only when the window runs out does the nightly
sweep act: anonymize where there is history worth keeping, remove outright where there is
not. Anonymized rows are soft-deleted, so they surface only on **Deleted accounts**,
where they can be restored or purged for good.

**Accounts that look after themselves** — an account that never verifies its address
is warned once (day 2 by default) and removed after a grace period counted from the
warning (day 3), never while verification is off and never with ledger rows behind it.
A member not seen for 30 days gets one "we missed you", and another only after they have
been back. Both are switches with their own day counts on the Security screen, and both
emails are template-builder slots.

**Impersonation** — an administrator views the site as a member, because "the button
does not work" is unanswerable from the outside. Never admin to admin, the real identity
in the session rather than in a link, both ends logged as the administrator, an hour's
expiry, and every account-altering screen closed while it runs.

**Legal pages and consent** — `/terms`, `/privacy` and `/cookies`, written in markdown
from the admin and served as plain crawlable pages with a contents sidebar. A policy is
versioned: published text is superseded by a new draft rather than edited, and the old
version stays readable at `?version=`, because a consent record points at it. Terms and
privacy are marked as requiring consent, so registration asks for it and records the
version accepted, with timestamp, IP and user agent. Publish a replacement and everyone
is outstanding again until they accept it.

**Public site** — a landing page with an FAQ section whose questions and markdown
answers are editable from the admin, and a footer that links the legal pages straight
off the enum.

**Cross-cutting** — an audit trail that records what changed and what it changed from,
database notifications whose *types* are rows rather than code, so a new one can be
added without a deploy and every account picks up a switch for it on their next visit. A
site configuration editable from the admin rather than from a deploy, 250 countries
seeded from a file in the repository rather than a network call, and a styled
confirmation modal in front of every destructive write.

**Passkeys** — WebAuthn through `spatie/laravel-passkeys`, behind `security.passkeys`.
The package does the cryptography; `PasskeyService` does the signing in, so the status
check, the audit trail and the login alert run exactly as they do for a password.

**Email marketing** — a block-based template builder with saved headers, footers and
calls to action; campaigns sent to chosen addresses, every account, or everybody
subscribed to a notification type; test sends; scheduling in the sender's time zone with
daily-to-quarterly recurrence; and a sent history. `{{token | default: "…"}}` resolves
the same way in a subject as in a block. A builder template can also stand in for a
system mailable (`SystemEmailEnum`, `WithSystemTemplate`); unassigned, the Blade view is
sent as before.

**Newsletter and announcements** — no subscribers table: an address is a `users` row
and the subscription is the `ANNOUNCEMENTS` switch it already carries. The public popup
shows the latest live announcement, falling back to the plain sign-up.

**Currencies** — rates against one default. The ledger is stored in the default and
`kMoneyFormat()` converts for the viewer, so changing somebody's currency never touches
a stored row.

**Languages** — `LocaleEnum` plus `lang/{code}.json`, a case offered only once its file
exists. `lang:extract` collects the strings, and `lang:translate` machine-translates
them in development — never at runtime.

## Documentation

The full documentation (installation, configuration, every feature, extending the kit and
going to production) is the companion `ezehstart-doc` site. Run `npm install && npm run dev`
in that folder.

## Getting started

```bash
composer setup     # install, key, migrate, npm install, npm run build
composer dev       # server + queue + vite together
```

Then seed the roles, the notification types, the countries, the site configuration and
an admin:

```bash
php artisan db:seed
```

That creates `[email protected]` / `password`. **Change it** in
`database/seeders/UserSeeder.php` before this becomes a real project.

For a dashboard with something in it — invented people, a ledger, posts, FAQs, and v1.0
of the three legal pages — there is a separate seeder, deliberately not part of the one
above:

```bash
php artisan db:seed --class=DemoSeeder
```

Run it as often as you like: every seeder under it matches on a natural key, so a second
run refreshes rather than doubles. The policies it publishes are boilerplate showing the
*shape* of a policy, **not legal advice** — and a published version is superseded rather
than edited, so replacing it means drafting v2.0 from Admin → Site configuration →
Policies and publishing that.

Seven commands run on the schedule, so a live install needs the scheduler running:
account deletion reminders and the deletion sweep daily, the unverified-account sweep
and the "we missed you" reminders daily, scheduled posts and email campaigns every
minute, and the activity-log prune daily (which does nothing until somebody sets a
retention window). Each takes `--dry-run`.

Two optional environment keys: `TURNSTILE_SITE_KEY` and `TURNSTILE_SECRET_KEY` for the
captcha — the switch does nothing without both — and `LARAVEL_PDF_DRIVER`, which is
`dompdf` and needs nothing installed.

## Working on it

```bash
php artisan test --compact               # the suite
php artisan test --compact --filter=X    # one file or one test
vendor/bin/pint --dirty                  # after touching any PHP
vendor/bin/phpstan analyse --memory-limit=1G
composer test                            # all three, as CI runs them
```

## The house style

This kit is opinionated, and the opinions are written down in **`.agents/my-skills/`** —
44 files covering where code goes, how it is named, and what this project deliberately
does not use. Start at [`agent.md`](.agents/my-skills/agent.md), finish at
[`checklist.md`](.agents/my-skills/checklist.md), and use
[`README.md`](.agents/my-skills/README.md) as the index.

AI agents get the same rules automatically: [`CLAUDE.md`](CLAUDE.md) orients a session,
[`AGENTS.md`](AGENTS.md) carries the Laravel Boost guidelines, and the `house-style`
skill in `.claude/skills/` (mirrored to `.agents/` and `.github/`) routes into the
library on its own.

The short version:

- Every screen is a Livewire single-file component at
  `resources/views/pages/**/⚡name.blade.php`, routed with `Route::livewire()`.
  There is no `app/Livewire`, and no `render()` method.
- Every status is an enum using `WithEnumHelpers`, with one `is{CASE}()` per case.
- Every model is `#[Unguarded]` with a `casts()` method and `#[Scope]` scopes.
- Business logic lives in a `#[Singleton]` service, resolved with `app()`.
- Every admin write is logged through `ActivityLogService`.
- Every action button is gated twice: `<x-dashboard.gate.button>` hides it and the
  method behind it re-checks with `kGate()`. Hiding a control is a courtesy; the method
  check is the boundary.
- Every destructive action confirms through `<x-dashboard.confirm-modal>`, never
  `wire:confirm` — the browser dialog cannot be styled, cannot carry a consequence, and
  is suppressed outright in some in-app browsers.
- There is no `app/Actions`, `app/Repositories`, `app/Jobs`, `app/Events`,
  `app/Policies`, or `app/Http/Requests` — each has a file in the library explaining
  what this project does instead.

## Stack

Laravel 13 · PHP 8.3+ · Livewire 4 · Flux UI free v2 · Tailwind v4 · Alpine · Pest 5 ·
Pint · Larastan.

## Releases

[`CHANGELOG.md`](CHANGELOG.md) records what changed in each version, and what an
existing project has to do to take it.

## License and trademark

The code is open source under the [MIT License](LICENSE). Use it, change it, and sell
what you build with it. Keep the copyright notice in copies of the kit's source.

The **name** is a different matter. "Ezeh Start" and its logo are trademarks of Kingsley
Uchenna Ezeh, and the MIT License doesn't grant them. "Built with Ezeh Start" is always
fine; naming your product, fork, company, domain or paid service after the kit needs
permission. [`TRADEMARK.md`](TRADEMARK.md) has the details. It's adapted from the
[Cachet trademark policy](https://cachethq.io/trademark).

The legal pages and policies the kit *serves* (terms, privacy, cookies, and the ones
`DemoSeeder` publishes) are placeholders that show the shape of a policy. They're not
legal advice, and shipping the tools for consent and deletion doesn't by itself make an
application compliant with any law.

## Adding a third workspace

Three files and two `match` arms:

1. `app/Http/Middleware/{Type}Middleware.php` — a copy of `UserMiddleware` with the new
   enum case.
2. `routes/{type}.php`.
3. A route group in `bootstrap/app.php`.
4. The case in `UserTypeEnum`, then the `match` in
   `UserService::middlewareGeneralCheck()` and the branch in
   `WithAuthWorker::userDashboardRedirect()`. Both are exhaustive, so PHP will tell you
   if you miss one.
Report a correction

Explore similar templates

Compare previews and descriptions within the same stack and category.