Reed Water is an IOT device that manages property water levels. We were tasked in creating the frontend of the user journey for potential clients. The website required 3 main features; Subscription Billing, eCommerce & Resource database.
The client's main request was being able to manage content on their own. We wanted to stay within reasonable budget, so instead of creating our own CMS, we opted for Strapi. Flexibility was important, and staying within the Node ecosystem was preference.
The clients needed a subscription model to accommodate purchasing and continued use of Reed products and services. Tiers for varied levels of features could be modified by the client, in the Strapi CMS.
We connected our front-end solution to authorize.net, which then sends a notification to the hardware that the customer owns. The external payment provider handles failed payment, or cancelation from their API.
With eComm solutions being few and in-between, Shopify is the usual go-to. The issue is we needed to create a custom solution that works within the client's current technical ecosystem.
Orders are sent to the Srapi CMS for the client to view & manage. Payment is collected from authorize.net, which first verifies the order before placing it in the shipping queue.
Introducing hardware and software as new as this, having docs, or in this case, Resources - is vital. We created a visual database for resources with the ability for Reed to upload PDF files, images, text, what comes in-a-box, and associate it with a product on the Strapi back-end.
We wanted to render on a server, while still keeping components modular. Again, instead of doing this from scratch, our favourite solution is Next.js. They take care of rendering React on the server, which really benefits in speed & SEO advantages.
Authentication & Next.js was pretty complicated originally. Eventually Zeit released a way to customize each page initialization (https://nextjs.org/docs/#custom-app). We check for a token stored in the users localStorage on every page load, using a custom HOC (higher order component) that wraps around each page.
For this clients scenario, we had to tap in to an external auth system. The one that controls the actual hardware. Fortunately, the engineers on the other team provided an OpenId solution, where users can login & register on our frontend app, while the external backend handles supplying the token.
Last but not least, was handling deployment. DevOps plays a crucial role in the Reed development ecosystem. Handling deployment for multiple moving parts became a challenge. Docker to the rescue, we containerized the whole project. We separated Strapi, the Mongo database, a web server named Caddy & finally the Next.JS app.
Below you can see the Docker Script on how we orchestrated Reeds' DevOps solution
version: '3' services: caddy: image: registry.gitlab.com/creatorsneverdie/reed/caddy:latest restart: unless-stopped ports: - 443:443 - 8443:8443 - 80:80 volumes: - caddy-certs:/root/.caddy depends_on: - api - web logging: options: max-size: 50m environment: ACME_AGREE: "true" HOST: reedwater.io WWW: "true" web: image: registry.gitlab.com/creatorsneverdie/reed/frontend:latest ports: - 3000:3000 depends_on: - api restart: unless-stopped logging: options: max-size: 50m environment: OIDC_AUTHORITY: **** OIDC_CLIENTID: **** OIDC_REDIRECT: **** OIDC_REDIRECT_SILENT: *** OIDC_POST_LOGOUT: *** MONGOURL:mongodb://@mongo/strapi AUTHORIZED_NET_API_LOGIN : **** AUTHORIZED_NET_TRANSACTION_KEY : **** API_ENDPOINT: **** API_ENDPOINT_SERVER: **** API_ENDPOINT_PORTAL: **** SENDGRID_API_KEY: **** MAIL_SENDER: **** api: image: registry.gitlab.com/creatorsneverdie/reed/backend:latest ports: - 1337:1337 environment: APP_NAME: api DATABASE_CLIENT: mongo DATABASE_HOST: mongo DATABASE_PORT:27107 DATABASE_NAME: **** HOST: **** volumes: - api-uploads:/usr/src/api/api/public/uploads restart: unless-stopped logging: options: max-size: 50m mongo: image: mongo:3.6.6 restart: unless-stopped tmpfs: - /var/lib/mongodb volumes: - mongo-data:/data/db mongo-express: image: mongo-express restart: always ports: - 8081:8081 environment: ME_CONFIG_BASICAUTH_USERNAME: **** ME_CONFIG_BASICAUTH_PASSWORD: **** volumes: api-uploads: driver: local mongo-data: driver: local caddy-certs: driver: local
Part of any great DevOps experience, requires some sort of CI (continuous integration). We host our projects on GitLab, who offer an amazing free solution. We wrote a .gitlab-ci file that pulled the docker-compose file above. Depending on which branch you pushed to, it would deploy to either the production or staging server. This allows for the client to watch as we iterate, without messing up the production server.
All-in-all, this was a great project for us to test different technologies. This really opened our eyes to the gap in finding a headless CMS that does exactly what we wanted. Maybe in the future, this can be the next open source project we tackle.