Index: petify-frontend/src/api/profile.ts
===================================================================
--- petify-frontend/src/api/profile.ts	(revision ae836471908c8a67e8fc2a25ad6c445b1c867e48)
+++ petify-frontend/src/api/profile.ts	(revision f6ed6e478015d417b9610fe651dfccdc3e22dc89)
@@ -35,4 +35,8 @@
   city: string
   address: string
+  workDays?: string
+  startTime?: string
+  endTime?: string
+  scheduleComplete?: boolean
 }
 
@@ -464,4 +468,30 @@
 }
 
+export async function updateMyClinicSchedule(
+  userId: number,
+  data: {
+    workDays: string
+    startTime: string
+    endTime: string
+  }
+): Promise<VetClinic> {
+  const url = joinUrl(getBaseUrl(), `/api/clinics/my/schedule`)
+  const response = await fetch(url, {
+    method: 'PUT',
+    headers: {
+      'Content-Type': 'application/json',
+      'X-User-Id': String(userId),
+    },
+    body: JSON.stringify(data),
+  })
+
+  if (!response.ok) {
+    const error = await response.json()
+    throw new Error(error.error || `Failed to update clinic schedule: ${response.statusText}`)
+  }
+
+  return await response.json()
+}
+
 export async function getClinicAvailableSlots(clinicId: number, date: string): Promise<AppointmentSlot[]> {
   const url = joinUrl(getBaseUrl(), `/api/appointments/clinics/${clinicId}/available-slots?date=${encodeURIComponent(date)}`)
Index: petify-frontend/src/api/reviews.ts
===================================================================
--- petify-frontend/src/api/reviews.ts	(revision ae836471908c8a67e8fc2a25ad6c445b1c867e48)
+++ petify-frontend/src/api/reviews.ts	(revision f6ed6e478015d417b9610fe651dfccdc3e22dc89)
@@ -20,9 +20,17 @@
 }
 
+export type UserReviewInteractionType =
+  | 'EVENT'
+  | 'PERSONAL_INTERACTION'
+  | 'ONLINE'
+  | 'PHONE_CALL'
+  | 'OTHER'
+
 export async function createReview(
   targetUserId: number,
   userId: number,
   rating: number,
-  comment: string
+  comment: string,
+  interactionType: UserReviewInteractionType
 ): Promise<Review> {
   const url = joinUrl(getBaseUrl(), `/api/reviews/${targetUserId}`)
@@ -36,4 +44,5 @@
       rating,
       comment,
+      interactionType,
     }),
   })
Index: petify-frontend/src/views/ClinicDashboardView.vue
===================================================================
--- petify-frontend/src/views/ClinicDashboardView.vue	(revision ae836471908c8a67e8fc2a25ad6c445b1c867e48)
+++ petify-frontend/src/views/ClinicDashboardView.vue	(revision f6ed6e478015d417b9610fe651dfccdc3e22dc89)
@@ -8,5 +8,5 @@
           <p v-if="clinic" class="clinic-subtitle">{{ clinic.name }} - {{ clinic.city }}, {{ clinic.address }}</p>
         </div>
-        <div class="toolbar">
+        <div v-if="canUseSchedule" class="toolbar">
           <button class="btn btn-outline-secondary btn-sm" type="button" @click="goToPreviousDay">
             Previous day
@@ -34,4 +34,45 @@
 
       <template v-else>
+        <section v-if="clinic && !canUseSchedule" class="setup-panel">
+          <div>
+            <p class="eyebrow">Required setup</p>
+            <h2>Add your working schedule</h2>
+            <p class="setup-copy">
+              Users can book appointment slots only after your clinic adds working days and opening hours.
+            </p>
+          </div>
+
+          <form class="schedule-form" @submit.prevent="saveSchedule">
+            <fieldset class="days-fieldset">
+              <legend>Working days</legend>
+              <label v-for="day in workDayOptions" :key="day.value" class="day-check">
+                <input
+                  v-model="scheduleForm.workDays"
+                  type="checkbox"
+                  :value="day.value"
+                />
+                <span>{{ day.label }}</span>
+              </label>
+            </fieldset>
+
+            <div class="time-grid">
+              <div class="form-group">
+                <label class="form-label" for="startTime">Start time</label>
+                <input id="startTime" v-model="scheduleForm.startTime" class="form-control" type="time" required />
+              </div>
+              <div class="form-group">
+                <label class="form-label" for="endTime">End time</label>
+                <input id="endTime" v-model="scheduleForm.endTime" class="form-control" type="time" required />
+              </div>
+            </div>
+
+            <div v-if="scheduleSetupError" class="alert alert-danger">{{ scheduleSetupError }}</div>
+            <button class="btn btn-primary" type="submit" :disabled="isSavingSchedule">
+              {{ isSavingSchedule ? 'Saving...' : 'Save schedule' }}
+            </button>
+          </form>
+        </section>
+
+        <template v-else>
         <div class="summary-strip">
           <div class="summary-item">
