Club come entità principale, branding e fix infrastruttura streaming.

Introduce clubs con abbonamento, branding Active Storage e flusso registrazione società; corregge healthcheck MediaMTX (immagine distroless) e allinea dominio produzione matchlivetv.it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-27 09:16:24 +02:00
parent 471291b2c4
commit 4083bc5dee
53 changed files with 1120 additions and 197 deletions

View File

@@ -40,11 +40,11 @@ module Api
private
def set_team
@team = current_user.teams.find(params[:team_id])
@team = current_user.manageable_teams.find(params[:team_id])
end
def set_match
@match = Match.joins(:team).merge(current_user.teams).find(params[:id])
@match = Match.joins(:team).merge(current_user.manageable_teams).find(params[:id])
end
def match_params

View File

@@ -4,7 +4,7 @@ module Api
before_action :set_session, except: :create
def create
match = Match.joins(:team).merge(current_user.teams).find(params[:match_id])
match = Match.joins(:team).merge(current_user.manageable_teams).find(params[:match_id])
session = Sessions::Create.new(user: current_user, match: match, params: session_params).call
render json: session_json(session), status: :created
end
@@ -102,7 +102,7 @@ module Api
def set_session
@session = StreamSession.joins(match: :team)
.merge(current_user.teams)
.merge(current_user.manageable_teams)
.find(params[:id])
end

View File

@@ -2,30 +2,32 @@ module Api
module V1
class TeamsController < BaseController
def index
teams = current_user.teams.includes(:matches)
teams = current_user.manageable_teams.includes(:club, :matches)
render json: teams.map { |t| team_json(t) }
end
def show
team = current_user.teams.find(params[:id])
team = current_user.manageable_teams.find(params[:id])
render json: team_json(team, detail: true)
end
def create
if current_user.user_teams.where(role: "owner").count >= 1
if current_user.owned_clubs.exists?
return render json: {
error: "Puoi gestire una sola squadra. Usa il sito per inviti o contattaci."
error: "Registra o gestisci la società dal sito web per aggiungere squadre."
}, status: :unprocessable_entity
end
team = Team.create!(team_params)
UserTeam.create!(user: current_user, team: team, role: "owner")
Billing::AssignPlan.call(team: team, plan_slug: "free")
club = Club.create!(name: team_params[:name], sport: team_params[:sport] || "volleyball",
primary_color: "#e53935", secondary_color: "#ffffff")
ClubMembership.create!(user: current_user, club: club, role: "owner")
team = club.teams.create!(name: team_params[:name], sport: club.sport)
Billing::AssignPlan.call(club: club, plan_slug: "free")
render json: team_json(team), status: :created
end
def recordings
team = current_user.teams.find(params[:id])
team = current_user.manageable_teams.find(params[:id])
unless team.entitlements.can_access_recordings?
return render json: {
error: "Archivio gare disponibile con Premium Light o Full",
@@ -39,13 +41,13 @@ module Api
end
def update
team = current_user.teams.find(params[:id])
team = current_user.manageable_teams.find(params[:id])
team.update!(team_params)
render json: team_json(team)
end
def add_member
team = current_user.teams.find(params[:id])
team = current_user.manageable_teams.find(params[:id])
team.entitlements.assert_can_invite!
member = User.find(params[:user_id])
UserTeam.find_or_create_by!(user: member, team: team) { |ut| ut.role = "member" }
@@ -53,7 +55,7 @@ module Api
end
def remove_member
team = current_user.teams.find(params[:id])
team = current_user.manageable_teams.find(params[:id])
ut = team.user_teams.find_by!(user_id: params[:user_id], role: "member")
ut.destroy!
head :no_content
@@ -71,7 +73,11 @@ module Api
id: team.id,
name: team.name,
sport: team.sport,
logo_url: team.logo_url,
logo_url: team.effective_logo_url,
primary_color: team.effective_primary_color,
secondary_color: team.effective_secondary_color,
club_id: team.club_id,
club_name: team.club.name,
youtube_connected: team.youtube_credential.present?,
plan_slug: ent.plan.slug,
plan_name: ent.plan.name,

View File

@@ -2,14 +2,14 @@ module Api
module V1
class YoutubeController < BaseController
def authorize
team = current_user.teams.find(params[:team_id])
team = current_user.manageable_teams.find(params[:team_id])
team.entitlements.assert_can_connect_youtube!
url = Youtube::OauthUrl.build(team_id: team.id, redirect_uri: ENV.fetch("YOUTUBE_REDIRECT_URI"))
render json: { authorization_url: url }
end
def callback
team = current_user.teams.find(params[:state])
team = current_user.manageable_teams.find(params[:state])
tokens = Youtube::OauthExchange.call(params[:code])
cred = team.youtube_credential || team.build_youtube_credential
cred.update!(