A Laravel 12 + Filament 4 backend that powers a curated wedding marketplace. The system lets administrators, agencies, and vendors collaborate on inquiries, bookings, and marketing assets while exposing a clean read-only API for the public website.
| Goal | Description |
|---|---|
| Centralize supply | Capture all agencies, vendors, services, and media in one authoritative database with soft-delete safety rails. |
| Empower operations | Provide Filament panels tailored for admins, agencies, and vendors, so each role can act on inquiries, availability, and promotions. |
| Feed the frontend | Deliver fast, filterable JSON endpoints for agencies and vendors so the marketing site can showcase live data. |
| Layer | Implementation | Reasoning |
|---|---|---|
| Framework | Laravel 12 (PHP 8.3) | Modern routing, queues, Eloquent ORM, first-class Sail support. |
| Admin UI | Filament 4 multi-panel (/admin, /agency, /vendor) with Filament Shield |
Accelerates CRUD, enforces role-aware permissions, gives widgets/dashboards out of the box. |
| Domain layer | app/Domain/* namespaces plus Eloquent models in app/Models |
Keeps business logic close to domain language while still leveraging Eloquent relations. |
| Database | PostgreSQL via Sail | Reliable relational storage with JSON support for flexible attributes. |
| Media | Spatie Laravel Media Library (media table) |
Unified handling for logos, banners, galleries; enforces single-file/logo collections. |
| APIs | Versioned read-only endpoints under routes/api.php (currently v1) |
Decouples public site needs from Filament; makes it easy to evolve versions later. |
| Auth | Panel auth today; Sanctum-ready for future API auth | Keeps options open for token-based access without over-engineering now. |
| Area | Highlights | Key Files |
|---|---|---|
| Users & Roles | Soft-deletable users with dependency-aware deletion, role assignments, login tracking. | app/Models/User.php, app/Filament/Resources/Users/Tables/UsersTable.php |
| Agencies | Rich profile fields, media attachments, vendor relationships, rating metrics. | app/Models/Agency.php, app/Filament/Resources/Agencies/* |
| Vendors | Category + pricing info, services, availability calendar, agency partnerships. | app/Models/Vendor.php, app/Filament/Resources/Vendors/* |
| Clients & Inquiries | Inquiry lifecycle (new → responded → booked), urgency flags, follow-up tracking, messaging. | app/Models/Client.php, app/Models/Inquiry.php, app/Filament/Resources/Inquiries/* |
| Matching & Bookings | Morph relationships for packages, bookings, reviews, FAQs that attach to agencies or vendors. | app/Models/Booking.php, app/Models/Package.php, etc. |
| Media | media migration + collections for logo/banner/gallery/documents enforce consistent storage. |
database/migrations/2025_11_23_000001_create_media_table.php |
| Public API | Read-only endpoints for agencies/vendors with filtering, sorting, pagination, media URLs. | routes/api.php, app/Http/Controllers/Api/V1/*, app/Http/Resources/* |
- Users cover admins, agencies, vendors, and clients; role logic flows through Filament resources and policies.
- Soft deletes are enforced everywhere, with guardrails in
UsersTablethat hide delete buttons when dependencies exist and deliver persistent warnings before force deletes. - Spatie Media Library allows avatars/documents to attach just like vendor logos.
- Attributes (business name, slug, location, contact, specialties, years in business) live in
app/Models/Agency. - Relationships: vendors (approved/pending/rejected), inquiries, portfolio images, packages, reviews, FAQs, bookings, tags.
- Helpers such as
incrementViewsCount()andupdateRatingStats()keep dashboard metrics accurate. - Filament resources provide search, Trashed filters, toggled columns, and scoped delete/restore/force actions.
- Vendors include pricing ranges (
min_price,max_price,price_unit), service areas, social links, arbitrary JSONattributes. - Connected to categories, owning agencies, services, event types, tags, availability slots.
- Availability helper
isAvailableOn()lets the frontend build calendars without duplicating logic. - Media collections mirror agencies for consistent UX.
- Inquiries capture event metadata, budget, urgency, multiple note channels, and timestamps for response/follow-up/closure.
- Convenience methods (
markAsResponded,recordFollowUp,close) prevent inconsistent status transitions. - Messages, bookings, vendors, and agencies all relate back to each inquiry for auditing.
- Services, packages, reviews, FAQs, and bookings rely on morph relationships so they can belong to either agencies or vendors.
- Tags offer cross-cutting categorization ("Luxury", "Destination", etc.).
- These abstractions keep the schema DRY yet flexible for future asset types.
registerMediaCollections()defines single-file vs. multi-file collections per model.- API resources expose
logo,banner,galleryURLs via Spatie helpers. - The
mediatable migration mirrors the official schema so conversions/responsive images can be enabled later without changes.
| Panel | Path | Purpose | Notable Logic |
|---|---|---|---|
| Admin | /admin |
Full CRUD across users, agencies, vendors, clients, inquiries, bookings. | Filament Shield permissions, soft-delete filters, dependency-aware deletes, dashboard widgets. |
| Agency | /agency |
Agency staff manage their vendors, respond to inquiries, maintain portfolios. | Custom AgencyPanelProvider scopes resources and branding. |
| Vendor | /vendor |
Vendors update profiles, services, availability, respond to leads. | Mirrors agency panel with vendor-specific navigation/resources. |
Why Filament?
- Rapid scaffolding with consistent UI components (tables, forms, infolists, dashboards).
- Built-in filters (search, column toggles, trashed) reduce bespoke UI work.
- Widgets put KPIs (e.g., inquiries per week) directly on panel dashboards.
Safety nets:
- Delete/force-delete actions only appear when the record lacks blocking dependencies (e.g., users tied to vendors/agencies).
- Confirmation copy explains consequences plainly and requires explicit admin confirmation.
Base URL: https://your-domain.test/api/v1
| Resource | Endpoint | Description |
|---|---|---|
| Agencies | GET /agencies |
Paginated list with filters (search, city, country, state, verified, featured, premium). |
| Agencies | GET /agencies/{slug} |
Single agency by slug; increments view count unless track_views=false. |
| Vendors | GET /vendors |
Paginated list; supports category + price filters, availability date, boolean flags. |
| Vendors | GET /vendors/{slug} |
Single vendor by slug; returns category, services, tags, media, stats. |
| Parameter | Applies to | Notes |
|---|---|---|
search |
Both | Fuzzy search across business name, description, city, country. |
city, state, country |
Both | Partial match filters for geo searches. |
verified, featured, premium |
Both | Accepts true/false; parsed into booleans. |
category_id |
Vendors | Exact match on the vendor's primary category. |
min_price, max_price |
Vendors | Numeric filters on price range columns. |
available_on |
Vendors | Y-m-d; ensures availability shows available/partially_booked. |
sort |
Both | Prefix with - for descending. Agencies: created_at, avg_rating, review_count, views_count. Vendors add min_price, max_price. |
page, per_page |
Both | Pagination (per_page capped at 50). |
track_views |
Detail endpoints | false skips the automatic view counter increment. |
GET /api/v1/agencies?city=Toronto&verified=true&sort=-avg_rating
Accept: application/json{
"data": [
{
"id": 1,
"slug": "evergreen-events",
"business_name": "Evergreen Events",
"description": "Full-service planning studio...",
"location": {
"city": "Toronto",
"country": "Canada"
},
"stats": {
"avg_rating": 4.9,
"review_count": 37,
"verified": true,
"featured": true,
"views_count": 1284
},
"media": {
"logo": "https://cdn.test/storage/.../logo.jpg",
"banner": "https://cdn.test/storage/.../banner.jpg",
"gallery": ["https://cdn.test/storage/.../gallery/1.jpg"]
}
}
],
"links": {
"first": "https://your-domain.test/api/v1/agencies?page=1"
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 1
}
}GET /api/v1/vendors/floral-boutique?track_views=false
Accept: application/json{
"data": {
"id": 5,
"slug": "floral-boutique",
"business_name": "The Floral Boutique",
"category": {
"id": 2,
"name": "Florist"
},
"pricing": {
"min_price": 500,
"max_price": 3000,
"price_unit": "event"
},
"location": {
"city": "Vancouver",
"country": "Canada"
},
"services": [
{"id": 11, "name": "Bouquet design", "price": 250}
],
"media": {
"logo": "https://cdn.test/.../logo.png",
"gallery": ["https://cdn.test/.../1.png"]
},
"stats": {
"avg_rating": 4.8,
"review_count": 22,
"views_count": 194,
"verified": true
}
}
}- Lists return Laravel pagination payloads (
data,links,meta). - Resources expose nested dictionaries (
location,contact,social,stats,media) so the frontend can read structured data without extra transforms. - When relationships are eager loaded (
tags,services), the resources automatically append them. - All API routes share
throttle:120,1, limiting each IP to 120 requests/minute. Adjust inroutes/api.phpif traffic requires more headroom.
- Database: PostgreSQL via Sail. Run
./vendor/bin/sail artisan migrate --seedto bootstrap data. - Media: Stored via Spatie Media Library under
storage/app/public, exposed viapublic/storage. Collections includelogo,banner,gallery,portfolio,documents. - Caching: Not enabled yet, but architecture leaves room for query/response caching when the frontend traffic grows.
cp .env.example .env
./vendor/bin/sail up -d
./vendor/bin/sail composer install
./vendor/bin/sail artisan key:generate
./vendor/bin/sail artisan migrate --seedThis project is easiest to run on Windows through WSL2. The repo uses Laravel Sail, Bash-style scripts, and a Docker-based PostgreSQL stack, so running it inside Ubuntu on WSL avoids most Windows path and shell issues.
- Install WSL2 with Ubuntu 24.04 or 22.04.
- Install Docker Desktop and enable WSL Integration for the Ubuntu distro.
- Install Git inside WSL.
Store the repo somewhere under /home/<your-user> rather than under /mnt/c/... for better performance.
sudo apt update && sudo apt upgrade -y
sudo apt install -y git
cd ~
git clone <your-repository-url> wedding-platform
cd wedding-platform/wedding-platform-backendcp .env.example .envUpdate these values in .env before starting the containers:
APP_URL=http://localhost
DB_CONNECTION=pgsql
DB_HOST=pgsql
DB_PORT=5432
DB_DATABASE=wedding_platform
DB_USERNAME=sail
DB_PASSWORD=password
QUEUE_CONNECTION=database
CACHE_STORE=database
SESSION_DRIVER=database
APP_PORT=80
VITE_PORT=5173
FORWARD_DB_PORT=5432
FORWARD_REDIS_PORT=6379
FORWARD_MAILPIT_PORT=1025
FORWARD_MAILPIT_DASHBOARD_PORT=8025./vendor/bin/sail up -d
./vendor/bin/sail composer install
./vendor/bin/sail npm install./vendor/bin/sail artisan key:generate
./vendor/bin/sail artisan migrate --seed
./vendor/bin/sail artisan storage:linkKeep this running in a separate WSL terminal:
cd ~/wedding-platform/wedding-platform-backend
./vendor/bin/sail npm run dev- Main app / default URL:
http://localhost - Admin panel:
http://localhost/admin - Agency panel:
http://localhost/agency - Vendor panel:
http://localhost/vendor - Mailpit dashboard:
http://localhost:8025 - Vite dev server:
http://localhost:5173
./vendor/bin/sail artisan test
./vendor/bin/sail artisan migrate:fresh --seed
./vendor/bin/sail artisan optimize:clear
./vendor/bin/sail down- Run project commands from WSL Ubuntu, not PowerShell, for the smoothest experience.
- The helper script in switch-env.sh is a Bash script and should also be run from WSL.
- If port 80 is already in use on Windows, change
APP_PORTin.env, then reopen the app on that port. - If Docker volumes or file watching feel slow, confirm the repo is inside the WSL filesystem, not on the Windows drive.
- If Docker commands fail inside WSL, open Docker Desktop and verify Settings → Resources → WSL Integration is enabled for the distro.
Helpful commands:
./vendor/bin/sail artisan make:filament-resource Vendor– scaffold additional resources../vendor/bin/sail artisan migrate:fresh --seed– reset the DB while iterating quickly../vendor/bin/sail artisan storage:link– expose media assets.
The project includes a comprehensive test suite covering all core models and their relationships, business logic, and edge cases.
# Run all tests
./vendor/bin/sail artisan test
# Run with verbose output
./vendor/bin/sail artisan test --verbose
# Run specific test file
./vendor/bin/sail artisan test tests/Unit/Models/VendorTest.php
# Run tests with coverage (requires Xdebug)
./vendor/bin/sail artisan test --coverage| Test Suite | Tests | Description |
|---|---|---|
AgencyTest |
17 | Agency relationships, rating stats, view counts, subscriptions, soft deletes |
BookingTest |
20 | Booking lifecycle, payment tracking, status transitions, scopes |
ClientTest |
16 | Client profiles, wedding calculations, planning status, preferences |
InquiryTest |
19 | Inquiry lifecycle, status transitions, messaging, urgency flags |
MessageTest |
12 | Message delivery, read status, attachments, system messages |
UserTest |
12 | User types, relationships, soft deletes, authentication |
VendorTest |
19 | Vendor profiles, availability, pricing, agency relationships |
Total: 117 tests with 190+ assertions
| Check | Command |
|---|---|
| PHPUnit tests | ./vendor/bin/sail artisan test |
| Pint / code style | ./vendor/bin/sail pint |
| PHPStan (if enabled) | ./vendor/bin/sail vendor/bin/phpstan analyse |
| Static analysis / IDE helpers | ./vendor/bin/sail artisan ide-helper:generate |
Aim to keep builds green before merging; run relevant tests whenever you touch domain logic or Filament resources.
The project includes comprehensive seeders that populate the database with realistic Indian wedding platform demo data for development and showcasing.
# Seed demo data (safe to run multiple times - idempotent)
./vendor/bin/sail artisan db:seed
# Fresh database with demo data
./vendor/bin/sail artisan migrate:fresh --seed| Entity | Count | Description |
|---|---|---|
| Categories | 65 | Wedding service categories with hierarchical structure |
| Event Types | 16 | Indian wedding types (Hindu, Muslim, Sikh, Christian, etc.) |
| Users | 57 | 2 admins, 8 agency owners, 31 vendors, 15 clients |
| Agencies | 8 | Wedding planning agencies across major cities |
| Vendors | 20 | Photographers, caterers, decorators, venues, etc. |
| Clients | 15 | Couples with realistic wedding details and budgets |
| Inquiries | 54 | Realistic conversation threads |
| Bookings | 62 | Various statuses (pending, confirmed, completed) |
| Reviews | 8 | Realistic reviews with ratings |
| Messages | 143 | Inquiry conversation messages |
| Services | 71 | Vendor service offerings |
| Packages | 84 | Agency and vendor packages |
| Role | Password | |
|---|---|---|
| Admin | admin@shaadimandap.com |
password |
| Agency | vikram@dreamshaadi.in |
password |
| Vendor | arjun@pixelperfect.in |
password |
| Client | aarav.gupta@gmail.com |
password |
| Seeder | Purpose |
|---|---|
CategorySeeder |
Wedding vendor categories (Photography, Venues, Catering, etc.) |
EventTypeSeeder |
Indian wedding event types |
DemoUserSeeder |
Admin, agency, vendor, and client user accounts |
DemoAgencySeeder |
Wedding planning agencies with packages and FAQs |
DemoVendorSeeder |
Vendors with services, packages, and realistic profiles |
DemoClientSeeder |
Couples with wedding details, budgets, and preferences |
DemoInquirySeeder |
Inquiry conversations between clients and vendors/agencies |
DemoBookingSeeder |
Bookings with payment details and various statuses |
DemoReviewSeeder |
Reviews with ratings and detailed feedback |
All seeders are idempotent - they check for existing data before inserting, making them safe to run multiple times without creating duplicates.
- Configure DB (
DB_*), queue (QUEUE_CONNECTION), mail (MAIL_*), storage (FILESYSTEM_DISK=public) in.envacross environments. - Always run
./vendor/bin/sail artisan storage:linkafter provisioning so media URLs work. - Queues: inquiries, notifications, and media conversions can move to queues—set
QUEUE_CONNECTION=databaseby default. - Monitoring: Laravel
/uphealth route is enabled for uptime checks.
- Expand public API – expose clients, inquiries (read-only), availability calendar endpoints, search suggestions.
- Authenticated API – issue Sanctum tokens so agencies/vendors can use the same endpoints outside Filament.
- Caching & performance – add response caching + ETags once marketing traffic scales.
- Analytics – stream view counts/events to a warehouse or queue for deeper dashboards.
- Automations – schedule follow-up reminders for inquiries that stay unanswered for N days.
Built with ❤️ by the Wedding Platform team. Contributions welcome—open an issue or PR with context about the panel or API you’re touching so we can review quickly.