---
# System prepended metadata

title: 'PA: Product and Presentation'

---

# PA: Product and Presentation

## A9: Product

  **Nexus** is a generalist web-based information system for managing social interactions between users by allowing them to publish their thoughts, interests, and creative content as well as see news about their friends and people of general interest. We aim to join people that share common passions by creating themed groups where people can express themselves in a safe and prosperous environment.
  
### 1. Installation

Below there's the link to the release with the final version of the source code in the group's Git repository:

> link.com # TODO ADICIONAR A TAG DE PA

The the full Docker command needed to start the image available at the group's GitLab Container Registry using the production database can be found below:

> sudo docker run -it -p 8000:80 --name=lbaw2261 -e DB_DATABASE="lbaw2261" -e DB_SCHEMA="lbaw2261" -e DB_USERNAME="lbaw2261" -e DB_PASSWORD="cGtzVMep" git.fe.up.pt:5050/lbaw/lbaw2223/lbaw2261

### 2. Usage

URL to our Nexus production product: https://lbaw2261.lbaw.fe.up.pt

#### 2.1. Administration Credentials

| Username | Email            | Password |
| -------- |----------------  | -------- |
| Admin    | admin@gmail.com  | password |

Talvez mais uma pelo menos?

#### 2.2. User Credentials

| Type          | Username  | Password |
| ------------- | --------- | --------  |
| User     | user@gmail.com   | password |
| Banned User  | banned@example.net   | password |

### 3. Application Help

The Nexus user has the possibility of when he feels doubts how to use any nexus page just click on the ? to appear a mini tutorial of the page.

![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/icon.png)


![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/tutorial.png)


![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/search.png)


### 4. Input Validation

In the first photo check if the credentials are correct in this case the account does not exist or the email or password are incorrect.


![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/emailerror.png)

In the second photo, check if the username only contains letters and numbers and dashes.

![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/emailerror.png)

In the third photo, no more tags are allowed if the maximum number of tags per post is reached.


![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/post.png)


We have done a lot of input validation. Almost every controller that receives data has input validation. We have also made more input validations on the client.
Its also worthy to note that we have done input sanitation. In this case, texts containing tags will have their tags removed from them, preventing the application from xss stored. 

Some more examples...


![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/code1.png)


![](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/docs/code2.png)


### 5. Check Accessibility and Usability

To evaluate our accessibility and usability correctness, we performed tests using 2 checklists. The results are included as PDF files in the group's repository. Links to those files can be found below:
> **Accessibility:** [Score Report](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/checklists/Checklist%20de%20Acessibilidade%20-%20SAPO%20UX.pdf) 
> **Usability:**     [Score Report](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/checklists/Checklist%20de%20Usabilidade%20-%20SAPO%20UX.pdf)

Websites where the checklists used can be found:

> Accessibility: https://ux.sapo.pt/checklists/acessibilidade/
> Usability: https://ux.sapo.pt/checklists/usabilidade/

We have done some popup forms with AJAX Request in Javascript. If there was no JavaScript it would still be possible to register, login, edit post and edit groups. However, we think that not having JavaScript would mostly disable every important feature of our app (including seeing the timeline and liking content) and a solution for that would implicate a bad user experience.


We haven't tried to make our website printable has it did't make a lot of sense for a social network. However, the result of printing is not that bad.


### 6. HTML & CSS Validation

To ensure code quality, we validated our HTML and CSS. The PDF results of the HTML and CSS code validation are present in the  group's repository. The direct link to these files can be found below:
> **HTML:** [Validator Report Files](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/tree/main/HTML_Validator)
> **CSS:** [Validator Report File](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/HTML_Validator/CSS%20VALIDATION.pdf)

In general, the results were positive. In the Html validation, there were 5 points intrisic to every page that we did no correct. Some of these seem to be from the libraries we imported. Two of them are duplicates and we found no need to fix them. In the css validation, there is nothing to point out. The only warnings given by the site were related to browser specific intructions and a warning informing that css variables were not being checked.  

Code validation was made using the following tools:
> HTML: https://validator.w3.org/nu/
> CSS: https://jigsaw.w3.org/css-validator/

### 7. Revisions to the Project

During the development of this project, as it would be expected, many changes were made, thus changes to the previous reports were needed. For that reason, where we describe the revisions made to the project since the requirements specification stage.

List of changes made:

- **ER: Requirements Specification**
   * Changed placeholders to business rules
   * Recover Password US was changed to visitor
   * Added US regarding most reported posts/comments for the administrator
   * Added US:
       *  US337 - Video Call added 
       *  US338 - Online Status
    
- **EBD: Database Specification**
   * Seed updated
   * Triggers update (there was a need to pass the post id to some of the notification triggers)

- **EAP: Architecture Specification and Prototype**
    - New version of the OpenAPI (called *'a9_openapi.yaml'*) was made to reflect the final list of web resources 

### 8. Web Resources Specification

In this final report, we updated our OpenAPI specification in YAML format to reflect the final product's web resources.

Link to the `a9_openapi.yaml` file in the group's repository can be found [here](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/a9_openapi.yaml)

