@startuml team-join-sequence title CR-Core — Player joins a public team (sequence diagram) actor Player participant "BaseCommand\n(TeamCommand)" as Base participant "SubCommand\n(TeamJoinSub)" as Sub participant "TeamService" as Service participant "TeamRepository" as Repo participant "Team" as Team Player -> Base : /team join activate Base Base -> Base : route args[0]="join" → TeamJoinSub Base -> Sub : execute(ctx) activate Sub Sub -> Service : getTeamByName(name) activate Service Service -> Repo : findByName(name) activate Repo Repo --> Service : Optional deactivate Repo Service --> Sub : Optional deactivate Service alt team not found Sub --> Base : CommandResult.failure("Team not found") else team found Sub -> Service : joinTeam(team.id, playerId) activate Service Service -> Service : validateJoinable(team, playerId) alt team is PRIVATE Service --> Sub : throw TeamAccessException Sub --> Base : CommandResult.failure(ex.message) else player already in a team Service --> Sub : throw TeamAccessException Sub --> Base : CommandResult.failure(ex.message) else allowed Service -> Team : addMember(playerId) activate Team Team --> Service : member deactivate Team Service -> Repo : save(team) activate Repo Repo --> Service : team deactivate Repo Service -> Service : onMemberAdded(team, member) Service -> Service : onPlayerJoined(team, member) Service --> Sub : true Sub --> Base : CommandResult.success("Joined " + team.name) end deactivate Service end deactivate Sub Base -> Base : handleResult → sender.sendMessage Base --> Player : reply deactivate Base @enduml