Professional Marketplace

The platform includes a public marketplace where professionals (architects, designers, consultants, etc.) can publish profiles, list services, display skills, and be discovered by others.


Routes

Route Component Access
/discover DiscoverPage All authenticated users
/u/:userId PublicProfilePage Public (unauthenticated too)

Profile Visibility

Profiles are opt-in public. The user_profiles.is_public boolean controls visibility:

Users toggle this in their profile settings (ProfileTab).


Profile Fields

Stored in user_profiles table:

Field Type Description
full_name varchar Display name
company text Company or studio name
bio text Short personal/professional description
avatar_url text Profile photo URL
location text City, country, or region
website_url text External website link
professional_type enum Role classification (see below)
is_public boolean Controls public visibility
services text[] Legacy simple service name list
services_detail jsonb Rich service objects (preferred, see below)
skill_tags text[] Free-form skill/expertise tags
preferred_factories jsonb Array of { name, country? } factory references
featured_moodboard_id uuid FK to moodboards — pinned to profile top
profile_views integer Incremented on each public profile view via increment_profile_views() RPC

Professional Types (enum)

designer | interior_designer | architect | manufacturer |
brand | supplier | sourcing_agent | consultant | other

Services

Services are stored in two columns for backwards compatibility:

ServiceItem structure

interface ServiceItem {
  id: string;
  name: string;
  description?: string;
  price?: string;
  previous_work?: { title: string; url?: string }[];
}

On the public profile, if services_detail is populated it takes precedence over services. Each service card has:


Hire Me Flow

Visitors can contact a professional directly from their public profile.

How it works

  1. Visitor clicks Hire Me (global) or Hire on a specific service card
  2. HireMeModal opens with optional service pre-selected
  3. Visitor fills in name, email, message, and optionally selects services
  4. On submit: inserts a row into profile_contact_requests and emits a hire_me_received flow event

DB Table: profile_contact_requests

Column Type Notes
id uuid PK
to_user_id uuid FK to user_profiles.user_id
from_name text Requester's name
from_email text Requester's email
message text Message body
services_requested text[] Selected service names (nullable)
created_at timestamptz Auto

Flow Event

Emits hire_me_received via flowEventService — can be used to trigger automated flows (e.g., email notification to the professional).


Discover Directory (/discover)

Lists all public profiles ordered by profile_views DESC, limit 60.

Features

Data fetched

SELECT user_id, full_name, company, bio, avatar_url, location,
       website_url, services, skill_tags, profile_views, professional_type
FROM user_profiles
WHERE is_public = true
ORDER BY profile_views DESC
LIMIT 60

Follower counts are fetched in a second query and merged client-side.


Public Profile Page (/u/:userId)

Full profile view for a single user.

Sections (in order)

  1. Header — avatar, name, professional type badge, company, location, follower count, website, bio, Follow + Hire Me buttons
  2. Skills & Expertise — skill tags as badges
  3. Services — rich service cards with Hire button per service
  4. Featured Board — pinned moodboard with image preview and comments
  5. Preferred Factories — factory name + country grid
  6. Moodboards — all other public moodboards with image previews and comments

Social


Flow Triggers Related to Profiles

Event When
hire_me_received Hire Me form submitted
profile_followed A user follows a public profile
profile_published User makes their profile public
preferred_factory_added User adds a preferred factory

These can be used in the Flow Builder to trigger automated actions (emails, notifications, etc.).


Key Components

Component Path
Profile editing src/components/core/Profile/ProfileTab.tsx
Public profile page src/pages/PublicProfilePage.tsx
Discover directory src/pages/DiscoverPage.tsx
Hire Me modal src/components/core/Profile/HireMeModal.tsx
Follow button src/components/features/social/FollowButton.tsx
Moodboard comments src/components/features/social/MoodboardComments.tsx
Reviews display src/components/features/profile/ReviewsSection.tsx
Review modal src/components/features/profile/ReviewModal.tsx
Booking widget (public) src/components/features/profile/BookingWidget.tsx
Booking modal src/components/features/profile/BookingModal.tsx
Appointments dashboard src/pages/AppointmentsPage.tsx

Ratings & Reviews

DB Tables

Public profile

Displays: aggregate score card, AI summary, per-dimension stars, individual reviews, reply thread. Authenticated users (not the owner) see "Write a Review" button.


Appointment Booking

DB Tables

Routes

Route Component Access
/appointments AppointmentsPage Authenticated (own appointments only)

Flow Events

Event When
appointment_booked Client submits booking
appointment_confirmed Professional confirms
appointment_cancelled Either party cancels
appointment_moved_to_inbox Professional clicks "Email Client"

Inbox Bridge

"Email Client" in AppointmentDetailDrawer creates a new agent_chat_conversations row (agent_id='kai') pre-seeded with appointment context, saves the conversation_id back to appointments.inbox_conversation_id, then navigates to /agent-hub?conversation=<id>.