Я разрабатываю веб-приложение для обмена навыками. Я реализовал авторизацию пользователей через JWT и OAuth 2.0 через google аккаунт. Теперь мне нужно, чтобы ты помог мне реализовать следующие шаги (Решение не должно быть слишком сложным и замудреным, лучше пусть оно будет проще):

1) Внедрить систему ролей (в соответствии с тз, объясни как это работает)
2) Реализовать сессии обмена опытом
3) Система рейтингов и отзывов
3) Объяснить свое решение и объяснить как его протестировать.


- Управление сеансами (создание, внесение в список, регистрация, выход).
  - Рейтинги и отзывы.
Веб-платформа Skill-Sharing - это место, где пользователи могут предлагать и изучать навыки. Пользователи создают профили, размещают информацию о сеансах обмена навыками, а другие могут присоединяться, оценивать и оставлять отзывы. ИИ может быть интегрирован, чтобы рекомендовать навыки на основе взаимодействия с пользователями.

Целевые пользователи
•	Поставщики навыков (наставники/преподаватели) - пользователи, предлагающие сеансы обмена навыками.
•	Искатели навыков (учащиеся) - пользователи, желающие получить новые навыки.
•	Модераторы/администраторы - пользователи с правами управления контентом, разрешения споров и поддержания целостности платформы.
2. Основные функции
Функции MVP (минимального жизнеспособного продукта)
1.	Аутентификация и профили пользователей
a.	Регистрация/вход в систему с помощью электронной почты, OAuth (Google, GitHub)
b.	Профиль с биографией, навыками и рейтингом
c.	Пользовательская панель для управления сессиями
2.	Сессии обмена навыками
a.	Создание, редактирование и удаление сессий (название, описание, дата/время, категория, максимальное количество участников).
b.	Список всех сессий (с фильтрами по местоположению, навыкам, дате).
c.	Присоединяйтесь к сессиям и покидайте их.
d.	Просмотр сведений о сеансе (включая участников).
3.	Отзывы и рейтинги
a.	Оценивайте сеансы (1-5 звезд).
b.	Оставляйте текстовые отзывы о сеансах.
c.	Просматривайте средние оценки и отзывы пользователей и сеансов.

Архитектура - монолит, API - REST, сервер -Go + Gin, бд - postgresql, фронтенд - Nextjs + tailwindcss. 

Структура сервера:

config/
controllers/
handlers/
middleware/
models/
repositories/
routes/
main.go

Schema:

-- Table: Users
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255),
    oauth_provider VARCHAR(50),
    oauth_id VARCHAR(255),
    name VARCHAR(100) NOT NULL,
    bio TEXT,
    skills VARCHAR(50)[] NOT NULL DEFAULT '{}',
    average_rating FLOAT DEFAULT 0.0,
    role VARCHAR(20) NOT NULL DEFAULT "user",
    jwt_refresh_token TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Create index on email for faster lookups
CREATE INDEX idx_users_email ON users(email);

-- Create GIN index on skills for efficient array searches
CREATE INDEX idx_users_skills ON users USING GIN(skills);

-- Trigger to update updated_at in Users
CREATE TRIGGER trigger_update_users_timestamp
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_timestamp();

-- Table: Sessions
CREATE TABLE sessions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    title VARCHAR(255) NOT NULL,
    description TEXT,
    category VARCHAR(50) NOT NULL,
    date_time TIMESTAMP WITH TIME ZONE NOT NULL,
    location VARCHAR(255) NOT NULL,
    max_participants INTEGER NOT NULL CHECK (max_participants > 0),
    creator_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Create index on creator_id for faster joins
CREATE INDEX idx_sessions_creator_id ON sessions(creator_id);

-- Trigger to update updated_at in Sessions
CREATE TRIGGER trigger_update_sessions_timestamp
BEFORE UPDATE ON sessions
FOR EACH ROW
EXECUTE FUNCTION update_timestamp();

-- Table: Session_Participants (many-to-many relationship)
CREATE TABLE session_participants (
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    joined_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    PRIMARY KEY (session_id, user_id)
);

-- Create index on user_id for faster joins
CREATE INDEX idx_session_participants_user_id ON session_participants(user_id);

