Skip to content

Assignment 4: Backend Design & Implementation

Assignment Instructions

Assignment Instructions

These are the 6.1040 assignment instructions for this assignment. It goes into greater depth about the expectations, requirements, and deliverables for this assignment. It also includes a rubric detailing how this assignment will be graded.


Community Carpool

A communal carpool coordination social network connecting users that are traveling to the same activity, using location data to help plan the most efficient and convenient routes.

Summary

I implemented my Concepts and was able to successfully deploy these Concepts to Vercel. This required a lot of functionality to be implemented, designing/structuring synchronizations, and database development! Many of these concepts will be modified (or implemented differently) as I progress with the project. As I continue to develop these ideas, I plan to modify my backend structure to better handle my needs. Everything below is my objective/goal.

Backend Deployment

GitHub Repository for Community Carpool's Backend

Vercel Deployment for Community Carpool's Backend

Abstract Data Model Diagram

Community Carpool - Data Abstraction Diagram

Concepts

Location


Purpose

A physical address/location associated with another entity (User, Activity, etc.)

Principle

Locations represent physical addresses on Earth that are associated with a User or an Activity. They must be valid addresses.

State

typescript
locations: set Location
address: string
locations: set Location
address: string

Actions

python
verifyRealAddress(address: str) -> Location
    ## Check public maps APIs to see whether address exists
    assert address is real

setLocation(address: str) -> Location
    location = verifyRealAddress(address: str)
    location.address = address
    locations += location
verifyRealAddress(address: str) -> Location
    ## Check public maps APIs to see whether address exists
    assert address is real

setLocation(address: str) -> Location
    location = verifyRealAddress(address: str)
    location.address = address
    locations += location

Map [Location | Entities]


Purpose

Display the Locations on a map.

Principle

Maps would display the Locations of Users, Activities, or other entities that have a Location associated with them on a visual graphic, making it easy for Users to visualize where things are geographically.

State

typescript
locations: set Location
map: set Entities
locations: set Location
map: set Entities

Actions

python
displayLocationOnMap(map: Map, location: Location) -> Map
    map += location

displayUserOnMap(map: Map, user: User) -> Map
    assert user.address != None
    map += User.address

removeUserFromMap(map: Map, user: User) -> Map
    map i= User.address

removeFromMap(map: Map, location: Location)
    assert location in map
    map -= location
displayLocationOnMap(map: Map, location: Location) -> Map
    map += location

displayUserOnMap(map: Map, user: User) -> Map
    assert user.address != None
    map += User.address

removeUserFromMap(map: Map, user: User) -> Map
    map i= User.address

removeFromMap(map: Map, location: Location)
    assert location in map
    map -= location

User


Purpose

Allow users to create a public-facing user profile so that they can use tha app.

Principle

Users are represented by user profiles, which enables users to register for Activity Groups, set their addresses, and serves as a one-stop-shop for information about that user.

State

typescript
registeredUsers: set User
username: string, password: string -> register(u: string, p: string) -> User

name: string
address: string -> setLocation(address) -> Location
activities: set Activity
carpools: set Carpools
registeredUsers: set User
username: string, password: string -> register(u: string, p: string) -> User

name: string
address: string -> setLocation(address) -> Location
activities: set Activity
carpools: set Carpools

Actions

python
register(username: str, password: str) -> user: User
    assert username not in registeredUsers
    user = User()
    user.username = username
    user.password = password
    user.name = None
    user.address = None
    registeredUsers[username] = user

authenticate(username: str, password: str) -> user: User
    assert username in registeredUsers
    registeredUsers[username].password == password

addName(user: User, name: str)
    user.name = name

renameUser(user: User, name: str)
    user.name = name

addHomeAddress(user: User, address: Location) -> Location
    location: Location = setLocation(address)
    user.address = location
    location.homeAddresses += user

updateHomeAddress(user: User, location: Location)
    user.address = location

deleteHomeAddress(user: User)
    user.address = None
register(username: str, password: str) -> user: User
    assert username not in registeredUsers
    user = User()
    user.username = username
    user.password = password
    user.name = None
    user.address = None
    registeredUsers[username] = user

authenticate(username: str, password: str) -> user: User
    assert username in registeredUsers
    registeredUsers[username].password == password

addName(user: User, name: str)
    user.name = name

renameUser(user: User, name: str)
    user.name = name

