Salon Fryzjerski Szymon — System Rezerwacji z AI Asystentem
Projekt Full-Stack · Python · React · AI

Salon Fryzjerski Szymon — system rezerwacji z asystentem AI

Pełna aplikacja webowa dla salonu fryzjerskiego: rezerwacja online, panel administracyjny, powiadomienia e-mail i inteligentny chatbot, który prowadzi klienta przez proces rezerwacji w naturalnej rozmowie. Zbudowana na FastAPI, React 19 i OpenAI Agents SDK z wektorową bazą wiedzy (RAG).

React 19 TypeScript FastAPI Python 3.13 PostgreSQL + pgvector OpenAI Agents SDK Docker Tailwind + shadcn/ui

Celem projektu było zbudowanie rzeczywistego, wdrożeniowego systemu rezerwacji dla lokalnego salonu fryzjerskiego — nie demo, lecz aplikacji, która radzi sobie z prawdziwymi wymaganiami: grafik pracy pracowników z wyjątkami (urlopy, zmiany godzin), konflikty terminów, powiadomienia mailowe, czarna lista numerów i e-maili, oraz asystent AI, który faktycznie potrafi zarezerwować wizytę w rozmowie z klientem.

Aplikacja składa się z trzech warstw: frontend w React 19 z TypeScriptem, backend w FastAPI ze SQLAlchemy 2.0 w trybie async, oraz warstwa AI oparta na OpenAI Agents SDK z 10 function tools i własną bazą wiedzy RAG (pgvector + embeddingi OpenAI).

01Funkcjonalności

AI

Asystent konwersacyjny

Agent AI prowadzi klienta przez rezerwację krok po kroku, pamięta kontekst rozmowy i weryfikuje dostępność w czasie rzeczywistym.

📅

System rezerwacji

Rezerwacja online z kodem potwierdzenia, walidacja konfliktów, anulowanie kodem, integracja z grafikiem.

👤

Zarządzanie zespołem

Profile pracowników ze zdjęciami, specjalizacjami (JSON), indywidualnym grafikiem i wyjątkami.

🔐

Panel administracyjny

Autentykacja HMAC + HTTP-only cookies, zarządzanie usługami, grafikiem, bazą wiedzy i czarną listą.

📚

Baza wiedzy (RAG)

Wektorowa baza pgvector, automatyczne chunkowanie, embeddingi OpenAI, wyszukiwanie semantyczne (cosine similarity).

✉️

Powiadomienia e-mail

Integracja z Brevo API — potwierdzenia, anulowania, wysyłane asynchronicznie w background tasks.

02Architektura systemu

Aplikacja jest podzielona na cztery niezależne warstwy. Frontend komunikuje się z backendem wyłącznie przez REST API, backend korzysta z PostgreSQL z rozszerzeniem pgvector do przechowywania zarówno danych relacyjnych (rezerwacje, usługi, grafik), jak i wektorów embeddingów dla bazy wiedzy. Agent AI jest izolowanym modułem, który komunikuje się z OpenAI API i wywołuje wewnętrzne serwisy przez function tools.

Klient (przeglądarka) React 19 · TypeScript Tailwind · shadcn/ui Chat Widget GSAP · Recharts sesja konwersacji Panel Admin HMAC auth HTTP-only cookies FastAPI · REST API v1 /api/v1/rag · /bookings · /services · /team · /admin Services Layer BookingService IngestService · Email AI Agent OpenAI Agents SDK 10× function_tool PostgreSQL + pgvector async SQLAlchemy 2.0 OpenAI API · Brevo API

03Stack technologiczny

Frontend

  • React 19najnowsza wersja, nowy compiler, Hooks API
  • TypeScriptpełne typowanie, zero any
  • Vite 7szybki dev server i build
  • Tailwind CSS 3utility-first styling
  • shadcn/ui + Radix40+ dostępnych komponentów UI
  • React Router 7routing po stronie klienta
  • React Hook Form + Zodwalidacja formularzy
  • GSAPanimacje scrollowe i przejścia
  • Rechartswykresy w dashboardzie admina

