2025-12-03 19:29:37 +00:00
|
|
|
package services
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"database/sql"
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"go.uber.org/zap"
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
"gorm.io/gorm"
|
2025-12-08 18:57:54 +00:00
|
|
|
"gorm.io/gorm/clause"
|
|
|
|
|
"veza-backend-api/internal/database"
|
|
|
|
|
"veza-backend-api/internal/models"
|
2025-12-03 19:29:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// RBACService handles role-based access control
|
|
|
|
|
type RBACService struct {
|
|
|
|
|
db *database.Database
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewRBACService creates a new RBAC service
|
|
|
|
|
func NewRBACService(db *database.Database, logger *zap.Logger) *RBACService {
|
|
|
|
|
return &RBACService{
|
|
|
|
|
db: db,
|
|
|
|
|
logger: logger,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Role represents a user role
|
|
|
|
|
type Role struct {
|
2025-12-04 01:15:48 +00:00
|
|
|
ID uuid.UUID `json:"id"`
|
2025-12-03 19:29:37 +00:00
|
|
|
Name string `json:"name"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Permissions []Permission `json:"permissions"`
|
|
|
|
|
IsSystem bool `json:"is_system"`
|
|
|
|
|
CreatedAt string `json:"created_at"`
|
|
|
|
|
UpdatedAt string `json:"updated_at"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Permission represents a permission
|
|
|
|
|
type Permission struct {
|
2025-12-04 01:15:48 +00:00
|
|
|
ID uuid.UUID `json:"id"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Resource string `json:"resource"`
|
|
|
|
|
Action string `json:"action"`
|
|
|
|
|
CreatedAt string `json:"created_at"`
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UserRole represents a user's role assignment
|
|
|
|
|
type UserRole struct {
|
2025-12-04 01:15:48 +00:00
|
|
|
ID uuid.UUID `json:"id"`
|
|
|
|
|
UserID uuid.UUID `json:"user_id"`
|
|
|
|
|
RoleID uuid.UUID `json:"role_id"`
|
|
|
|
|
Role *Role `json:"role,omitempty"`
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateRole creates a new role
|
2025-12-04 01:15:48 +00:00
|
|
|
func (s *RBACService) CreateRole(ctx context.Context, name, description string, permissions []uuid.UUID) (*Role, error) {
|
2025-12-03 19:29:37 +00:00
|
|
|
// Check if role already exists
|
|
|
|
|
var count int
|
|
|
|
|
err := s.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM roles WHERE name = $1", name).Scan(&count)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to check role existence: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if count > 0 {
|
|
|
|
|
return nil, fmt.Errorf("role with name '%s' already exists", name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create role
|
2025-12-04 01:15:48 +00:00
|
|
|
var roleID uuid.UUID
|
2025-12-03 19:29:37 +00:00
|
|
|
query := `
|
2025-12-04 01:15:48 +00:00
|
|
|
INSERT INTO roles (id, name, description, is_system, created_at, updated_at)
|
|
|
|
|
VALUES (gen_random_uuid(), $1, $2, false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
2025-12-03 19:29:37 +00:00
|
|
|
RETURNING id
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
err = s.db.QueryRowContext(ctx, query, name, description).Scan(&roleID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to create role: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assign permissions to role
|
|
|
|
|
if len(permissions) > 0 {
|
|
|
|
|
for _, permID := range permissions {
|
|
|
|
|
_, err = s.db.ExecContext(ctx, `
|
|
|
|
|
INSERT INTO role_permissions (role_id, permission_id, created_at)
|
|
|
|
|
VALUES ($1, $2, CURRENT_TIMESTAMP)
|
|
|
|
|
`, roleID, permID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to assign permission to role", zap.Error(err))
|
|
|
|
|
// Continue with other permissions
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the created role with permissions
|
|
|
|
|
role, err := s.GetRoleByID(ctx, roleID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to get created role: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-04 01:15:48 +00:00
|
|
|
s.logger.Info("Role created successfully", zap.String("role_name", name), zap.String("role_id", roleID.String()))
|
2025-12-03 19:29:37 +00:00
|
|
|
return role, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRoleByID gets a role by ID
|
2025-12-04 01:15:48 +00:00
|
|
|
func (s *RBACService) GetRoleByID(ctx context.Context, roleID uuid.UUID) (*Role, error) {
|
2025-12-03 19:29:37 +00:00
|
|
|
query := `
|
|
|
|
|
SELECT r.id, r.name, r.description, r.is_system, r.created_at, r.updated_at
|
|
|
|
|
FROM roles r
|
|
|
|
|
WHERE r.id = $1
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
var role Role
|
|
|
|
|
err := s.db.QueryRowContext(ctx, query, roleID).Scan(
|
|
|
|
|
&role.ID, &role.Name, &role.Description, &role.IsSystem, &role.CreatedAt, &role.UpdatedAt,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err == sql.ErrNoRows {
|
|
|
|
|
return nil, fmt.Errorf("role not found")
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("failed to get role: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get permissions for this role
|
|
|
|
|
permissions, err := s.GetRolePermissions(ctx, roleID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to get role permissions", zap.Error(err))
|
|
|
|
|
} else {
|
|
|
|
|
role.Permissions = permissions
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &role, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRolePermissions gets permissions for a role
|
2025-12-04 01:15:48 +00:00
|
|
|
func (s *RBACService) GetRolePermissions(ctx context.Context, roleID uuid.UUID) ([]Permission, error) {
|
2025-12-03 19:29:37 +00:00
|
|
|
query := `
|
|
|
|
|
SELECT p.id, p.name, p.description, p.resource, p.action, p.created_at
|
|
|
|
|
FROM permissions p
|
|
|
|
|
JOIN role_permissions rp ON p.id = rp.permission_id
|
|
|
|
|
WHERE rp.role_id = $1
|
|
|
|
|
ORDER BY p.name
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
rows, err := s.db.QueryContext(ctx, query, roleID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to get role permissions: %w", err)
|
|
|
|
|
}
|
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
|
|
var permissions []Permission
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
var perm Permission
|
|
|
|
|
err := rows.Scan(&perm.ID, &perm.Name, &perm.Description, &perm.Resource, &perm.Action, &perm.CreatedAt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to scan permission", zap.Error(err))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
permissions = append(permissions, perm)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return permissions, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AssignRoleToUser assigns a role to a user
|
2025-12-04 01:15:48 +00:00
|
|
|
// MIGRATION UUID: userID migré vers uuid.UUID, roleID aussi
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
// Transactionnelle : Toutes les vérifications et l'INSERT sont dans une seule transaction avec FOR UPDATE
|
2025-12-04 01:15:48 +00:00
|
|
|
func (s *RBACService) AssignRoleToUser(ctx context.Context, userID uuid.UUID, roleID uuid.UUID) error {
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
return s.db.GormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
2025-12-08 18:57:54 +00:00
|
|
|
var err error
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
// 1. VALIDATION : User existe ? (SELECT avec FOR UPDATE pour éviter race condition)
|
2025-12-08 18:57:54 +00:00
|
|
|
var user models.User
|
|
|
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, userID).Error; err != nil {
|
|
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
|
|
|
return fmt.Errorf("user not found")
|
|
|
|
|
}
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
return fmt.Errorf("AssignRoleToUser: failed to check user existence: %w", err)
|
|
|
|
|
}
|
2025-12-03 19:29:37 +00:00
|
|
|
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
// 2. VALIDATION : Role existe ? (SELECT avec FOR UPDATE pour éviter race condition)
|
2025-12-08 18:57:54 +00:00
|
|
|
var role models.Role
|
|
|
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&role, roleID).Error; err != nil {
|
|
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
|
|
|
return fmt.Errorf("role not found")
|
|
|
|
|
}
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
return fmt.Errorf("AssignRoleToUser: failed to check role existence: %w", err)
|
|
|
|
|
}
|
2025-12-03 19:29:37 +00:00
|
|
|
|
2025-12-08 18:57:54 +00:00
|
|
|
// 1. Vérifier si l'utilisateur a déjà ce rôle (avec verrou)
|
|
|
|
|
var existingRole models.UserRole
|
|
|
|
|
err = tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
|
|
|
|
Where("user_id = ? AND role_id = ?", userID, roleID).
|
|
|
|
|
First(&existingRole).Error
|
|
|
|
|
|
|
|
|
|
if err == nil {
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
return fmt.Errorf("role already assigned to user")
|
|
|
|
|
}
|
2025-12-08 18:57:54 +00:00
|
|
|
if err != gorm.ErrRecordNotFound {
|
|
|
|
|
return fmt.Errorf("failed to check existing role: %w", err)
|
|
|
|
|
}
|
2025-12-03 19:29:37 +00:00
|
|
|
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
// 4. INSERTION : Assignation (INSERT dans la transaction)
|
2025-12-08 18:57:54 +00:00
|
|
|
// Note: 'role' column is required by schema (legacy/redundant field)
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
err = tx.Exec(`
|
2025-12-08 18:57:54 +00:00
|
|
|
INSERT INTO user_roles (id, user_id, role_id, role, created_at)
|
|
|
|
|
VALUES (gen_random_uuid(), ?, ?, ?, CURRENT_TIMESTAMP)
|
|
|
|
|
`, userID, roleID, role.Name).Error
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
if err != nil {
|
|
|
|
|
// Si contrainte UNIQUE violée (race condition détectée), la contrainte DB gère cela
|
|
|
|
|
// La vérification du doublon avant l'INSERT devrait gérer la plupart des cas
|
|
|
|
|
return fmt.Errorf("AssignRoleToUser: failed to assign role to user: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. LOG (dans la transaction, mais ne dépend pas d'états non commit)
|
|
|
|
|
s.logger.Info("Role assigned to user successfully",
|
|
|
|
|
zap.String("user_id", userID.String()),
|
|
|
|
|
zap.String("role_id", roleID.String()),
|
|
|
|
|
)
|
2025-12-03 19:29:37 +00:00
|
|
|
|
P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.
Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.
Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).
Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.
Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 10:14:38 +00:00
|
|
|
// 6. RETOUR nil = commit automatique
|
|
|
|
|
return nil
|
|
|
|
|
})
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RemoveRoleFromUser removes a role from a user
|
2025-12-04 01:15:48 +00:00
|
|
|
// MIGRATION UUID: userID migré vers uuid.UUID, roleID aussi
|
|
|
|
|
func (s *RBACService) RemoveRoleFromUser(ctx context.Context, userID uuid.UUID, roleID uuid.UUID) error {
|
2025-12-03 19:29:37 +00:00
|
|
|
result, err := s.db.ExecContext(ctx, `
|
|
|
|
|
DELETE FROM user_roles
|
|
|
|
|
WHERE user_id = $1 AND role_id = $2
|
|
|
|
|
`, userID, roleID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to remove role from user: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rowsAffected, err := result.RowsAffected()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to get rows affected: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if rowsAffected == 0 {
|
|
|
|
|
return fmt.Errorf("role not assigned to user")
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-04 01:15:48 +00:00
|
|
|
s.logger.Info("Role removed from user successfully", zap.String("user_id", userID.String()), zap.String("role_id", roleID.String()))
|
2025-12-03 19:29:37 +00:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUserRoles gets all roles for a user
|
|
|
|
|
func (s *RBACService) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]*Role, error) {
|
|
|
|
|
query := `
|
|
|
|
|
SELECT r.id, r.name, r.description, r.is_system, r.created_at, r.updated_at
|
|
|
|
|
FROM roles r
|
|
|
|
|
JOIN user_roles ur ON r.id = ur.role_id
|
|
|
|
|
WHERE ur.user_id = $1
|
|
|
|
|
ORDER BY r.name
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
rows, err := s.db.QueryContext(ctx, query, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to get user roles: %w", err)
|
|
|
|
|
}
|
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
|
|
var roles []*Role
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
var role Role
|
|
|
|
|
err := rows.Scan(&role.ID, &role.Name, &role.Description, &role.IsSystem, &role.CreatedAt, &role.UpdatedAt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to scan role", zap.Error(err))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get permissions for this role
|
|
|
|
|
permissions, err := s.GetRolePermissions(ctx, role.ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to get role permissions", zap.Error(err))
|
|
|
|
|
} else {
|
|
|
|
|
role.Permissions = permissions
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roles = append(roles, &role)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return roles, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CheckPermission checks if a user has a specific permission
|
|
|
|
|
func (s *RBACService) CheckPermission(ctx context.Context, userID uuid.UUID, resource, action string) (bool, error) {
|
|
|
|
|
query := `
|
|
|
|
|
SELECT COUNT(*)
|
|
|
|
|
FROM permissions p
|
|
|
|
|
JOIN role_permissions rp ON p.id = rp.permission_id
|
|
|
|
|
JOIN user_roles ur ON rp.role_id = ur.role_id
|
|
|
|
|
WHERE ur.user_id = $1 AND p.resource = $2 AND p.action = $3
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
var count int
|
|
|
|
|
err := s.db.QueryRowContext(ctx, query, userID, resource, action).Scan(&count)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, fmt.Errorf("failed to check permission: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count > 0, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUserPermissions gets all permissions for a user
|
|
|
|
|
func (s *RBACService) GetUserPermissions(ctx context.Context, userID uuid.UUID) ([]Permission, error) {
|
|
|
|
|
query := `
|
|
|
|
|
SELECT DISTINCT p.id, p.name, p.description, p.resource, p.action, p.created_at
|
|
|
|
|
FROM permissions p
|
|
|
|
|
JOIN role_permissions rp ON p.id = rp.permission_id
|
|
|
|
|
JOIN user_roles ur ON rp.role_id = ur.role_id
|
|
|
|
|
WHERE ur.user_id = $1
|
|
|
|
|
ORDER BY p.resource, p.action
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
rows, err := s.db.QueryContext(ctx, query, userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to get user permissions: %w", err)
|
|
|
|
|
}
|
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
|
|
var permissions []Permission
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
var perm Permission
|
|
|
|
|
err := rows.Scan(&perm.ID, &perm.Name, &perm.Description, &perm.Resource, &perm.Action, &perm.CreatedAt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to scan permission", zap.Error(err))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
permissions = append(permissions, perm)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return permissions, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreatePermission creates a new permission
|
|
|
|
|
func (s *RBACService) CreatePermission(ctx context.Context, name, description, resource, action string) (*Permission, error) {
|
|
|
|
|
// Check if permission already exists
|
|
|
|
|
var count int
|
|
|
|
|
err := s.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM permissions WHERE resource = $1 AND action = $2", resource, action).Scan(&count)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to check permission existence: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if count > 0 {
|
|
|
|
|
return nil, fmt.Errorf("permission with resource '%s' and action '%s' already exists", resource, action)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create permission
|
2025-12-04 01:15:48 +00:00
|
|
|
var permID uuid.UUID
|
2025-12-03 19:29:37 +00:00
|
|
|
query := `
|
2025-12-04 01:15:48 +00:00
|
|
|
INSERT INTO permissions (id, name, description, resource, action, created_at)
|
|
|
|
|
VALUES (gen_random_uuid(), $1, $2, $3, $4, CURRENT_TIMESTAMP)
|
2025-12-03 19:29:37 +00:00
|
|
|
RETURNING id
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
err = s.db.QueryRowContext(ctx, query, name, description, resource, action).Scan(&permID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to create permission: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
permission := &Permission{
|
|
|
|
|
ID: permID,
|
|
|
|
|
Name: name,
|
|
|
|
|
Description: description,
|
|
|
|
|
Resource: resource,
|
|
|
|
|
Action: action,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.logger.Info("Permission created successfully", zap.String("permission_name", name))
|
|
|
|
|
return permission, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetAllRoles gets all roles
|
|
|
|
|
func (s *RBACService) GetAllRoles(ctx context.Context) ([]*Role, error) {
|
|
|
|
|
query := `
|
|
|
|
|
SELECT id, name, description, is_system, created_at, updated_at
|
|
|
|
|
FROM roles
|
|
|
|
|
ORDER BY name
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
rows, err := s.db.QueryContext(ctx, query)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to get roles: %w", err)
|
|
|
|
|
}
|
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
|
|
var roles []*Role
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
var role Role
|
|
|
|
|
err := rows.Scan(&role.ID, &role.Name, &role.Description, &role.IsSystem, &role.CreatedAt, &role.UpdatedAt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to scan role", zap.Error(err))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get permissions for this role
|
|
|
|
|
permissions, err := s.GetRolePermissions(ctx, role.ID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.logger.Error("Failed to get role permissions", zap.Error(err))
|
|
|
|
|
} else {
|
|
|
|
|
role.Permissions = permissions
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roles = append(roles, &role)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return roles, nil
|
2025-12-06 16:21:59 +00:00
|
|
|
}
|