```yaml=
openapi: 3.0.0

info:
  version: "2.0"
  title: "LBAW Nexus Web API"
  description: "Web Resources Specification (A9) for Nexus"

servers:
  - url: https://lbaw2261.lbaw.fe.up.pt
    description: Production server
  - url: localhost:8000
    description: Localhost server

tags:
  - name: "M01: Authentication and Individual Profile"
  - name: "M02: Feed"
  - name: "M03: Groups"
  - name: "M04: Requests"
  - name: "M05: Messages"
  - name: "M06: Notifications"
  - name: "M07: Search"
  - name: "M08: User Administration and Static pages"

paths:
  /login:
    get:
      operationId: R101
      summary: "R101: Login Form"
      description: "Provide login form. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"
      responses:
        "200":
          description: "Ok. Show log-in UI05"
    post:
      operationId: R102
      summary: "R102: Login Action"
      description: "Processes the login form submission. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                email: # <!--- form field name
                  type: string
                password: # <!--- form field name
                  type: string
              required:
                - email
                - password

      responses:
        "302":
          description: "Redirect after processing the login credentials."
          headers:
            Location:
              schema:
                type: string
              examples:
                302Success:
                  description: "Successful authentication. Redirect to user profile."
                  value: "/home"
                302Error:
                  description: "Failed authentication. Redirect to login form."
                  value: "/login"

  # ==================================================================

  /logout:
    get:
      operationId: R103
      summary: "R103: Logout Action"
      description: "Logout the current authenticated user. Access: USR, ADM"
      tags:
        - "M01: Authentication and Individual Profile"
      responses:
        "302":
          description: "Redirect after processing logout."
          headers:
            Location:
              schema:
                type: string
              examples:
                302Success:
                  description: "Successful logout. Redirect to login form."
                  value: "/login"

  # ==================================================================

  /register:
    get:
      operationId: R104
      summary: "R104: Register Form"
      description: "Provide new user registration form. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"
      responses:
        "200":
          description: "Ok. Show sign-up UI"

    post:
      operationId: R105
      summary: "R105: Register Action"
      description: "Processes the Register form submission. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                email: # <!--- form field name
                  type: string
                password: # <!--- form field name
                  type: string
                username: # <!--- form field name
                  type: string
                birthdate: # <!--- form field name
                  type: string
                bio: # <!--- form field name
                  type: string
              required:
                - email
                - password
                - username
                - birthdate

      responses:
        "302":
          description: "Redirect after processing the register credentials."
          headers:
            Location:
              schema:
                type: string
              examples:
                302Success:
                  description: "Successful register. Redirect to user profile."
                  value: "/home"
                302Error:
                  description: "Failed to register. Redirect to register form."
                  value: "/register"

  # ==================================================================

  /google_redirect:
    get:
      operationId: R106
      summary: "R106: Redirect to Google Authentication Provider"
      description: "Redirect to Google Authentication. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      responses:
        "200":
          description: "Redirect successful"

  # ==================================================================

  /callback:
    get:
      operationId: R107
      summary: "R107: Google Authentication Provider Callback"
      description: "Return from Google Authentication Provider. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      responses:
        "200":
          description: "Google Login callback was successful"

  # ==================================================================

  /resetAuthPassword:
    get:
      operationId: R108
      summary: "R108: Change Authenticated User's Password Page"
      description: "Change Authenticated User's Password. Access: USR"
      tags:
        - "M01: Authentication and Individual Profile"

      responses:
        "200":
          description: "Show Change Password Form UI"

  # ==================================================================

  /forgot-password:
    get:
      operationId: R109
      summary: "R109: Forgot Password Form Page"
      description: "Forgot Password Form Page. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      responses:
        "200":
          description: "Show Forgot Password Form UI"

  # ==================================================================

  /forgot-password-sent:
    get:
      operationId: R110
      summary: "R110: Forgot Password Sent Page"
      description: "Forgot Password Sent Page. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      responses:
        "200":
          description: "Show Forgot Password Sent Page UI"

  # ==================================================================

  /reset_password_without_token:
    post:
      operationId: R111
      summary: "R111: Send Password Recovery Email"
      description: "Send Password Recovery Email. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                email:
                  type: string
              required:
                - email

      responses:
        "200":
          description: "Show Email Sent Page UI"
        "400":
          description: "Email not asscociated to any account"

  # ==================================================================

  /reset_password_with_token:
    post:
      operationId: R112
      summary: "R112: Password Update"
      description: "Password Update Form Submission. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                password:
                  type: string
                password_confirmation:
                  type: string
                token:
                  type: string
              required:
                - password
                - password_confirmation
                - token

      responses:
        "200":
          description: "Login into the account"
        "400":
          description: "Invalid token or password mismatch"

  # ==================================================================

  /password/reset/{token}:
    get:
      operationId: R113
      summary: "R113: Get Set New Password Form"
      description: "Get Set New Password Form. Access: PUB"
      tags:
        - "M01: Authentication and Individual Profile"

      parameters:
        - in: path
          name: token
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Show Set New Password Form UI"

  # ==================================================================

  /profile/{username}:
    get:
      operationId: R114
      summary: "R114: Profile page"
      description: "Show the profile page . Access: PUB/USR"
      tags:
        - "M01: Authentication and Individual Profile"

      parameters:
        - in: path
          name: username
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Ok. Show profile page"
        "404":
          description: "Profile not found"

  # ==================================================================

  /like_list/{username}:
    get:
      operationId: R115
      summary: "R115: User liked content list"
      description: "Show User liked content. Access: USR"
      tags:
        - "M01: Authentication and Individual Profile"

      parameters:
        - in: path
          name: username
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Show user liked content UI"
        "403":
          description: "Not authenticated or cannot access user liked content"

  # ==================================================================

  /comment_list/{username}:
    get:
      operationId: R116
      summary: "R116 Show the comments list page"
      description: "Show the comments list of the user. Access: USR"
      tags:
        - "M01: Authentication and Individual Profile"

      responses:
        "200":
          description: "Ok. Show comments list of the user page"
        "403":
          description: "Forbidden access to resource"
        "404":
          description: "User Not found"

  # ==================================================================

  /edit_profile/{username}:
    get:
      tags:
        - "M01: Authentication and Individual Profile"

      operationId: "R117"
      summary: "R117: Get user edit profile page"
      description: "Get user edit profile page. Access: USR, ADM"

      parameters:
        - name: username
          in: path
          description: "User username"
          required: true
          schema:
            type: string

      responses:
        "200":
          description: "User profile"
        "404":
          description: "User not found"
        "403":
          description: "Forbidden"

  # ==================================================================

  /api/profile/{id}:
    post:
      operationId: R118
      summary: "R118: Edit Profile"
      description: "Edit Profile. Access: OWN"
      tags:
        - "M01: Authentication and Individual Profile"

      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
                email:
                  type: string
                visibility:
                  type: boolean
                birthdate:
                  type: string
                bio:
                  type: string
                photo:
                  type: object # is it object?

      responses:
        "200":
          description: "Profile edited successfully"
        "403":
          description: "Forbidden. User is not the owner of the profile"

  # ==================================================================

  /api/profile/{username}:
    post:
      operationId: R119
      summary: "R119: Edit a Profile"
      description: "Edit a Profile"
      tags:
        - "M01: Authentication and Individual Profile"
      parameters:
        - in: path
          name: username
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                password:
                  type: string
                visibility:
                  type: boolean
                bio:
                  type: string
                picture:
                  type: string
                  format: binary
      responses:
        "200":
          description: "The profile was edit successfully"
        "403":
          description: "Forbidden access to resource, the profile is not yours"

    delete:
      operationId: "R120"
      summary: "R120: Delete a Profile"
      description: "Deletes a profile. Access: USR"
      tags:
        - "M01: Authentication and Individual Profile"
      parameters:
        - in: path
          name: username
          schema:
            type: string
          required: true
      responses:
        "200":
          description: "The profile was deleted successfully"
        "403":
          description: "Forbidden access to resource, the profile is not yours"

  # ==================================================================

  /broadcast/auth:
    get:
      tags:
        - "M01: Authentication and Individual Profile"

      operationId: "R121"
      summary: "RR121: Get auth in pusher"
      description: "Get auth token from the server so that the client can connect to pusher presence channel and make pusher requests. Access: USR"
      responses:
        "200":
          description: "Auth"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /:
    get:
      operationId: R201
      summary: "R201: Website root redirect to home"
      description: "Website root. Access: PUB"
      tags:
        - "M02: Feed"

      responses:
        "302":
          description: "Redirect to home"
          headers:
            Location:
              schema:
                type: string
              examples:
                302:
                  description: "Redirect to home"
                  value: "/home"

  # ==================================================================

  /home:
    get:
      operationId: R202
      summary: "R202 View Home Page"
      description: "Show the home page. Access: PUB"
      tags:
        - "M02: Feed"
      responses:
        "200":
          description: "Ok. Show home page UI"

  # ==================================================================

  /post/{id}:
    get:
      operationId: R203
      summary: "R203: View Post Page"
      description: "Shows post, with comments, likes etc. Access: PUB/USR"
      tags:
        - "M02: Feed"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Ok, show Post Page UI02"
        "403":
          description: "Forbidden access to resource, the post might be private or it does not exists"

  # ==================================================================

  /api/post/feed/{type_feed}/offset/{offset}:
    get:
      operationId: R204
      summary: "R204 Get Posts"
      description: "Gets the posts according to the parameters and returns the results as json. Access: USR and PUB for viral"
      tags:
        - "M02: Feed"
      parameters:
        - in: path
          name: type_feed
          description: 'Filter parameter. Can be "for_you", "friends", "groups", "viral" '
          schema:
            type: string
          required: true

        - in: path
          name: offset
          description: Offset of content to show.
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    text:
                      type: string
                    post_date:
                      type: string
                    owner:
                      type: string
                    photo:
                      type: string
                    likes_count:
                      type: integer
                    comments_count:
                      type: integer
                    ranking:
                      type: number
                    images:
                      type: array
                      items:
                        type: string
                    hasLiked:
                      type: boolean
                    isOwner:
                      type: boolean
                    auth:
                      type: integer

                example:
                  - id: 123
                    text: "The dark side of the force is stronger!!!"
                    post_date: "2022-05-04 22:22:22"
                    owner: Darth Vader
                    photo: user/1.png
                    likes_count: 10
                    comments_count: 5
                    ranking: 4.1292965
                    images:
                      - post/666.png
                      - post/667.png
                    hasLiked: true
                    isOwner: false
                    auth: 0

  # ==================================================================

  /api/comment:
    put:
      operationId: R205
      summary: "R205: Edit comment"
      description: "Edit comment. Access: OWN"
      tags:
        - "M02: Feed"

      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id_comment:
                  type: integer
                text:
                  type: string
              required:
                - id_comment
                - text

      responses:
        "200":
          description: "The comment was edited successfully"
        "403":
          description: "Forbidden access to resource"

  # ==================================================================

  /api/comment/{id_post}:
    post:
      operationId: "R206"
      summary: "R206: Create Comment"
      description: "Create a Comment associated with a certain Post. Access: USR"
      tags:
        - "M02: Feed"

      parameters:
        - in: path
          name: id_post
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Comment created successfully"
        "403":
          description: "Forbidden access to resource"

  # ==================================================================

  /api/comment/{id_comment}:
    delete:
      tags:
        - "M02: Feed"

      operationId: "R207"
      summary: "R207: Delete Comment"
      description: "Delete Comment. Access: OWN, ADM"
      parameters:
        - name: id_comment
          in: path
          description: "coment_id"
          required: true
          schema:
            type: string
      responses:
        "200":
          description: "Comment deleted"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /api/post/{id}:
    delete:
      operationId: R208
      summary: "R208: Delete Post"
      description: "Deletes a post. Access: OWN"
      tags:
        - "M02: Feed"
      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true
      responses:
        "200":
          description: "The post was deleted successfully"
        "403":
          description: "Forbidden access to resource, the post is not yours"

    post:
      operationId: R209
      summary: "R209: Edit a Post"
      description: "Edit a post. Access: OWN"
      tags:
        - "M02: Feed"

      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                text:
                  type: string
                picture:
                  type: array
                  items:
                    type: string
                    format: binary
              required:
                - text
      responses:
        "200":
          description: "The post was edit successfully"
        "403":
          description: "Forbidden access to resource, the post is not yours"

  # ==================================================================

  /api/like_post:
    post:
      operationId: "R210"
      summary: "R210: Toggle like on post"
      description: "Toggle like on post. Access: USR"
      tags:
        - "M02: Feed"

      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id_user:
                  type: integer
                id_post:
                  type: integer

      responses:
        "200":
          description: "The like was sucessful"
        "403":
          description: "Forbidden access to resource"

  # ==================================================================

  /api/like_comment:
    post:
      operationId: "R211"
      summary: "R211: Toggle like on comment"
      description: "Toggle like on comment. Access: USR"
      tags:
        - "M02: Feed"

      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id_user:
                  type: integer
                id_comment:
                  type: integer

      responses:
        "200":
          description: "The like was sucessful"
        "403":
          description: "Forbidden access to resource"

  # ==================================================================

  /api/post:
    post:
      operationId: R212
      summary: "R212: Create a Post"
      description: "Creates a post. Access: USR"
      tags:
        - "M02: Feed"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                text:
                  type: string
                group:
                  type: string
                picture:
                  type: array
                  items:
                    type: string
                    format: binary
              required:
                - text

      responses:
        "201":
          description: "The post was created successfully"
        "400":
          description: "There is something wrong with the request body"

  # ==================================================================

  /group/{name}:
    get:
      operationId: R301
      summary: "R301: Group Profile page"
      description: "Group Profile. Access: PUB/USR"
      tags:
        - "M03: Groups"
      parameters:
        - in: path
          name: name
          schema:
            type: string
          required: true
      responses:
        "200":
          description: "Success. Show group page"
        "404":
          description: "Group Profile does not exist"

  # ==================================================================

  /group/{name}/edit:
    get:
      operationId: "R302"
      summary: "R302 Page to edit group"
      description: "Page to edit group. Access: OWN"
      tags:
        - "M03: Groups"

      parameters:
        - in: path
          name: name
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Show Edit Group Page UI"
        "403":
          description: "Abort. Not allowed to edit group if not owner"

  # ==================================================================

  /group/member_list/{name}:
    get:
      tags:
        - "M03: Groups"
      summary: "R303: Get group members"
      description: "Get group members of a group. Access: MEM, ADM (OWN of group is member)"
      operationId: "R303"
      parameters:
        - name: name
          in: path
          description: "Group name"
          required: true
          schema:
            type: string
      responses:
        "200":
          description: "Group members"
        "404":
          description: "Group not found"
        "403":
          description: "Forbidden"

  # ==================================================================

  /api/group/{id_group}/owner/{id_user}:
    post:
      operationId: R304
      summary: "R304: Promote member to owner"
      description: "Promote member to owner. Access: OWN"
      tags:
        - "M03: Groups"

      parameters:
        - in: path
          name: id_group
          schema:
            type: integer
          required: true
        - in: path
          name: id_user
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "New owner added successfully"
        "403":
          description: "Forbidden access to resource. User is not owner of the group"

  # ==================================================================

  /api/group/{id_group}/member/{id_user}:
    delete:
      operationId: R305
      summary: "R305: Remove a group a member"
      description: "Deletes a group member. Access: OWN"
      tags:
        - "M03: Groups"

      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                id_group:
                  type: integer
                id_user:
                  type: integer

      responses:
        "200":
          description: "The member was removed successfully"
        "403":
          description: "Forbidden access to resource or this member doesnt belong in this group"

  # ==================================================================

  /api/group:
    post:
      operationId: R306
      summary: "R306: Create a Group"
      description: "Creates a Group. Access: USR"
      tags:
        - "M03: Groups"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  description:
                    type: string
                  visibility:
                    type: integer
                  image:
                    type: string
                    format: binary

      responses:
        "201":
          description: "The group was created successfully"
        "400":
          description: "There is something wrong with the request body"

  # ==================================================================

  /api/group/{name}:
    post:
      operationId: R307
      summary: "R307: Edit a Group"
      description: "Edit a Group. Access: OWN"
      tags:
        - "M03: Groups"
      parameters:
        - in: path
          name: name
          schema:
            type: string
          required: true

      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                visibility:
                  type: boolean
                picture:
                  type: string
                  format: binary
      responses:
        "200":
          description: "The group was edit successfully"
        "403":
          description: "Forbidden access to resource, the Group is not yours"

    delete:
      operationId: R308
      summary: "R308: Delete Group"
      description: "Deletes a group. Access: OWN"
      tags:
        - "M03: Groups"
      parameters:
        - in: path
          name: name_group
          schema:
            type: string
          required: true
      responses:
        "200":
          description: "The group was deleted successfully"
        "403":
          description: "Forbidden access to resource, the group is not yours"

  # ==================================================================

  /api/group_member/{id}:
    get:
      operationId: R309
      summary: "R309: Get group member"
      description: "Get group member. Access: USR"
      tags:
        - "M03: Groups"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "The group members were returned successfully"
        "403":
          description: "Forbidden access to resource"

    delete:
      operationId: R310
      summary: "R310: Delete group member"
      description: "Delete group member from group with id. Access: OWN"
      tags:
        - "M03: Groups"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "The group member was deleted successfully"
        "403":
          description: "Forbidden access to resource"

  # ==================================================================

  /api/group/{name}/owner/{id}:
    post:
      operationId: R311
      summary: "R311: Promote a Member"
      description: "Promote a member: OWN"
      tags:
        - "M03: Groups"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "The group member was promoted successfully"
        "403":
          description: "Forbidden access to resource"

  # ==================================================================

  /group_list/{username}:
    get:
      operationId: R312
      summary: "R312: Group list of username"
      description: "Group list of username. Access: USR"
      tags:
        - "M03: Groups"
      parameters:
        - in: path
          name: username
          schema:
            type: string
          required: true
      responses:
        "200":
          description: "Success. Show group list of username page"
        "404":
          description: "Does not exist any user with this username"

  # ==================================================================

  /user/friends/requests:
    get:
      operationId: R401
      summary: "R401 View friends requests"
      description: "Show the friends requests page.Access: USR"
      tags:
        - "M04: Requests"
      responses:
        "200":
          description: "Ok. Show friends requests page"
        "403":
          description: "Forbidden access to resource"
        "404":
          description: "Not found"

  # ==================================================================

  /group/{group_name}/requests:
    get:
      operationId: R402
      summary: "R402: Group Requests"
      description: "Group Requests. Access: OWN"
      tags:
        - "M04: Requests"
      parameters:
        - in: path
          name: group_name
          schema:
            type: string
          required: true
      responses:
        "200":
          description: "Success. Show group requests page"
        "404":
          description: "Does not exist any Group Requests"

  # ==================================================================

  /api/user/friend/request/{id_sender}/reject:
    put:
      operationId: "R403"
      summary: "R403 Reject a friend request"
      description: "Reject a friend request. Access: USR"
      tags:
        - "M04: Requests"

      parameters:
        - in: path
          name: id_sender
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "The request was rejected with success"
        "403":
          description: "You need to authenticate to use this endpoint"

  # ==================================================================

  /api/group/request/{id}/send:
    post:
      operationId: "R404"
      summary: "R404: Send a group join request"
      description: "Send a group join request. Access: USR"
      tags:
        - "M04: Requests"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "The request was sent"
        "403":
          description: "You need to authenticate to use this endpoint"

  # ==================================================================

  /api/group/request/{id}:
    delete:
      operationId: R405
      summary: "R405: Delete group request"
      description: "Delete group request. Access: OWN"
      tags:
        - "M04: Requests"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Group request deleted successfully"
        "403":
          description: "Forbidden access to resource. User is not owner of the group"

  # ==================================================================

  /api/group/{group_name}/request/{id_sender}/accept:
    put:
      operationId: "R406"
      summary: "R406 Accept group join request"
      description: "Accept group join request. Access: OWN"
      tags:
        - "M04: Requests"

      parameters:
        - in: path
          name: group_name
          schema:
            type: string
          required: true

        - in: path
          name: id_sender
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "The request was Accepted with Success"
        "403":
          description: "You need to authenticate to use this endpoint"

  # ==================================================================

  /api/user/friend/request/{id_sender}/accept:
    put:
      operationId: R407
      summary: "R407: Accept friend request"
      description: "Accept friend request. Access: USR"
      tags:
        - "M04: Requests"

      parameters:
        - in: path
          name: id_sender
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Friend request accepted successfully"
        "403":
          description: "Forbidden. User is not the receiver of the friend request"

  # ==================================================================

  /api/group/{group_name}/request/{id_sender}/reject:
    put:
      tags:
        - "M04: Requests"
      summary: "R408: Reject request"
      description: "Reject group request. Access: OWN"
      operationId: "R408"
      parameters:
        - name: group_name
          in: path
          description: "Group name"
          required: true
          schema:
            type: string
        - name: id_sender
          in: path
          description: "Request sender id"
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: "Request rejected"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /api/user/friend/request/{id_rcv}/send:
    post:
      tags:
        - "M04: Requests"
      summary: "R409: Send friend request"
      description: "Send friend request. Access: USR"
      operationId: "R409"
      parameters:
        - name: id_rcv
          in: path
          description: "Request receiver id"
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: "Friend request sent"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /user/friends/{username}:
    get:
      operationId: R410
      summary: "R410: View user's friend list"
      description: "Show the friends of user. Access: USR"
      tags:
        - "M04: Requests"
      responses:
        "200":
          description: "Ok. Show friends of user page"
        "403":
          description: "Forbidden access to resource"
        "404":
          description: "User Not found"

  # ==================================================================

  /messages:
    get:
      operationId: R501
      summary: "R501: Show User's Messages Page"
      description: "Show User's Messages Page. Access: USR"
      tags:
        - "M05: Messages"

      responses:
        "200":
          description: "Show Message Page UI"
        "403":
          description: "Not authenticated or cannot access the messages"

  # ==================================================================

  /messages/{sender_username}:
    get:
      operationId: R502
      summary: "R502 View message page"
      description: "Show the messages page UI04. Access: USR"
      tags:
        - "M05: Messages"
      responses:
        "200":
          description: "Ok. Show message page"
        "403":
          description: "Forbidden access to resource"
        "404":
          description: "Not found"

  # ==================================================================

  /api/message/{id}:
    post:
      operationId: "R503"
      summary: "R503: Send a message"
      description: "Send a message to a certain user. Access: USR"
      tags:
        - "M05: Messages"

      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true

      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                text:
                  type: string

      responses:
        "201":
          description: "Successfully created"
        "400":
          description: "Text cannot be null"
        "403":
          description: "Failure"

  # ==================================================================

  /notifications:
    get:
      operationId: R601
      summary: "R601: Notification Page"
      description: "Notification Page. Access: USR"
      tags:
        - "M06: Notifications"

      responses:
        "200":
          description: "Show Notification List UI"
        "403":
          description: "Not authenticated or cannot access the notifications"

  # ==================================================================

  /api/user/notifications/seen:
    put:
      operationId: "R602"
      summary: "R602: Mark all notifications as seen"
      description: "Mark all notifications as seen of a certain user. Access: USR"
      tags:
        - "M06: Notifications"

      responses:
        "200":
          description: "The notifications were marked as seen"
        "403":
          description: "You need to authenticate to use this endpoint"

  # ==================================================================

  /api/user/notification/{id}/seen:
    put:
      tags:
        - "M06: Notifications"
      summary: "R603: Mark notification as seen"
      description: "Mark notification as seen. Access: USR"
      operationId: "R603"
      parameters:
        - name: id
          in: path
          description: "Notification id"
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: "Notification marked as seen"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /api/user/notifications:
    get:
      tags:
        - "M06: Notifications"
      summary: "R604: Get notifications"
      description: "Get notifications. Access: USR"
      operationId: "R604"
      responses:
        "200":
          description: "Notifications"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /api/search/{query_string}/type/{type_search}/order/{type_order}/offset/{offset}:
    get:
      operationId: R701
      summary: "R701: Search API"
      description: "Searches for works and returns the results as JSON. Access: PUB"

      tags:
        - "M07: Search"

      parameters:
        - in: path
          name: query_string
          description: String to use for full-text search
          schema:
            type: string
          required: true

        - in: path
          name: type_search
          description: "Filter parameter can be: users, groups, posts or topics."
          schema:
            type: string
          required: true

        - in: path
          name: order
          description: "Order parameter can be: match, date, likes, comments."
          schema:
            type: integer
          required: true

        - in: path
          name: offset
          description: Offset of content to show.
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: Json Search Results
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object # It can be users, groups, posts or topics

  # ==================================================================

  /search/{query}:
    get:
      operationId: R702
      summary: "R702: Search"
      description: "Show Search hits page. Access: PUB"
      tags:
        - "M07: Search"

      parameters:
        - in: query
          name: query
          description: "Queried String"
          schema:
            type: string
          required: true

      responses:
        "302":
          description: "Ok. Show search page"

  # ==================================================================

  /about:
    get:
      operationId: R801
      summary: "R801: About Page"
      description: "Show Nexus About page. Access: PUB"
      tags:
        - "M08: User Administration and Static pages"

      responses:
        "302":
          description: "Ok. Show about page UI"
        "404":
          description: "Page not available"

  # ==================================================================

  /contacts:
    get:
      operationId: R802
      summary: "R802: Contacts Page"
      description: "Show Nexus Contact page. Access: PUB"
      tags:
        - "M08: User Administration and Static pages"

      responses:
        "302":
          description: "Ok. Show contacts page UI"
        "404":
          description: "Page not available"

  # ==================================================================
  /features:
    get:
      operationId: R803
      summary: "R803: Main Features Page"
      description: "Show Nexus Feature page. Access: PUB"
      tags:
        - "M08: User Administration and Static pages"

      responses:
        "302":
          description: "Ok. Show features page UI"
        "404":
          description: "Page not available"

  # ==================================================================

  /admin:
    get:
      operationId: R804
      summary: "R804: Admin Page"
      description: "Show administrator page. Access: ADM"
      tags:
        - "M08: User Administration and Static pages"

      responses:
        "302":
          description: "Ok. Show admin UI"
        "404":
          description: "Page not available"

  # ==================================================================

  /admin/statistics:
    get:
      operationId: R805
      summary: "R805: Admin statistics"
      description: "Show Admin statistics. Access: ADM"
      tags:
        - "M08: User Administration and Static pages"

      responses:
        "200":
          description: "Show admin statistics UI"
        "403":
          description: "Not authenticated or cannot access admin statistics"

  # ==================================================================

  /admin/report/{username}:
    get:
      operationId: R806
      summary: "R806: Get User Report"
      description: "Get User Report. Access: ADM"
      tags:
        - "M08: User Administration and Static pages"

      parameters:
        - in: path
          name: username
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Show User Report UI"
        "403":
          description: "Not authenticated or cannot access user report"

  # ==================================================================

  /api/report/reject_all/{userID}:
    put:
      operationId: "R807"
      summary: "R807: Reject all pending reports from a user"
      description: "Reject all pending reports from a user. Access: ADM"
      tags:
        - "M08: User Administration and Static pages"

      parameters:
        - in: path
          name: userID
          schema:
            type: integer
          required: true

      responses:
        "200":
          description: "Success"

  # ==================================================================

  /api/report:
    put:
      tags:
        - "M08: User Administration and Static pages"
      summary: "R808: Report user"
      description: "Report user. Access: ADM"
      operationId: "R808"
      requestBody:
        description: "Report"
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                decision:
                  type: integer
                id:
                  type: integer
      responses:
        "200":
          description: "Report sent"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

    post:
      operationId: "R809"
      summary: "R809: Create a report"
      description: "Create a report of a post or comment. Access: USR"
      tags:
        - "M08: User Administration and Static pages"

      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id_post:
                  type: integer
                id_comment:
                  type: integer
                description:
                  type: string

      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: object
                properties:
                  id_reporter:
                    type: integer
                  id_admin:
                    type: integer
                  report_date:
                    type: string
                  description:
                    type: string
                  decision:
                    type: string
                  id_post:
                    type: integer
                  id_comment:
                    type: integer

              example:
                - id_reporter: 1
                  id_admin: null
                  report_date: "2022-05-04 22:22:22"
                  description: "It's offensive"
                  decision: "Pendent"
                  id_post: 5
                  id_comment: null

  # ==================================================================

  /api/user/ban/{userID}/{time_option}:
    put:
      tags:
        - "M08: User Administration and Static pages"
      summary: "R810: Ban user"
      description: "Ban user. Access: ADM"
      operationId: "R810"
      parameters:
        - name: userID
          in: path
          description: "User ID"
          required: true
          schema:
            type: integer
        - name: time_option
          in: path
          description: "Time option"
          required: true
          schema:
            type: integer
            oneOf:
              - minimum: 0
                maximum: 8
      responses:
        "200":
          description: "User banned"
        "400":
          description: "Invalid time option"
        "403":
          description: "Forbidden"
        "419":
          description: "Not a valid CSRF token"

  # ==================================================================

  /api/admin/pendent_reports/{query_string}:
    get:
      operationId: "R811"
      summary: "R811: Get the pendent reports"
      description: "Get the pendent reports. Access: ADM"
      tags:
        - "M08: User Administration and Static pages"

      parameters:
        - in: path
          name: query_string
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    username:
                      type: string
                    photo:
                      type: string
                    ban_date:
                      type: string
                    decision_date:
                      type: string

        "403":
          description: "Forbidden"

  # ==================================================================

  /api/admin/past_reports/{query_string}:
    get:
      operationId: "R812"
      summary: "R812: Get the past reports"
      description: "Get the past reports. Access: ADM"
      tags:
        - "M08: User Administration and Static pages"

      parameters:
        - in: path
          name: query_string
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    username:
                      type: string
                    photo:
                      type: string
                    ban_date:
                      type: string
                    decision_date:
                      type: string

        "403":
          description: "Forbidden"

  # ==================================================================

  /api/user/friend/{id}:
    get:
      operationId: R813
      summary: "R813: User friends"
      description: "Saw the user:USR"
      tags:
        - "M08: User Administration and Static pages"
      parameters:
        - in: path
          name: id
          description: "User"
          schema:
            type: string
          required: true

      responses:
        "200":
          description: "Success show the user friends page"
        "403":
          description: "Forbidden access to resource"
        "404":
          description: "User not found"

  # ==================================================================
```

