v1.0 Dashboard Public Profile GitHub
✅ Complete (Core) Phase 18

Phase 18 — Public Business Profile Pages

Every tenant automatically gets a public-facing mini-website at /p/{slug} — like Google My Business + Practo + Fresha, but AI-powered and live-synced with their KaiVox dashboard.

What It Does

The public profile is a standalone web page that customers (end-users of the business) can visit to see business details, view services, read FAQs from the Knowledge Brain, see staff/doctors, check opening hours, read reviews, and initiate contact. The profile is automatically created when first visited — no manual setup required by the tenant.

Profile URL

Every tenant gets one URL format: https://kaivoxai.com/p/{slug}
Example: https://kaivoxai.com/p/citycareclinic
No subdomains, no custom domains in v1 — one consistent format.

Key Routes

URLAuth?Description
GET /p/{slug}❌ NonePublic profile page — no login required for visitors
GET /settings/profile✅ AuthProfile settings editor (tenant dashboard)
POST /settings/profile✅ AuthSave profile settings
DELETE /settings/profile/cover✅ AuthRemove cover photo
POST /settings/profile/reviews✅ AuthAdd a manual review
POST /settings/profile/reviews/{id}/approve✅ AuthApprove a review for display
DELETE /settings/profile/reviews/{id}✅ AuthDelete a review

Key Files

TypePath
Controllerapp/Http/Controllers/PublicProfileController.php — GET /p/{slug}
Controllerapp/Http/Controllers/BusinessProfileController.php — settings CRUD
Modelapp/Models/BusinessProfile.php
Modelapp/Models/Review.php
Tablebusiness_profiles — tenant_id, cover_photo, gallery (JSON), social_links (JSON), seo_title, seo_description, is_public, announcement_text, announcement_expires_at, whatsapp_number, website_url, maps_embed_url
Tablereviews — tenant_id, customer_id, rating (1–5), body, reviewer_name, is_verified, is_approved, source (manual/post_call)
Viewresources/views/public/profile.blade.php — self-contained HTML (no layouts.app)
Viewresources/views/settings/profile.blade.php — tenant settings tab

Public Profile Sections

SectionData Source
Sticky topbar — Call AI + Book Now CTAsTenant phone number
Cover photo + brand colorbusiness_profiles.cover_photo, CSS custom property
Open/Closed status dotWorking hours (live check at render time)
Contact row (phone, WhatsApp, email, website, address)Tenant + business_profiles
Social links (FB, IG, X, LinkedIn, YouTube)business_profiles.social_links JSON
Announcement banner (auto-hides when expired)business_profiles.announcement_*
Services catalog (duration + price)services table (active only)
Staff/team grid with "Book" buttonstaff table (active only)
Industry-specific sectionsTenant's active industry pack slug
FAQ accordionknowledge_items where category = faq (active only)
Reviews with star ratingsreviews where is_approved = true
Google Maps embedbusiness_profiles.maps_embed_url
Opening hours (today highlighted)working_hours table
Upcoming closuresholidays table (next 30 days)
KaiVox powered-by badgeAlways shown (branding)

Industry-Specific Sections

Automatically shown based on the tenant's active industry pack:

PackExtra Section
medical / dentalEmergency contact banner ("Dental emergency? Call now")
mental_healthCrisis protocol section with iCall/Vandrevala helplines, confidentiality note
legal"Free consultation available" badge on attorney cards
fitness"Join free trial" CTA button
home_servicesEmergency Callout button highlighted prominently

Profile Settings (Tenant Editor)

Tenants configure their public profile at Settings → Public Profile:

  • Profile URL banner with copy-link button and live/hidden badge
  • Visibility toggle (public/hidden)
  • Cover photo upload (stored in storage/app/public/covers/) + remove
  • Tagline and description
  • Contact links: WhatsApp number, website URL
  • Social links: Facebook, Instagram, X, LinkedIn, YouTube
  • Announcement banner with expiry datetime
  • SEO title and meta description
  • Google Maps embed URL
  • Reviews management sidebar: add manual review, approve/hide, delete

Auto-Create Profile

When PublicProfileController receives a request for /p/{slug} and the tenant has no business_profiles record, it creates a default one with is_public = true automatically. Tenants do not need to explicitly create their profile — it exists from day one.

What's Complete

  • GET /p/{slug} public profile page — no auth required
  • Auto-creates BusinessProfile if missing on first visit
  • Self-contained view (no layouts.app dependency)
  • Dynamic brand color from tenant via CSS custom property
  • All profile sections wired to live tenant data
  • Industry-specific sections (emergency, crisis, consult, trial, callout)
  • FAQ accordion from Knowledge Brain (category=faq)
  • Reviews with approval workflow
  • Profile settings editor in tenant dashboard
  • Visibility toggle (public/hidden)
  • "Public Profile" nav item in sidebar (Settings section)
  • BusinessProfile model with accessors: cover_photo_url, gallery_urls, has_active_announcement
  • Review model with accessors: display_name, stars_html, source_label

What's Deferred

  • Gallery photo upload (multiple images)
  • Real-time booking widget (embedded slot picker without calling)
  • "Leave your number" missed-call lead capture form
  • Automatic review requests post-call via SMS link
  • Profile analytics (view count, call clicks, booking clicks)
  • Google Business Review import