ArsDigita Archives

Threaded BBoard Design Documentation

part of the ArsDigita Community System by Tzu-Mainn Chen

I. Essentials

II. Introduction

At arsDigita, one of the more frequent requests is for a threaded bulletin board. ACS 4.0 will contain an updated bboard that will meet current requirements; however, it has not yet been released, and many clients want a threaded bboard now.

When this issue came up for USLaw, Michael Yoon proposed a quick-and-dirty solution: implement bboard functionality using the general-comments application (hence gc-bboard), thus making development simpler and more supportable by pre-existing ACS code.

III. Historical Considerations

The ACS 3.x bboard package was one of the first applications written for the ACS; as a result, its implementation is unwieldy and over-sized, containing items such as a permissions model within its code (more recent applications use general-permissions). In addition, the ACS 3.x bboard package has limited support for threaded discussions.

IV. Design Tradeoffs

The threaded-bboard package was developed in order to solve both of these problems. By using general-comments, the package is able to use pre-existing data models and code; general-comments also allows for a tree-like structure of comments, which makes it ideal for threading purposes.

V. Data Model Discussion

The data model is not extensive, as the major chunk is pre-written in general comments. The one addition to general_comments is a boolean intended to mark a comment as part of a bboard or not. This allows for easier querying.

alter table general_comments add (bboard_p char(1) default 'f' check(bboard_p in ('t','f')));

create index gc_comment_date_idx on general_comments(comment_date);
create index gc_show_p_idx on general_comments(bboard_p, approved_p);
create index gc_comment_on_what_ids_idx on general_comments(comment_id, on_what_id);

create or replace view gc_bboard_messages
as select * from general_comments where bboard_p = 't';

The major new table is gc_bboard_topics:


create sequence gc_bboard_topics_id_seq;

create table gc_bboard_topics (
	topic_id   	integer primary key,
	name		varchar(100) unique not null,
	active_p 	char(1) default 'f' check(active_p in ('t','f')),
	max_bboard_display_depth integer default 2,
	max_bboard_display_messages integer default 10,
	creation_user	references users,
	creation_date   date default sysdate,
	creation_ip	varchar(50),
	group_id	references user_groups,
	auto_subscribe_p char(1) default 'f' check (auto_subscribe_p in ('t', 'f'))

-- denormalization to make the topic of each comment easily accessible
create table gc_comment_topic_map (
	comment_id	references general_comments,
	topic_id	references gc_bboard_topics,
	primary key(comment_id, topic_id)
The few remaining tables are for alerts:

-- when a bboard entry is inserted, an insertion is done into this table as
-- well, so we know if a bboard entry needs to be processed for alerts
create sequence gc_bboard_alert_id_seq;
create table gc_bboard_alerts (
	alert_id	integer 
			constraint gc_bboard_alert_id_pk
			primary key,
	--didn't specify it to be unique since message might be edited
	comment_id	references general_comments not null,
	--if date_sent is null, that means not sent yet
	--check to see if approve before sending
	date_sent	date

--  shows who should get an email for that message; entries are deleted once
-- an email is sent
create table gc_comment_user_recipients (
	comment_id	references general_comments,
	user_id		references users

--gc_topic_user_map shows who is subscribed to a topic
create table gc_topic_user_map (
	topic_id	references gc_bboard_topics,
	user_id		references users,
	primary key (topic_id, user_id)

--gc_comment_user_map shows who is subscribed to a thread
create table gc_comment_user_map (
	comment_id	references general_comments,
	user_id		references users,
	primary key (comment_id, user_id)

--gc_contributor_user_map shows who is subscribed to an author
create table gc_contributor_user_map (
	contributor_id  references users,
	user_id		references users,
	primary key (contributor_id, user_id)

--gc_keyword_user_map shows who is subscribe to a keyword
create table gc_keyword_user_map (
	keyword         varchar(100) not null,
	user_id 	references users,
	primary key (keyword, user_id)

VI. Legal Transactions

Site Administrators

Site administrators may perform group administrator functions for every bulletin board topic.

Group Administrators

Group administrators can create public or private group bulletin boards. They can also edit messages, toggle message approval, delete message branches, manage various display and alert properties, and administer bulletin board permissions using general_permissions.


Once they are registered, users can post messages in public bulletin boards, or in any group bulletin board of which they are members. They can also sign up for various alerts, based on topic, author, thread, or keyword.


There are two essential procedures :
  • gc_bboard_message_add - gc_bboard_message_add inserts a message into the system, using ad_general_comment_add; it also takes the exact same arguments, plus topic_id and an optional subscribe_p (for alerts; more on that later).

  • gc_bboard_message_list - gc_bboard_message_list returns a Tcl list-of-lists of bboard message information in an order intended to allow for easy processing into HTML: comment_id, one_line_item_desc, c_date, gq.user_id, the_level, creation_user, email, approved_p, content, n_messages, n_new_messages. gc_bboard_message_list takes thes following arguments:
    • on_which_table - a varchar that, along with on_what_id, will be matched in general_comments to determine which bboard node to start at. Typical values are gc_bboard_topics (to process an entire topic) and general_comments (to receive a subtree of a topic tree).
    • on_what_id - used with on_which_table to select the starting point of the query.
    • count_messages_p - a boolean that instructs the procedure to count messages and new messages (inserted within the last 24 hours) branching off from each selected node.
    • approved_p - a boolean that instructs the procedure to select approved, unapproved, or all messages.
    • max_bboard_display_depth - an integer that tells the procedure what depth of messages to look for; it defaults to returning the whole tree.
    • max_bboard_display_messages - an integer that tells the procedure the maximum number of messages to return.
    • reverse_p - a boolean; if false, then the procedure returns the typica message tree, starting from the selected node. If true, then the procedure takes the node and goes in reverse, returning a list of messages going back to the root of the message tree.
There are a few minor procedures and scheduled procs:
  • gc_send_bboard_alerts - sends alerts to users who are subscribed. A group bboard has to option to autosubscribe new members - this is toggled in the bboard admin page.

  • gc_bboard_email_process - located in gc_bboard_email_procs.tcl This procedures allows the feature where users can reply to a bboard posting by sending an email. The process is exactly like that which is used for the ticket tracker (in fact, gc_bboard_email_process is directly modified from ticket_email_process in ticket-email.tcl). Thus, to set this feature up, you need to:
    • make sure that email-handler.tcl exists somewhere in a Tcl directory
    • make sure that and exist in /web/yourservice_name/bin/
    • set up a qmail alias - for sloan, the alias file name was .qmail-sloanspace-bboard-robot-default, containing the line |/web/sloan/bin/ dbi:Oracle: sloan sloanrules gc_bboard
    • add parameters in the .ini file:
      AlertEmailDomain=some email domain
      AlertEmailName=some email name (for sloan, it was sloanspace-bboard-robot; this needs to match your qmail alias)
    Since there are likely to be many, many problems along the way, here are some useful links:

VIII. Configuration/Parameters

None other than those described in Section VII.

IX. Future Changes

  • Add more parameters.
  • Permissioning isn't always throughly checked on some smaller pages (subscription, filter, etc).
  • Make sure permissioning is done through general_permissions, and not through scope
  • Right now, filtering is done on subject only; get Intermedia to work so that it can be done on content as well.
  • Ability to rate bboard messages, on site or through email. Filter and feature messages based on rating.
  • Ability to subscribe to digest version of messages.
  • gc_bboard_email_process is simply a copy of ticket_email_process; a generic procedure for both would be nice.
  • When admins edit other people's posts, an email should be sent to the original author. Should have increased auditing of comments.