Minds AIssistant — aplikacja do notatek z coachem AI
Projekt Full-Stack · React · Node.js · PostgreSQL · Gemini AI

Minds AIssistant — notatnik z coachem AI

Aplikacja SPA do zarządzania dziennikiem osobistym, w której każda notatka może stać się punktem wyjścia do rozmowy z wbudowanym coachem AI. Asystent oparty na Google Gemini 2.0 Flash analizuje treść notatki i prowadzi empatyczny coaching metodą Haima Ginotta — zadaje otwarte pytania, odzwierciedla emocje i pomaga znaleźć własne odpowiedzi.

React 19 Vite Node.js + Express PostgreSQL Passport.js Google Gemini 2.0 Google OAuth 2.0 bcrypt + sesje

Projekt łączy dwa pomysły w jeden spójny produkt: dziennik osobisty z widokiem kalendarza i asystent AI specjalizujący się w coachingu. Zamiast ogólnego chatbota, Gemini otrzymuje szczegółowy prompt systemowy definiujący jego rolę jako terapeutycznego coacha — z konkretnymi instrukcjami językowymi, technikami komunikacji i zasadami bezpieczeństwa w przypadku kryzysu.

Backend to Express.js z autentykacją przez Passport.js (strategia lokalna + Google OAuth 2.0), sesjami serwerowymi, bcrypt i rate limitingiem. Wszystko bez ORM — czyste zapytania SQL przez bibliotekę pg.

01Funkcjonalności

📅

Widok kalendarza

Notatki zwizualizowane w siatce miesięcznej. Dni z notatkami pokazują ich tytuły bezpośrednio w komórkach. Kliknięcie dnia otwiera widok dzienny.

📝

CRUD notatek

Tworzenie, edycja (dialog MUI) i usuwanie notatek. Każda notatka: tytuł, treść, timestamp. Sortowanie według daty malejąco.

🤖

Coach AI per notatka

Każda notatka ma przycisk otwierający chatbota. Gemini automatycznie analizuje treść przy starcie i generuje pierwsze empatyczne pytanie.

🔐

Autentykacja dualna

Rejestracja i logowanie e-mail/hasło (bcrypt, Passport local) oraz logowanie przez Google OAuth 2.0 — jeden klik, bez hasła.

🛡️

Bezpieczeństwo

Rate limiting logowania (max 3 próby / 15 min), sesje httpOnly z wygaśnięciem po 1h, weryfikacja po stronie serwera każdego żądania API.

🔄

Persystencja sesji

Odświeżenie strony nie wylogowuje — /api/check-session weryfikuje sesję przy starcie aplikacji i przywraca stan zalogowania.

02Coach AI — Gemini jako terapeuta Ginotta

Najciekawszy element projektu: prompt systemowy (plik startInfo.js, ~600 znaków) definiuje Gemini jako empatycznego coacha personalnego według metody Haima Ginotta (autor “Między rodzicami a dziećmi”). To nie ogólny “pomocny asystent” — to konkretna rola z konkretnymi zasadami językowymi.

Jak działa pierwsza odpowiedź

📖

Użytkownik klika “Czat”

Treść notatki trafia do komponentu Chatbot.jsx

🔧

createInitialPrompt()

System prompt coacha + treść notatki → ukryta wiadomość startowa (hideInChat: true)

💬

Gemini odpowiada

Powitanie, interpretacja emocji, otwarte pytanie — automatycznie, bez udziału użytkownika

// Chatbot.jsx — inicjalizacja rozmowy z kontekstem notatki
const createInitialPrompt = (noteContent) => {
    const fullPrompt = `${startInfo}\n\nOto notatka użytkownika:\n---\n${noteContent}\n---`;
    return [{ role: "user", text: fullPrompt, hideInChat: true }];
    // ↑ hideInChat: true — prompt nie pojawia się w widoku czatu
};

// Po otwarciu chatbota: od razu wywołaj Gemini z kontekstem
useEffect(() => {
    const initialPrompt = createInitialPrompt(note.content);
    setChatHistory([...initialPrompt, { role: "model", text: "Analizuję Twoją notatkę..." }]);
    generateBotResponse(initialPrompt); // ← pierwszy call do Gemini API
}, [note]);

