🎓 User Platform

Полный разбор архитектуры Full-Stack приложения

Детальное руководство по каждому файлу и методу проекта

🐍

FastAPI Backend

Современный Python фреймворк

JavaScript Frontend

Чистый JS без фреймворков

🗄️

SQLite Database

Локальная база данных

🔐

JWT Аутентификация

Безопасный доступ

📁 Структура проекта

Организация файлов и папок

📂 user-platform/
📄 README.md
📄 requirements.txt
📂 backend/
📄 run.py
📂 app/
📄 __init__.py
📄 main.py
📄 database.py
📂 frontend/
📄 index.html
📄 style.css
📄 app.js
📄 auth.js
📄 dashboard.js
💡 Важно: Каждая папка должна содержать файл __init__.py для создания Python пакета

🐍 Backend: main.py

Сердце нашего приложения

from fastapi import FastAPI
from .database import init_db
from .middleware.cors import setup_cors
from .routes import auth, users

# 🚀 Инициализация базы данных
init_db()

# 📱 Создание FastAPI приложения
app = FastAPI(
  title="User Platform API",
  description="Backend для пользовательской платформы",
  version="1.0.0"
)

# 🌐 Настройка CORS для frontend
setup_cors(app)

# 🔗 Подключение маршрутов
app.include_router(auth.router)
app.include_router(users.router)
📌 init_db()
Создает таблицы в базе данных и добавляет тестового администратора
🌐 setup_cors(app)
Настраивает CORS для разрешения запросов от frontend
🔗 app.include_router()
Подключает модули с API endpoints к основному приложению

🗄️ Database: database.py

Работа с SQLite и управление соединениями

import sqlite3
from contextlib import contextmanager

# 🗂️ Путь к файлу базы данных
DATABASE_URL = "app.db"

def init_db():
  # 📊 Создание таблицы пользователей
  conn.execute('''
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      username TEXT UNIQUE NOT NULL,
      email TEXT UNIQUE NOT NULL,
      hashed_password TEXT NOT NULL,
      role TEXT DEFAULT 'user'
    )
  ''')

@contextmanager
def get_db():
  # 🔄 Контекстный менеджер для автоматического закрытия соединения
  conn = sqlite3.connect(DATABASE_URL)
  conn.row_factory = sqlite3.Row
  try:
    yield conn
  finally:
    conn.close()
🎯 Контекстный менеджер: Автоматически закрывает соединение с БД даже при ошибках
⚠️ Важно: row_factory = sqlite3.Row позволяет обращаться к колонкам по имени вместо индекса

📊 Модели данных: user.py

Pydantic модели для валидации и типизации

from pydantic import BaseModel, EmailStr
from typing import Optional
from enum import Enum

# 🎭 Роли пользователей
class UserRole(str, Enum):
  GUEST = "guest"
  USER = "user"
  ADMIN = "admin"

# 💎 Статусы пользователей
class UserStatus(str, Enum):
  BASIC = "basic"
  PREMIUM = "premium"

# 👤 Базовая модель пользователя
class UserBase(BaseModel):
  username: str
  email: EmailStr
  full_name: Optional[str] = None

# 📝 Модель для создания пользователя
class UserCreate(UserBase):
  password: str

Валидация данных

Pydantic автоматически проверяет типы данных

📧

Email валидация

EmailStr проверяет формат email

🎭

Enum ограничения

Только разрешенные значения ролей и статусов

🔐 Аутентификация: auth.py

Регистрация, вход и JWT токены

@router.post("/register", response_model=User)
def register(user_data: UserCreate):
  # 🔍 Проверка существующего пользователя
  existing = conn.execute(
    "SELECT id FROM users WHERE username = ? OR email = ?",
    (user_data.username, user_data.email)
  ).fetchone()

  if existing:
    raise HTTPException(status_code=400)

  # 🔒 Хеширование пароля
  hashed_password = get_password_hash(user_data.password)

  # 💾 Сохранение в базу
  cursor = conn.execute('''
    INSERT INTO users (username, email, hashed_password)
    VALUES (?, ?, ?)
  ''', (user_data.username, user_data.email, hashed_password))