addHomeAddress(user: User, address: Location) -> Location
    location: Location = setLocation(address)
    user.address = location
    location.homeAddresses += user

updateHomeAddress(user: User, location: Location)
    user.address = location

deleteHomeAddress(user: User)
    user.address = None

Session [User]


Purpose

Authenticate a User for a period of time and set them as the active User

Principle

When a Session starts, a user's credentials and data is saved and they are "logged in" for the duration of the Session, which ultimately expires when a User "logs out". Sessions store data associated with that user for the period that the Session is active.

State

typescript
activeSessions: set Session
user: activeSessions -> User
activeSessions: set Session
user: activeSessions -> User

Actions

python
startSession(user: User) -> session: Session
    assert user not in activeSessions
    activeSessions += session
    session.user = user

getUser(session: Session) -> user: User
    assert session in activeSessions
    user = session.user

end(session: Session)
    assert session in activeSessions
    activeSessions -= session
    session.user = None
startSession(user: User) -> session: Session
    assert user not in activeSessions
    activeSessions += session
    session.user = user

getUser(session: Session) -> user: User
    assert session in activeSessions
    user = session.user

end(session: Session)
    assert session in activeSessions
    activeSessions -= session
    session.user = None

Activity [User]


Purpose

A subset of Users in a private group, where data is only accessible to those in the group.

Principle

Activities are subsets of Users who all share a commonality (participating in the same activity). Private messaging, information, and data can be accessed by Users who have been approved to join the Activity and is only accessible to Activity members.

State

typescript
managers: set User
members: set User
activityGroups: set Activity
destination: one Location
name: string
creator: one User
schedule: set Time
managers: set User
members: set User
activityGroups: set Activity
destination: one Location
name: string
creator: one User
schedule: set Time

Actions

python
createActivity(manager: User, destination: Location, name: str) -> Activity
    assert name not in activityGroups
    activity = Activity()
    activity.name = name
    activity.managers += manager
    activity.destination = destination
    activityGroups += activity

modifyDestination(activity: Activity, manager: User, destination: Location)
    assert manager in activity.managers
    activity.destination = destination

setActivityPassword(activity: Activity, user: User, code: str)
    assert user in activity.managers
    assert activity.password == None
    activity.password = code

modifyActivityPassword(activity: Activity, user: User, og_pass: str, new_pass: str)
    assert user in activity.managers
    assert activity.password == og_pass
    activity.password = new_pass

addMember(activity: Activity, user: User, password: str)
    assert user not in activity.members
    assert user not in activity.managers
    assert activity.password == password
    activity.members += user

addManager(activity: Activity, manager: User, user: User)
    assert manager in activity.managers
    assert user not in activity.managers
    activity.members -= user
    activity.managers += user

removeMember(activity: Activity, manager: User, user: User)
    assert manager in activity.managers
    assert user in activity.members
    assert user not in activity.managers
    activity.members -= user

removeManager(activity: Activity, manager: User)
    assert manager in activity.managers
    assert user not in activity.members
    activity.managers -= manager
createActivity(manager: User, destination: Location, name: str) -> Activity
    assert name not in activityGroups
    activity = Activity()
    activity.name = name
    activity.managers += manager
    activity.destination = destination
    activityGroups += activity

modifyDestination(activity: Activity, manager: User, destination: Location)
    assert manager in activity.managers
    activity.destination = destination

setActivityPassword(activity: Activity, user: User, code: str)
    assert user in activity.managers
    assert activity.password == None
    activity.password = code

modifyActivityPassword(activity: Activity, user: User, og_pass: str, new_pass: str)
    assert user in activity.managers
    assert activity.password == og_pass
    activity.password = new_pass

addMember(activity: Activity, user: User, password: str)
    assert user not in activity.members
    assert user not in activity.managers
    assert activity.password == password
    activity.members += user

addManager(activity: Activity, manager: User, user: User)
    assert manager in activity.managers
    assert user not in activity.managers
    activity.members -= user
    activity.managers += user

removeMember(activity: Activity, manager: User, user: User)
    assert manager in activity.managers
    assert user in activity.members
    assert user not in activity.managers
    activity.members -= user

removeManager(activity: Activity, manager: User)
    assert manager in activity.managers
    assert user not in activity.members
    activity.managers -= manager

Carpool [User, Activity]


Purpose

A subset of Users in the same ActivityGroup that will commute together.

Principle

