Add Pulse architecture documentation
This commit is contained in:
324
Projects/Pulse/Architecture.md
Normal file
324
Projects/Pulse/Architecture.md
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
# 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*
|
||||||
Reference in New Issue
Block a user