---
title: #2 - Retrofitting the Privacy Policy
published: false
date: 2025-09-02 20:41:21 UTC
tags: WebDevelopment,FullStackDevelopment,Nodejs,DevLife
canonical_url: https://campfire.dlseitz.dev/2-retrofitting-the-privacy-policy
header:
    image: /assets/2-privacy-policy-head-img.png
    attribution: 'Image generated with Sora. | © 2025 Derek L. Seitz'
---

Hey there everyone! Welcome to **_Campfire Logs: The Art of Trial & Error._** In my last log, "[#1 - The Great Gitea Migration](https://hashnode.com/post/cmeuf5cdo000o02l8cem786pt), I introduced you to my self-hosted [Gitea](https://about.gitea.com/) and shared the nerves, hiccups, and (eventual) success of migrating it into my [dlseitz.dev](https://dlseitz.dev) ecosystem.

Today I want to tell you about a recent blunder of mine (you guessed it, a forgotten privacy policy), and my experience trying to retrofit a solution into my existing codebase (ever tried adding a new field to your form JSON after youve already wired everything up? Yeah). Ill also talk a little bit about my philosophy on mistakes like this and explore ways to help prevent them in the future (spoiler alert: theres no absolutely foolproof way).

Let me say real quick that this log will not be as lengthy as my last, but you can still grab a coffee or some marshmallows and a stick as we get started. Theres also a **_TL;DR_** section at the bottom of the page for anyone in a hurry.

Lets get to it!

## **How Did I Miss That?**

Its true. I forgot to add a privacy policy to my website before it went live. And while that may be a very small thing to overlook in the grand scheme of thingsespecially for a solo developerbeing transparent with how you handle clients information can really help to build trust.

