In this series of articles, I’m doing a walkthrough of a hobby project I’ve worked on, a payment system for the Ethereum blockchain. Go read the intro article for more context about this project.
In this part, I will cover the following topics:
- Product details, whitelistings, coupon codes
- Displaying purchases and subscriptions, products available, and past purchases
- Data models for products and whitelistings
None of what is described in this article is about web3, it’s all really web2 development. However, I do have to describe it to lay the foundation for parts 3 and 4 that will be focused on interacting with the blockchain, and with a recap of what I’ve learned about what crypto wallets and blockchain for developing mass-consumer product experiences.
Below are the data models used for products, purchases, and whitelistings and coupons (click to enlarge).
The follow diagram shows three user flows: the first flow shows products for non-signed in users, the second flow for signed in users, and a third flow just to display the current status of the access rights.
The first flow, described by step 1, is very basic. It is simply a call from the frontend to a dedicated backend endpoint that queries all the products available, at the regular prices. You can also see it in this file.
The second flow, described by steps 2 to 5, shows the flow for when a user is logged in. After a user authenticates with a crypto wallet as covered in part 1 of this article series, there will be a JWT (JSON Web Token) stored locally in the web browser, and that JWT will be used by the frontend to show authenticated information to the user, based on his access rights.
This is done via HTTP headers. The frontend injects the JWT by adding the “Authorization” header in step 3, sends that request to the backend, and then the backend unpacks the JWT via a middleware. Based on whether the token is present, and whether it is valid or not, the backend will either return an error code or will run the adequate business logic.
Note that the gated access to products is be done from the backend via another middleware, in the file
paidcustomer.middleware.ts (source code is here)For this simple project, I am only doing a single middleware and consider that all paid users would have access to the same rights. However, if different plans would give access to different features based on different product price points, then it would be easy to extend this example by adding extra middleware files that would do layered gating of the full feature set.
Then based on the crypto wallet address, the backend will show additional products, or will show discounted prices. You can read the source code here. This is also where it is possible to implement the logic for coupon codes and whitelists (i.e. giving access for free to the products entirely).
Note that I have implement the system so that it can support subscriptions in the form of time-limited gated access: users can pay to access a product for a certain time, after which their access will be revoked. This is what you’d want to implement a payment system for any SaaS product or any content/media publication. From there, it is pretty easy and straightforward to implement one-time payments and one-time products, for example purchasing an ebook, an online course, or even a physical product.
Finally, in the third and last flow, the data stored in the localStorage of the web browser is used to display to the user what plans or products have been purchased and are active. The code is in the membership component, which you can read here.
In part 3, I will cover the processing of payments, including the user of idempotent queries to avoid double processing.
Join my mailing list below to be notified when I post new articles