Back to Claude Opus 4.6

Agent Work: M3ssag1n8 Messaging App

Claude Opus 4.6 · COMP 318: Concurrent Program Design

Project 2: M3ssag1n8

For this project, you will build a web-based messaging application, similar to Discord, Slack, etc., using HTML, CSS, and TypeScript. Your COMP 318 m3ssag1n8 application will be an independent web client that can be served as static resources from any web server. For the dynamic messaging content, you will use OwlDB as the back-end web service to store all the application's messages and other information. Note that this means that the functionality and behavior of your application will be limited by the capabilities of OwlDB. In other words, if something cannot be done in the browser or by using OwlDB, then your messaging application will not be able to incorporate that feature.

Throughout this document, if you see the word must then that means this is a requirement of the project that you must do. If you see the word should, then that means you *should* follow the given advice, but you do not have to. If you choose not to, however, you could lose points if you use an inferior method.

Note that this document describes the requirements of the project. By default, everything is a requirement (whether you see the word "must" or not) unless specified otherwise (using "should" or some other clear statement). The word "must" is used to emphasize particularly important requirements and/or constraints.

Timeline

The timeline and deadlines of the project are given in the table below. The deliverables for each deadline are specified near the end of this document. All deliverables are due at 5 PM on their due date.

DateEvent
10/28/24 (Monday)Project Assigned
11/11/24 (Monday)Check-in Due
11/13/24 (Wednesday)Group Member Evaluation Due
11/15/24 (Friday)Peer Code Review Due
Week of 11/18/24Group Meeting with TA
11/26/24 (Tuesday)Group Member Evaluation Due
12/6/24 (Friday)Project Deadline
12/13/24 (Friday)Extended Project Deadline
12/17/24 (Tuesday)Group Member Evaluation Due

No further extensions past the Extended Project Deadline will be granted. You must ensure that you complete your project by the final deadline without exception. You will lose write access to your GitHub repository at that time.

Life happens, especially in college. You should plan for the unexpected. Over the course of the project, not every group member will be able to contribute equally at all times (though they should do so on average). People will get sick. People will have midterms or other large assignments. You need to plan around the expected and adjust when the unexpected happens. Note that this means if you plan to do all of the work in the last few days, you will not succeed. Someone may get sick. Someone may flake. Or any number of other things may happen to make it so everyone can not pull that final all-nighter you counted on. Plan ahead and work throughout the duration of the project. The adage "slow and steady wins the race" applies here. If everyone in your group works steadily and consistently for reasonable amounts of time each week, you will be far better off than trying to do huge amounts of work in short periods of time. You have been warned.

Honor Code Policy

The honor code policy is available in the course syllabus. You must follow the policy.

Table of Contents