Backend

  • FastAPIasync framework, auto-generowane OpenAPI
  • SQLAlchemy 2.0async ORM z typed Mapped[]
  • PostgreSQL + pgvectorbaza relacyjna z wektorami
  • OpenAI Agents SDKagent z function tools
  • langchain-text-splitterschunking dokumentów dla RAG
  • Pydantic v2walidacja i schematy
  • httpxasync klient HTTP (Brevo)
  • tiktokentokenizacja tekstu
  • Docker Composekonteneryzacja środowiska dev

04Serce aplikacji — Agent AI

Najciekawszy technicznie element projektu. Agent zbudowany na OpenAI Agents SDK otrzymuje 10 function tools, które pozwalają mu wykonać realne operacje na bazie danych — od sprawdzania dostępności po utworzenie rezerwacji. Prompt systemowy wymusza anty-halucynacyjne zasady (m.in. agent NIGDY nie potwierdzi rezerwacji bez faktycznego wywołania create_booking), a stan sesji jest persystowany w PostgreSQL.

Przepływ rezerwacji przez chat

Użytkownik: “Chcę umówić strzyżenie na jutro 14:00 u Szymona” │ ▼ ┌─────────────────────┐ │ OpenAI Agents SDK │ ← analiza intencji │ + instrukcje prompt│ └─────────────────────┘ │ ▼ ┌─────────────────────┐ ┌──────────────────┐ │ Tool: save_service │───────▶│ session_state │ │ Tool: save_barber │ │ (persisted in │ │ Tool: save_datetime │ │ PostgreSQL) │ └─────────────────────┘ └──────────────────┘ │ ▼ ┌─────────────────────┐ ┌──────────────────┐ │ Tool: get_available │───────▶│ BookingService │ │ _slots │◀───────│ .get_availability│ └─────────────────────┘ └──────────────────┘ │ ▼ Podsumowanie → prośba o potwierdzenie │ ▼ [użytkownik: “tak”] │ ┌─────────────────────┐ ┌──────────────────┐ │ Tool: create_ │───────▶│ BookingService │ │ booking │◀───────│ .create_booking │ └─────────────────────┘ └──────────────────┘ │ ▼ REZERWACJA UTWORZONA · Kod: ABC123 (+ email via Brevo w background task)

Przykład function tool

Każde narzędzie agenta jest zwykłą async funkcją z dekoratorem @function_tool. SDK automatycznie generuje schematy JSON dla OpenAI na podstawie typowania argumentów:

@function_tool
async def get_available_slots(
    ctx: RunContextWrapper[BookingContext],
    date_str: str,
    service_id: Optional[str] = None,
    team_member_id: Optional[str] = None,
) -> str:
    # pobierz kontekst z sesji — agent pamięta co już wybrano
    state = ctx.context.session_state
    service_id     = service_id     or state.get("service_id")
    team_member_id = team_member_id or state.get("team_member_id")

    if not service_id:
        return json.dumps({"error": "Brak usługi — najpierw save_service"})

    booking_date = _parse_date(date_str)
    if booking_date < date.today():
        return json.dumps({"error": "Data w przeszłości"})

    # faktyczne sprawdzenie w bazie, z uwzględnieniem grafiku i innych rezerwacji
    availability = await ctx.context.booking_service.get_availability(
        booking_date=booking_date,
        service_id=UUID(service_id),
        team_member_id=UUID(team_member_id)
    )

    slots = sorted(availability.keys())
    return json.dumps({"date": booking_date.isoformat(), "slots": slots})

Anty-halucynacyjne zabezpieczenia w prompcie agenta: NIGDY nie mów, że rezerwacja została potwierdzona bez wywołania create_booking. NIGDY nie wymyślaj kodów rezerwacji — kod pochodzi wyłącznie z wyniku narzędzia. Rezerwacja jest potwierdzona TYLKO gdy tool zwróci {"success": true}.

