그룹 + 신뢰도 조합으로 제목 자동화하는 모범 사례

안녕하세요,

그룹 소속과 신뢰 수준(trust level)의 조합에 따라 사용자 타이틀을 자동으로 할당하는 가장 좋은 방법을 찾고 있습니다. 예를 들어:

  • 사용자가 그룹 A에 속해 있고 신뢰 수준이 1이면, 타이틀은 "A TL1"이어야 합니다.
  • 사용자가 그룹 A에 속해 있고 신뢰 수준이 2이면, 타이틀은 "A TL2"이어야 합니다.
  • 사용자가 그룹 B에 속해 있고 신뢰 수준이 1이면, 타이틀은 "B TL1"이어야 합니다.
  • …그리고 이어서 같은 방식으로 적용됩니다.

지금까지 조사한 결과, 주요 방법은 다음과 같습니다:

  1. Dynamic Groups 플러그인을 사용하여 각 그룹 + 신뢰 수준 조합마다 별도의 그룹을 생성합니다(예: a-tl1, a-tl2, b-tl1 등).
  2. 이 각 그룹에 기본 타이틀을 설정합니다.

이 방식이 작동하는 것 같지만, 조합이 많다면 상당数量的의 그룹을 생성하고 유지 관리해야 합니다.

질문 사항:

  • 이 설정(많은 수의 동적 그룹과 각각의 고유한 기본 타이틀)이 타이틀을 자동으로 동기화 상태로 유지하는 가장 좋거나 유일한 방법인가요?
  • 그룹 + 신뢰 수준과 같은 조건에 기반하여 타이틀을 동적으로 할당하면서, 이렇게 많은 추가 그룹을 관리하지 않아도 되는 다른 접근 방식(Discourse 코어, Automations 또는 다른 플러그인 사용)이 있나요?

어떤 조언이나 경험 공유가든 감사하겠습니다. 미리 감사합니다!

그룹 멤버십(A 또는 B)에 따라 제목을 구성하고, 그 뒤에 신뢰 수준에 따라 제목을 추가하는 컴포넌트를 사용하는 방식이 괜찮을까요?

그렇게 하면 그 모든 결합된 서브그룹이 필요 없을 것 같습니다 :thinking:

또 다른 아이디어: 신뢰 수준을 제목으로 자동 설정하는 플러그인을 기반으로, 신뢰 수준과 그룹 멤버십에 따라 더 복잡한 제목 업데이트를 만들 수 있을지도 모르겠습니다.

제안해 주셔서 감사합니다.

불행히도 저는 프로그래밍 경험이 전혀 없어서 플러그인을 개발하거나 수정할 수 없습니다. 해당 기능(그룹 멤버십과 신뢰 수준을 결합하여 칭호를 부여하는 것)을 추가할 수 있는지, 혹은 관련 조언이 있는지 플러그인 제작자에게 이미 문의를 보냈습니다.

사용자의 기본 그룹이라면, 다른 주제에서 언급하신 대로 그렇게 하면 훨씬 쉬울 것 같습니다.

그런 다음 user.primary_group을 통해 기본 그룹을 가져오고, user.title을 사용하여 제목을 설정하면 됩니다.

@joo add_primary_group_title 설정(기본값: 꺼짐)을 추가했습니다. 이 설정은 다음과 같은 기능을 합니다:

  • 사용자의 기본 그룹을 제목으로 추가합니다.
  • 제목 뒤의 텍스트, 예:

         이전과 같이 설정을 통해 편집할 수 있습니다.

ask.discourse.com의 마법을 살짝 빌려왔습니다.

P.S. 'can’을 들여쓰기한 방법에 대해 궁금해하신다면,  를 사용했습니다. 죄송합니다.

안녕하세요! 업데이트와 지원에 감사드립니다!

이전에 제 요구 사항을 충분히 명확히 설명하지 못했을 수 있어서, 이해하기 쉬운 예시를 들어 다시 한 번 설명드리겠습니다:

우리 포럼에 두 개의 주요 그룹이 있다고 가정해 보겠습니다:

  • 그룹 A: 디자이너 (Designers)
  • 그룹 B: 개발자 (Developers)

각 그룹별로 신뢰 수준(Trust Level)이 다른 사용자에게 완전히 다른 제목(Title)이 부여되도록 하려면 다음과 같이 설정하고 싶습니다:

디자이너 그룹의 경우:
신뢰 수준 1 → “주니어 디자이너”
신뢰 수준 2 → “디자이너”
신뢰 수준 3 → “시니어 디자이너”
신뢰 수준 4 → “수석 디자이너”