@@ -59,4 +100,7 @@
 
             <div class="slot-grid">
+              <div v-if="daySlots.length === 0" class="panel-empty full-width">
+                This is not a working day for your clinic.
+              </div>
               <div
                 v-for="slot in daySlots"
@@ -131,4 +175,5 @@
           </aside>
         </div>
+        </template>
       </template>
     </section>
@@ -147,4 +192,5 @@
   getMyNotifications,
   markMyClinicAppointmentNoShow,
+  updateMyClinicSchedule,
   type AppNotification,
   type AppointmentSlot,
@@ -174,7 +220,9 @@
 const notifications = ref<AppNotification[]>([])
 const isLoading = ref(false)
+const isSavingSchedule = ref(false)
 const updatingAppointmentId = ref<number | null>(null)
 const accessError = ref('')
 const scheduleError = ref('')
+const scheduleSetupError = ref('')
 const notificationsError = ref('')
 const NON_BLOCKING_STATUSES = new Set(['CANCELLED', 'CANCELED', 'NO_SHOW'])
@@ -182,4 +230,19 @@
 
 const canUseDashboard = computed(() => auth.isAuthenticated && auth.user?.userType === 'CLINIC')
+const canUseSchedule = computed(() => Boolean(clinic.value?.scheduleComplete))
+const scheduleForm = ref({
+  workDays: [] as string[],
+  startTime: '09:00',
+  endTime: '17:00',
+})
+const workDayOptions = [
+  { value: 'MONDAY', label: 'Mon' },
+  { value: 'TUESDAY', label: 'Tue' },
+  { value: 'WEDNESDAY', label: 'Wed' },
+  { value: 'THURSDAY', label: 'Thu' },
+  { value: 'FRIDAY', label: 'Fri' },
+  { value: 'SATURDAY', label: 'Sat' },
+  { value: 'SUNDAY', label: 'Sun' },
+]
 
 const appointmentsByDateTime = computed(() => {
@@ -205,8 +268,7 @@
   const now = new Date()
 
-  for (let hour = 9; hour < 17; hour += 1) {
-    for (const minute of [0, 30]) {
-      const dateTime = `${selectedDate.value}T${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`
-      const label = `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`
+  for (const time of getClinicTimesForDate(selectedDate.value)) {
+      const dateTime = `${selectedDate.value}T${time}`
+      const label = time
       const key = normalizeDateTime(dateTime)
       const appointment = appointmentsByDateTime.value.get(key)
@@ -252,5 +314,4 @@
         })
       }
-    }
   }
 
@@ -274,7 +335,6 @@
   const slots: AppointmentSlot[] = []
 
