ACS Documentation : ACS Core Architecture Guide : Subcommunities
A user can be a member of more than one subcommunity (an employee is located at an office, works on one or more projects, and is a member of a team, within a department), so subsites provide an intuitive partitioning of information (to find out when a project is scheduled to launch, go to the project subsite; to learn about benefits, go to the HR department subsite; etc), improving the usability of the site as a whole.
This does not imply that navigating subsites is the only way for users to get information from subcommunities. Rather, the ACS will also provide a user-centric portal (along the lines of My Yahoo!) that integrates relevant content from all subcommunities to which the user belongs. The real challenge is figuring out what is actually relevant to the user; doing this is what's known, in industry terms, as personalization. (New Stuff is a simple example of personalization, based on the assumption that most users will be interested in new content.) User profiling provides the foundation for really effective personalization.
In practice, "subcommunity" is simply a fancy name for "user group." Accordingly, we use the user groups data model to represent subcommunities.
For each type of subcommunity (i.e.,
you can define a site specification, to designate modules that you
believe any subcommunity of that type will find useful. For example,
to build a family collaboration service along the lines of MyFamily.com, you (as the site
The data model for site specifications consists of two simple tables:
To define a site specification for a given
create table ad_site_specifications ( site_spec_id integer not null constraint ad_site_specs_pk primary key, on_which_table varchar(30) not null, on_what_id varchar(30) constraint ad_site_specs_uk unique (on_which_table, on_what_id) ); -- on_what_id is not numeric because the primary key of the -- user_group_types table (the group_type column) is a varchar; -- should we add a numeric primary key to user_group_types? ugh. create table ad_site_spec_modules ( site_spec_id not null constraint ad_site_spec_mods_spec_id_fk references ad_site_specifications (site_spec_id), module_key not null constraint ad_site_spec_mods_mod_key_fk references acs_modules (module_key), constraint ad_site_spec_mods_pk primary key (site_spec_id, module_key) ); -- We may want to add audit trails for these tables -- Note: The above tables supersede the existing --
user_group_typelike "Family" or "Merchant", we insert a row into
ad_site_specificationswith "user_group_types" as the value of the
on_which_tablecolumn and the appropriate
user_group) is created, a corresponding subsite will be created automatically if a site specification exists for that type of subcommunity (
user_group_type). The modules designated by the specification are installed in the subsite and made available for immediate use. This is what we mean by saying that a site specification can function as an initial template for subsites ("initial" in the sense that subsite administrators can remove default modules and/or add new ones).
Subsites themselves are also represented as site specifications. For
example, a "Merchant" subsite would be created by copying the site
specification for the "Merchant"
resulting in another row in the
table (with "user_groups" as the value of
and the appropriate
group_id as the value of
on_what_id) and all the corresponding child rows in
One important issue to consider is change propagation, i.e.,
what, if anything, happens to a subsite (
spec) when its template (
user_group_type site spec) is
modified, e.g., a module is added or removed. The simplest model is to
have subsites branch irrevocably from their templates upon creation,
so that no changes made to templates are ever propagated to
subsites. This is what the ACS implements.
A more sophisticated and complex change propagation model, which the ACS does not implement, is presented below, in Appendix B.
On the opposite extreme, another degenerate case is the subcommunity of one, i.e., the individual user. By allowing for personal subsites, we can use standard modules to provide a Yahoo!-like suite of integrated services:
Personal subsites are represented by rows in the
Calendar - Yahoo! Calendar Address Book - Yahoo! Address Book Webmail - Yahoo! Mail Publishing - Yahoo! GeoCities
ad_site_specificationstable, with "users" as the value of
on_which_tableand the appropriate
user_idas the value of
A predefined site specification (with an
value of "users" and an
on_what_id value of
null) is used as the template for all personal
Finally, not all modules make sense in the context of a personal subsite (e.g., "information pushing" services like News and collaborative services like Chat or Discussion Forums), so the Package Management metadata for each module should explicitly state whether or not it can be used in a personal subsite.
general_permissionsrow granting "administer" permission on the appropriate row in the
Responsibility can be delegated at either the subsite level (by
granting the "administrator" role to other group members) or the
module level (by inserting
granting "administer" permission on the appropriate row in the
(One implication of this model is that we could decide to replace the
predefined Site-Wide Administration group with the "administrator"
role of the
all_users site spec. Practically speaking,
this might prove challenging.)
(Also, this model does not make sense with personal subsites, where the user experience should be seamless, whether performing what are normally considered "administrative" actions or regular end-user actions.)
with subsite-wide administration pages at:
The path for a given subsite module is:
with module-level administration pages at:
So, for instance, the URL for the Boston office's subsite on our hypothetical corporate website would be:
and news specific to the Boston office would be found at:
Since the virtual directories that correspond to
user_group_types appear directly under the actual page
root, there is the possibility of name collision with directories in
the filesystem. To address this, we log an error for each collision
detected when the server starts (which Watchdog will
then report to the site administrators) and give precedence to the
The aforementioned special cases of the public site and personal subsites are handled differently:
The public site is served from directly under the page root. Continuing our example from above, company-wide news would appear at:
As for personal subsites, their URLs take the form:
or (if the user has chosen a screen name):
(Should we also support
/news/should be served only public news (i.e., news items for the
all_userspseudo-subcommunity), while a visitor to
/offices/boston/news/should be served only news items specific to the Boston office subcommunity.
In order to make this work, we need to be able to relate entities to their enclosing subcommunities, which should be a straightforward process:
ad_site_specificationsin each "top-level" table (i.e., tables that do not already have a parent table, such as
ad_connAPI (to be determined) to identify the enclosing subcommunity.
site_spec_idas a criterion in any query against the top-level table(s).
/" for the
/users/123" for the personal subsite of user #123, etc.
More "how-to" info and examples coming soon
For instance, an employee's contact information should be available both in the company directory (i.e., Address Book) and (at least, in part) on the subsites of her project(s), for access by the customer. Another example is Calendar: calendar events should "cascade" down, so that an employee's calendar is comprised of events from every level up the organizational hierarchy.
If we make the simplifying assumption that each entity has one and
only one owner, what remains is to establish a many-to-one (instead of
one-to-one) relationship between subsite and entity, so that, for
instance, an address book entry "owned" by the company-wide directory
all_users subcommunity) would be viewable in the context
of other subsites. We can do this generically with a table like:
The current definition of the
user_groups includes a
parent_group_id that allows us to establish these
hierarchical relationships between actual user groups, but does not
address two separate but related needs:
user_group, and the project itself is a
parent_group_idcolumn alone is not enough to represent all of these relationships, so the current data model would force us to extend the automatically-generated
project_infodata model, e.g.:
There is no reason that these relationships cannot be stored generically, just as all manner of user-to-user-group relationships are stored in the
create table project_info ( ... customer_id not null constraint project_info_customer_id_fk references customer_info (group_id) ); create table project_partner_map ( project_id not null constraint proj_partner_map_project_id_fk references project_info (group_id), partner_id not null constraint proj_partner_map_partner_id_fk references partner_info (group_id), );
user_group_maptable. We accomplish by introducing a new table,
create table user_group_relationships ( insert two group_id columns and a descriptor for the relationship here );
user_groupsbut also at the
user_group_typeslevel. Our data model should be able to express business rules like "every project must be assigned to a team" and "every department must belong a company":
create table user_group_type_relationships ( insert two group_type columns and a descriptor for the relationship here );
user_groups uniqueness constraint would change
parent_group_id. Thus, each node in the
subcommunity hierarchy becomes its own namespace, like directories in
a filesystem, instead of the single flat namespace for user groups
that exists today.
Secondly, it would probably make sense for subsite URLs to reflect the
subcommunity hierarchy. For example, consider an outsourced intranet
company is the top-level subcommunity.
Multiple companies might have offices in Boston, and the subsites for
those offices should be located at unambiguous URL paths such as:
user_group_typesite spec and its children makes it possible to do nice things like add a new module at the
user_group_typelevel and have it become instantly available to all subcommunities of that type. The price is the extra complexity of handling situations like: a module is removed from the
user_group_typesite spec; what happens to all the dependent
To support this model of change propagation, we would probably add
more columns to
Of course, there would also need to be code and user interface to handle conflict cases like the module removal scenario above.
create table ad_site_specifications ( ... parent_spec_id constraint ad_site_specs_parent_spec_id_fk references ad_site_specifications (site_spec_id), sync_with_parent_p char(1) not null constraint ad_site_spec_sync_w_parent_p_cc check (sync_with_parent_p in ('t', 'f')) );
ad_site_spec_copy(source_spec_id, on_which_table, on_what_id)