Carpools are subsets of Users in the same Activity who will commute to the Activity together. Private messaging, information, and data can be accessed by Users who have been approved to join the Carpool and is only accessible to Carpool members.

State

typescript
driver: one User
members: set User
capacity: Integer
activity: one Activity
schedule: getActivityTimes(Activity) -> set Times
driver: one User
members: set User
capacity: Integer
activity: one Activity
schedule: getActivityTimes(Activity) -> set Times

Actions

python
createCarpoolGroup(driver: User, activity: Activity, capacity: int, name: str) -> Carpool
    assert name not in activity.carpools
    carpool = Carpool()
    carpool.name = name
    carpool.driver = user
    carpool.capacity = capacity
    carpool.destination = activity.destination
    activity.carpools += carpool
    
addMember(carpool: Carpool, user: User)
    assert user not in carpool.members
    assert user != carpool.driver
    assert carpool.capacity < len(carpool.members)
    carpool.members += user

changeDriver(carpool: Carpool, og_driver: User, new_driver: User)
    assert og_driver == carpool.driver
    assert new_driver in carpool.members
    carpool.members -= new_driver
    carpool.members += og_driver
    carpool.driver = new_driver

removeMember(carpool: Carpool, user: User)
    assert user in carpool.members
    assert user != carpool.driver
    carpool.members -= user
createCarpoolGroup(driver: User, activity: Activity, capacity: int, name: str) -> Carpool
    assert name not in activity.carpools
    carpool = Carpool()
    carpool.name = name
    carpool.driver = user
    carpool.capacity = capacity
    carpool.destination = activity.destination
    activity.carpools += carpool
    
addMember(carpool: Carpool, user: User)
    assert user not in carpool.members
    assert user != carpool.driver
    assert carpool.capacity < len(carpool.members)
    carpool.members += user

changeDriver(carpool: Carpool, og_driver: User, new_driver: User)
    assert og_driver == carpool.driver
    assert new_driver in carpool.members
    carpool.members -= new_driver
    carpool.members += og_driver
    carpool.driver = new_driver

removeMember(carpool: Carpool, user: User)
    assert user in carpool.members
    assert user != carpool.driver
    carpool.members -= user

Post [User]


Purpose

Enables Users to share information with each other.

Principle

Users can create content and upload it to Carpool Community as a Post, allowing other Users to interact with this content, Comment on it, and react to it. Posts are a semi-public form of communication, where Users choose which subset of Users can view the Post.

State

typescript
posts: set Post
content: Post -> one Content
user: Post -> one User
reactions: Reaction -> set Reactions
posts: set Post
content: Post -> one Content
user: Post -> one User
reactions: Reaction -> set Reactions

Actions

python
createPost(user: User, content: Content) -> Post
    post = Post()
    post.creator = user
    post.content = content
    posts += post

modifyPost(user: user, post: Post, content: Content)
    assert post in posts
    assert post.creator == user
    post.content = content

deletePost(user: user, post: Post)
    assert post in posts
    assert post.creator == user
    posts -= post
createPost(user: User, content: Content) -> Post
    post = Post()
    post.creator = user
    post.content = content
    posts += post

modifyPost(user: user, post: Post, content: Content)
    assert post in posts
    assert post.creator == user
    post.content = content

deletePost(user: user, post: Post)
    assert post in posts
    assert post.creator == user
    posts -= post

Comment [User, Post]


Purpose

Enables Users to comment on already existing Posts.

Principle

Users can comment on Posts and share their thoughts with other Users on Community Carpool. These Comments would be public to everyone that can view the Post they are associated with, and unlike Posts, Comments cannot exist without a "parent-Post".

State

typescript
comments: Post -> set Comments
content: Comment -> one Content
author: Comment -> one User
reactions: Reaction -> set Reactions
comments: Post -> set Comments
content: Comment -> one Content
author: Comment -> one User
reactions: Reaction -> set Reactions

Actions

python
createComment(user: User, post: Post, content: Content) -> Comment
    assert post in posts
    comment = Comment()
    comment.creator = user
    comment.content = content
    comment.post = post
    post.comments += comment
    comments += comment

modifyComment(user: user, comment: comment, content: Content)
    assert comment in comments
    assert comment.creator == user
    comment.content = content

deleteComment(user: user, comment: Comment)
    assert comment in comments
    assert comment.creator == user or comment.post.creator == user
    comment.post.comments -= comment
    comments -= comment