Now, its pretty safe to say that the vast majority of us are guilty of clicking the little checkbox saying we agree to the privacy policy and terms & conditions _without actually reading over them_. There are even studies published that back this up. In 2019, [Pew Research Center found that only about 1 in 5 Americans](https://www.pewresearch.org/internet/2019/11/15/americans-and-privacy-concerned-confused-and-feeling-lack-of-control-over-their-personal-information/?utm_source=chatgpt.com#:~:text=How%20Americans%20handle%20privacy%20policies%3A) actually read privacy policies before agreeing to them, and most of those said they dont really understand the laws surrounding them. Ill let you dive into all of that on your own, but the takeaway here is pretty clear: most people simply dont engage with privacy policies. Not in any meaningful way, at least.

So why did it matter _to me?_ Why was I a little shocked that I didnt think about it sooner?

Because integrity matters, and two of my core values are centered around **_transparency_** and **_privacy_**. Now, Im not saying Im perfect or better than anyone (far from it). What I am saying is that I make genuine effort to stay true to the things I value most, making sure the effort is clear through my work.

[So, I decided to add a privacy policy.](https://dlseitz.dev/privacy-policy/)

## **The Developers Burden**

This is where the actual fun started: coding the retrofit. No, reallyit was fun (at first). The goal was to ensure that a user consented to my websites privacy policy before they could submit their info using the contact form. However, I really dont know why I was so dead set on a checkbox being the mechanism for it. I guess my subconscious knew it was the hard way since there are _much_ simpler ways to accomplish this.

When I wrote out my course of action, I started with the front end, then the backend app, and finally the database, so this was the order I worked in. In hindsight, I think that the reversed order would have saved me a bunch of headache in the long run (sort of like stringing lights on a Christmas tree). I dont think that I did it in the _wrong_ order, just in an order that introduced more opportunity for bugs.

The front end part of this endeavor went pretty smoothly. I started by creating a new [Nunjucks](https://mozilla.github.io/nunjucks/) template for the privacy policy webpage (I use the [static site generator (SSG)](https://www.cloudflare.com/learning/performance/static-site-generator/) [11ty (Eleventy)](https://11ty.dev) to build out my site). Next, I created a new stylesheet for the page-specific CSS rules. As weird as this may sound, having separate stylesheets for different concerns does it for the neat freak inside of meI completely lit up with joy when I first realized that was even a thing (that part seemed to have been left out in school). Then, the last thing before moving on to the JavaScript was to add the policy page to my footer nav links.

So far, so good.

### Where Things Start Getting Slippery

Now, my backend application isnt really all that complicated. Its a simple [Front Controller](https://www.geeksforgeeks.org/system-design/front-controller-design-pattern/) with [Chain of Responsibility](https://medium.com/@artemkhrenov/the-chain-of-responsibility-pattern-in-javascript-building-elegant-request-handlers-b9a72a16d7cc) [design pattern](https://sourcemaking.com/design_patterns) written on [Node.js](https://nodejs.org) with [Express](https://expressjs.com). It consists of the main app that receives the forms [JSON payload](https://www.ibm.com/docs/en/baw/24.0.x?topic=protocol-common-json-payload-cases-case-types#:~:text=The%20workflow%20REST%20protocol%20defines,following%20workflow%20REST%20protocol%20resources:) through a [POST request](https://www.w3schools.com/tags/ref_httpmethods.asp) to its [API](https://www.ibm.com/think/topics/api), then three modules that handle the rest. The [router module](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes) transports the payload through the appropriate logic, the [middleware module](https://www.w3schools.com/nodejs/nodejs_middleware.asp) runs security checks (spam, bots, etc.), and the [controller module](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes) formats and stores it in my [PostgreSQL](https://www.postgresql.org/) database before emailing it to me. The backend work for the retrofit was only to make sure the router expected the added checkbox [Boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean) in the payload, the controller knew where to insert it and a timestamp into the database, and the database had a place for the new data to go.

Simple.

After wiring everything upthe HTML, CSS, vanilla JS, database fields, router, and controllerI figured my form was ready to test. But thats when the headaches started. Submitting dummy info kept throwing me into a loop where I couldnt tell if the culprit was the checkboxs [`required` attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/:required) or my custom JS validation. Alright, let me just crack my knuckles and pop my neck Ive got this.

Even after a hard refresh ( **Ctrl+Shift+R** ) finally cleared the caching issues, I was immediately hit with a new problem: [_500 Internal Server Error_](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/500). But hey, at least now my form payload was making it to the server progress nonetheless! [PM2](https://pm2.keymetrics.io/) logs insisted my timestamp column didnt exist in the table (even though it did). I tore through my controller logic and even rebuilt the table from scratch (thinking it may be a lower-level bug way above my pay grade), but nothing changed. Frustrated, I gave up for the night. It was late, and I clearly didnt have this, at least not yet.

### A Hard Refresh Makes Things Click

The next day, after a hard refresh of my own, I decided to sidestep the checkbox entirely by replacing it with a consent by affirmative action clause above the submit buttonshort, sweet, and to the point. I thought for sure this solved everythingbut nope. I think sleeping on the problem was the real hero here, because when I looked over the controller logic again, the issue was embarrassingly obvious: I had set the column type in the database table to `timestamp`, but was also trying to manually insert a timestamp value via [`NOW()`](https://www.postgresql.org/docs/current/functions-datetime.html) in the controller. Since the database automatically assigns a timestamp when a new record is created, my insert kept failing. Simply letting the database do database things made all the difference in the world.

At this point, though, the checkbox was already long gone. And honestly, I wasnt even slightly upset about it. It meant one less hurdle for potential clients trying to reach out and one less datapoint to validate and store. Sometimes, simplicity really is the best policy.

## Forgive Your Mistakes: Do Better Next Time

Heres the thing about mistakes: theyre not signs you dont belong theyre signs youre doing the work. Every overlooked field, every broken query, every duh moment is just part of the feedback loop. For me, integrity means owning those errors instead of hiding them, and transparency means being willing to talk about them openly (even in public, like this log). [Imposter syndrome](https://www.psychologytoday.com/us/basics/imposter-syndrome) loves to whisper that youll be found out as a fraud and that making mistakes proves youre not cut out for this. In reality, though, mistakes are how you learn and get better. As long as we keep building, keep refining, and keep letting our values guide the process, the mistakes stop being failures and start being steppingstones.

If theres one thing Ill do differently next time, its slowing down before I overcomplicate the solution. A quick sanity check am I letting the database do its thing, or fighting it?could have saved hours. And honestly, just walking away for the night did more for debugging than any frantic console.log ever could. No process will ever be perfect, but building in those pauses makes the next mistake easier to catch.

## TL;DR

I launched my site without a privacy policyoops. While most people dont read them, transparency and privacy are core values of mine, so I had to fix it.

The retrofit was a mix of fun and frustration: I wired up the front end, backend, and database, only to hit errors caused by my own overengineering (checkbox validation, manual timestamp insertion, etc.). After some trial, error, and sleep, I realized simpler was betterso I dropped the checkbox and used a clear consent clause instead and let my database do what databases do: _database_.

Lesson learned: mistakes happen, especially when building solo. What matters is staying true to your values, keeping the process transparent, and refining along the way.

## Before You Go

Thanks to everyone for reading! I appreciate you taking the time to learn about my developer experiences. I encourage you all to tell me what you thought about the article (what worked for you, what didnt) in the comments. Or perhaps you have a similar story you may want to share. One persons trip-up is another persons what not to do.

Be sure to check back soon for installment #3 of Campfire Logs: The Art of Trial & Error, where I will be taking a step back from the technical aspects of developing. Weve talked about retrofitting the technical aspects of the privacy policy, but I want to shift gears to discuss how I created my websites privacy policy and the data privacy concerns that came along with it.