개발자 그룹의 경우:
신뢰 수준 1 → “주니어 개발자”
신뢰 수준 2 → “개발자”
신뢰 수준 3 → “시니어 개발자”
신뢰 수준 4 → “테크 리드”

즉, “디자이너” 그룹에 속해 있고 신뢰 수준이 3인 사용자의 제목은 "시니어 디자이너"가 되어야 합니다.
“개발자” 그룹에 속해 있고 신뢰 수준이 2인 사용자의 제목은 "개발자"가 되어야 합니다.

그룹별 및 신뢰 수준별로 이러한 규칙을 설정할 수 있고, 사용자의 그룹이나 신뢰 수준이 변경될 때 제목이 자동으로 부여되기를 바랍니다.

이 기능을 구현하는 방법에 대한 조언을 주실 수 있을까요? 아니면 이 기능을 플러그인의 새로운 기능으로 추가해 주실 의향이 있으신가요?

정말 감사합니다!

또한, 저는 테스트 사이트 http://ask.discourse.com/ 에서 이 작업을 수행하려고 합니다.
프로그래밍 경험이 없어서 제가 직접 구현할 수 있는 지 확신이 서지 않습니다.

텍스트 상자에서 제목을 더 쉽게 편집할 수 있도록 {group_nane}와 같은 플레이스홀더 값을 사용할 수도 있습니다. 확인해 보겠습니다.

아래 링크를 확인해 보시는 것이 좋습니다:

안녕하세요!

제 필요에 맞게 플러그인을 수정했고, 제가 무엇을 했는지, 현재 워크플로우, 그리고 조언을 구하는 몇 가지 질문/요청을 공유하고 싶습니다.


1. 제 수정 사항

파일 경로 및 내용:

파일: app/jobs/scheduled/update-all-titles.rb

# frozen_string_literal: true

module AddTitleBasedOnTrustLevel
  class UpdateTitles < ::Jobs::Scheduled
    every SiteSetting.update_title_frequency.hours

    def execute(args)
      group_titles = JSON.parse(SiteSetting.group_trust_level_titles || "{}")

      User.find_each do |user|
        # Skip admins and moderators, do not update their titles
        next if user.admin? || user.moderator?

        group_id = user.primary_group_id
        next unless group_id

        group = Group.find_by(id: group_id)
        next unless group

        group_key = group.name.downcase
        tl = user.trust_level

        titles = group_titles[group_key]
        next unless titles.is_a?(Array)
        next unless tl >= 1 && tl <= 4

        new_title = titles[tl]
        next unless new_title.present?

        user.update_column(:title, new_title) if user.title != new_title
      end
    end
  end
end

파일: config/settings.yml

plugins:
  add_title_based_on_trust_level_enabled:
    default: false
    client: true
  group_trust_level_titles:
    default: '{"designers": ["", "Junior Designer", "Designer", "Senior Designer", "Chief Designer"], "developers": ["", "Junior Developer", "Developer", "Senior Developer", "Tech Lead"]}'
    type: string
    client: true
    multiline: true
  update_title_frequency:
    default: 24
    type: integer

2. 테스트 방법

현재 rails console를 통해 이 로직을 수동으로 실행하여 기능이 작동하는지 확인하고 있습니다. 요구사항에 따라 사용자 칭호를 일괄 업데이트합니다.


3. 플러그인 설정 항목 문제

/admin/plugins 페이지에서 이 플러그인에 대한 “설정” 버튼이 없습니다. 현재 설정을 변경하려면 /admin/plugins/add-title-based-on-trust-level/settings를 직접 방문해야 합니다.
플러그인 페이지에서 설정 버튼이나 링크가 표시되도록 하여 더 쉽게 접근할 수 있는 방법이 있을까요?


4. 현재 설정

이것이 저의 현재 JSON 구성입니다 (스크린샷도 첨부할 예정입니다):

{
  "designers": ["", "Junior Designer", "Designer", "Senior Designer", "Chief Designer"],
  "developers": ["", "Junior Developer", "Developer", "Senior Developer", "Tech Lead"]
}


5. 질문 / 가능한 개선 사항

  • 이 접근 방식(모든 사용자를 순회하며 칭호를 업데이트하는 것)은 사용자가 많을 경우 성능 문제를 일으킬 위험이 있나요? 더 나은 모범 사례가 있을까요?
  • 예약된 작업이나 관리자 설정 UI에 대한 최적화에 대한 조언이 있을까요?
  • 제 방법에서 주의해야 할 안전하지 않거나 문제적인 부분이 있나요?