05RAG — wektorowa baza wiedzy

Drugi filar systemu AI. Pliki markdown z bazą wiedzy salonu (cennik, godziny, poradniki fryzjerskie, informacje o zespole) są automatycznie chunkowane, zamieniane na wektory embeddingów przez OpenAI i zapisywane w PostgreSQL w kolumnie typu Vector(1536) dzięki rozszerzeniu pgvector. Podczas rozmowy agent wywołuje narzędzie search_knowledge, które liczy embedding zapytania i robi wyszukiwanie po cosine similarity.

Dzięki temu chatbot nie opiera się na ogólnej wiedzy modelu — wszystkie fakty o salonie pochodzą wyłącznie z kontrolowanej bazy wiedzy, którą administrator edytuje w panelu.

# Model SQLAlchemy z kolumną wektorową
class KnowledgeChunk(Base):
    __tablename__ = "knowledge_chunks"

    id:         Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
    category:   Mapped[str]       = mapped_column(String(50), index=True)
    title:      Mapped[str]       = mapped_column(String(200))
    content:    Mapped[str]       = mapped_column(Text)
    embedding:  Mapped[Any]       = mapped_column(Vector(1536))  # ← pgvector
    source:     Mapped[str]       = mapped_column(String(100))

06Struktura projektu

Projekt podzielony jest na frontend (app/) i backend (backend/) z jasnym rozdzieleniem warstw: endpointy → serwisy → repozytoria → modele.

fryzjer_szymon/ ├── app/ # Frontend React │ └── src/ │ ├── components/ # ChatWidget, Navigation, shadcn/ui │ ├── pages/ │ │ ├── BookingPage.tsx # strona rezerwacji │ │ └── admin/ # 8 stron panelu admin │ ├── sections/ # Hero, Services, Team, About… │ ├── hooks/ # useBooking, useChatAPI │ ├── services/ # ragApi.ts — klient API │ └── types/ # TypeScript interfaces │ ├── backend/ │ ├── src/ │ │ ├── api/v1/endpoints/ # endpointy FastAPI │ │ │ └── admin/ # endpointy panelu admin │ │ ├── services/ │ │ │ ├── rag/ # ★ booking_agent.py (462 linie) │ │ │ │ ├── ingest_service.py │ │ │ │ └── knowledge_service.py │ │ │ ├── booking/ # logika rezerwacji │ │ │ ├── team/ · service/ · admin/ │ │ │ └── email.py # integracja Brevo │ │ ├── schemas/ # modele Pydantic │ │ ├── core/exceptions.py # wyjątki domenowe │ │ └── main.py # entry point + lifespan │ └── database/ │ ├── models.py # modele SQLAlchemy │ ├── repositories/ # 9 repozytoriów (Repository Pattern) │ └── data/ # pliki markdown bazy wiedzy │ ├── docker-compose.yml # PostgreSQL + Adminer └── requirements.txt

Wzorce architektoniczne

  • Repository Pattern — każda encja ma swoje repozytorium (BookingRepository, ServiceRepository…), które hermetyzuje dostęp do bazy
  • Service Layer — logika biznesowa oddzielona od endpointów i dostępu do danych
  • Dependency Injection — FastAPI Depends() + własny kontener dla agenta
  • Domain Exceptions — własna hierarchia wyjątków mapowana na kody HTTP w globalnym handlerze
  • Lifespan events — auto-ingest bazy wiedzy przy starcie aplikacji z inteligentną detekcją zmian

07REST API — wybrane endpointy

Backend udostępnia ponad 40 endpointów w /api/v1. Dokumentacja auto-generowana przez FastAPI dostępna jest pod /docs (Swagger) i /redoc.

