# Pulse — Архитектура проекта ## Обзор **Pulse** — персональное productivity-приложение для управления задачами, привычками и напоминаниями с интеграцией Telegram-бота. ## Технологический стек ### Backend (pulse-api) - **Язык:** Go 1.22 - **Web-фреймворк:** chi/v5 - **База данных:** PostgreSQL 16 - **ORM:** sqlx (raw SQL + struct mapping) - **Аутентификация:** JWT (access 15 мин / refresh 365 дней) - **Email:** Resend API - **Telegram:** go-telegram-bot-api/v5 - **Scheduler:** robfig/cron/v3 - **Контейнеризация:** Docker + Docker Compose ### Frontend (pulse-web) - **Фреймворк:** React 18 - **Сборщик:** Vite 5 - **Стили:** TailwindCSS - **Состояние:** Zustand (auth), TanStack Query (data fetching) - **Анимации:** Framer Motion - **Иконки:** Lucide React - **Контейнеризация:** nginx:alpine ### Инфраструктура - **Хостинг:** VM Ubuntu (192.168.31.60) - **Reverse proxy:** Nginx Proxy Manager - **SSL:** Let's Encrypt (auto-renew) - **Git:** Gitea (git.digital-home.site) - **Домены:** - API: api.digital-home.site - Web: pulse.digital-home.site ## Структура Backend ``` homelab-api/ ├── cmd/api/ │ └── main.go # Точка входа, инициализация ├── internal/ │ ├── bot/ │ │ ├── bot.go # Telegram bot, long polling │ │ └── handlers.go # Обработчики команд и callback │ ├── config/ │ │ └── config.go # Загрузка переменных окружения │ ├── handler/ │ │ ├── auth.go # Регистрация, логин, JWT │ │ ├── habits.go # CRUD привычек │ │ ├── health.go # Health check │ │ ├── profile.go # Профиль пользователя │ │ └── tasks.go # CRUD задач │ ├── middleware/ │ │ └── auth.go # JWT middleware │ ├── model/ │ │ ├── habit.go # Модель привычки │ │ ├── task.go # Модель задачи │ │ └── user.go # Модель пользователя │ ├── repository/ │ │ ├── db.go # Подключение к PostgreSQL │ │ ├── habit.go # SQL-запросы для привычек │ │ ├── task.go # SQL-запросы для задач │ │ └── user.go # SQL-запросы для пользователей │ ├── scheduler/ │ │ └── scheduler.go # Cron jobs для уведомлений │ └── service/ │ ├── auth.go # Бизнес-логика авторизации │ ├── email.go # Отправка email через Resend │ ├── habit.go # Бизнес-логика привычек │ └── task.go # Бизнес-логика задач ├── Dockerfile ├── docker-compose.yml ├── go.mod └── go.sum ``` ## Структура Frontend ``` pulse-web/ ├── public/ │ └── favicon.svg # Иконка молния ⚡ ├── src/ │ ├── api/ │ │ ├── client.js # Axios instance + interceptors │ │ ├── habits.js # API привычек │ │ ├── profile.js # API профиля │ │ └── tasks.js # API задач │ ├── components/ │ │ ├── CreateHabitModal.jsx │ │ ├── CreateTaskModal.jsx │ │ ├── EditHabitModal.jsx │ │ ├── EditTaskModal.jsx │ │ └── Navigation.jsx # Нижняя навигация │ ├── pages/ │ │ ├── ForgotPassword.jsx │ │ ├── Habits.jsx # Управление привычками │ │ ├── Home.jsx # Главная (сегодня) │ │ ├── Login.jsx │ │ ├── Register.jsx │ │ ├── ResetPassword.jsx │ │ ├── Settings.jsx # Настройки профиля │ │ ├── Stats.jsx # Статистика │ │ ├── Tasks.jsx # Управление задачами │ │ └── VerifyEmail.jsx │ ├── store/ │ │ └── auth.js # Zustand store для авторизации │ ├── App.jsx # Роутинг │ ├── index.css # Глобальные стили │ └── main.jsx # Entry point ├── Dockerfile ├── docker-compose.yml ├── index.html ├── nginx.conf ├── package.json ├── tailwind.config.js └── vite.config.js ``` ## База данных ### Таблицы ```sql -- Пользователи users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, username VARCHAR(100) NOT NULL, password_hash VARCHAR(255) NOT NULL, email_verified BOOLEAN DEFAULT FALSE, telegram_chat_id BIGINT, notifications_enabled BOOLEAN DEFAULT TRUE, timezone VARCHAR(50) DEFAULT 'Europe/Moscow', morning_reminder_time TIME DEFAULT '09:00', evening_reminder_time TIME DEFAULT '21:00', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ) -- Задачи tasks ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), title VARCHAR(255) NOT NULL, description TEXT, icon VARCHAR(10) DEFAULT '📋', color VARCHAR(7) DEFAULT '#6B7280', due_date DATE, priority INTEGER DEFAULT 0, -- 0=none, 1=low, 2=medium, 3=high reminder_time TIME, completed_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ) -- Привычки habits ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), name VARCHAR(255) NOT NULL, description TEXT, icon VARCHAR(10) DEFAULT '✨', color VARCHAR(7) DEFAULT '#10B981', frequency VARCHAR(20) DEFAULT 'daily', -- daily, weekly, custom target_days INTEGER[], -- [1,3,5] для пн,ср,пт target_count INTEGER DEFAULT 1, reminder_time TIME, archived BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ) -- Логи привычек habit_logs ( id SERIAL PRIMARY KEY, habit_id INTEGER REFERENCES habits(id), user_id INTEGER REFERENCES users(id), date DATE NOT NULL, count INTEGER DEFAULT 1, created_at TIMESTAMP DEFAULT NOW() ) -- Email токены email_tokens ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), token VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL, -- verification, password_reset expires_at TIMESTAMP NOT NULL, created_at TIMESTAMP DEFAULT NOW() ) ``` ## API Endpoints ### Авторизация | Method | Endpoint | Описание | |--------|----------|----------| | POST | /auth/register | Регистрация | | POST | /auth/login | Вход | | POST | /auth/refresh | Обновить токены | | POST | /auth/verify-email | Подтвердить email | | POST | /auth/forgot-password | Запросить сброс пароля | | POST | /auth/reset-password | Сбросить пароль | ### Профиль (требует JWT) | Method | Endpoint | Описание | |--------|----------|----------| | GET | /profile | Получить профиль | | PUT | /profile | Обновить профиль | ### Задачи (требует JWT) | Method | Endpoint | Описание | |--------|----------|----------| | GET | /tasks | Список задач | | GET | /tasks/today | Задачи на сегодня | | POST | /tasks | Создать задачу | | GET | /tasks/{id} | Получить задачу | | PUT | /tasks/{id} | Обновить задачу | | DELETE | /tasks/{id} | Удалить задачу | | POST | /tasks/{id}/complete | Отметить выполненной | | POST | /tasks/{id}/uncomplete | Снять отметку | ### Привычки (требует JWT) | Method | Endpoint | Описание | |--------|----------|----------| | GET | /habits | Список привычек | | POST | /habits | Создать привычку | | GET | /habits/{id} | Получить привычку | | PUT | /habits/{id} | Обновить привычку | | DELETE | /habits/{id} | Удалить (архивировать) | | POST | /habits/{id}/log | Отметить выполнение | | GET | /habits/{id}/logs | История выполнений | | DELETE | /habits/{id}/logs/{logId} | Удалить запись | | GET | /habits/stats | Общая статистика | | GET | /habits/{id}/stats | Статистика привычки | ## Telegram Bot ### Команды | Команда | Описание | |---------|----------| | /start | Показать Chat ID | | /tasks | Задачи на сегодня | | /habits | Привычки на сегодня | | /help | Справка | ### Inline кнопки - ✅ Выполнено — отмечает задачу/привычку - 🗑 Удалить — удаляет задачу - ⏰ +30 мин — откладывает напоминание ### Уведомления 1. **Утреннее** (настраивается): задачи и привычки на сегодня 2. **Вечернее** (настраивается): итоги дня 3. **Индивидуальные**: по reminder_time каждой задачи/привычки ## Docker Compose ### Backend (homelab-api) ```yaml services: db: image: postgres:16-alpine environment: POSTGRES_USER: homelab POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: homelab volumes: - db_data:/var/lib/postgresql/data networks: - backend api: build: . environment: - DATABASE_URL=postgres://homelab:${DB_PASSWORD}@db:5432/homelab?sslmode=disable - JWT_SECRET=${JWT_SECRET} - RESEND_API_KEY=${RESEND_API_KEY} - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} depends_on: - db networks: - backend - services_proxy ``` ### Frontend (pulse-web) ```yaml services: web: build: . networks: - services_proxy ``` ## Дизайн ### Цвета - **Primary (Deep Teal):** #115E59 - **Accent (Burnished Amber):** #F59E0B - **Surface:** #F8FAFC - **Text:** #1E293B ### Шрифты - **Body:** Inter (Google Fonts) ### UI-компоненты - Карточки с тенями и закруглениями (rounded-2xl) - Backdrop blur для header - Framer Motion анимации - Inline кнопки в Telegram ## Репозитории - **Backend:** https://git.digital-home.site/daniil/pulse-api - **Frontend:** https://git.digital-home.site/daniil/pulse-web --- *Создано: 2026-02-06*