훌륭한 작업과 유용한 플러그인을 제공해 주셔서 정말 감사합니다.
제안이 있거나, 향후 그룹+신뢰 등급 기반 칭호 구성을 개선할 계획이 있다면 여러분의 생각을 듣고 싶습니다.

@joo 정말 멋진 아이디어네요!

지금 플러그인을 보면, 저도 같은 방식으로 구현한 것 같네요 (마지막 테스트를 돌리고 있었습니다). 각 사용자를 반복문으로 순회하는 방식으로 처리하셨는데, 큰 규모의 포럼에서는 이 작업에 시간이 좀 걸릴 수 있습니다.

그래서 저는 SQL UPDATE를 사용했습니다:

(Assk Discourse의 쿼리를 가져와서 수정했습니다)

이 방식이라면 tl1_title_on_promotion 설정에서 Junior {group_name} 같은 형식을 사용할 수 있게 되어, 최종 타이틀이 Junior Developer가 됩니다.

동작하려면 add_primary_group_title 옵션도 반드시 체크해야 한다는 점을 유의해 주세요.

설명해 주셔서 감사합니다. 이제 {group_name} 템플릿이 어떻게 작동하는지 이해했습니다.

하지만 이것이 바로 제가 논리 구조의 차이에 대해 말씀드린 부분입니다. 제 핵심 요구사항은 동일한 신뢰 수준(Trust Level)에 대해, 사용자 그룹에 따라 완전히 다른 제목 구조를 적용할 수 있어야 한다는 것입니다.

예를 들어, 신뢰 수준 3의 경우:

  • “디자이너(Designers)” 그룹의 제목은 "시니어 디자이너(Senior Designer)"여야 합니다.
  • “개발자(Developers)” 그룹의 제목은 "테크 리드(Tech Lead)"여야 합니다.

이 두 제목은 구조가 완전히 다릅니다.

AI를 사용해 이 기능을 구현하려고 시도했지만 성공하지 못했습니다. 플러그인을 수정하여 이러한 더 세밀한 논리를 지원할 수 있을지 궁금합니다.

아, 그럼 내가 당신을 오해했었군요.

그래서 위에서 언급한 당신의 코드가 제대로 작동했나요?

아니요, 이전에 AI와 함께 시도했던 코드도 작동하지 않았습니다. 모든 설정을 마쳤는데도 아무 반응이 없었습니다.

가장 최근 시도에 사용한 전체 코드를 보여드리고 싶습니다. 어디서 잘못되고 있는지 확인해 주실 수 있으실지 기대하고 있습니다.

1. plugin.rb

# name: add-title-by-group-trust-level
# about: assign titles via primary group + trust level using SQL
# version: 0.2
# authors: your-name

# Note: I'm not sure if I need a 'require' line here to load the job file.
# I suspect this might be the missing piece.
enabled_site_setting :add_title_by_group_trust_enabled

2. app/jobs/scheduled/update-all-titles.rb

module ::Jobs
  class UpdateTitles < ::Jobs::Scheduled
    every SiteSetting.update_title_frequency.hours

    def execute(args)
      return unless SiteSetting.add_title_by_group_trust_enabled

      mappings = JSON.parse(SiteSetting.group_trust_level_titles || '{}')

      User.transaction do
        mappings.each do |group_key, titles|
          next unless titles.is_a?(Array)

          (1...titles.size).each do |tl|
            title = titles[tl]
            next if title.blank?

            group = Group.find_by("LOWER(name) = ?", group_key.downcase)
            next unless group

            User.where(primary_group_id: group.id, trust_level: tl, admin: false, moderator: false)
                .where.not(title: title)
                .update_all(title: title)
          end
        end
      end
    end
  end
end

3. config/settings.yml

plugins:
  add_title_by_group_trust_enabled:
    default: false
    client: true
  group_trust_level_titles:
    default: '{"designers":["","Junior Designer","Designer","Senior Designer","Chief Designer"],"developers":["","Junior Developer","Developer","Senior Developer","Tech Lead"]}'
    type: string
    client: true
    multiline: true
  update_title_frequency:
    default: 24
    type: integer

사이트 설정에서 구성한 방법:

group_trust_level_titles 설정에 이 JSON을 붙여넣었습니다:

{
  "designers": ["", "Junior Designer", "Designer", "Senior Designer", "Chief Designer"],
  "developers": ["", "Junior Developer", "Developer", "Senior Developer", "Tech Lead"]
}

