The Prototype Worked. Then GutPacer Had to Become a Product.

A family bowel-care logger became a lesson in notification semantics, broken deployments, LINE authentication, and the difference between a working demo and a trustworthy care tool.

GutPacer did not begin with a product roadmap. It began with a recurring family question: Was there a bowel movement today, and was the medication taken?

In home care, that question is easy to ask and surprisingly hard to answer a few days later. A family caregiver may remember the event but not the date. A note may exist on paper, in a message thread, or only in somebody’s head. When care moves temporarily from home to a facility, even the person responsible for recording it changes.

The first version of GutPacer was deliberately small: one static web page, one AWS Lambda API, DynamoDB for daily records, and a LINE notification when a record appeared to be missing. It could record bowel movements, stool type, medication, notes, and whether the person was at home or staying in a facility. It could also export a PDF for later review.

It worked for one family. That was the beginning of the engineering work, not the end.

The first mistake was hidden inside a reasonable shortcut

The reminder Lambda originally checked whether a daily record existed. That sounded correct until we looked at what a record actually meant.

A record could exist because medication had been logged, even when no bowel movement had been recorded. The notifier saw the row and treated the day as complete. From the database’s point of view, the item existed. From the caregiver’s point of view, the question had not been answered.

The fix was tiny: check the bowel field, not the existence of the record. The lesson was larger. In care software, a database event and a care event are not interchangeable. A technically valid row can still represent an unanswered human question.

We found the same tension in the location setting. When the person is staying in a facility, sending the family a home-care reminder is not helpful. It is noise, and repeated noise teaches people to ignore the system. GutPacer therefore needs to understand not only whether a record is absent, but whether the family is currently expected to create that record at all.

That is not medical intelligence. It is workflow context, and getting it wrong is enough to make a simple reminder system unusable.

Adding a PIN exposed three versions of “the same” backend

The earliest GutPacer URL was protected mostly by obscurity. Before sharing it more widely, we added a PIN header to the browser and Lambda.

The API itself accepted the PIN. The browser still failed.

The missing piece was CORS preflight: the Lambda response did not allow the custom X-Pin header. A direct API test passed, while the real browser request was blocked before it reached the handler. Once we added the header to Access-Control-Allow-Headers, the flow worked.

Then we discovered a more dangerous source of confusion. The repository contained both a current ES module Lambda and an older CommonJS implementation. Both looked deployable. Only one supported the current authentication and CORS behavior.

We moved the legacy implementation into an explicitly unsupported directory and documented one canonical handler. This was less glamorous than adding a feature, but it removed a failure mode that had already cost time: deploying code that looked familiar but no longer represented the product.

Automation revealed that deployment had never been healthy

We added smoke tests and a GitHub Actions workflow so API changes would be tested before Lambda deployment. That work uncovered two separate infrastructure problems.

First, the notification Lambda was packaged with its source directory inside the zip file, while the configured handler expected index.mjs at the archive root. The code was correct; the artifact shape was not.

Second, the shared AWS region configuration pointed somewhere other than the region where the GutPacer Lambdas actually lived. The deployment role then attempted to update a function in the wrong region and failed with an authorization error. It looked like an IAM problem, but changing permissions would only have hidden the real issue.

We fixed the package layout, made the deployment region explicit, and added manual workflow triggers for recovery. The uncomfortable discovery was that the notifier’s automated deployment had been failing since it was introduced.

This is why a green local test suite is not enough. The build artifact, cloud region, handler name, role policy, and deployed runtime form one system. “The code passes” describes only one part of it.

A family tool still handles sensitive data

GutPacer is small, but its notes and daily records can contain sensitive information. We added output escaping after finding that free-text notes were being inserted into generated HTML. We covered both the history view and the HTML used for PDF export, because fixing only the visible screen would have left the second rendering path exposed.

