per forum user pref: forum_id user_id static_bias static_coef
  topic_user_relevancy: topic_id user_id read_bias static_bias static_coef
  topic_relevancy: topic_id channel_id relevancy
  post_user_relevancy: post_id channel_id user_id relevant/offtopic agree/disagree
  post_relevancy: post_id channel_id relevancy_decayed n_relevant, n_offtopic, n_relevancy, n_agree n_disagree
  
  on post:
    insert post_user_relevancy for all channels user is member of, relevant=null or false, agree=null
    insert post_relevancy for all inserted post_user_relevancy relevancy_total = 1, relevancy_decayed = 3 (new post bonus), n_relevant=0, n_offtopic = 0, n_relevancy = 1, n_agree=0, n_disagree = 0
    insert/update topic_relevancy for all inserted post_relevancy
  
  on tag as relevant:
    post_relevancy n_relevant++, n_relevancy++, n_relevant+=2, relevancy_decayed+= rel_delta = min(0, 1 - (log7 day's age of post + 1))*2 
      if n_offtopic = n_relevant - 1 topic_relevancy.relevancy += relevancy_decayed 
        else topic_relevancy.relevancy+= rel_delta
  
  on tag as offtopic:
    post_relevancy n_offtopic++, n_relevancy++ 
      if n_offtopic = n_relevant: topic_relevancy.relevancy -= relevancy_decayed

  periodic decay:
    every hour: for each post_relevancy with relevancy_decayed > 0
      set relevancy_decayed = min(0, 1 - (log168 post age in hours + 1))* (2 * n_relevant + n_relevancy - n_offtopic)
      update topic relevancy with sum of deltas
  
  per user topic score =
    (topic_relevancy.relevancy + topic_user_relevancy.read_bias + topic_user_relevancy.static_bias) * topic_user_relevancy.static_coef
  
  
  all users as member of main channel
  user can create private and public channels and add members and subchannels