DEV Community

Derek L. Seitz
Derek L. Seitz

Posted on • Originally published at campfire.dlseitz.dev on

#2 - Retrofitting the Privacy Policy

Hey there everyone! Welcome to Campfire Logs: The Art of Trial & Error. In my last log, "#1 - The Great Gitea Migration”, I introduced you to my self-hosted Gitea and shared the nerves, hiccups, and (eventual) success of migrating it into my 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 you’ve already wired everything up? Yeah…). I’ll also talk a little bit about my philosophy on mistakes like this and explore ways to help prevent them in the future (spoiler alert: there’s 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. There’s also a TL;DR section at the bottom of the page for anyone in a hurry.

Let’s get to it!

How Did I Miss That?

It’s 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 things—especially for a solo developer—being transparent with how you handle clients’ information can really help to build trust.

Now, it’s 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 actually read privacy policies before agreeing to them, and most of those said they don’t really understand the laws surrounding them. I’ll let you dive into all of that on your own, but the takeaway here is pretty clear: most people simply don’t 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 didn’t think about it sooner?

Because integrity matters, and two of my core values are centered around transparency and privacy. Now, I’m not saying I’m 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.

The Developer’s Burden

This is where the actual fun started: coding the retrofit. No, really—it was fun (at first). The goal was to ensure that a user consented to my website’s privacy policy before they could submit their info using the contact form. However, I really don’t 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 don’t 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 template for the privacy policy webpage (I use the static site generator (SSG) 11ty (Eleventy) 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 me—I 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 isn’t really all that complicated. It’s a simple Front Controller with Chain of Responsibility design pattern written on Node.js with Express. It consists of the main app that receives the form’s JSON payload through a POST request to its API, then three modules that handle the rest. The router module transports the payload through the appropriate logic, the middleware module runs security checks (spam, bots, etc.), and the controller module formats and stores it in my PostgreSQL database before emailing it to me. The backend work for the retrofit was only to make sure the router expected the added checkbox 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 up—the HTML, CSS, vanilla JS, database fields, router, and controller—I figured my form was ready to test. But that’s when the headaches started. Submitting dummy info kept throwing me into a loop where I couldn’t tell if the culprit was the checkbox’s required attribute or my custom JS validation. Alright, let me just crack my knuckles and pop my neck… I’ve 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. But hey, at least now my form payload was making it to the server… progress nonetheless! PM2 logs insisted my timestamp column didn’t 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 didn’t 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 button—short, sweet, and to the point. I thought for sure this solved everything—but 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() 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 wasn’t 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

Here’s the thing about mistakes: they’re not signs you don’t belong — they’re signs you’re 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 loves to whisper that you’ll be found out as a fraud and that making mistakes proves you’re 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 there’s one thing I’ll do differently next time, it’s 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 policy—oops. While most people don’t 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 better—so 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 didn’t) in the comments. Or perhaps you have a similar story you may want to share. One person’s trip-up is another person’s “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. We’ve talked about retrofitting the technical aspects of the privacy policy, but I want to shift gears to discuss how I created my website’s privacy policy and the data privacy concerns that came along with it.

Top comments (0)