-  for (let hour = 9; hour < 17; hour += 1) {
-    for (const minute of [0, 30]) {
-      const dateTime = `${date}T${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`
+  for (const time of getClinicTimesForDate(date)) {
+      const dateTime = `${date}T${time}`
       const key = normalizeDateTime(dateTime)
       if (new Date(dateTime).getTime() < now.getTime()) continue
@@ -282,7 +342,6 @@
       slots.push({
         dateTime,
-        label: `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`,
+        label: time,
       })
-    }
   }
 
@@ -291,5 +350,5 @@
 
 async function loadSchedule() {
-  if (!auth.user?.userId || !canUseDashboard.value || !selectedDate.value) return
+  if (!auth.user?.userId || !canUseDashboard.value || !canUseSchedule.value || !selectedDate.value) return
 
   const requestId = ++latestScheduleRequest
@@ -319,4 +378,38 @@
 }
 
+async function saveSchedule() {
+  if (!auth.user?.userId) return
+  if (scheduleForm.value.workDays.length === 0) {
+    scheduleSetupError.value = 'Choose at least one working day'
+    return
+  }
+
+  if (!scheduleForm.value.startTime || !scheduleForm.value.endTime) {
+    scheduleSetupError.value = 'Start and end time are required'
+    return
+  }
+
+  if (scheduleForm.value.startTime >= scheduleForm.value.endTime) {
+    scheduleSetupError.value = 'Start time must be before end time'
+    return
+  }
+
+  try {
+    isSavingSchedule.value = true
+    scheduleSetupError.value = ''
+    clinic.value = await updateMyClinicSchedule(auth.user.userId, {
+      workDays: scheduleForm.value.workDays.join(','),
+      startTime: scheduleForm.value.startTime,
+      endTime: scheduleForm.value.endTime,
+    })
+    hydrateScheduleForm()
+    await loadSchedule()
+  } catch (error) {
+    scheduleSetupError.value = error instanceof Error ? error.message : 'Failed to save clinic schedule'
+  } finally {
+    isSavingSchedule.value = false
+  }
+}
+
 async function loadNotifications() {
   if (!auth.user?.userId || !canUseDashboard.value) return
@@ -417,4 +510,45 @@
 }
 
+function hydrateScheduleForm() {
+  scheduleForm.value = {
+    workDays: clinic.value?.workDays ? clinic.value.workDays.split(',').map((day) => day.trim()).filter(Boolean) : [],
+    startTime: clinic.value?.startTime?.slice(0, 5) || '09:00',
+    endTime: clinic.value?.endTime?.slice(0, 5) || '17:00',
+  }
+}
+
+function getClinicTimesForDate(date: string): string[] {
+  if (!clinic.value?.workDays || !clinic.value.startTime || !clinic.value.endTime) return []
+  if (!isClinicWorkingDay(date)) return []
+
+  const times: string[] = []
+  const start = timeToMinutes(clinic.value.startTime)
+  const end = timeToMinutes(clinic.value.endTime)
+
+  for (let minutes = start; minutes < end; minutes += 30) {
+    times.push(minutesToTime(minutes))
+  }
+
+  return times
+}
+
+function isClinicWorkingDay(date: string): boolean {
+  const day = new Date(`${date}T00:00:00`).toLocaleDateString('en-US', { weekday: 'long' }).toUpperCase()
+  return clinic.value?.workDays?.split(',').map((item) => item.trim().toUpperCase()).includes(day) ?? false
+}
+
+function timeToMinutes(time: string): number {
+  const parts = time.slice(0, 5).split(':').map(Number)
+  const hours = parts[0] ?? 0
+  const minutes = parts[1] ?? 0
+  return hours * 60 + minutes
+}
+
+function minutesToTime(total: number): string {
+  const hours = Math.floor(total / 60)
+  const minutes = total % 60
+  return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`
+}
+
 function formatDateTime(value: string): string {
   return new Date(value).toLocaleString('en-US', {
@@ -439,4 +573,5 @@
   try {
     clinic.value = await getMyClinic(auth.user.userId)
+    hydrateScheduleForm()
     accessError.value = ''
   } catch (error) {
@@ -445,5 +580,9 @@
   }
 
-  await Promise.all([loadSchedule(), loadNotifications()])
+  if (canUseSchedule.value) {
+    await Promise.all([loadSchedule(), loadNotifications()])
+  } else {
+    await loadNotifications()
+  }
 })
 
@@ -510,5 +649,6 @@
 .summary-strip,
 .schedule-section,
-.appointments-panel {
+.appointments-panel,
+.setup-panel {
   background: white;
   border: 1px solid #e2e8f0;
@@ -529,4 +669,75 @@
   color: #718096;
   margin: 0;
+}
+
+.setup-panel {
+  display: grid;
+  gap: 24px;
+  padding: 28px;
+}
+
+.setup-panel h2 {
+  color: #1a202c;
+  font-size: 1.45rem;
+  margin: 0 0 8px;
+}
+
+.setup-copy {
+  color: #718096;
+  margin: 0;
+}
+
+.schedule-form {
+  display: grid;
+  gap: 20px;
+  max-width: 720px;
+}
+
+.days-fieldset {
+  border: 0;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  margin: 0;
+  padding: 0;
+}
+
+.days-fieldset legend {
+  color: #2d3748;
+  font-weight: 700;
+  margin-bottom: 8px;
+  width: 100%;
+}
+
+.day-check {
+  align-items: center;
+  border: 1px solid #cbd5e0;
+  border-radius: 8px;
+  cursor: pointer;
+  display: inline-flex;
+  gap: 8px;
+  padding: 9px 12px;
+}
+
+.day-check:has(input:checked) {
+  background: #fff7ed;
+  border-color: #f97316;
+  color: #9a3412;
+}
+
+.time-grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 180px));
+  gap: 16px;
+}
+
+.form-group {
+  display: grid;
+  gap: 8px;
+}
+
+.form-label {
+  color: #2d3748;
+  font-weight: 700;
 }
 
@@ -625,4 +836,8 @@
 }
 
+.full-width {
+  grid-column: 1 / -1;
+}
+
 .slot-card {
   border: 1px solid #e2e8f0;
Index: petify-frontend/src/views/OwnerProfileView.vue
===================================================================
--- petify-frontend/src/views/OwnerProfileView.vue	(revision ae836471908c8a67e8fc2a25ad6c445b1c867e48)
+++ petify-frontend/src/views/OwnerProfileView.vue	(revision f6ed6e478015d417b9610fe651dfccdc3e22dc89)
@@ -208,4 +208,23 @@
 
                   <div class="form-group">
+                    <label class="form-label" for="interactionType">How did you interact?</label>
+                    <select
+                      id="interactionType"
+                      v-model="newReview.interactionType"
+                      class="form-control"
+                      required
+                    >
+                      <option value="" disabled>Select an option</option>
+                      <option
+                        v-for="option in interactionTypeOptions"
+                        :key="option.value"
+                        :value="option.value"
+                      >
+                        {{ option.label }}
+                      </option>
+                    </select>
+                  </div>
+
+                  <div class="form-group">
                     <label class="form-label" for="comment">Comment</label>
                     <textarea
@@ -226,5 +245,5 @@
                       type="submit"
                       class="btn btn-primary"
-                      :disabled="isSubmittingReview || newReview.rating === 0"
+                      :disabled="isSubmittingReview || newReview.rating === 0 || !newReview.interactionType"
                     >
                       <span v-if="isSubmittingReview">Submitting...</span>
@@ -287,5 +306,10 @@
 import { useRoute, RouterLink } from 'vue-router'
 import { getUserProfile, getUserListings, getUserPets, loadUserVerificationStatus } from '../api/profile'
-import { createReview, getReviewsByOwner, deleteReview as deleteReviewAPI } from '../api/reviews'
+import {
+  createReview,
+  getReviewsByOwner,
+  deleteReview as deleteReviewAPI,
+  type UserReviewInteractionType,
+} from '../api/reviews'
 import { useAuthStore } from '../stores/auth'
 
@@ -305,7 +329,20 @@
 const isSubmittingReview = ref(false)
 const reviewError = ref<string | null>(null)
-const newReview = ref({
+const interactionTypeOptions: Array<{ value: UserReviewInteractionType; label: string }> = [
+  { value: 'EVENT', label: 'Met at an event' },
+  { value: 'PERSONAL_INTERACTION', label: 'Personal interaction' },
+  { value: 'ONLINE', label: 'Online interaction' },
+  { value: 'PHONE_CALL', label: 'Phone call' },
+  { value: 'OTHER', label: 'Other' },
+]
+
+const newReview = ref<{
+  rating: number
+  comment: string
+  interactionType: UserReviewInteractionType | ''
+}>({
   rating: 0,
   comment: '',
+  interactionType: '',
 })
 
@@ -445,4 +482,9 @@
   }
 
+  if (!newReview.value.interactionType) {
+    reviewError.value = 'Please choose how you interacted with this user'
+    return
+  }
+
   isSubmittingReview.value = true
   reviewError.value = null
@@ -453,5 +495,6 @@
       auth.user.userId,
       newReview.value.rating,
-      newReview.value.comment
+      newReview.value.comment,
+      newReview.value.interactionType
     )
 
@@ -459,4 +502,5 @@
     newReview.value.rating = 0
     newReview.value.comment = ''
+    newReview.value.interactionType = ''
     await loadReviews()
   } catch (err) {