POST
/api/v1/rag/askzapytanie do asystenta AI (konwersacja)
GET
/api/v1/bookings/availabilitywolne terminy dla usługi i pracownika
POST
/api/v1/bookingsutworzenie rezerwacji + e-mail potwierdzający
POST
/api/v1/bookings/{id}/cancelanulowanie przez kod potwierdzenia
GET
/api/v1/teamlista aktywnych pracowników
POST
/api/v1/admin/auth/loginlogowanie z HMAC + HTTP-only cookie
PATCH
/api/v1/admin/bookings/{id}zmiana statusu rezerwacji
POST
/api/v1/admin/knowledge/syncsynchronizacja całej bazy wiedzy (re-embedding)

08Panel administracyjny

Osobna sekcja aplikacji z autoryzacją HMAC i HTTP-only cookies (zabezpieczenie przed XSS). Umożliwia pełne zarządzanie salonem z poziomu przeglądarki:

  • Dashboard z metrykami i wykresami (Recharts)
  • Rezerwacje z filtrowaniem, zmianą statusów i usuwaniem
  • Usługi — CRUD cennika, kategorii, kolejności wyświetlania
  • Zespół z uploadem zdjęć (serwowanym przez StaticFiles)
  • Grafik pracy — tygodniowy grafik salonu + wyjątki indywidualne (urlopy)
  • Baza wiedzy — edytor plików markdown z re-ingestem po zapisie
  • Czarna lista — blokowanie numerów telefonów i e-maili

09Dokumentacja — 9 faz rozwoju

Projekt zawiera kompletną dokumentację w postaci poradników Faza 0–8, które prowadzą przez cały proces budowy aplikacji od pustego repozytorium do wdrożenia. Każda faza dodaje konkretną warstwę funkcjonalności, z uzasadnieniem decyzji projektowych i przykładami kodu.

  • Faza 0 — Setup projektu, Docker, FastAPI Hello World
  • Faza 1 — CRUD usług (model, repo, schema, endpoint)
  • Faza 2 — Zespół, JSON column, upload zdjęć
  • Faza 3 — Godziny otwarcia i grafik z wyjątkami
  • Faza 4 — System rezerwacji, konflikty, BackgroundTasks
  • Faza 5 — E-mail (Brevo) i czarna lista
  • Faza 6 — RAG: pgvector, embeddingi, cosine similarity
  • Faza 7 — AI Agent: OpenAI Agents SDK, function tools
  • Faza 8 — Panel admin: HMAC auth, HTTP-only cookies

10Czego dowodzi ten projekt

Poza samą aplikacją, projekt pokazuje konkretne kompetencje istotne z perspektywy pracodawcy:

Full-stack

Od modelu SQLAlchemy po animację GSAP — samodzielnie wyprowadzony produkt end-to-end.

Nowoczesny AI

Praktyczna integracja LLM: function calling, RAG, embeddingi, kontrola halucynacji, persystencja sesji.

Async Python

FastAPI + async SQLAlchemy 2.0 + httpx — wszystkie operacje I/O w pełni asynchroniczne.

Czysta architektura

Repository Pattern, Service Layer, Dependency Injection, domain exceptions — nie jeden plik z wszystkim.

TypeScript + React 19

Typed API client, custom hooks, formularze z Zod, komponenty shadcn/ui.

DevOps basics

Docker Compose, zmienne środowiskowe, lifespan events, auto-ingest przy starcie.

Bezpieczeństwo

HMAC auth, HTTP-only cookies, CORS, walidacja Pydantic, ochrona przed prompt injection.

Dokumentacja

9 faz poradników krok po kroku — umiejętność przekazywania wiedzy, nie tylko pisania kodu.

Zobacz pełny kod na GitHubie

Repozytorium zawiera frontend, backend, konfigurację Dockera, schematy bazy danych, poradniki 0–8 i wszystkie szczegóły implementacji.

Zobacz kod na GitHub

11Aplikacja w akcji

Poniżej filmik pokazujący system w działaniu — od strony klienta (rezerwacja przez chatbota) po panel administracyjny.

Udostępnij jeśli spodobał Ci się mój projekt