1. [Application Overview](#application-overview) 2. [Database Structure](#database-structure) 3. [User Interface](#user-interface) 4. [Layout and Styling](#layout-and-styling) 5. [Accessibility](#accessibility) 6. [Application Extensions](#application-extensions) 7. [Icons](#icons) 8. [Validation](#validation) 9. [Constraints](#constraints) 10. [Design](#design) 11. [Concurrency](#concurrency) 12. [Testing](#testing) 13. [Deliverables](#deliverables) 14. [Design Document](#design-document) 15. [Grading](#grading)

Application Overview

You will build a web-based messaging application similar to Discord, Slack, etc. Your application must have the following elements:

1. A user must log in to use the application. Logging in only requires a username, not a password. 2. Once logged in, there is a set of zero or more *workspaces*. Users can create, view, and delete workspaces. These same workspaces should be visible to all users who log in. In other words, there is no segregation of users: all users can see all workspaces. 3. Each workspace is a set of zero or more *channels*. Users can create, view, and delete channels. 4. Each channel is a set of zero or more *posts*. Users can create and view posts. Posts cannot be deleted. There are also additional features of posts that will be described below.

Your application does not need to look exactly like this, but the following figure should give you a feel for the different elements of the application.

Notice the following elements:

1. There is a "logout" link. When no one is logged in, the user should not be able to interact with the interface in any way other than to log in. 2. The currently logged-in user name is displayed. 3. There is a mechanism to allow the user to select a workspace (in this case, by clicking the "workspaces" button that pops up a dialog allowing users to create, delete, or open a workspace - you do not need to match this behavior). 4. The open workspace name (COMP 318) is displayed along with a list of channels in that workspace. 5. The user can create, delete, or open a channel. 6. The open channel name (Project 2) is displayed. 7. The posts within the open channel are displayed.

In an actual messaging application, users would likely have different permissions controlling who can access and/or delete specific resources. To simplify this project, you do not need to have such authorization mechanisms.

The elements described above and their requirements will be further clarified below.

Database Structure

All application state must be stored in a single OwlDB database. Your client must be able to interoperate with any other correctly built client that obeys this storage structure. You must not store application state any other way.

You must validate all data you receive from OwlDB using appropriate JSON schemas. This will "protect" your client from malformed data written to the database by other misbehaving clients.

Three main elements must be stored in the database:

1. Each *workspace* should be a document in the top level of the database that contains a single collection called *channels*. 2. Each *channel* in a workspace should be a document in the *channels* collection of the workspace with a single collection called *posts*. 3. Each *post* in a channel should be a document in the *posts* collection of the channel.

The contents of each *workspace* document must be a JSON object. As the only thing you need to know about a workspace is its name, this JSON object will typically be empty ("{}"). However, extensions may each add one additional property (that is the extension's name) to the JSON object, so you must not require/enforce that it is empty, just that it is a valid JSON object. You should ignore properties in the object for extensions you do not know about.

The contents of each *channel* document must be a JSON object. As the only thing you need to know about a channel is its name, this JSON object will typically be empty ("{}"). However, extensions may each add one additional property (that is the extension's name) to the JSON object, so you must not require/enforce that it is empty, just that it is a valid JSON object. You should ignore properties in the object for extensions you do not know about.

The contents of a *post* document must be a JSON object with the following properties:

1. "msg" (required): the value of this property must be an arbitrary string, which is the post's content. 2. "parent" (optional): if this message is a top-level post in the channel, this field must either be missing or have an empty string ("") as its value. If this message is a reply to another post (at any level), this field must be a string that gives the document path (this is the path within the database, so it should not include the database name). 3. "reactions" (optional): the value of this property (if it exists) must be a JSON object. The JSON object must map strings corresponding to reaction names to JSON arrays. These JSON arrays must contain strings that correspond to user names. If the "reactions" property does not exist in the document, then no one has reacted to this post in any way. If a property in the JSON object maps to an empty JSON array, then no one has currently selected that reaction. 4. "extensions" (optional): the value of this property (if it exists) must be a JSON object. Extensions may each optionally add one property to this JSON object. The property name must be the name of the extension. The value of each extension's property is defined by that extension. You should ignore properties in this object for extensions you do not know about.

Note that there are *many* other ways you could store messaging data in OwlDB. However, you must store the data in this way.

User Interface

As described in the application overview, the user interface must support the following capabilities:

1. Login/logout 2. Workspace selection, creation, and removal 3. Channel selection, creation, and removal 4. View and react to all posts within a channel 5. Formatting posts 6. Creating and replying to posts

Workspace/channel lists do not need to update automatically (but users must have a button or other mechanism to update them). Posts must be updated in real-time. Note that this means you must subscribe to the currently open channel in OwlDB.

Your user interface should be developed in a modular and encapsulated way using web components. The following sections provide more detail on the above six elements.

1. Login/Logout

Your application must use a modal dialog to force people to log in. Once a user has been logged in, there should be a clear and obvious way to log out. Once the logout is complete, the modal dialog to log in must reappear. Note that a "modal dialog" is a dialog box on top of the page that is the only element of the page that the user can interact with. While it is displayed, the rest of the page remains visible in the background, but they cannot interact with any other part of the page until they have closed the modal dialog (in this case, closing it should only be possible by successfully logging in). You should blur the background behind the modal dialog to indicate to the user that they cannot yet interact with it.

To log in, you must use OwlDB's authentication methods to acquire a bearer token, which must then be used for all future interactions with OwlDB until the user logs out. When they log out, you must alert OwlDB so that the token will be destroyed. As we do not have an encrypted way to communicate with OwlDB, and OwlDB only requires a username to log in, you will only need to ask the user for a username, not a password. In any actual system, you would need an encrypted way of exchanging and verifying credentials (such as passwords). Note, however, that the bearer token authorization mechanisms you will use in your application would remain the same even if you had mechanisms to verify the user's identity properly.

When no user is logged in, the user must not be able to do anything in the application other than attempt to log in.

Any errors that occur when logging in or logging out should be prominently displayed to the user.

2. Workspaces

There should be a clear and obvious way for users to open, create, or remove a workspace from the system. As there is no authorization, any user should be able to perform any of these actions on any workspace. Users should not be allowed to create workspaces with duplicate names.

At most, one workspace may be "open" at any time. This means when a workspace is opened, the currently open workspace should automatically be "closed". When a workspace is opened, the name of the workspace and the set of channels that existed within that workspace at the time it was opened should become visible in a clear and obvious way.

At any time, a logged-in user should be able to perform any of these three workspace operations (regardless of what else is visible in the user interface). When a user opens an existing workspace or creates a new workspace, that workspace should automatically be opened. When a user deletes a workspace, the currently open workspace (whether it was the one that was deleted or not) should automatically be closed.

There should be a way to "refresh" the list of workspaces that currently exist. This does not need to happen automatically when someone else creates or removes a workspace, but instead can be done in response to a user performing an action (such as pushing a button). It must be obvious to a user how to do this.

If a user tries to create a workspace that already exists, open a workspace that no longer exists, or remove a workspace that no longer exists, a clear and prominent error must be displayed to the user. The user must be able to dismiss this error, and the error must remain visible until the user does so, or they reattempt a different workspace operation.

3. Channels

There should be a clear and obvious way for users to open, create, or remove a channel from the currently open workspace (and *only* the currently open workspace). As there are no authorization mechanisms, any user should be able to perform any of these actions on any channel within the currently open workspace. Users should not be allowed to create channels with duplicate names within the same workspace.

At most, one channel may be "open" at any time and that open channel must be a channel within the currently open workspace. This means when a new channel is opened, the previously open channel should automatically be "closed". When a channel is opened, the name of the channel and the set of posts within that channel should become visible in a clear and obvious way. The posts that are visible should be "live", meaning that as posts are added to the channel in OwlDB, they should become visible in the channel's view.

There should be a way to "refresh" the list of channels that currently exist in the currently open workspace. This does not need to happen automatically when someone else creates or removes a channel, but instead can be done in response to a user performing an action (such as pushing a button). It must be obvious to a user how to do this.

If a user tries to create a channel that already exists, open a channel that no longer exists, or remove a channel that no longer exists, a clear and prominent error must be displayed to the user. The user must be able to dismiss this error, and the error must remain visible until the user does so, or they reattempt a different channel operation.

4. Displaying and Reacting to Posts

Users should easily be able to view all of the posts within the currently open channel. Posts must form a hierarchy, meaning that you should be able to reply to any post. Each reply creates a new level in the hierarchy. At each level, the user can either add a new post at that level (which will be at the same level), or they may reply to a post at that level (which will create a new, deeper level in the hierarchy).

In other words, posts can be organized like this:

P-1
P-2
  P-2-1
    P-2-1-1
    P-2-1-2
  P-2-2
P-3
  P-3-1
  P-3-2
    P-3-2-1
P-4

Posts should not be named like this; rather the naming in the diagram is to help you visualize the structure. "P-X" is the X'th post at the top level. "P-X-Y" is the Y'th post in the reply thread to post P-X. "P-X-Y-Z" is the Z'th post in the reply thread to post P-X-Y. This hierarchy can continue forever.

In OwlDB, all of these posts must be stored in the same channel collection. The parent field must be used to indicate this hierarchy. For example, the parent of post "P-X-Y-Z" is post "P-X-Y". Within each level of the hierarchy, the posts must be displayed in order, with the oldest post first. Each reply thread must be displayed right after the post the thread is replying to. Indentation must be used to indicate which level the post is at.

Each post must be a document within the channel collection. You cannot rely on anything about the names of the post documents. You must display them based on when they were created and their "parent" properties, as described above.

For each post, you must display the following:

1. The user who authored the post. 2. The time at which the post was created. 3. The contents of the post. 4. The number and type of reactions that have been made to the post.

Note that the document has no explicit fields for 1 & 2. They are contained in the document's metadata in an unforgeable way. In addition, users must be able to react to any post at most once for each type of available reaction. And they must be able to remove those reactions.

Your system must support at least the following reactions:

1. :smile: 2. :frown: 3. :like: 4. :celebrate:

You may support as many additional reactions as you would like. The name of a reaction must start and end with a colon and contain only letters and dashes. These are the property names that should be used in the "reactions" object within the post document. You may display these reactions using any icon you deem appropriate using iconify icons. If the "reactions" object includes reactions you don't support, you may display them by name or ignore them.

When users click on one of the reactions, their username must be added to the reactions object in the appropriate array. Next to each icon, the number of users who reacted that way should be displayed. If a user clicks on a reaction they have already reacted with, their username must be removed from the appropriate array in the reactions object. The reaction numbers must update as they change.

5. Formatting Posts

Your posts must support a limited form of markdown, including the following:

1. Text surrounded by single \* symbols must be rendered in italics. In other words, \*text\* should display as *text*. Consider using the HTML <em> tag for this. 2. Text surrounded by double \* symbols must be rendered in bold. In other words, \*\*text\*\* should display as text. Consider using the HTML <strong> tag for this. 3. Text and a URL surrounded by \[\]() must be rendered as links. In other words, \[codeskulptor\](https://py3.codeskulptor.org) should display as [codeskulptor](https://py3.codeskulptor.org). Consider using the HTML <a> tag for this. 4. Reaction names must be rendered as their associated emoji. In other words, :smile: should display as a smile emoji (or other appropriate emoji icon of your choice). You should use iconify icons for this.

This formatting should only occur when the post is displayed in the channel. The post must be stored as the original plain text in OwlDB, and it should not be styled as it is being typed.

You should also make sure that line breaks actually display in posts. When you are typing a post in your input box, Shift+Enter should add a "\n" character to the post. So, you need to convert all "\n" characters to line breaks when you display the posts. An easy way to do that is to convert all "\n" characters to "\<br\>" HTML elements.

6. Creating and Replying to Posts

When a channel is open, an input box must always be displayed to allow a new post to be entered into that channel. The input box should default to being at the bottom of the channel, for creating a new post at the top level. Each post must have a "reply" button. When pressed, the input box must move to the appropriate level of the post hierarchy in the location where the post should appear when it is submitted. Note that if other posts appear, the input box should not move, as that would be jarring to the user. If the input box is in position for a reply, it must have a "close" button that closes the reply (without posting anything) and moves the input box back to the bottom of the channel (ready to create a new post at the top level). After a reply is successfully posted, the input box should also move back to the bottom of the channel.

The input box must have buttons for "bold", "italic" and "link". The user may either type the markdown described above to achieve these effects, select some text, and then click the button to add the correct formatting symbols around the selection, or just click the button, which must insert empty formatting symbols into the input box.

The input box must also have buttons for the four required reaction emojis. The user may type the reaction name (e.g., :smile:) in the input box or click the emoji button to insert the associated text.

The input box must also have a "Post" button. When that button is pressed, or the user types the "Enter" key while the input box is in focus, the post must be stored in OwlDB.

When the user types Shift+Enter, a newline must be inserted into the input box (and the post should not be submitted).

Layout and Styling

The layout and styling of your application, including organization, fonts, colors, user interface elements, etc. is up to you. However, your application must meet the following criteria:

1. You must use multiple colors clearly and sensibly to differentiate your user interface elements. 2. You must utilize flex or grid to layout your user interface sensibly. 3. You must use a modal dialog box to require users to log in (with the rest of the page blurred behind it). 4. All required elements must be visible, and it must be obvious how a user should interact with them. 5. No elements should overflow in a way that makes them invisible or inaccessible to the user.

You may assume a minimum screen size of 640 pixels by 480 pixels. There is no maximum screen size. Note that for an actual application, you would need to be able to display appropriately on all screens, including phones. However, this likely requires your interface to reorganize itself to work effectively on a narrow screen. Doing so is beyond the scope of this project.

Accessibility

Not everyone is like you. Everyone has different physical and mental abilities. It is vitally important to think about that when developing applications. As you develop your application, you should specifically consider at least the following two questions and address them as much as you can:

1. How easy would it be to use your application for someone who does not have perfect vision? 2. How easy would it be to use your application for someone lacking the fine motor skills to use a mouse?

In general, accessibility questions can be challenging to answer. However, you must think about these and other accessibility issues and work to address them.

Application Extensions

You must add one additional extension to your messaging client. That extension may be anything you want. You must name your extension using your group's name. That will guarantee that no two extensions have the same name.

To support your extension, you may modify the database storage following the guidelines for the database structure. Note that you can also add additional collections with unique names that do not conflict with the required collections. So as not to interfere with other extensions, all such collection names should be prefixed with your extension name.

The extension must not do anything that would break other clients that do not know about your extension. Note that such oblivious clients would not have the additional behavior but should otherwise work correctly.

Your extension will be evaluated based on its uniqueness, the clarity of your description of what it is and how it works, and whether it interferes with other working clients. The extension will be worth 15 points of your final project grade.

Icons

The provided index.html document loads the [iconify icons](https://iconify.design) package. You may use this package to display any icons you desire in your user interface.

To display an icon, you should add an iconify-icon element to your HTML, such as the following:

<iconify-icon icon="mdi:close" aria-label="close"></iconify-icon>

Note that you should always have an aria-label attribute for all icons so that screen readers know how to identify the icon for sight-impaired users. You may add other attributes to the element (such as width / height) if so desired. You can include such elements directly in your HTML or add/remove them dynamically using TypeScript.

Iconify icons lets you use almost any open-source icon imaginable by setting the icon attribute appropriately. Search the icons at [icon-sets.iconify.design](https://icon-sets.iconify.design) for their names.

Validation

As a NoSQL database, OwlDB allows data to be stored in any structure. Therefore, you must validate all data you receive from OwlDB using appropriate JSON schemas. This will "protect" your client from malformed data written to the database by other misbehaving clients. You must use the [AJV](https://ajv.js.org) and [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts) packages for this purpose.

Your JSON schemas must be written as constant JavaScript objects in your program as follows:

import type { JSONSchema } from "json-schema-to-ts";

const ResultSchema = {
  $id: "result.json",
  $schema: "http://json-schema.org/draft-07/schema",
  title: "Result",
  type: "object",
  required: ["result"],
  properties: {
    result: {
      type: "string"
    }
  },
  additionalProperties: false
} as const satisfies JSONSchema;

Note this is exactly the same as the JSON format you've written JSON schemas in previously. However, instead of being stored as a JSON object in a file, it is expressed as the equivalent JavaScript object. The schema object must be declared as const and you must also have as const at the end of the declaration. These are not redundant. The const declaration ensures that the variable (ResultSchema) cannot be reassigned. The as const at the end tells TypeScript that it should use the narrowest possible types for this object. In other words, the type of "object" will be inferred to be only the exact string "object", not the more general type string. The further addition of satisfies JSONSchema at the end is optional, but it gives more information to TypeScript and helps with type checking the schema and autocompletion.

To then create a TypeScript type that you can use for variables that match the schema, you must declare the type as follows:

import { FromSchema } from "json-schema-to-ts";

type Result = FromSchema<typeof ResultSchema>;

This statically analyzes the schema at compile time (which is only possible because of the "as const" modifier) and generates the correct TypeScript type that matches the schema. This is much more robust than trying to write the TypeScript type associated with a schema yourself, and has further advantages in validation, as will be shown below. The name of the type and the title in the schema should match, for clarity. If you have nested schemas (using $ref declarations), you must add a second type parameter to the FromSchema indicating the objects those references come from. For example:

const ArrayResultSchema = {
  $id: "arrayresult.json",
  $schema: "http://json-schema.org/draft-07/schema",
  title: "ArrayResult",
  type: "array",
  items: {
    $ref: "result.json"
  },
} as const satisfies JSONSchema;

type ArrayResult = FromSchema<
    typeof ArrayResultSchema,
    { references: [typeof ResultSchema] }
>;

The types created by using FromSchema can now be used as a generic type constraint or variable type. You must always use schemas and generated types to validate and declare the types of any data returned by an API call.

To actually do the validation, you must use AJV, which uses a JSON schema to validate an unknown object against that schema. To create a "validator" using AJV and JSON schemas, you would do the following:

import { $Compiler, wrapCompilerAsTypeGuard } from "json-schema-to-ts";
import Ajv from "ajv";

// Create an Ajv instance to use for validation. You only need to do this once.
const ajv = new Ajv();

// Create a "compile" function using AJV that can be used to validate data against a JSON schema.
// You only need to do this once and then can use the "compile" function to create as many validators
// as you need.
const $compile: $Compiler = (schema) => ajv.compile(schema);
const compile = wrapCompilerAsTypeGuard($compile);

// Create a "validator" that returns true if its argument conforms to ResultSchema and false otherwise.
// All schemas referenced by this one must already have been compiled.
let isResultType = compile(ResultSchema);

// Received data is a JSON string received from an API call, for example.
// This is an oversimplification and your code will not look like this.
let receivedData: string = getUnknownData();
let data: unknown = JSON.parse(receivedData);

// Check if the unknown data conforms to the ResultSchema
if (isResultType(data)) {
    // The data was validated to conform to the schema and TypeScript now knows that data
    // conforms to ResultType, so you can use it as such
    let result: ResultType = data;
}

The compile function creates what is know as a "type guard". This is a function that takes data of an unknown type and returns true or false depending on whether that data conforms to a specified type. You can then use that type guard (isResultType in the above code, for example) in an if statement to determine whether the data conforms to that type or not. TypeScript is able to understand such type guards and will then allow you to use the data within the body of the if as the given type. Using validation and type guards is standard practice and is well supported by TypeScript.

You may have as many schemas as necessary to validate all of the data you receive from OwlDB. You may also use schemas for other purposes if you so desire.

Constraints

Your m3ssag1n8 client must be written entirely in the TypeScript programming language using HTML and CSS for the web page. You must correctly and completely implement the entire specification described in this document. Your client must work with any service that correctly implements the OwlDB API specification that has a database with data stored in the format specified in this description. You may use any API calls in the OwlDB specification.

For the most part, you have complete freedom in designing and implementing your client (as long as it correctly implements the specifications within this document). However, you must obey the following five restrictions.

1. Package.json

You must not modify the package.json or package-lock.json files in any way. If you find that you are going to commit changes to these files to git, you should immediately stop what you are doing, figure out what happened, and undo it. When we build/test/run your project, we will replace the package.json file in your repository with the original provided file. If this breaks your project, you may lose a significant amount of points. Note that if you ever run "npm install \<pkg\>", then the package "\<pkg\>" will be installed for you locally whether it is listed in package.json or not (simply deleting it from package.json does not remove it). So, once you do that, you might have a situation where you are relying on dependencies that you should not. If you make a mistake, it is in your best interests to figure out how to properly clean it up. Create a fresh clone from your GitHub repository and/or talk with the staff about how to fix the problem.

2. Database URL

You must use the database specified in the file named ".env". The .env file should define three variables:

  • DATABASE_HOST: this is the host name you must use to access the database (such as "http://localhost:3318")
  • DATABASE_PATH: this is the path you must use relative to DATABASE_HOST to access the database (such as "/v1/m3ssag1n8/")
  • AUTH_PATH: this is the path you must use relative to DATABASE_HOST to log in and log out (such as "/auth")

You may change the values of these variables to whatever you would like as you develop your project (and check that into git). Note that if each group member would like to use different values, each person can have a file named ".env.local" that defines these variables to be whatever they would like, which will override the ".env" file. You should not check ".env.local" into git! When we run your code, we will use our own ".env" file with these variables set to refer to the OwlDb database we will use for testing. To access these variables in your TypeScript code, you would access the variable process.env.DATABASE_HOST. Note that process.env will first try to get values from ".env.local" and then ".env" if ".env.local" does not exist. The values will *always* be available through process.env regardless of which file they came from. You must not hard code the database URL into your code. You must always use the variables in ".env" or ".env.local" right from the start.

Note that the DATABASE_HOST should not have a trailing slash and the DATABASE_PATH and AUTH_PATH should start with a slash. Therefore, to get to the database, you simply concatenate DATABASE_HOST and DATABASE_PATH and to get to the authorization endpoint, you simply concatenate DATABASE_HOST and AUTH_PATH.

3. Packages

The only packages you may use within your application are "ajv" version 8.17.1 and "@microsoft/fetch-event-source" version 2.0.1 and possibly "json-schema-to-ts" version 3.1.1. The AJV package will verify data using JSON schemas. The fetch-event-source package augments the SSE event source to allow bearer tokens and other information. The json-schema-to-ts package allows type checking schema validation and mostly runs at compile time (to ensure proper types and type checking), though if you use certain functions from the package, they will be bundled into your code and operate at run time (which is allowed). The provided package.json file lists other packages that can exclusively be used to build and test your project (i.e., parcel, prettier, typedoc, etc.). These additional packages (or any other third-party packages) must not be used in your application.

4. External Resources

The only external resources you may load in your HTML are [iconify icons](https://iconify.design) and any fonts from [Google Fonts](https://fonts.google.com). You must not load any other external resources from outside of your project.

5. Validation

You must validate all data returned in a response body from OwlDB, as described in the [Validation](#validation) section.

6. Shadow DOM

You must use mode "open" whenever you attach a shadow DOM to an element. Otherwise, the machine grading infrastructure cannot access your entire page. This will likely result in you failing many tests, even if your application works correctly. Using mode "open" will also make it easier for you to test, debug, and develop your application.

Design

This is a large project. You need to plan out your design and incorporate the design principles taught in the class in order to succeed. Your design will be evaluated in three ways:

1. After the first check-in, you will meet with a TA to review your system design. You should think about the feedback you receive and work to improve your overall design. 2. The staff will evaluate the design of your final submission. 3. You will describe how you integrated design principles that were taught in the class in your final design document.

Building large software is about more than just "getting it to work". It is about thinking carefully about how you design that software so that it can be tested, maintained, and extended. Poor design choices lead to more difficult implementation and debugging. Your group should be discussing and improving your design over the course of the project.

Concurrency

Modern software relies on concurrency, and this project is no exception. You need to plan for this concurrency in your design and consider it as you implement that design. TypeScript provides many features that help you manage concurrency, which you should take advantage of.

Your use of concurrency will be evaluated in three ways:

1. Your code will be tested for correctness and performance when interacting with the interface while there are many database updates and many user inputs. 2. The staff will evaluate the design of your final submission. 3. In your final design document, you will describe how you managed concurrency in your system.

Testing

As you are well aware, you should always test your code as you develop it. For large projects, such as this, this is even more important. Your test files should all be in the "cypress/e2e/" directory with names of the form "*test*.cy.ts", Where *test* should be replaced with any descriptive name that you want (but all test files must have the suffix ".cy.ts"). Whether it is explicitly stated or not, it is expected that there will be tests in your repository for every deadline in the project. These tests should run when using the "npm test" command.

As this project has a major user interface component, you will use the [Cypress](https://www.cypress.io) testing framework to test your application. We will test (and grade) your application using the Chrome web browser, so we highly recommend that you do all of your testing with Chrome, to ensure your application works the same for you as it will for us.

When you run "npm test", it will run Cypress in the terminal using the Chrome web browser (which you must have installed on your machine). Note that before you run "npm test", you will need to run "npm start" in another terminal, as Cypress expects your web server to already be running. You will also likely need to have the appropriate ssh tunnel open to access the reference OwlDB, unless you use cy.intercept to stub all of the OwlDB network requests.

When "npm test" runs, it will run all of the test files you have in your "cypress/e2e/" directory. Those files can be unit tests or end-to-end tests (despite the directory name). After you run "npm test", you can also run "npm run report" to view the code coverage of your source files for the tests you just ran.

We have provided you with the skeleton for a set of "custom commands" for Cypress in "cypress/support/commands.ts". You must implement these commands and you must implement them correctly. These are the "hooks" into your user interface to perform actions in your application. They allow tests to not have to understand how to use your interface in order to test it. For example, a test can login to your application by calling cy.login("username"); This will call your custom "login" command, which should find the username input box, type the username in, and then click the "login" button. This decouples the test from needing to know how to access those elements in your application. You can, and should, implement and use these commands in your own tests. If you have any confusion about what any particular command should do, you should ask! You should be able to implement all of the commands in 1-5 lines of code or so.

These custom commands will be used by the machine grader to grade your application. That means if you do not implement these commands, or you implement them incorrectly, you risk receiving a low score regardless of how well your application works. Make sure you implement them and that they work correctly.

To help you to see how a test might use your custom commands, we have provided a basic test file "cypress/e2e/e2e.cy.ts". This test file does some very basic tests that use each of the custom commands. At a minimum, you should pass all of these tests in order to give yourself some confidence that your commands are working correctly. However, passing these test neither guarantees that your commands are 100% correct nor that the features that they "test" are fully working. These are very rudimentary tests that don't really test much other than the bare minimum.

> Additional Clarification: > > You may modify the provided tests in "e2e.cy.ts" in any way you see fit. However, understand that they use the custom commands in the same way that our grading tests will. So, if you are modifying the tests because they don't work with your custom commands, your commands are incorrect and you are likely to lose points from the machine grader because of that.

As you debug your tests, you may also find it helpful to use the Cypress graphical interface. You can do so by running:

npx cypress open

This will open Cypress in a web browser. You should only do this after you have run "npm test" at least once in your directory to set everything up (if you create a new clone from GitHub, you need to run "npm test" again before opening Cypress in the graphical interface). Otherwise you will run into problems. Make sure you pick Chrome as the browser to use. The graphical interface shows you more information about the tests as the test is run, including screenshots. The CLI version only shows screenshots (by placing them in the directory it tells you) of the point at which a test fails.

Deliverables

The deliverables for each deadline must be submitted by 5 PM on their due date. It is your responsibility to check, double-check, and triple-check that you have submitted what you are supposed to submit, in the correct format, and using the correct procedure. You should submit things early, and all group members should confirm that they believe they have been submitted correctly.

Note that we will run your code by using npm start and npm run build. So, you should ensure that your program works in both cases. Specifically, for interactive testing we will do the following:

1. Replace your package.json and .env files with our own. 2. Run npm install. 3. Run npm start. 4. Access your client at the URL printed to the console.

For machine grading, we will do the following:

1. Replace your package.json and .env files with our own. 2. Run npm install. 3. Run npm run build. 4. Replace all of the tests in the cypress/e2e directory with our own (your command.ts file will remain). 5. Start a web server in the dist directory created by the build step. 6. Run npm test (with additional flags to modify the output format) to run Cypress on the grading tests.

Your client must run correctly when following these processes and only access the database (in both your code and tests) that we provided in the ".env" file.

For all deadlines, you must have the required custom Cypress commands implemented correctly.

Check-In

Before the check-in deadline, all of your code must be committed and pushed to your group's GitHub repository. Your code must type check ("npm run check") and build ("npm run build") without errors. Your code should be properly formatted (if running prettier, i.e., "npm run format", changes anything in your submitted code, you will lose points).

> Correction: > > There is an error in the provided tsconfig.json file that leads to type errors in code that you did not write. Therefore, we will not penalize you if your code does not type check for the check-in. We tried to create pull requests in everyone's repositories with the fix using GitHub classroom, but the feature did not work properly (we have a support ticket into GitHub). You can easily fix it yourself (and you should do so) by changing "ESnext" to "es2023" in the file (case matters, make sure you have "es2023" in lowercase). Once you do that, everything should type check properly. Again, though, we will not penalize any group for failing to type check at the check-in. You will be penalized at future deadlines, though, so you should make this change and type check your code regularly.

For the check-in, the following features must work:

1. You must access the OwlDB database specified in whatever ".env" file we choose to use. You may not hardwire the database URL into your code (or tests) and you may not assume anything about the database URL that we will use in .env other than it will be a URL to a service that fully supports the OwlDB API. 2. A user must be able to log in. (They do not need to be able to log out.) 3. A user must be able to open a workspace. (They do not need to be able to create, delete, or change workspaces.) 4. A user must be able to open a channel in the currently open workspace. (They do not need to be able to create, delete, or change channels.) 5. A user must be able to view all of the posts in the currently open channel. (They do not need to be able to create new posts, reply to existing posts, or react to existing posts.)

You must submit correct implementations of the login, openWorkspace, and openChannel custom Cypress commands in order to allow these features to be tested. You may, but do not have to, also have other commands implemented, but they will not be used at the check-in.

You can/should set up correctly stored workspace(s), channel(s), and posts in OwlDB (using Swagger, curl, or other method) to test these features.

Other features do not need to work correctly, but partially implemented features should not render the required features inoperable.

You do not need to validate HTTP responses and your channels do not need to be "live" for the check in. In other words, you may assume OwlDB responses are always formatted correctly and you do not need to display new posts (or new reactions to existing posts) that were made after the channel was opened. These two features fall under "other features" that are not required for the check in.

Also, you do not need to display the posts with formatting for the check in. In other words, "\*\*this should be bold\*\*" can be displayed as "\*\*this should be bold\*\*" rather than "this should be bold". You may display them with the proper formatting, you just are not required to for the check in.

You can test your code by using the reference OwlDB server with the database "m3ssag1n8". The provided ".env" file references that database. This database has workspaces, channels, and posts that are properly structured in OwlDB. This database is read-only, so if you try to do any operation that would modify it, the operation will fail and you will get back a "405 Method Not Allowed" HTTP response code.

Project Deadline

Before the project deadline, you must submit the following:

1. All of your code must be committed and pushed to your group's GitHub repository. Your code must type check with "npm run check" and build with "npm run build" without errors. Your code should be properly formatted (if running prettier, i.e., "npm run format", changes anything in your submitted code, you will lose points). 2. All of your documentation (produced by running "npm run doc") must be committed and pushed to your group's GitHub repository. This documentation should be viewable in a web browser, which you should confirm. 3. All of the Cypress custom commands must be implemented correctly for your application in the correct file and pushed to your group's GitHub repository. 4. All of your tests must be committed and pushed to your group's GitHub repository. They should run with "npm test", which you should confirm.

Note that this is the same as what you must submit by the extended deadline, except for the final design document. Your final grade on the project will be a combination of your grade at the deadline and your grade at the extended deadline. The extended deadline truly is an "extension" of the project deadline. You are expected to have your project complete by the actual deadline. The extension is to provide you time to refactor your code, clean up any lingering issues, finalize your documentation, write the final design document, etc.

This is a 6+1 week project. You have no excuse whatsoever for trying to submit within the last few hours before the deadline. Therefore, you should all have time to check and verify your submissions carefully!

This should be obvious, but the benefits of making that one final change shortly before the deadline are far outweighed by the risk of breaking something. In many cases, students lose more points than they would have gained by making that change. Please don't do it, no matter how tempting it is.

Extended Project Deadline

Before the extended project deadline, you must submit the following:

1. All of your code must be committed and pushed to your group's GitHub repository. Your code must type check with "npm run check" and build with "npm run build" without errors. Your code should be properly formatted (if running prettier, i.e., "npm run format", changes anything in your submitted code, you will lose points). 2. All of your documentation (produced by running "npm run doc") must be committed and pushed to your group's GitHub repository. This documentation should be viewable in a web browser, which you should confirm. 3. All of the Cypress custom commands must be implemented correctly for your application in the correct file and pushed to your group's GitHub repository. 4. All of your tests must be committed and pushed to your group's GitHub repository. They should run with "npm test", which you should confirm. 5. A PDF design document must be committed and pushed to your group's GitHub repository named "design.pdf" (do not name it "Design.pdf", "design.PDF" or anything else). This file must be a properly constructed PDF file viewable by a standard PDF reader. No other formats will be accepted or looked at. If you are unsure of how to generate a PDF file, you should seek help from the TAs long before the deadline. The contents of this document will be described below.

You are responsible for ensuring that everything you want graded is on GitHub. You should look at what is there through the web interface. Someone in your group should also do a fresh clone of the repository and confirm that everything is as you expect. No late submissions will be accepted. If you fail to check that you have properly pushed your submission, you run the risk of not having the final versions of your code and documentation graded.

This is a 6+1 week project. You have no excuse whatsoever for trying to submit within the last few hours before the deadline. Therefore, you should all have time to check and verify your submissions carefully!

This should be obvious, but the benefits of making that one final change shortly before the deadline are far outweighed by the risk of breaking something. In many cases, students lose more points than they would have gained by making that change. Please don't do it, no matter how tempting it is.

Design Document

Your design document must contain the following elements:

1. The full names, netids, and GitHub ids of all members of your group. 2. An architectural diagram of your system, showing all of the modules and how they interact, along with a clear and concise description of your design, referring to the architectural diagram. 3. A clear and concise description of how you incorporated three different design principles that were taught in the class in your architecture. 4. A clear and concise description of how you incorporated two different accessibility principles that were taught in the class in your system. 5. A clear and concise description of the extension you added to the application. 6. A clear and concise description of how you managed concurrency in your system.

The entire document must adhere to the following restrictions:

1. The written portion of the document must be 4 pages or less. 2. The architectural diagram should appear on the fifth page and may be no larger than a single page. 3. The margins around all edges must be 0.75 inches or more. 4. The font size must be greater than or equal to 10 points.

You may receive a 0 for the design document if you violate any of these restrictions.

Grading

The project will be graded out of 300 points as follows:

  • 120 points: correctness
  • 40 points: user interface design/usability/accessibility
  • 20 points: design review
  • 60 points: documentation (code and design document)
  • 40 points: design
  • 20 points: testing

The points your group receives will be allocated among your group members at the instructor's discretion. Points will only be distributed equally among group members if each member:

1. Contributed to the project equally. Note that "equally" does not mean "did the same things". You may split up the work in an equitable fashion that does not involve each student working on one-third of each component of the project. As such, "equal" is a subjective measure that will be considered carefully across all of the elements of the project. 2. Behaved reliably and responsibly throughout the project. Each member should attend group meetings, contribute to discussions about the project, meet deadlines agreed upon by the group, and so on. 3. Treated the other group members with respect.

If each group member meets all of these expectations, points will be allocated equally among the group, otherwise they will not be, with students who fail to meet one or more of these expectations receiving a lower fraction of the points (depending on the degree of the problems) than the other group members. No group member can receive fewer than 0 or more than 100 points on the project.

Note that each group member will also get an individual grade for completing all of the self/peer assessments throughout the project.