DEV Community

Cover image for Building a Laravel Marketplace with PostgreSQL While Debugging React State
Zahid Hasan Tonmoy
Zahid Hasan Tonmoy

Posted on Originally published at zahidhasantonmoy.vercel.app

Building a Laravel Marketplace with PostgreSQL While Debugging React State

I spent the last few days building instead of just watching — a small Laravel marketplace project backed by PostgreSQL, plus some hands-on React work. I also got stuck a couple of times, and writing down where I got stuck turned out to be the most useful part of the process.

On the Laravel side, I went back to fundamentals first: routes, controllers, views, and Blade. I practiced the full request cycle — a route hitting a controller, the controller passing data to a view, and Blade handling variables, loops, and conditionals. I also worked through basic form validation, mostly to get the muscle memory right before moving on to anything more complex.

The more interesting part was designing the database for a marketplace-style project with PostgreSQL. The plan is four roles — Admin, Moderator, Seller, and Buyer — with two business rules that shaped most of the schema decisions: a seller can't buy their own product (though buying from other sellers is fine), and a seller's product doesn't go live the moment it's created. It has to be approved by an Admin or Moderator first.

Translating those two rules into actual migrations is where the real learning happened. I added a role field to the users table, defaulting to buyer. Then I built a products table with seller_id, title, description, price, stock, status, approved_by, and approved_at. New products start with a pending status so the approval workflow has something to act on.

Working through this made migration concepts click in a way tutorials hadn't — up() and down(), foreign keys, nullable columns, defaults, and relationships. The seller relationship uses cascading deletes (delete a seller, their products go too), but the approver relationship just sets approved_by to null if that admin or moderator is removed — the product itself stays. Seeing why those two behaviors need to be different made foreign key constraints feel a lot less abstract.

I also hit a real environment issue: running Laravel's db:table command failed because of a missing PHP intl extension. It took a minute to realize the error wasn't in my code at all — it was a missing PHP extension. Small as it was, debugging it felt like as much a part of "learning Laravel" as writing the migrations themselves.

On the React side, I worked with useState and useEffect, fetching show data from the TVMaze API. The main lesson here was that fetch only rejects on a network failure — not on an HTTP error like a 404 or 500. So I started checking response.ok explicitly and throwing an error when it fails, then wrapped the whole request in try/catch/finally to keep loading, data, and error states cleanly separated:

useEffect(() => {
  const fetchShows = async () => {
    setLoading(true);
    try {
      const res = await fetch("https://api.tvmaze.com/search/shows?q=all");
      if (!res.ok) throw new Error("Failed to fetch shows");
      const data = await res.json();
      setShows(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };
  fetchShows();
}, []);
Enter fullscreen mode Exit fullscreen mode

I also ran into a small but genuinely confusing bug: logging state right after calling setShows still showed the old value. It wasn't that the update failed — it was that the log was reading a stale value from that render's closure, before React had re-rendered with the new state. Chasing that down taught me more about how React's state updates and re-renders actually work than any explanation had.

The biggest takeaway from this stretch is that learning a framework isn't about memorizing syntax — it's routes, controllers, migrations, relationships, API calls, and state management all working together inside one real application. Next up: building out the approval flow and seller dashboard on top of this schema, and getting more reps in with React's data-fetching patterns.


This article was originally published on Zahid Hasan Tonmoy's Portfolio.
Connect with Zahid on GitHub & LinkedIn.

Top comments (0)