Zasady coacha z promptu systemowego

  • Akceptuj i nazywaj uczucia — “Widzę, że ta sytuacja budzi w Tobie frustrację” zamiast “Nie przejmuj się”
  • Opisuj sytuację, nie oceniaj osoby — problem wraca, zastanówmy się co jest przyczyną
  • Unikaj pytań “Dlaczego?” — zastąp przez “Co sprawiło, że…” / “Co się wtedy działo w Twojej głowie?”
  • Najpierw empatia, potem rozwiązania — użytkownik musi poczuć się zrozumiany
  • Protokół bezpieczeństwa — jeśli notatka sugeruje kryzys, Gemini kieruje do specjalisty i bezpłatnego telefonu zaufania

Integracja bezpośrednia z Gemini API: wywołanie odbywa się z poziomu frontendu przez fetch(VITE_API_URL). Klucz API jest zapisany w zmiennej środowiskowej Vite (VITE_API_URL zawiera pełne URL z kluczem), więc backend nie pośredniczy w komunikacji z AI. Historia rozmowy jest utrzymywana lokalnie w stanie komponentu.

03Architektura systemu

React SPA (Vite) Notebook · Kalendarz Login · Register Chatbot.jsx startInfo.js (system prompt) history state · hideInChat Google OAuth 2.0 passport-google-oauth2 callback → /notebook Express.js Backend (Node.js) Passport.js · express-session · bcrypt · rate-limit PostgreSQL tabela users · tabela notes zapytania przez pg (bez ORM) Google Gemini 2.0 generateContent API wywołanie z frontendu

04Autentykacja — Passport.js + sesje

Backend obsługuje dwa przepływy logowania przez Passport.js bez tokenów JWT — tradycyjne sesje serwerowe przechowywane w Express session store.

Strategia lokalna (e-mail + hasło)

  • Rejestracja: walidacja pól (brak pustaków, zgodność haseł, min. 6 znaków), sprawdzenie unikalności e-maila, bcrypt hash z 10 rundami soli, automatyczne logowanie po rejestracji przez req.login()
  • Logowanie: Passport Local Strategy porównuje hash przez bcrypt.compare(), rate limiter blokuje po 3 nieudanych próbach w 15 minutach

Google OAuth 2.0

  • Przekierowanie do /auth/google → Google → callback /auth/google/notes
  • Jeśli e-mail z Google istnieje w bazie — logowanie. Jeśli nie — automatyczne założenie konta (password = "google", placeholder w bazie)
  • Po sukcesie przekierowanie do /notebook po stronie frontendu
// Sesja z httpOnly cookie, wygasa po 1h
app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
        secure: process.env.NODE_ENV === 'production', // HTTPS w produkcji
        httpOnly: true,        // niedostępne dla JS w przeglądarce
        sameSite: "lax",
        maxAge: 60 * 60 * 1000 // 1 godzina
    }
}));

// Rate limiter: max 3 próby logowania / 15 minut
const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 3,
    message: { message: "Too many login attempts. Try again later." }
});

05Stack technologiczny

Frontend

  • React 19komponenty funkcyjne, hooki, SPA
  • React Router 7routing: / · /login · /register · /notebook
  • Vitedev server, zmienne VITE_*
  • AxiosHTTP client z withCredentials: true
  • React Bootstrap 2Button, dialog, layouty
  • MUI (Material UI) 6NoteEditorDialog, ikony
  • date-fns 4kalendarz: format, parseISO, eachDayOfInterval
  • Google Gemini 2.0 Flashintegracja z frontendu przez fetch()

Backend

  • Node.js + Express.jsserwer REST, middleware chain
  • pg (node-postgres)zapytania SQL bezpośrednio, bez ORM
  • PostgreSQL2 tabele: users, notes
  • Passport.jslocal + google-oauth2 strategy
  • bcrypt10 rund soli, haszowanie przy rejestracji
  • express-sessionsesje serwerowe, httpOnly cookie
  • express-rate-limitochrona endpointu /login
  • CORSwhitelist origin frontend :5173

