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.
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
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
/notebookpo 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
07REST API (Express)
rejestracja — walidacja, bcrypt hash, auto-login przez
req.login()logowanie (rate limited 3/15min) — Passport local strategy, sesja
inicjalizacja Google OAuth 2.0 — redirect do Google
callback OAuth — utwórz lub zaloguj użytkownika, redirect do
/notebookweryfikacja sesji przy starcie SPA — zwraca
{loggedIn, user}wylogowanie —
req.logout() + session.destroy()pobranie notatek użytkownika — wymaga sesji, ORDER BY created_at DESC
dodanie notatki — wymaga sesji, INSERT zwraca nową notatkę
edycja tytułu i treści notatki po
noteidusunię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 GitHub09Aplikacja w akcji
Poniżej wideo pokazujące aplikację w działaniu — rejestracja, dodawanie notatek w widoku kalendarza i rozmowa z coachem AI.