NourishMap

Food market locator for the City of Orlando and recipe book encouraging healthy eating

Categories: Project ManagementLeadershipFrontendBackendDevOpsNonprofitTechnical Writing

Tools: FigmaAstroVitestCypressGitHub ActionsNetlify

Team: 
  • Manuel OsorioTechnical Project ManagerLead Software Engineer
  • Jean FernandezCo-lead Software Engineer
  • Allison LejuneData Security & Compliance Engineer
  • Andres JimmyQA Engineer
  • Axel DiazFront End Developer
  • Calvin ChaparroSoftware Engineer
  • Ethan PlazaSoftware Engineer
  • Gabriel HernandezQA Engineer
  • John CollinsBrand Identity Designer
  • Raymond YnoaAPI Integration Engineer
  • Zohaib AhmadzaiSoftware Engineer

Client Brief

What: A web app designed to help lower-income families access fresh food in food deserts.

Where: Downtown and central Orlando.

Why: To ease access to nutritious food for underserved communities.

Long-Term Goals: Improve access to fresh food and track available pantry resources.

Relation to Project: NourishMap aligns with the goal of empowering food-insecure communities by providing a direct tool for discovering food resources.

Project Overview

NourishMap is a web application that helps users find food markets and pantries in the City of Orlando. The app also includes a recipe book with healthy meal ideas. My team consisted of 9 other developers with varying skill sets allowing my co-lead (Jean) and I to assign tasks accordingly. The goal of the project was to provide a valuable resource for the community and promote healthy eating habits.

My Role

As the Technical Project Manager and Lead Software Engineer, I managed the project lifecycle, led the development team, and ensured the project met deadlines and stayed within budget. My role, also included designing the project architecture, writing code, and testing to ensure a high-quality product. I regularly met with stakeholders to gather requirements, update them on progress, and addressing concerns as they came up. I met with Jean each week to plan out the weekly team meetings, and to discuss upcoming features. One of the most rewarding aspects was working one-on-one with my team members to help them grow as developers. My focus throughout was to support the team with the resources needed to complete the project successfully.

Challenges

Throughout the development of the project we faced several challenges, one of the biggest being not having a budget to work with on the project. We instead had to rely on free tools and resources to build the web app. Through our initial planning phase we performed a requirements' analysis. The three requirements that kept coming up was the need of a some type of interactive map, ability to find food products, and provide recipes that promote healthy eating while meeting dietary, budget restrictions.