📝

Frontend Form

Форма регистрации

🐍

FastAPI

Валидация данных

🔒

Password Hash

bcrypt хеширование

🗄️

SQLite

Сохранение в БД

⚡ Frontend: app.js

Управление навигацией и состоянием приложения

// 🌐 Базовый URL API
const API_BASE = 'http://localhost:8000';

// 🎯 Главная функция навигации
function showPage(pageName) {
  // 🎪 Скрываем все страницы
  document.querySelectorAll('.page').forEach(page => {
    page.classList.remove('active');
  });

  // 🔦 Показываем выбранную страницу
  document.getElementById(`${pageName}-page`).classList.add('active');

  // 📥 Загружаем данные при необходимости
  if (pageName === 'users') {
    loadAllUsers();
  } else if (pageName === 'dashboard' && token) {
    loadDashboard();
  }
}
🧭 showPage(pageName)
Управляет отображением страниц Single Page Application
👥 loadAllUsers()
Загружает список всех пользователей с сервера
📊 loadDashboard()
Загружает данные для личного кабинета

🔐 Frontend: auth.js

Работа с регистрацией, входом и JWT токенами

// 📝 Функция регистрации пользователя
async function registerUser(event) {
  event.preventDefault();
  console.log('🔄 Начало регистрации...');

  const userData = {
    username: document.getElementById('reg-username').value,
    email: document.getElementById('reg-email').value,
    password: document.getElementById('reg-password').value
  };

  try {
    // 🚀 Отправка запроса на сервер
    const response = await fetch(`${API_BASE}/auth/register`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(userData)
    });

    if (response.ok) {
      alert('✅ Регистрация успешна!');
      showPage('login');
    }
  } catch (error) {
    alert('❌ Ошибка соединения');
  }
}
🎯 Async/Await: Позволяет писать асинхронный код как синхронный, делая его более читаемым
⚠️ Безопасность: Токены JWT хранятся в localStorage - в продакшене используйте httpOnly cookies

📊 Frontend: dashboard.js

Личный кабинет и управление товарами

// 🛍️ Загрузка товаров пользователя
async function loadMyItems() {
  if (!token) return;

  try {
    const response = await fetch(`${API_BASE}/users/me/items`, {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    });

    if (response.ok) {
      const items = await response.json();
      displayItems(items, 'my-items');
    }
  } catch (error) {
    console.error('Error loading items:', error);
  }
}

// 🖼️ Отображение товаров
function displayItems(items, containerId) {
  const container = document.getElementById(containerId);
  container.innerHTML = items.map(item => `
    <div class="item-card">
      <h3>${item.title}</h3>
      <p>${item.description}</p>
    </div>
  `).join('');
}
🔐 Authorization Header
JWT токен передается в заголовке для аутентификации
🎨 displayItems()
Динамически создает HTML элементы для отображения товаров
🔄 Array.map()
Преобразует массив объектов в массив HTML строк

🚀 Запуск проекта

Пошаговая инструкция по запуску

1️⃣

Установка зависимостей

cd backend
pip install -r requirements.txt
2️⃣

Запуск Backend

python run.py
# Сервер на localhost:8000
3️⃣

Запуск Frontend

cd frontend
python -m http.server 4000
# Сайт на localhost:4000
4️⃣

Тестирование

Откройте браузер:
http://localhost:4000
🎯 Тестовые данные:
• Администратор: admin / password
• Можно зарегистрировать нового пользователя

🎯 Итоги и лучшие практики

Ключевые моменты для запоминания

🏗️

Архитектура

Четкое разделение frontend/backend

🔐

Безопасность

JWT токены + хеширование паролей

📊

База данных

SQLite с контекстными менеджерами

🎨

Frontend

Чистый JavaScript + async/await

✅ Что мы изучили
• FastAPI и Pydantic модели
• JWT аутентификация
• SQLite работа с БД
• JavaScript fetch API
• SPA навигация
• CORS настройка
🚀 Для дальнейшего развития
• Docker контейнеризация
• PostgreSQL вместо SQLite
• React/Vue.js вместо чистого JS
• Redis для кэширования
• Unit тесты