Skip to content

Assignment 4: Backend Design & Implementation (Beta)

October 12th, 2023

Concept States

Concept 1: User
State:

registered: set User 
username, password: registered -> one String
registered: set User 
username, password: registered -> one String

Actions

register(n: String, p: String, out u: User) 
    u not in registered 
    registered += u 
    u.username := n 
    u.password := p 

authenticate(n, p: String, out u: User)
    u in registered 
    u.username = n and u.password = p
register(n: String, p: String, out u: User) 
    u not in registered 
    registered += u 
    u.username := n 
    u.password := p 

authenticate(n, p: String, out u: User)
    u in registered 
    u.username = n and u.password = p

Concept 2: Session[User]
State:

active: set Session 
user: active -> one User
active: set Session 
user: active -> one User

Actions

start(u: User, out s: Session) 
    s not in active 
    active += s 
    s.user := u
getUser(s: Session, out u: User)
    s in active
    u := s.user 
end(s: Session) 
    active -= s
start(u: User, out s: Session) 
    s not in active 
    active += s 
    s.user := u
getUser(s: Session, out u: User)
    s in active
    u := s.user 
end(s: Session) 
    active -= s

Concept 3: Group[User]
State:

groups: set Group 
name: Group -> one String 
admin: Group -> one User 
members: Group -> set User
groups: set Group 
name: Group -> one String 
admin: Group -> one User 
members: Group -> set User

Actions

create(u: User, n: String) 
    groups += Group (name=n, admin=u, members = {}) 
delete(g: Group) 
    groups -= g 
addMember(g: Group, u: User) 
    groups[g]['members'] += u 
deleteMember(g: Group, u: User) 
    groups[g]['members'] -= u
create(u: User, n: String) 
    groups += Group (name=n, admin=u, members = {}) 
delete(g: Group) 
    groups -= g 
addMember(g: Group, u: User) 
    groups[g]['members'] += u 
deleteMember(g: Group, u: User) 
    groups[g]['members'] -= u

Concept 4: Post[User]
State:

posts: set Post
author: Post -> one User 
content: Post -> String 
sharedWith: Post -> set User
posts: set Post
author: Post -> one User 
content: Post -> String 
sharedWith: Post -> set User

Actions

create(a: User, n: Note, c: String, l: Link, s: set User, out post: Post) 
    post := Post (author=a, content=c, link= l, note=n, sharedWith=g) 
    posts += post 
delete(post: Post)
    posts -= post 
view(u: User, p: Post, out p: Post) 
    if u in p.sharedWith return p
create(a: User, n: Note, c: String, l: Link, s: set User, out post: Post) 
    post := Post (author=a, content=c, link= l, note=n, sharedWith=g) 
    posts += post 
delete(post: Post)
    posts -= post 
view(u: User, p: Post, out p: Post) 
    if u in p.sharedWith return p

Concept 5: Note[User, Post]
State:

notes: set Note 
author: Note -> one User 
content: Note -> String 
target: Note -> lone Post
notes: set Note 
author: Note -> one User 
content: Note -> String 
target: Note -> lone Post

Actions

create(a: User, c: String, post: Post)
    note := Note (author=a, content=c)
    notes += note
    post += note
create(a: User, c: String, post: Post)
    note := Note (author=a, content=c)
    notes += note
    post += note

Concept 6: Link[Post]
State:

description: Link -> String 
url: Link -> String 
paywall: Link -> one Boolean
target: Link -> one Post
description: Link -> String 
url: Link -> String 
paywall: Link -> one Boolean
target: Link -> one Post

Actions

create(d: String, u: String, post: Post) 
    link := Link (description=d, url=u)
    post += link
create(d: String, u: String, post: Post) 
    link := Link (description=d, url=u)
    post += link

Synchronizations

include User 
include Session[User.User] 
include Group[User.User] 
include Post[User.User, Link.Link, Note.Note] 
include Note[User.User, Post.Post]
include Link[Post.Post]

sync createUser(n: String, p: String) 
    User.register(n, p) 
    Group.create(n, "Everyone")

sync startSession(n: String, p: String) 
    User.authenticate(n, p) 
    Session.start 

sync createLink(d: String, u: String) 
    Link.create(d, u)

sync createNote(a: User, c: String) 
    Note.create(a, c)

sync createGroup(u: User, name: String) 
    Group.create(u, name)

sync addGroupMember(g: Group, u: User)
    Group.addMember(g, u)

sync removeGroupMember(a: User, u: User, g: Group)
    Group.deleteMember(g, u)

sync createPost(u: User, n: Note, c: String, l: Link, g: Group) 
    Post.create(u, n, c, l, g)

sync viewPost(u: User, p: Post) 
    Post.view(u, p)
include User 
include Session[User.User] 
include Group[User.User] 
include Post[User.User, Link.Link, Note.Note] 
include Note[User.User, Post.Post]
include Link[Post.Post]

sync createUser(n: String, p: String) 
    User.register(n, p) 
    Group.create(n, "Everyone")

sync startSession(n: String, p: String) 
    User.authenticate(n, p) 
    Session.start 

sync createLink(d: String, u: String) 
    Link.create(d, u)

sync createNote(a: User, c: String) 
    Note.create(a, c)

sync createGroup(u: User, name: String) 
    Group.create(u, name)

sync addGroupMember(g: Group, u: User)
    Group.addMember(g, u)

sync removeGroupMember(a: User, u: User, g: Group)
    Group.deleteMember(g, u)

sync createPost(u: User, n: Note, c: String, l: Link, g: Group) 
    Post.create(u, n, c, l, g)

sync viewPost(u: User, p: Post) 
    Post.view(u, p)

Data Model Diagram

diagram

Design Reflection

One of the design features left ambiguous was regarding a "draft" feature. In the case where a draft might exist, a user first creates a post just visible to themselves, or published to no groups. They would optionally take the next step to publish it to one or more groups, otherwise it would just stay put in its draft state. I decided instead to allow the user the option to either specify a group to publish to, or by default publish to all groups. This would reduce the friction needed to make a post in general, and also encourage publishing content to a wider audience. Another design decision that I made was to keep track of links and notes by using "targets" in each concept, keeping a record of which post each annotation is linked to. An alternate option would be to keep track of this information in each post, but I chose the target approach to reduce complexity, so the database can manage notes and links by themselves as opposed to through the post concept. For example, features such as getting the links of each post is useful if the user wants a condensed version of their feed. Nested deletion is still used in this representation, so deleting one post will delete its associated link and note.

Backend repository: https://github.com/anna8murphy/pulse-backend

Vercel deployment: https://pulse-backend.vercel.app/