06Struktura projektu

Minds-AIssistant/ ├── client/ # Frontend React (Vite) │ ├── public/ │ │ └── styles.css # globalne style (Montserrat, McLaren, zmienne CSS) │ └── src/ │ ├── components/ │ │ ├── App.jsx # routing, check-session przy starcie │ │ ├── Home.jsx # strona powitalna (niezalogowany) │ │ ├── Login.jsx # formularz logowania + link do Google OAuth │ │ ├── Register.jsx # formularz rejestracji z walidacją │ │ ├── Header.jsx # nawigacja + przycisk wylogowania │ │ ├── Footer.jsx │ │ ├── Notebook.jsx # ★ kalendarz miesięczny + renderCalendarGrid() │ │ ├── CreateArea.jsx # formularz dodawania nowej notatki │ │ ├── DailyNotesView.jsx # widok dzienny + zarządzanie stanem chatu │ │ ├── Note.jsx # karta notatki (delete, edit, “Czat z AI”) │ │ ├── NoteEditorDialog.jsx # dialog edycji (MUI Dialog) │ │ ├── Chatbot.jsx # ★ komponent chatbota + Gemini API calls │ │ ├── ChatForm.jsx # input + submit wiadomości │ │ └── ChatMessage.jsx # renderowanie pojedynczej wiadomości │ ├── startInfo.js # ★ system prompt coacha AI (metoda Ginotta) │ └── main.jsx # render root │ └── server/ ├── index.js # ★ cały backend: Express, Passport, pg, routes └── package.json

07REST API (Express)

POST
/register
rejestracja — walidacja, bcrypt hash, auto-login przez req.login()
POST
/login
logowanie (rate limited 3/15min) — Passport local strategy, sesja
GET
/auth/google
inicjalizacja Google OAuth 2.0 — redirect do Google
GET
/auth/google/notes
callback OAuth — utwórz lub zaloguj użytkownika, redirect do /notebook
GET
/api/check-session
weryfikacja sesji przy starcie SPA — zwraca {loggedIn, user}
GET
/logout
wylogowanie — req.logout() + session.destroy()
GET
/api/shownotes
pobranie notatek użytkownika — wymaga sesji, ORDER BY created_at DESC
POST
/api/postnote
dodanie notatki — wymaga sesji, INSERT zwraca nową notatkę
PATCH
/api/edit
edycja tytułu i treści notatki po noteid
DELETE
/api/delete
usunięcie notatki po id z body (DELETE z body)

08Czego dowodzi ten projekt

Full-stack Node.js

React SPA + Express REST API + PostgreSQL — kompletny stos JavaScript, od bazy po UI.

Integracja AI z promptem

Nie “dodaj chatbota” — zaprojektowany system prompt definiujący konkretną rolę z zasadami komunikacji i protokołem bezpieczeństwa.

Passport.js multi-auth

Dwa przepływy logowania w jednym serwisie: local (bcrypt) + Google OAuth 2.0 z automatycznym tworzeniem konta.

Sesje serwerowe

Express-session + httpOnly cookie — tradycyjna autentykacja zamiast JWT, z check-session przywracającym stan po odświeżeniu.

Kalendarz od zera

renderCalendarGrid() z date-fns — własna implementacja widoku miesięcznego z offset pustych komórek i filtrowaniem notatek per dzień.

Kontekst AI z notatką

Ukryty prompt startowy (hideInChat) przesyła treść notatki przed pierwszym pytaniem użytkownika — rozmowa zaczyna się od analizy, nie od zera.

Zobacz pełny kod na GitHubie

Repozytorium zawiera pełny frontend i backend — w tym system prompt coacha AI, implementację kalendarza i całą logikę autentykacji.

Zobacz kod na GitHub

09Aplikacja w akcji

Poniżej wideo pokazujące aplikację w działaniu — rejestracja, dodawanie notatek w widoku kalendarza i rozmowa z coachem AI.

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