`

Branding

The branding was a more recent addition to the project. Throughout the duration of working on NourishMap we didn't have a brand identity or even a name leaving it with the placeholder of "Food Market App". I eventually came up with the name as a play on the word "Nourishment". I brought in John Collins to help with the branding and he came up with the logo and color scheme. The initial idea was to have the logo be a map marker in the shape of a carrort along side a map. John was able to take that idea and when creating the wordmark logo while incorporating the a stylize carrot that functions as a map marker while being the "i" in NourishMap.

Logo Design

Colors

Black

#1F271B
rgb(31,39,27)

White

#FBFEFB
rgb(251,254,251)

Silver

#C0C0C0
rgb(192,192,192)

Gray

#5D595F
rgb(93,89,95)

Orange

#F68837
rgb(246,136,55)

Green

#80C144
rgb(128,193,68)

Project Architecture

NourishMap was developed in monorepo-esque fashion but reality this is possible because of the underline technology that we ended up using. The use of astro allowed for us to mix SSR (Server Side Rendering) & SSG (Static Site Generation). With SSG enable were also able to set up our api end-points and database systems.

Frontend Systems

Our frontend pulls data from our internal API and interfaces with a third-party API to display the locations of food markets and pantries on a map. We kept the design simple and user-friendly to make it easy for users to find the information they need. While Astro is a static site generator they also have a server side rendering feature that made it easy to create a static site has dynamically populated components.

Backend Systems

Astro allowed us to build a simple yet extensive backend system. One of features I implemented was a user authentication that allowed for the creation of new user accounts and session management. With in that system I also created a role based permission system so the primary stakeholders could manage the site without having to worry about the technical details of the site. I worked closely with members of the team to implement some of the other features such the contact and location APIs.

Database Systems

For our relational database we used the AstroDB library which allowed us to build and deploy a libSQL database. During the period of our project we used their now deprecated platform, Astro Studio, which I recently migrated to Turso. We created and use the following schema:

classDiagram
    class Role {
        +id: text
        +name: text
        +canManageUsers: integer
        +canManageRoles: integer
        +canManageMarkets: integer
        +canViewContactFormLogs: integer
        +canManageProducts: integer
    }

    class User {
        +id: text
        +name: text
        +email: text
        -password: text
        +verified: integer
        +role: text
    }

    class EmailVerification {
        +id: text
        +userId: text
        +expiresAt: integer
        -token: text
    }

    class Market {
        +id: text
        +name: text
        +address: text
        +lat: integer
        +long: integer
    }

    class Products {
        +id: text
        +name: text
        +price: integer
        +description: text
        +image: text
        +marketId: text
    }

    class ContactFormLog {
        +id: text
        +body: text
        +created: text
    }

    class Session {
        +id: text
        +userId: text
        +expiresAt: integer
    }

    class Recipes {
        +id: text
        +query: text
        +data: text
    }

    %% Relationships
    User --> Role : "role"
    EmailVerification --> User : "userId"
    Products --> Market : "marketId"
    Session --> User : "userId"

Testing

We used Vitest and Cypress for our test suites. This allowed for use to quickly create unit tests and integrate end-to-end testing. We adapted a test-driven development (TDD) methodology was tests were fully setup to prevent introducing new bugs to the production site. Since we were using AstroDB (and drizzle), a local database (found in .astro/content.db) is regenerated each time the server is run. This allowed us to create a seed file that would populate the database with needed data, and the cypress (e2e) test would run against that data. Similarly, we used vitest to mock api controllers and front end components.



Locations API Handlers:

flowchart LR
  A[Session Validation] -->|Valid Session| B[Check Permissions]
  A -->|No Session| C[Return 401: Unauthorized]
  B -->|Permission Granted| D[Proceed to Action]
  B -->|Permission Denied| E[Return 401: Unauthorized]

Products API Handlers:

sequenceDiagram
    participant User
    participant API_Handler
    participant Database

    User->>API_Handler: GET /products
    alt Products found
        API_Handler->>Database: SELECT * FROM Products
        Database->>API_Handler: [products data]
        API_Handler->>User: 200 OK, [products data]
    else No products found
        API_Handler->>User: 404 Not Found, {message: "No products found"}
    end

    User->>API_Handler: POST /products (create product)
    alt Product created successfully
        API_Handler->>Permission: hasPermission(canManageProducts)
        Permission->>API_Handler: true
        API_Handler->>Database: INSERT INTO Products (...) VALUES (...)
        Database->>API_Handler: success
        API_Handler->>User: 200 OK, {message: "Product created"}
    else Missing required fields
        API_Handler->>User: 400 Bad Request, {error: "Missing required fields", fields: {...}}
    end

    User->>API_Handler: PUT /products/:id (update product)
    alt Product updated successfully
        API_Handler->>Permission: hasPermission(canManageProducts)
        Permission->>API_Handler: true
        API_Handler->>Database: UPDATE Products SET (...) WHERE id = :id
        Database->>API_Handler: success
        API_Handler->>User: 200 OK, {message: "Product updated"}
    else Missing required fields
        API_Handler->>User: 400 Bad Request, {error: "Missing required fields", fields: {...}}
    end

    User->>API_Handler: DELETE /products/:id
    alt Product deleted successfully
        API_Handler->>Database: DELETE FROM Products WHERE id = :id
        Database->>API_Handler: success
        API_Handler->>User: 200 OK, {message: "Product deleted"}
    else Missing required fields
        API_Handler->>User: 400 Bad Request, {error: "Missing required fields"}
    end

Contact Us Page Test:

sequenceDiagram
    participant User
    participant Browser
    participant Server

    User->>Browser: Opens Contact Us page
    Browser->>Server: Sends GET request to /contact
    Server-->>Browser: Sends HTML form
    Browser->>User: Displays form

    User->>Browser: Fills out form and clicks submit
    Browser->>Server: Sends POST request with form data
    Server->>Database: Stores form data
    alt Success
        Server-->>Browser: Sends success message
        Browser->>User: Displays success message
    else Failure
        Server-->>Browser: Sends error message
        Browser->>User: Displays error message
    end

Authentication Tests:

sequenceDiagram
  participant User
  participant API_Handler
  participant Database

  User->>API_Handler: POST /auth/signup
  API_Handler->>Database: INSERT INTO Users (...) VALUES (...)
  alt Signup successful
      Database->>API_Handler: success
      API_Handler->>User: 200 OK (redirect to login page)
  else Signup failed (e.g., email already exists)
      Database->>API_Handler: error
      API_Handler->>User: 400 Bad Request, {error: "Signup failed"}
  end

Sign In

sequenceDiagram
  participant User
  participant API_Handler
  participant Database

  User->>API_Handler: POST /auth/signin (email, password)
  API_Handler->>Database: SELECT * FROM Users WHERE email = :email
  alt User found and password matches
      Database->>API_Handler: [user data]
      API_Handler->>User: 200 OK (redirect to homepage or dashboard)
  else User not found or password incorrect
      Database->>API_Handler: null
      API_Handler->>User: 401 Unauthorized (redirect to login page with error message)
  end

Deployment

The deployment process for the most part straight forward. We used Netlify and Turso (recently migrated from now deprecated Astro Studio). Whenever a pull request is made netlify would build a preview and a GitHub action that was set up for AstroDB would check if the database migrations introduced (if any) were possible. Assuming all integration were successful and the PR was approved by at least one team member and lead engineer, it can be merged to the master branch and would trigger a production deployment.

Lessons Learned

I jumped at the opportunity to be able to lead a team. I've had prior leadership experience leading several teams at a time for small scale project where I had the role of "Art Director". I also spend sometime as a student leader for a graphic design centered club. With this project I was able to bring in all my past leadership and freelance experience together to facilitate the success of the project.

During the duration of this project there was quite a bit to learning about leading a software project. One of the most important things was the importance of delegating. During the last week of the design phase, I set up all the tools we're going to be using and setup some basic user authentication. Once the team was fully onboarded with all our tools, I was able to start assigning tasks using GitHub issues and project boards. The tasks were usually broken down and the team members were split into pairs to work on them allowing them to work together and learn from each other. This also made it easier for me to having smaller standups with the team to see how they were progressing and if they needed any help, and gave me more time to focus on the project as a whole.

Results

While we were unable to complete all the goals for the project we were able to lay the groundwork for future capstone students that would pick up the project were my team left off. At the end we created an extensive documentation that served as the project handoff and something that the stakeholders can reference when approving any requirements that is within budget.

Next Steps

NourishMap has a lot of the underlining backend APIs setup that don't yet directly interface with the frontend. The main focus for continuing this project would be to design and implement the UI that would interact with those endpoints. Some of those end points include:

  • An admin panel
    • That would allow user's with the proper roles to add, update, or delete farmers markets or other fresh food vendors.
    • Mail system that allows permissible roles to view and reply to requests made via the contact form.
    • Add curated recipes to the system.
  • Bring a greater focus on the sites mission of promoting healthy eating.
  • Create an onboarding process for new users were they can list some vital information such as food allergies and other dietary restriction.

Acknowledgements

I would like to thank my team for their hard work and dedication to the project. I would also like to thank Lauren and Mike from the City of Orlando's Sustainability/Future-ready City Initiative for your support throughout the project, making this possible for CTSD Capstone students at Valencia College. And Professor Walauskis, thank you for the encouragement not just throughout my time in the Summer Capstone Project but also throughout my time in the CTSD Program. You were a major factor in reigniting my joy for learning and coding.

View Other Projects

Table Of Contents