**Note:** Administrator can make all CRUD operations in any user profile content.

### 9. Implementation Details

#### 9.1. Libraries Used

In this Nexus Project we used many libraries, frameworks and services:

| Library                                             | Description                                                                                                | Link to Example |
|:--------------------------------------------------- |:---------------------------------------------------------------------------------------------------------- |:---------------: |
| [Bootstrap](https://getbootstrap.com/)              | Bootstrap was used to built the frontend of the entire Nexus Website.                                      | [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/resources/views/layouts/app.blade.php#L16)             |
| [Font Awesome](https://fontawesome.com/)            | Font Awesome was used for good and consistent icons across the entire Nexus Website                        | [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/resources/views/partials/sidebar/left_sidebar.blade.php#L10)            |
| [Carbon](https://carbon.nesbot.com/)                | Carbon was used for date/time formatting in posts, comments and messages                                   | [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/resources/views/partials/post_item.blade.php#L18)             |
| [Socialite](https://laravel.com/docs/9.x/socialite) | Socialite was used for Google Auth Sign in                                                                 |   [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/app/Http/Controllers/Auth/LoginController.php#L57)              |
| [Pusher](https://pusher.com/)                       | Pusher was used to create realtime notifications and serve as a presence channel for siggnaling videocalls |      [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/public/js/app.js#L4)           |
| [Mailtrap](https://mailtrap.io/)                    | Mailtrap alows for password recovery mail sending/receiving                                                |    [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/app/Http/Controllers/PasswordRecoverController.php#L57)    |
| [IntroJS](https://introjs.com/)                     | To create step-by-step guided tutorials to serve as a contextual help for our users                        |     [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/public/js/app.js#L333)    | 
| [WebRTC API](https://webrtc.org/)                   | For creating Peer-to-peer comunications to share audio and video                                           |       [Link](https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/blob/main/public/js/app.js#L120)    |

#### 9.2 User Stories

> This subsection should include all high and medium priority user stories, sorted by order of implementation. Implementation should be sequential according to the order identified below. 
>
> If there are new user stories, also include them in this table. 
> The owner of the user story should have the name in **bold**.
> This table should be updated when a user story is completed and another one started. 

A version of the board that was used during the development of the project can be found here:
> https://git.fe.up.pt/lbaw/lbaw2223/lbaw2261/-/boards


| **Identifier** | **Name**                        | **Module**                                 | **Priority** |  **Team Members**   | **State** |
|:--------------:|:------------------------------- |:------------------------------------------ |:------------:|:-------------------:|:---------:|
|     US101      | View Public Timeline            | M02: Feed                                  |     High     |      **João**       |   100%    |
|     US102      | View Public Profiles            | M01: Authentication and Individual Profile |     High     |      **David**      |   100%    |
|     US103      | Search for Public Profiles      | M07: Search                                |     High     |      **João**       |   100%    |
|     US104      | Exact Match Search              | M07: Search                                |     High     |      **João**       |   100%    |
|     US105      | Full-text Search                | M07: Search                                |     High     |      **João**       |   100%    |
|     US106      | About US                        | M08: User Administration and Static pages  |     High     |      **David**      |   100%    |
|     US107      | Main Features                   | M08: User Administration and Static pages  |     High     |      **David**      |   100%    |
|     US108      | Contacts                        | M08: User Administration and Static pages  |     High     |      **David**      |   100%    |
|     US109      | Search over Multiple Attributes | M07: Search                                |    Medium    |      **João**       |   100%    |
|     US110      | Search Filters                  | M07: Search                                |    Medium    |      **João**       |   100%    |
|     US111      | Search for Content              | M07: Search                                |    Medium    |      **João**       |   100%    |
|     US112      | Search by Topic                 | M07: Search                                |    Medium    |      **João**       |   100%    |
|     US113      | Order by Date                   | M07: Search                                |    Medium    |      **João**       |   100%    |
|     US201      | Login                           | M01: Authentication and Individual Profile |     High     |     **Ricardo**     |   100%    |
|     US202      | Register                        | M01: Authentication and Individual Profile |     High     |     **Ricardo**     |   100%    |
|     US203      | Recover Password                | M01: Authentication and Individual Profile |    Medium    |      **Marco**      |   100%    |
|     US301      | Logout                          | M01: Authentication and Individual Profile |     High     |     **Ricardo**     |   100%    |
|     US302      | View my profile                 | M01: Authentication and Individual Profile |     High     |      **David**      |   100%    |
|     US303      | Edit Profile                    | M01: Authentication and Individual Profile |     High     |      **Marco**, Ricardo      |   100%    |
|     US304      | View Personalized Timeline      | M02: Feed                                  |     High     |      **João**       |   100%    |
|     US305      | View Friends Profiles/Feed      | M02: Feed                                  |     High     |      **Marco**      |   100%    |
|     US306      | Make a Post                     | M02: Feed                                  |     High     |     **Ricardo**     |   100%    |
|     US307      | Edit Post                       | M02: Feed                                  |     High     | **Marco**, Ricardo  |   100%    |
|     US308      | Delete Post                     | M02: Feed                                  |     High     |     **Ricardo**     |   100%    |
|     US309      | View Personal notifications     | M06: Notifications                         |    Medium    |     **Ricardo**     |   100%    |
|     US310      | Manage friend Requests          | M04: Requests                              |    Medium    |     **Ricardo**     |   100%    |
|     US311      | Manage Friends                  | M04: Requests                              |    Medium    | **Ricardo**, Marco  |   100%    |
|     US312      | Make Comments                   | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US313      | React to Post                   | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US314      | React to Comment                | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US315      | Create groups                   | M03: Groups                                |    Medium    | **Marco**, Ricardo  |   100%    |
|     US316      | Request to Join  Group          | M03: Groups                                |    Medium    |     **Ricardo**     |   100%    |
|     US317      | Delete account                  | M01: Authentication and Individual Profile |    Medium    |     **Ricardo**     |   100%    |
|     US318      | See Reactions                   | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US319      | Make Reports                    | M08: User Administration and Static pages  |    Medium    |      **Marco**      |   100%    |
|     US320      | Likes Notification              | M06: Notifications                         |    Medium    |     **Ricardo**     |   100%    |
|     US321      | Comments Notification           | M06: Notifications                         |    Medium    |     **Ricardo**     |   100%    |
|     US322      | Friend Requests Notification    | M06: Notifications                         |    Medium    |     **Ricardo**     |   100%    |
|     US323      | Edit Comment                    | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US324      | Delete Comment                  | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US325      | Reply to Comments               | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US326      | Timeline Filter                 | M02: Feed                                  |    Medium    |      **João**       |   100%    |
|     US327      | Post Topics                     | M02: Feed                                  |    Medium    |      **Marco**      |   100%    |
|     US328      | Personalized Recommendations    | M02: Feed                                  |    Medium    |     **Ricardo**             |   100%      |
|     US329      | Direct Messages                 | M05: Messages                              |    Medium    |    **Ricardo**     |   100%    |
|     US401      | Administer User Accounts        | M08: User Administration and Static pages  |     High     | **Marco**, Ricardo |   100%    |
|     US402      | Administrator Accounts          | M08: User Administration and Static pages  |    Medium    |      **David**      |   100%    |
|     US403      | Remove  User Posts              | M08: User Administration and Static pages  |    Medium    |      **Marco**      |   100%    |
|     US404      | (un)Ban User Accounts           | M08: User Administration and Static pages  |    Medium    |      **Marco**      |   100%    |
|     US405      | Receive Reports                 | M08: User Administration and Static pages  |    Medium    |  **Marco**, João   |   100%    |
|     US501      | Edit Group Information          | M03: Groups                                |     High     | **Marco**, Ricardo  |   100%    |
|     US502      | Remove Member                   | M03: Groups                                |    Medium    |      **Marco**      |   100%    |
|     US503      | Manage Join Requests            | M03: Groups                                |    Medium    |     **Ricardo**     |   100%    |
|     US504      | Transfer Ownership              | M03: Groups                                |    Medium    |      **David**      |   100%    |
|     US505      | Remove Post From Group          | M03: Groups                                |    Medium    |      **Marco**      |   100%    |
|     US601      | View Group’s Members            | M03: Groups                                |     High     |      **Marco**      |   100%    |
|     US602      | Post on Group                   | M03: Groups                                |     High     |      **Marco**, Ricardo      |   100%    |
|     US603      | Leave Group                     | M03: Groups                                |     High     |      **Marco**      |   100%    |

*Table 1: Nexus User Stories (High and Medium priority)*

| **Identifier** | **Name**                     | **Module**                                 | **Priority** | **Team Members** | **State** |
|:--------------:|:---------------------------- |:------------------------------------------ |:------------:|:----------------:|:---------:|
|     US114      | Ordering of Results          | M07: Search                                |     Low      |     **João**     |   100%    |
|     US337      | Video Call                   | M05: Messages                              |     Low      |   **Ricardo**    |   100%    |
|     US406      | Posts/Comments Most Reported | M08: User Administration and Static pages  |     Low      | **Marco**, João  |   100%    |
|     US506      | Change Group Visibility      | M03: Groups                                |     Low      |    **Marco**     |   100%    |
|     US701      | Register using API           | M01: Authentication and Individual Profile |     Low      |    **Marco**     |   100%    |
|     US702      | Login using API              | M01: Authentication and Individual Profile |     Low      |    **Marco**     |   100%    |
|     US338      |          Online Status      |    M05: Messages    |     Low      | **Ricardo** | 100% |
|     US330      | Account Verification         | M01: Authentication and Individual Profile |     Low      |       N/A        |    0%     |
|     US331      | Birthday Notifications       | M06-Notifications                          |     Low      |       N/A        |    0%     |
|     US332      | Delete Messages              | M05: Messages                              |     Low      |       N/A        |    0%     |
|     US333      | Polls                        | M02: Feed                                  |     Low      |       N/A        |    0%     |
|     US334      | Manage Post Visibility       | M02: Feed                                  |     Low      |       N/A        |    0%     |
|     US335      | Tag friends                  | M02: Feed                                  |     Low      |       N/A        |    0%     |
|     US336      | Block User                   | M08: User Administration and Static pages  |     Low      |       N/A        |    0%     |
|     US507      | Group Announcements          | M03: Groups                                |     Low      |       N/A        |    0%     |


*Table 2: Nexus User Stories (Low priority)*

---

## A10: Presentation

### 1. Product presentation

**Nexus** is a revolutionary new social network that connects people from all walks of life. With a sleek and intuitive interface, users can easily create profiles, share their interests and passions by making posts, comments and likes and by creating or joining pre-existing thematic groups to connect with friends and family. This communication is further facilitated by Nexus built-in chat with possibility to make video calls so you can be closer to the ones you love.

URL to the final product:
> https://lbaw2261.lbaw.fe.up.pt

### 2. Video presentation

To showcase our product's main features, we created a short 2 minute MP4 video that was uploaded to Moodle.

The presentation video can also be found [here](TODO.COM)


## Revision history

Changes made during the first submission:

1. Added A9
2. Added A10
5. PA Revision

GROUP2261, 01/01/2023
 
- David Ferreira, up202006302@g.uporto.pt
- João Alves, up202007614@g.uporto.pt
- Marco André, up202004891@g.uporto.pt (Editor)
- Ricardo Matos, up202007962@g.uporto.pt