
Build a single, feature-rich feedback collection app for startup owners and product managers, enabling bulk email outreach, billing, and authentication to capture user insights.
Follow the end-to-end flow of a feedback app, from Google OAuth sign-in and credit purchases to creating campaigns, sending surveys, and compiling a feedback report.
Study a full-stack tech stack for building campaigns and surveys with Google authentication, OAuth, Stripe payments, Express backend, Passport JS, React, Redux, Redux Form, email provider, and MongoDB.
Explore front-end mockups for a full-stack app, including a landing page with Google OAuth login, campaign dashboards with yes/no stats, and a two-screen flow to create and review surveys.
Explore the application architecture that connects a React frontend with an Express API and a MongoDB database, using HTTP/JSON data flow to power a fullstack app.
Discover how Node.js listens on a port and delegates to Express, a library that makes route handlers for HTTP requests easier, by building a new project.
Generate an express app by creating index.js, requiring express, creating an app, adding a route with app.get, sending a response, and listening on port 5000 to test on localhost.
Explore the core express concepts behind a route handler, including app.get for http methods, the route path, req and res objects, res.send with json, and app.listen on port 5000.
Deploy your express app by following the deployment checklist: set dynamic port binding for Heroku, declare node and npm versions, define a start script, and ignore node_modules.
Master the Heroku deployment workflow—from the pre-deployment checklist to first-time and redeployments—by creating an account, committing code with git, and installing the Heroku CLI.
Log into the Heroku CLI, create an app, add a git remote, and push to deploy your Node app to Heroku for automatic build and hosting.
Learn how to perform follow-up deployments on Heroku after code changes. Save files, git add, commit, and push to Heroku master, then verify with logs and open the app.
Implement Google OAuth sign-in on the server side, exploring the complex OAuth flow with Express and MongoDB. Prepare for deployment on Heroku and distinguish OAuth from email-password authentication.
Explore the OAuth flow for authenticating users in our web app, including redirects between the client, the server, and Google, and exchanging a code for user details.
Learn how Passport JS automates the OAuth flow in an Express app, understand the core Passport vs. strategies distinction, and wire up Google sign-in while reviewing the documentation.
Install passport and the passport google oauth 20 strategy, wire them into your express app with index.js, and configure passport.use(new GoogleStrategy(...)) for Google authentication.
Wire up passport and the Google strategy in index.js with a client ID and client secret from Google’s OAuth API. Prepare for the OAuth flow and user permission.
Discover secure management of Google oauth credentials by moving client id and client secret to a config file, gitignore it, and integrate with the passport google strategy.
Configure google oauth by storing google client id and secret in keys.js, import them into index.js, and pass them to the google strategy with a callback url of /auth/google/callback.
Test the Google OAuth flow by wiring a /auth/google route to passport's Google strategy with profile and email scopes, then run the server and resolve redirect uri mismatch errors.
Explore how OAuth redirect URI mismatch occurs in a Google OAuth flow. Fix it by updating authorized redirect URIs in the Google Developer Console to match localhost:5000/auth/google/callback.
Explore how Google OAuth redirects and the /auth/google/callback route exchange a code for a user profile using Passport's Google strategy, validating the OAuth flow and access token handling.
Shows how Google OAuth returns an access token, refresh token, and user profile, and how the callback uses them to create a user, completing phase one.
Install nodemon and add a dev script in package.json to run nodemon index.js, enabling automatic server restarts on code changes and simplifying development for future developers.
Refactor an express app by moving passport config into a services file and extracting routes into a routes folder. Expose an exported function to attach auth routes to the app.
Explore how cookie based authentication solves stateless HTTP by issuing tokens via Google OAuth and storing them as cookies managed by the browser.
Learn how to sign in users with OAuth using a stable Google ID to identify returning users. Compare this to email/password authentication and manage user records with cookies and MongoDB.
Explore the basics of MongoDB and Mongoose, learn how collections and records store json-like data, and understand model classes and instances for interacting with a schemaless database.
Connect an express app to a remotely hosted MongoDB, compare local vs remote setups, and prepare for deployment to Heroku.
Install and configure mongoose, connect to the provisioned MongoDB using a secure URI stored in config keys, then run npm run dev and handle deprecation warnings.
Take a break to align on using mongoose with the Express API for authentication, creating a users collection and a model to store Google IDs and link surveys or posts.
Learn to build a Mongoose model class for a users collection by defining a schema with Google ID, using destructuring, and loading the model on app startup via index.js.
Create a new user record by leveraging the Mongoose user model during Google OAuth, using profile.id as the Google ID, and persisting with save; ensure the model loads before use.
Learn to prevent duplicate users by querying the users collection with Mongoose findOne on Google ID, using promises, and conditionally creating or skipping a new user after Google OAuth.
Explore how passport callbacks handle Google authentication via the OAuth process by querying or creating a Mongo user with Mongoose, using promises and the done callback to complete authentication.
Encode users by implementing passport serializeUser and deserializeUser to issue a cookie with a Mongo user id after Google OAuth, then restore the user from that cookie on subsequent requests.
Deserialize user converts the cookie's user id back into a Mongoose user, using passport deserializeUser and a done callback.
Enable cookie-based authentication in the node with React fullstack app using cookie-session and Passport in Express. Configure a 30-day max age and encryption keys.
Learn how cookies and Passport manage authentication after the OAuth flow, exposing req.user for each request and testing with a current user API route.
Add a logout route that calls the passport-provided log out function to clear the user cookie, then verify the current user is undefined after signing out.
Explore how Express middleware via app.use handles requests, how cookie session stores data in the cookie for passport authentication, and the differences with express session.
Separate development and production keys to protect data and enable safe testing. Load credentials via a Keystart file, with MongoDB and Google API keys on Heroku and dev keys locally.
Create a production Mongo database and a separate production Google API project to isolate data and credentials, then configure production credentials, including an OAuth client ID and redirect URI.
Configure production google api credentials with the correct authorized JavaScript origin and redirect uri for your Heroku domain, and route keys by production or development using node_env.
Establish a version control scheme that exports development or production keys via dev.js and prod.js, uses Heroku environment variables, and updates gitignore to protect dev keys.
Configure production environment variables on Heroku using config vars, add Google client ID and secret, cookie key, and MongoDB URI, then deploy and test OAuth.
Debug oauth redirect issues by adjusting the google strategy to trust proxies and enforce https callback URLs, ensuring the redirect_uri matches production and development environments.
Learn why the React front end runs on its own development server using Create React App, with localhost:3000, and how it bundles into bundle.js beside Express.
Learn to run the client and the server together using concurrently, with dual package.json files and npm scripts, to launch both the front end and back end from one command.
Explore how a React front end and an Express back end work together, fix a routing stumbling block with a proxy config, and enable Google OAuth through /auth/google.
Explore using the Create React App proxy to forward dev requests from localhost:3000 to the Express backend, enabling relative links; in production CRA disappears and Express serves the built assets.
Examine why this two-server architecture uses a React dev proxy to an Express API, leverages cookies for authentication, and routes the OAuth flow through development and production contexts.
Explore async/await in ES 2017 to simplify promise-based fetch calls, refactor asynchronous code with awaits and arrow functions, and preview Babel transpilation.
Refactor the passport.js Google strategy callback to async/await, replacing promise chains with await for finding existing users and saving new ones, and verify Node supports async/await.
Shift to a client side setup with a fully featured React, Redux, and React Router front end, implementing client authentication, routing for root and surveys pages, and a landing page.
Learn to set up a React front end with Redux and React Router, bootstrap index.js and app.js, install client dependencies, and render the root App component to the DOM.
Create and export a root App component, render it with ReactDOM.render into the index root, and organize code in a components folder using import syntax for Redux and React Router.
Troubleshoot npm errors when running the dev script by deleting client/package-lock.json, running npm install, and rechecking the server and client status after installation. Ignore minor version warnings during install.
Learn to wire Redux into a React app by creating a store, using a provider, and connecting reducers like auth and surveys list to manage state.
Create the auth reducer and import it into reducers index.js to replace the dummy reducer. Plan two reducers: auth reducer for login status and a surveys reducer to list surveys.
Wire the auth reducer into a reducers index with combineReducers, export the combined reducers, and pass them to createStore, then test and troubleshoot common import and export errors.
Explore why auth matters: how the auth reducer marks login state, how header and routes (dashboard, new survey) adapt based on whether a user is logged in, using React Router.
Configure react router in app.js to display different components based on the current route, such as landing, surveys, and new, with authentication-driven access logic.
Configure react router dom by wrapping the app in a browser router and defining routes with path and component, starting with the root route to display the landing component.
Learn to configure routes in a node with React app, add dashboard and survey paths, and enforce exact path matching with React Router to render components at / and /surveys.
Learn to control route rendering with React Router by using exact props, show the survey new page under /surveys/new, and keep the header visible across all routes.
Learn to build a dedicated header component in a React app, style it with Materialize CSS, and install it via npm.
Hook up materialize css from an npm module and import its minified css into index.js, enabling webpack to bundle css with javascript output and load non-js files from node modules.
Wire up materialize as an npm module with Webpack, then implement a header nav bar featuring a left brand logo and a right login with Google, using className in React.
Explain how the current user API determines login status by querying the server on app boot, dispatching a Redux action to the auth reducer, and updating header content.
Learn how a React app checks authentication by calling the backend API current user route with axios, dispatching via Redux Thunk to the auth reducer, and updating the header.
Explore the basics of redux thunk, refactor an action creator to use async await, dispatch actions after api requests, and update auth state through the redux store and reducers.
Refactor the app into a class-based component and fetch the current user on startup using componentDidMount, wiring in a redux thunk action creator via react-redux connect.
Learn to connect a class-based app component to a redux store with react redux connect, wire action creators, and verify the fetch user flow from app load to auth state.
Refactor the fetch user action creator from promise chaining to async/await, streamline arrow functions, and preserve dispatch of the response payload using Axios.get.
Dispatch a fetch user action and pass only the response data to the auth reducer; return null while pending, the user model when logged in, or false when not.
Hook the header to the Redux store and render content according to the auth state (null, false, or user object) to reflect login status.
Learn to render header content based on user authentication, showing login with Google or logout, while preventing flash by waiting for auth state and testing with throttling.
Fix the auth flow by adding a post-auth redirect to /surveys after passport authentication, update the header on login, and demonstrate the Google OAuth callback handling.
Implement header logout button by clearing the cookie token and redirecting to root route, ensuring the landing page reappears. Compare ajax logout and full http logout with Redux updates.
Create a dedicated landing component with concise marketing text, center its content, and export it. Integrate it into App.js routing and make the logo navigate to the root.
Replace the logo anchor with a React Router link to navigate within the app, using the to prop and this.props.auth to send logged-in users to /surveys and guests to /.
Plan and implement billing in a fullstack web app by handling credit card payments. Track credits that enable sending surveys, and integrate client and server billing.
Explore billing basics, including handling credit card inputs via Stripe, using a payment processor to avoid storing raw numbers, and managing credits, plans, and fraud considerations.
learn how to securely bill with Stripe, never handling card numbers on your backend; use Stripe-generated forms to collect details and tokens, then complete charges to add credits.
Sign up for a Stripe account in test mode, obtain publishable and secret keys, set them in env variables, and install React Stripe Checkout to enable client-side payments.
Configure stripe keys on server and client sides for secure checkout. Use Create React App to manage dev and prod keys with environment variables and front end back end separation.
Define client side environment variables in a create react app with dot env files. Prefix variables with react_app and access them via process.env to load publishable stripe key for development.
wire up the React Stripe Checkout in a payments wrapper, configure amount and currency, and handle the token callback with the publishable key from env. Integrate it into the header.
Learn to integrate a Stripe payments component into a react app, render it in the header, and handle stripe tokens using environment variables in test mode.
Fix the payment flow by sending Stripe tokens to the API to add credits. Improve clarity and styling by setting Stripe checkout name and description, and using a custom button.
Reuse the fetch user action to update header credits after sending a Stripe token to the backend, via a handle token action creator that updates the auth reducer's user model.
Wire the payments component to post the Stripe token using redux actions, wiring handle token with connect. Test token flow from the checkout form and anticipate the server route handler.
Create a new billing route in express to handle post requests to /api/stripe, wire it into the app, and process the Stripe charge to update user credits.
Explore how to securely charge a user by using Stripe on the backend: install the stripe npm package, exchange the front-end token for a charge, and create a charge object.
Configure Stripe in Express using the secret key from config keys, then install and wire the body-parser middleware to expose req.body for post requests.
Wire up the body parser and log req.body to verify the Stripe token reaches the server, then call Stripe charges.create with amount, currency, description, and source to finalize the charge.
Finalize a charge with the Stripe library by handling asynchronous API calls using promises or async/await to bill 500 cents in US dollars and inspect the resulting charge object.
Define a credits property on the user model with a default of zero, then after billing, add five credits, save the user, and return the updated user to the client.
Verify the updated user credits in the browser dev tools and secure the stripe route by adding a login check, then generalize authentication across routes.
Extract this route-specific login check into a single middleware in express and apply it only to selected routes to ensure users are authenticated.
Display the user's credit balance in the header by rendering this.props.auth.credits as a new list item after the payments button, and apply spacing for visual clarity.
See how the header updates credits after a Stripe payment, as the backend returns an updated user model and Redux refreshes the header.
Learn how to deploy a fullstack app to production with Create React App and express, handling assets and routes on production vs development, and forwarding unknown routes to index.html.
Configure express in production on Heroku to serve static assets from client/build and to fall back to index.html for unknown routes, ensuring react router handles routes.
Compare deployment approaches for Node with React app, focusing on building the client before deployment, and deploying via Heroku with either local builds or server-side builds, following Git conventions.
Add a Heroku post-build step to install client dependencies and build production assets after server installation, enabling seamless fullstack deployment.
Redeploys the app and tests client-side routing with React Router, clarifying Express server responsibilities for serving assets, loading main.js, and handling navigation without full page reloads.
Learn to build a survey endpoint in our Node with React app on an Express server that creates surveys, sends them via email, and records yes-or-no feedback in Mongo database.
Define three routes for surveys: get api/surveys, post api/surveys, and post api/surveys/webhooks, to fetch user surveys, create surveys with title, subject, body, recipients, and record feedback via the email provider.
Learn to create a new survey by posting to an express route handler, persist it with a Mongoose survey model, and link surveys to their creators via the user model.
Examine deficiencies in the survey schema, add yes and no counters, and embed a recipients sub document collection (Mongo/Mongoose) with email and clicked to prevent multiple votes.
Explore subdocument collections in MongoDB and how recipients with email and clicked properties belong to a survey. Understand how a 4 MB limit and 200,000 recipient threshold shape schema choices.
Export the recipient subdocument schema with email and a responded boolean defaulting to false, and import it into the survey model. Attach it as an array inside the survey model.
Add an underscore user field to the survey schema as a Mongoose objectId ref to the user, and include date sent and last responded fields to track activity.
Define a new survey route in express that checks user login and credits, then handles POST /api/surveys using a survey route file, middleware, and linked survey/recipient models.
Implement a require credits middleware to enforce a minimum credits balance before creating surveys, wired after login in the survey route and returning not enough credits on failure.
Create and save a new survey in the database using a Mongoose model, pulling title, subject, body, and recipients from req.body for later email delivery.
Build the survey recipients subdocument by turning a comma-separated email list into an array of objects with an email property. Link the survey to the user and set date sent.
Create and send a survey email by building a route handler that creates a survey, renders a template email, and sends it to recipients before saving to the database.
Use a single batch mailer; SendGrid customizes links per recipient and notifies your server via a webhook when someone clicks.
Sign up for a free SendGrid account, generate a full-access API key, configure dev and prod keys, and install the SendGrid npm package to enable emailing via the mailer.
Set up and extend a SendGrid mailer in node to send emails. Define ES6 mailer class that configures subject, recipients, template body, and from address, and outputs json for SendGrid.
Demonstrates wiring a mailer into a route, creating a mailer instance with subject and recipients, and composing the html body via a survey template function.
Develop a mailer class with an es2015 constructor, from email, subject, and html content, plus a recipients formatter for SendGrid.
learn how the mailer constructor initializes from, subject, body, and recipients, formats recipient emails with SendGrid helpers, registers content, enables click tracking, and implements add recipients.
Learn to finalize a mailer class by formatting recipients, adding content, and applying per-recipient personalization with SendGrid, leveraging add content, add recipients, and add personalization.
Define a SendGrid API object with the key from the Keys object and implement an async send method that posts mailer data as json to /v3/mail/send.
Test the mailer by calling mailer.send to verify email delivery via SendGrid, then post an axios request to /api/surveys with a fake survey (title, subject, body, recipients).
Edit the email template to replace the plain body with a centered HTML snippet that includes the survey body and yes/no links. Use backtick strings for multi-line HTML.
Refine the route handler to send emails through mailer, save surveys, deduct a credit, and update the user model with async flow and error handling that returns 422 on failure.
Verify SendGrid click tracking by examining the activity dashboard, where a click event reveals exactly who clicked the email, making click data the linchpin of the app.
Configure environment-specific redirect domains for survey emails using a redirect domain key in config. Wire it into the survey template and test in development and production.
Note: This course assumes you've got the basics of React and Redux down. Check out my course 'Modern React with Redux', its the perfect preparation!
Go beyond the basics of React and Redux! This course will teach you to combine the ultra-popular React, Redux, Express, and MongoDB technologies to build a fullstack web application.
Advanced Deployment? You will learn it. Billing/Payments? Included. Handling Email? Of course!
------------------------------
What Will You Build?
All of my courses are 'learn-by-doing': no boring endless lectures with Powerpoints, only live, interactive coding examples. In this course we'll build one massive web application that profiles the advanced features of React, Redux, Express, and Mongo. By putting each concept into a real app, you'll get a better idea of when to use each unique and powerful feature.
Build a large feedback-collection app. This mega app will include the full gamut of features, including everything from authentication to email handling. You'll learn how to build an app that can be used to send mass emails to a big list of users for the purpose of collecting feedback. It's my goal to ensure you understand each feature we build into this app so you can apply them to your own personal or professional projects in the future.
------------------------------
Here's what we'll learn:
I've built the course that I would have wanted to take when I was learning to build fullstack apps. A course that explains the concepts and how they're implemented in the best order for you to learn and deeply understand them.