We also enabled point-in-time recovery on the DynamoDB tables. Backups do not make a design good, but they change an accidental deletion from a permanent event into a recoverable one.

These changes did not make the app look different. They changed whether we could responsibly keep using it.

One family and several families are different architectures

The original DynamoDB table used the date as its key. For one household, that is beautifully simple. For two households, it is not merely limited; it is the wrong data boundary. Two people can have the same date, and an API protected by one shared PIN has no reliable way to decide whose record it is reading.

We could have added a userId field to the request body and called it multi-user support. We did not. A client can alter its own request body. The server must derive identity from something the server can verify.

The current development version uses LINE Mini App authentication. The browser obtains a LINE ID token, the backend verifies that token with LINE, and the verified sub becomes the user boundary. GET, POST, and DELETE operations all use that verified identity. If the request body claims a different user ID, the API ignores it.

The new DynamoDB design reflects that boundary:

partition key: verified LINE user ID
sort key:      record date

Profiles, notification preferences, and location settings move into a separate user table. The migration script is dry-run by default, and the replacement tables have point-in-time recovery enabled before real family data is moved.

We added offline tests specifically for the boundary: reads query only the verified user, writes overwrite any body-supplied identity, and deletes require both the verified user and date. Authentication is not complete because a login screen appears. It is complete only when every data operation respects the same boundary.

LINE Mini App integration was not just “add login”

GutPacer started the LINE transition while LIFF applications were being presented as LINE Mini Apps. That created its own small layer of archaeology: development, review, and production each have a separate Mini App URL; the frontend still initializes the LIFF SDK using the identifier embedded in that URL; and the default endpoint pages must be replaced with the actual GutPacer deployment for each environment.

None of this is conceptually difficult. It is operationally exacting. A correct token verifier is useless if the development Mini App still opens LINE’s placeholder page. A correct frontend is unsafe if the production Lambda still trusts a shared PIN. A successful login is not proof of tenant isolation.

So we have kept the existing production path stable while building the LINE-authenticated API beside it. The current public deployment remains the single-family PIN version. The LINE Mini App and multi-user tables are development work for a closed beta, not a generally released service.

That distinction matters to us. A feature can be implemented before the product is ready to ask another family to trust it.

What “MVP” means now

For GutPacer, MVP no longer means “the form saves a record.” It means a small number of invited families can use the tool without seeing or changing one another’s data, existing records can be migrated and read back, notifications go to the intended person, failures can be investigated, and a family can understand how to ask for support or deletion.

The remaining work is less visible than the original prototype:

  • connect and test the development Mini App on a real LINE account;
  • migrate the original household without losing history;
  • complete per-user notification routing;
  • verify isolation with multiple test identities;
  • publish clear privacy, contact, and deletion information;
  • run a closed beta before describing the service as released.

This is slower than putting a sign-up button on the page. It is also the honest distance between a personal tool and a product that handles care records.

The product is the boundary, not the form

The visible part of GutPacer is still intentionally modest: a fast daily form, a history, a PDF, and a reminder. Most of the struggle has happened behind that screen.

We learned that a reminder must understand what was actually recorded. A browser test can reveal what an API test misses. A deployment error can be a region error disguised as IAM. A table that is elegant for one family can be unsafe for the second. And authentication is only meaningful when it becomes the data key all the way down.

GutPacer does not diagnose, treat, or make care decisions. It records observations and helps a family revisit them. That narrow promise is exactly why the infrastructure around it has to be precise: the software should not create a new uncertainty while trying to reduce an old one.

The project remains in development. You can follow its current status on the GutPacer product page and inspect the open-source repository. The same public trail shows both the useful parts and the unfinished ones.


GutPacer is one of the care tools being built at VEAI LAB. I apply the same discipline across the portfolio: explicit product status, small serverless systems, testable boundaries, and public engineering notes when something fails. For technical project management or cloud engineering work, see hire-veai.com.

Thanks for reading — built with care, for caregivers.