문제점:

UpdateTitles 작업이 Sidekiq 스케줄러(/sidekiq/scheduler)에 표시되지 않습니다.

하지만 AI가 알려준 방법에 따라 Rails 콘솔에서 테스트해 보니, 핵심 로직은 완벽하게 정상 작동하며 조건에 맞는 모든 사용자를 올바르게 출력했습니다.

Rails 콘솔에서 사용한 테스트 스크립트는 다음과 같습니다:

mappings = JSON.parse(SiteSetting.group_trust_level_titles || '{}')

mappings.each do |group_key, titles|
  next unless titles.is_a?(Array)

  (1...titles.size).each do |tl|
    title = titles[tl]
    next if title.blank?

    group = Group.find_by("LOWER(name) = ?", group_key.downcase)
    unless group
      puts "Could not find group: #{group_key}"
      next
    end

    users = User.where(primary_group_id: group.id, trust_level: tl, admin: false, moderator: false)
                .where.not(title: title)
    next if users.empty?

    puts "====== Group: #{group.name} Trust Level: #{tl} New Title: '#{title}' ======"
    users.each do |user|
      puts "User id:#{user.id}, username:#{user.username}, current title:'#{user.title}'"
    end
  end
end

즉, 로직 자체는 올바른 것 같지만 Discourse가 예약 작업을 등록하지 않고 있습니다. 어쨌든 더 많이 수정하려고 할수록 더 혼란스러워집니다… 이것이 올바른 접근 방식인지 확신이 들지 않으며, 코딩을 잘 모르는 터라 구현하는 것이 매우 어렵게 느껴집니다. 더 나은 방법이 있을까요?

음… 객체 설정을 사용하시려는 건가요:

신뢰 수준, 그룹, 직책과 같은 필드를 포함합니다.

업데이트 내용을 공유하고 도움을 주신 모든 분께 감사의 말씀을 전하고자 합니다.

최근 변경 사항 덕분에 플러그인이 제가 의도한 대로 정확히 작동하고 있습니다! 이제 사용자의 기본 그룹과 신뢰 수준에 따라 다른 타이틀을 올바르게 지정합니다.

아래에 최종적으로 정상 작동하는 코드를 게시합니다. 코드는 정확해 보이지만, 개발자가 아닌 관계로 제가 놓쳤을 수 있는 개선 또는 최적화가 필요한 부분이 있는지 궁금합니다.

app/jobs/scheduled/update-all-titles.rb

# frozen_string_literal: true

module ::Jobs
  class AssignGroupBasedTitles < ::Jobs::Scheduled
    every SiteSetting.update_title_frequency.hours

    def execute(args)
      return unless SiteSetting.add_title_by_group_trust_enabled

      rules_json_string = SiteSetting.group_based_title_rules
      return if rules_json_string.blank?

      begin
        # JSON 문자열을 Ruby 배열로 수동 파싱합니다.
        rules = JSON.parse(rules_json_string)
      rescue JSON::ParserError
        # JSON이 잘못된 형식인 경우, 에러를 기록하고 작업을 실패하지 않도록 종료합니다.
        Rails.logger.error("Group-Based Titles Plugin: Failed to parse group_based_title_rules JSON.")
        return
      end
      
      # 파싱된 규칙이 비어 있지 않은 배열인지 확인하는 안전 검사.
      return unless rules.is_a?(Array) && rules.present?

      User.transaction do
        rules.each do |rule|
          group_id = rule["group_id"]
          trust_level = rule["trust_level"]
          title = rule["title"]

          next if group_id.blank? || trust_level.blank? || title.blank?

          User.where(primary_group_id: group_id, trust_level: trust_level)
              .where.not(title: title)
              .update_all(title: title)
        end
      end
    end
  end
end

config/settings.yml

plugins:
  add_title_by_group_trust_enabled:
    default: true
    client: true

  group_based_title_rules:
    type: objects
    default: []
    schema:
      properties:
        group_id:
          type: integer
          name: "User Group"
          component: "group-chooser"
        trust_level:
          type: integer
          name: "Trust Level"
          min: 1
          max: 4
        title:
          type: string
          name: "Title"
  
  update_title_frequency:
    default: 24
    type: integer

plugin.rb

# frozen_string_literal: true

# name: add-title-by-group-trust-level
# about: Assign titles based on primary group and trust level.
# version: 2.1.0
# authors: Your Name

enabled_site_setting :add_title_by_group_trust_enabled

after_initialize do
  require_relative "./app/jobs/scheduled/update-all-titles.rb"
end