---
# System prepended metadata

title: Original App Design Project - README Template

---

Original App Design Project - README Template
===

# Staple

## Table of Contents
1. [Overview](#Overview)
1. [Product Spec](#Product-Spec)
1. [Wireframes](#Wireframes)
2. [Schema](#Schema)

## Overview
### Description
Allows those with a passion for cooking to connect through a dedicated social media app. Users will be able to post new recipes, interact with other users' recipes, and search for other users/existing recipes based on their preferences.

### App Evaluation

- **Category:** Social networking
- **Mobile:** Designed strictly for mobile usage, allowing users to use their camera to take recipe photos in addition to viewing and interacting with recipe posts on the go.
- **Story:** Connects users with trending recipes and food inspiration. Users will be able to interact through the comments and voting system, which encourage a sense of community.
- **Market:** Anyone interested in food and cooking can use this app. Users are able to search for specific interests based on cuisine and diet.
- **Habit:** Users will open and use this app whenever they want to find or share recipe ideas and instructions. Users both consume (view recipes) and create (post recipes).
- **Scope:** Staple has a focus on posting and viewing recipes. The main feed acts as a trending page which allows users to interact with each other by reacting to recipe titles and photos.


## Product Spec

### 1. User Stories (Required and Optional)

**Required Must-have Stories**

* User sees app icon in home screen and styled launch screen
* User can sign up to create a new account (username, password, email, phone number)
* User can log in
* User can log out
* User stays logged in across restarts
* User can upload a photo, add an ingredient list, and recipe instructions
* User can either submit their post (through Parse) or cancel their submission
* User can view popular recipes on home page
* Users can add and view comments on a recipe
* Users can upvote/downvote a recipe
* User can tap a recipe photo to view a detailed recipe page
* User can view detailed information on a recipe (title, ingredient list, instructions)
* User can view another user's username, profile picture, and number of posts
* User can add a profile picture
* User can search for recipes by keyword or user 
* User can view detailed recipes from the Edamam API
* User can edit their profile picture
* User can change their username and password
* User can delete their account

**Optional Nice-to-have Stories**
    
* User can save posts made by other users and access them from inside the app
* User can edit an existing recipe
* User can pull to refresh
* User can load past posts infinitely
* Configure autolayout to standardize view on devices
* User can invite their contacts to join
* User can upload video for recipe instructions
* User can select their cuisine preferences when making an account
* User can set the cuisine type when uploading a post
* User can view recipes automatically configured to their set preferences during account creation

### 2. Screen Archetypes

* Login Screen
   * User can enter their username and password to log in
* Registration Screen
   * User can sign up to create a new account (username, password, email, and phone number)
* Stream
    * User can view the past recipes (photos and titles) and the author's profile picture and name
    * User can upvote/downvote a recipe
    * Users can view comments on a recipe
    * Users can add a comment
    * User can tap a recipe photo to view a detailed recipe page
    * User can tap a profile picture to be brought to the desired user's profile page
    * User can log out
* Creation
    * User can upload a photo, add a recipe title, add an ingredient list/recipe
* Search
    * User can search for recipes or users in a text bar
    * User can view existing recipes from the Edamam API
* Other User Profile Screen
    * User can view another user's username, profile picture, and number of posts
    * User can view photos of recipes
* Personal Profile Screen
    * User can view their username, profile picture, and number of posts
    * User can view photos of recipes
* Detailed Recipe Screen
    * User can view a title, ingredient list, and instructions for a specific recipe
    * User can go back to the previous screen
* User Preferences Screen
    * User can change their profile picture, username, and password
    * User can log out
    * User can delete their account

### 3. Navigation

**Tab Navigation** (Tab to Screen)

* Home Screen
* Create a Recipe
* Search User/Recipe
* Personal Profile Screen

**Flow Navigation** (Screen to Screen)

* Login Screen
    => Registration Screen
    => Stream
* Registration Screen
    => Stream
    => Login Screen
* Stream
    => Detailed Recipe Screen
    => Other User Profile Screen
* Creation Screen
    => Stream
* Search Screen
    => Other User Profile Screen
    => Detailed Recipe Screen
* Other User Profile Screen
    => Detailed Recipe Screen
* Personal Profile Screen
    => User Preferences Screen
    => Detailed Recipe Screen
* Detailed Recipe Screen
    => Back to previous screen (Stream, Search Screen, User Profile Screen, Other User Profile Screen)
* User Preferences Screen
    => Login Screen

## Wireframe
![](https://i.imgur.com/mkxT16x.jpg)

## Schema 

### Models
        
#### User:
| Property      | Type     | Description                                   |
| ------------- | -------- | --------------------------------------------- |
| username      | String*  | Username                                      |
| password      | String*  | Password                                      |
| email         | String   | User email                                    |
| phoneNumber   | String   | User phone number                             |
| profileImage  | File     | User profile picture                          |
| numberOfPosts | Number   | Total number of posts by a user               |
| createdAt     | DateTime | Date when user is created (default field)     |
| updatedAt     | DateTime | Date when user is last updated (default field)|
    
#### Stream Post (Main Feed):
| Property      | Type           | Description                                    |
| ------------- | -------------  | ---------------------------------------------- |
| objectID      | String         | Unique id for the user post (default field)    |
| author        | Pointer (User) | Image author                                   |
| recipeName    | String         | Recipe title                                   |
| ingredientList| String         | Recipe ingredients                             |                 
| recipeSteps   | String         | Recipe procedure                               |  
| profileImage  | Pointer (User) | Image of the user profile                      |  
| recipeImage   | File           | Recipe image that a user posts                 |
| commentsCount | Number         | Number of comments on a post                   |
| comments      | Pointer (Array)| Lists of comments on a post                    |
| upvoteCount   | Number         | Number of upvotes on a post                    |
| downvoteCount | Number         | Number of downvotes on a post                  |
| createdAt     | DateTime       | Date when post is created (default field)      |
| updatedAt     | DateTime       | Date when post is last updated (default field) |
    
#### Stream Comments (Main Feed):
| Property  | Type           | Description                                      |
| --------- | -------------- | ------------------------------------------------ |
| objectID  | String         | Unique id for the comment                        |
| post      | Pointer (Post) | Associated post                                  |
| text      | String         | Comment text                                     |
| author    | Pointer (User) | Comment author                                   |
| createdAt | DateTime       | Date when comment is created (default field)     |
| updatedAt | DateTime       | Date when comment is last updated (default field)|
    
### Networking    
* Login Screen:
    * (Read/GET) User logs into app
      * User can also create new profile
    
* Registration Screen:
    * (Create/POST) User signs up
    
* Stream:     
    * (Read/Get) Read recipe name
    * (Read/ GET) Read username 
    * (Read/GET) Get a picture of the recipe
    * (Create/POST) Create an upvote on a post
    * (Delete) Delete existing upvote
    * (Create/POST) Create an downvote on a post
    * (Delete) Delete existing downvote
    * (Create/POST) Create a comment on a post
    * (Delete) Delete existing comment
    
    
* Creation:
    * (Create/POST) Create the name of the recipe 
    * (Create/POST) Create ingredients' list of the recipe
    * (Create/POST) Create recipe instructions
    * (Create/POST) add a picture of the recipe
    * (Create/POST) Submit the post
    * (Delete) cancel the post

* Search:
    * (Read/GET) Search for the recipe
    * (Read/GET) Search for the user
    

* Other User Profile Screen: 
    * (Read/GET) Name of the user
    * (Read/GET) Number of user's post
    * (Read/GET) User's picture
    * (Read/GET) Access detailed recipe by clicking picture objects
    
* Profile Screen:
    * (Read/GET) Query logged in user object
    * (Read/GET) Number of user's post
    * (Read/GET) User's picture
    * (Read/GET) Access detailed recipe by clicking picture objects
    
* Detailed Recipe Screen:
    * (Read/GET) Name of the recipe
    * (Read/GET) Ingredients of the recipe
    * (Read/GET) Recipe instructions
   
* Preferences Screen: 
    * (Update/PUT) Update user profile image
    * (Update/PUT) Update Username
    * (Update/PUT) Update Password
    * (Delete/DELETE) Delete user profile
    * (Create/POST) Lets a user log out

- Basic snippets for Parse network requests:
```
// (Read/GET) Query all posts where user is author
let query = PFQuery(className:"Post")
query.whereKey("author", equalTo: currentUser)
query.order(byDescending: "createdAt")
query.findObjectsInBackground { (posts: [PFObject]?, error: Error?) in
   if let error = error {
      print(error.localizedDescription)
   } else if let posts = posts {
      print("Successfully retrieved \(posts.count) posts.")
      // TODO: Do something with posts...
   }
}
```

```
// (Read/GET) Create a post
PFObject *post = [PFObject objectWithClassName:@"post"];
post[@"title"] = @"Green Eggs & Ham";
post[@"author"] = @"John Doe";
post[@"instructions"] = @"the most enlightening of instructions"
post[@"ingredients"] = @"the lovliest of ingredients"
[post saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
  if (succeeded) {
    // The object has been saved.
  } else {
    // There was a problem, check error.description
  }
}];
```

```
// (Read/GET)
// Fetch posts for a user's home feed
PFQuery *query = [PFQuery queryWithClassName:@"post"];
[query whereKey:@"author" equalTo:@"John Doe"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
  if (!error) {
    // The find succeeded.
    NSLog(@"Successfully retrieved %d scores.", objects.count);
    // Do something with the found objects
    for (PFObject *object in objects) {
        NSLog(@"%@", object.objectId);
    }
  } else {
    // Log details of the failure
    NSLog(@"Error: %@ %@", error, [error userInfo]);
  }
}];
```

```
// (Delete/DELETE)
// Delete account
[PFObject deleteAllInBackground:objectArray block:^(BOOL succeeded, NSError * _Nullable error) {
    if (succeeded) {
        // The array of objects was successfully deleted.
    } else {
        // There was an error. Check the errors localizedDescription.
    }
}];
```

```
// (Update/Put)
// Changing user's profile picture
PFQuery *query = [PFQuery queryWithClassName:@"user"];

// Retrieve the object by id
[query getObjectInBackgroundWithId:@"John Doe"
                             block:^(PFObject *user, NSError *error) {
    // Now let's update it with some new data. In this case, profile picture
    // will get sent to the cloud. Others haven't changed
    user[@"username"] = @"xxDinoxx";
    user[@"password"] = @"defSecure";
    // keep going
    [author saveInBackground];
}];
```