-- Table: Feedback
CREATE TABLE feedback (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
    comment TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Create index on session_id and user_id for faster joins
CREATE INDEX idx_feedback_session_id ON feedback(session_id);
CREATE INDEX idx_feedback_user_id ON feedback(user_id);

-- Trigger to update average_rating in Users when feedback is added
CREATE TRIGGER trigger_update_average_rating
AFTER INSERT OR UPDATE ON feedback
FOR EACH ROW
EXECUTE FUNCTION update_average_rating();


routes.go:
package routes

import (
        "/controllers"
        "/handlers"
        "/middleware"
        "/repositories"
        "/config"
        "github.com/gin-contrib/cors"
        "github.com/gin-gonic/gin"
        "github.com/jmoiron/sqlx"
)

// SetupRouter configures the Gin router
func SetupRouter(db *sqlx.DB) *gin.Engine {
        r := gin.Default()
        cfg := config.LoadConfig()
    
        // Настройка CORS
        corsConfig := cors.DefaultConfig()
        corsConfig.AllowOrigins = []string{"http://localhost:3000"}
        corsConfig.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}
        corsConfig.AllowHeaders = []string{"Origin", "Content-Type", "Authorization"}
        corsConfig.AllowCredentials = true
        r.Use(cors.New(corsConfig))
    
        // Initialize repositories
        userRepo := repositories.NewUserRepository(db)
        sessionRepo := repositories.NewSessionRepository(db)
    
        // Initialize controllers
        userController := controllers.NewUserController(userRepo)
        sessionController := controllers.NewSessionController(sessionRepo)
    
        // Initialize auth handlers
        authHandler := handlers.NewAuthHandler(db)
        oauthHandler := handlers.NewOAuthHandler(db, cfg)
    
        // Auth routes (публичные маршруты)
        authGroup := r.Group("/auth")
        {
            authGroup.POST("/register", authHandler.Register)
            authGroup.POST("/login", authHandler.Login)
            authGroup.POST("/refresh", authHandler.RefreshToken)
            
            // OAuth routes
            authGroup.GET("/google", oauthHandler.GoogleLogin)
            authGroup.GET("/google/callback", oauthHandler.GoogleCallback)
        }
    
        // API routes (защищенные маршруты)
        api := r.Group("/api")
        api.Use(middleware.JWTAuthMiddleware())
        {
            // Logout route
            api.POST("/logout", authHandler.Logout)
            
            // User routes
            users := api.Group("/users")
            {
                users.GET("", userController.GetAll)
                users.GET("/:id", userController.GetByID)
                // Маршруты требующие прав администратора
                adminUsers := users.Group("")
                adminUsers.Use(middleware.RoleAuthMiddleware("admin"))
                {
                    adminUsers.POST("", authHandler.Register)
                    adminUsers.PUT("/:id", userController.Update)
                    adminUsers.DELETE("/:id", userController.Delete)
                }
                
                // Профиль текущего пользователя
                users.GET("/me", authHandler.GetMe)
            }
    
            // Session routes
            sessions := api.Group("/sessions")
            {
                sessions.GET("", sessionController.GetAll)
                sessions.GET("/:id", sessionController.GetByID)
                sessions.POST("", sessionController.Create)
                sessions.PUT("/:id", sessionController.Update)
                sessions.DELETE("/:id", sessionController.Delete)
                sessions.GET("/:id/participants", sessionController.GetParticipants)
            }
        }
    
        return r
    }

models/session.go:
package models

import (
	"time"

	"github.com/google/uuid"
)

// Session represents a skill-sharing session
type Session struct {
	ID              uuid.UUID `json:"id" db:"id"`
	Title           string    `json:"title" db:"title"`
	Description     string    `json:"description" db:"description"`
	Category        string    `json:"category" db:"category"`
	DateTime        time.Time `json:"date_time" db:"date_time"`
	Location        string    `json:"location" db:"location"`
	MaxParticipants int       `json:"max_participants" db:"max_participants"`
	CreatorID       uuid.UUID `json:"creator_id" db:"creator_id"`
	CreatedAt       time.Time `json:"created_at" db:"created_at"`
	UpdatedAt       time.Time `json:"updated_at" db:"updated_at"`
}

// SessionRequest for creating/updating sessions
type SessionRequest struct {
	Title           string    `json:"title" binding:"required"`
	Description     string    `json:"description"`
	Category        string    `json:"category" binding:"required"`
	DateTime        time.Time `json:"date_time" binding:"required"`
	Location        string    `json:"location" binding:"required"`
	MaxParticipants int       `json:"max_participants" binding:"required,min=1"`
}

models/feedback.go:
package models

import (
	"time"

	"github.com/google/uuid"
)

// Feedback represents user feedback for a session
type Feedback struct {
	ID        uuid.UUID `json:"id" db:"id"`
	SessionID uuid.UUID `json:"session_id" db:"session_id"`
	UserID    uuid.UUID `json:"user_id" db:"user_id"`
	Rating    int       `json:"rating" db:"rating"`
	Comment   string    `json:"comment" db:"comment"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
}

// FeedbackRequest for creating/updating feedback
type FeedbackRequest struct {
	Rating  int    `json:"rating" binding:"required,min=1,max=5"`
	Comment string `json:"comment"`
}