The icon for the "teita" application

Rails Application for My Family's Greengrocer

Introduction

Hello, I’m higasun. I usually work in Tokyo as a software engineer.

In this post, I’d like to share the story of how I created a Rails application for my family’s greengrocer. When I say “greengrocer,” it’s no longer like selling fruits and vegetables to customers in front of the store these days. It delivers produce to restaurants and various facilities.

The following GIF shows a quick look at the app. I developed it over a couple of months during breaks from research and work. As of January 2025, the app saves each person about 30 minutes of work per day.

Background

I started developing this app about a year ago. At that time, I was working on applied machine learning research in graduate school, writing Python scripts for experiments, and occasionally creating simple Vue apps.

One day, when I was back home, I took a fresh look at the family business and realized there were a lot of analog processes. For example, we would receive order forms by fax from clients, and then someone would manually write the necessary quantities onto paper to tally them up.

Seeing that, I thought, “I can definitely write a program to make this work easier. Actually, if I don’t do it, who will?” And so I decided to develop an application.

Development Flow

Identifying Tasks to Automate

The first step was deciding which tasks to be automated.

Since I used to help out with the business, I had a sense of where we could achieve big efficiency gains. The main target was the input and tallying of quantities for purchasing.

Here’s how the process looked in my family’s shop:

  1. Each employee checks the order forms for the clients they’re responsible for, then writes down how many of each item to purchase on a piece of paper.
  2. Another person tallies up the total quantities per item and places the orders.

All of this was done with physical paper on a clipboard, which was especially time-consuming.

So I decided to create an app that would allow:

  1. Each employee to input quantities from their own smartphone.
  2. An employee in charge of tallying to see a pre-calculated total on a laptop.

This would make the ordering process much smoother.

FYI

In my family’s shop, that clipboard has always been called “手板 (ていた、teita).” So I decided to name the app “teita” in alphabetic form.

Design and Implementation

First, I sat down with the folks at the shop to figure out the requirements. Once the requirements were somewhat clear, I could determine what data I needed, and from there, I set up the database tables. For instance, I modeled items, clients, employee information, and how employees are linked to their respective clients—essentially a straightforward representation of the resources and their relationships in everyday operations.

To design the tables, I used the following book as a reference:

達人に学ぶDB設計徹底指南書: 初級者で終わりたくないあなたへ

Once the schema was in place, it was a matter of implementing it in a standard Rails fashion. I tried to stick to the framework conventions as much as possible, which let me leverage official documentation and community knowledge effectively.

Entering Data

Even if the app is finished, it’s useless without actual data in the database. We had to digitize all the product information that had been managed on paper. This meant manually entering thousands of rows of data into the database.

Yes, it was a lot of work, but I found ways to make it more efficient (and even enjoyable):

  • Using my iPhone’s OCR to capture text.
  • Letting GPT clean up inconsistencies in product names.

What I Built

Each employee can use their smartphone to enter quantities like this:

Meanwhile, the person in charge of tallying can check how many of each item need to be ordered by looking at an aggregation page. After placing an order, they can mark the item as done to avoid duplications.

Additional Features

After I released the initial version with the features above (in about 2–3 months), I spent the next 2–3 months adding:

  • Management of cost and selling prices for products
  • A time tracking feature for clock-ins and clock-outs

I talked with the folks to figure out which tasks were most important, weighed implementation costs, and decided which features to add accordingly.

Technologies Used

Framework

I used Ruby on Rails because I was interning at a company that used Rails at the time. I’d never built a full-fledged web app before, but Rails felt approachable. Reading through the Ruby on Rails Guides was also a great way to learn web development fundamentals.

Front-End

I used Hotwire—the technology that ships with Rails 7—for the front-end development.

Styling

I used Tailwind CSS. Since the app needed to be accessible from both PC and mobile, I made sure the styling was responsive.

For Rails, you can specify Tailwind when you run rails new, or you can install it later using the tailwindcss-rails gem.

Infrastructure

I also deployed the app on Google Cloud to learn more about it (my future employer was using Google Cloud). The Rails app runs on Cloud Run, and the database is Cloud SQL. It’s pretty straightforward, like this:

I wanted to keep costs low, so I set the minimum instances for Cloud Run to 0 at night. During the day, I keep the minimum instances at 1 to avoid cold starts.

For Cloud SQL, I’m using the smallest and cheapest db-f1-micro.

⚠️ Note that db-f1-micro isn’t covered by the Cloud SLA, so keep that in mind if you choose to use it.

With this setup, the monthly cost is just over 2,000 yen (~$20 or so).

Testing

I wrote RSpec tests mainly for the Model and Controller layers in the MVC architecture. For Views, I manually checked.

CI/CD

Ideally, I’d have set up a pipeline using GitHub Actions so that tests trigger automatically, and if they pass, Docker images would be built and deployed. But since it was just me working on this, and I wanted to roll it out quickly, I didn’t build a full pipeline.

Instead, I run tests locally, and if they pass, I execute Cloud Build to run DB migrations and build/push the Docker image. I create Cloud Run revisions using the gcloud command.

IP Restrictions

I want to restrict access only to people at the shop, so I implemented IP restrictions. Given the simple setup (no Cloud Load Balancing to save costs), I added logic in the Rails app itself to limit requests by IP.

If you want to do IP restriction in a Rails app, you need to make sure you set the trusted proxy IPs; otherwise, there’s a risk that remote_ip might be spoofed. This article is a great reference (written in Japanese):

X-Forwarded-For の正しい取り扱い方とCloudFrontを通したときのクライアントIPの取得方法

Helpful Articles from Zenn

I benefited greatly from many Zenn articles while building this app. Here are some that were especially helpful. I’d like to express my gratitude to all the authors. 🙇🏻‍♂️

Note that all of them are written in Japanese.

An Introduction to Building Your Own Python Web Application for Stuck Third-Year Web Engineers

This series walks you through creating a simple Python web framework from scratch. By building a basic HTTP server, I gained a better understanding of the core structure of web frameworks. Coming from a Python-only background, these insights helped me adapt to a new framework like Rails more smoothly.

Hotwire Basics for Cats: Turbo Edition

This article summarizes Hotwire, which became the default in Rails 7. It was incredibly helpful. I used Hotwire in my own app to implement features like incremental search and inline editing.

Conclusion

Looking back, there are tons of things I could’ve done better. Still, hearing from the team (and my family) that this app has made their work easier and faster has been a rewarding experience—it reminded me how fun development can be.

If you ever get the chance, why not try building an app for your family or those around you?


ℹ️ This article is same as the one I published on Zenn. Thank you for understanding.