createComment(user: User, post: Post, content: Content) -> Comment
    assert post in posts
    comment = Comment()
    comment.creator = user
    comment.content = content
    comment.post = post
    post.comments += comment
    comments += comment

modifyComment(user: user, comment: comment, content: Content)
    assert comment in comments
    assert comment.creator == user
    comment.content = content

deleteComment(user: user, comment: Comment)
    assert comment in comments
    assert comment.creator == user or comment.post.creator == user
    comment.post.comments -= comment
    comments -= comment

Reaction [User, Entity]

Clarification on Entity

Entity is being used as a generalized term for a Concept. In this case, an Entity can be a Post, Comment, or a Message.

Purpose

Enables Users to React to an Entity (another Concept), demonstrating support for/against the Entity publicly.

Principle

Users can React to an Entity, which will appear publicly to all parties that can view the original Entity. This acts as a sort of feedback mechanism for others to gauge Users responses to something.

State

typescript
reactionTotals: Entity -> set Reaction -> one integer
reactedUsers: Entity -> set User -> one Reaction
reactions: set Reaction
reactionTotals: Entity -> set Reaction -> one integer
reactedUsers: Entity -> set User -> one Reaction
reactions: set Reaction

Actions

python
react(user: User, entity: Entity, r: Reaction)
    assert r in reactions
    assert entity.reactedUsers.users != user
    entity.reactionTotals[r] += 1
    entity.reactedUsers[user] = r

modifyReaction(user: user, entity: Entity, r: Reaction)
    assert r in reactions
    assert user in entity.reactedUsers
    entity.reactionTotals[entity.reactedUsers[user]] -= 1
    entity.reactionTotals[r] += 1
    entity.reactedUsers[user] = r

deleteReaction(user: user, entity: Entity)
    assert user in entity.reactedUsers
    entity.reactionTotals[entity.reactedUsers[user]] -= 1
    entity.reactedUsers -= user
react(user: User, entity: Entity, r: Reaction)
    assert r in reactions
    assert entity.reactedUsers.users != user
    entity.reactionTotals[r] += 1
    entity.reactedUsers[user] = r

modifyReaction(user: user, entity: Entity, r: Reaction)
    assert r in reactions
    assert user in entity.reactedUsers
    entity.reactionTotals[entity.reactedUsers[user]] -= 1
    entity.reactionTotals[r] += 1
    entity.reactedUsers[user] = r

deleteReaction(user: user, entity: Entity)
    assert user in entity.reactedUsers
    entity.reactionTotals[entity.reactedUsers[user]] -= 1
    entity.reactedUsers -= user

Message [User]


Purpose

Messages allow Users to directly communicate with each other privately.

Principle

Messages serve as a private form of communication between two (or more) Users who may or may not share a connection through Activities or Carpools. It is a general, private form of communication.

State

typescript
messages: set Message
messages: set Message

Actions

python
sendMessage(sender: User, recipient: User, content: Content)
    assert sender in registeredUsers
    assert recipient in registered Users
    assert sender != recipient
    message = Message()
    message.content = content
    message.time = now()
    sender.messages[recipient][sent] += message
    recipient.messages[sender][recieved] += message
sendMessage(sender: User, recipient: User, content: Content)
    assert sender in registeredUsers
    assert recipient in registered Users
    assert sender != recipient
    message = Message()
    message.content = content
    message.time = now()
    sender.messages[recipient][sent] += message
    recipient.messages[sender][recieved] += message

Reflection

Overall, implementing the backend of a project whose scope is as complex and detailed as this one made me realize how much thought and planning goes into these kind of RESTful database designs. Time and time again, I would develop a concept, then realize that I omitted a key piece of information or did not efficiently handle a particular edge case. This required me to redo many portions of the assignment throughout the past two weeks. Using Concepts was also tremendously useful, as it allowed me to reuse certain functions and behaviors across multiple different use-cases. Generalizing data objects into these broader concept categories is incredibly efficient and useful. Abstracting logic and the capabilities of the code is essential to minimizing bugs, ensuring a consistent user-experience, and maintaining a level of uniformity/interdependence throughout the project. Given that this was my first time ever working with REST and developing such a backend, I learned a tremendous amount and am very proud of the final result!

Discourse Engagement

Thank you to all of the TAs and Staff (especially @BarishNamazov) who answered my questions on Discourse throughout the past two weeks!