What You Only See After Building the House
How to look at the site I made through someone else's eyes
unstackd.io went online.
I connected the domain, changed the nameservers, typed the address into the browser. The familiar screen appeared. Hero slogan, timeline, footer. All there. It felt good.
But feeling good and being done right were different matters.
I looked at the site as a single "product" and inspected it through the eyes of four experts. Senior web developer, UI/UX designer, security specialist, service developer. All four were AI, of course. But the points each raised from their own perspective were real.
The results were longer than expected.
First point: ignoreBuildErrors: true.
This is a setting I'd added weeks ago every time a build error appeared. "Build even if there are errors." By the logic of someone who doesn't know programming, it was reasonable. When an error appears, the site won't load, and if the site won't load, nothing moves forward—so load it first and think later.
The problem was—this was the same as cutting the seatbelt and driving.
TypeScript is a tool that checks whether types match in your code. Set "this variable must be a number," and if you accidentally put in a string, it warns you at the build stage. I'd turned on a setting that ignored all those warnings.
Fixing it took ten commits.
Second point: security.
The admin API had no input validation. What this means is—when someone sends data to the server, they could slip in arbitrary fields beyond the ones they're supposed to send ("title," "content," "status," and such).
The probability of a hacker coming to a solo-operated site is low. But "low probability" doesn't mean "you don't have to."
I made something called a whitelist. Define a list of allowed fields in advance, and discard everything not on the list. In code it looks like this:
const ALLOWED_FIELDS = ['title_ko', 'title_ja', 'title_en', 'desc_ko', ...];
function sanitizeBody(body) {
return Object.fromEntries(
Object.entries(body).filter(([key]) => ALLOWED_FIELDS.includes(key))
);
}
I didn't write a single line myself. AI wrote it. All I did was instruct: "there's this security vulnerability, fix it."
The third was a slightly embarrassing problem.
There was a huge empty space below the homepage. There were only nine entries, yet you had to scroll way down before the footer appeared. Looking for the cause, there were two. The hero area had "minimum height 75%" applied, and the content area had "fill all remaining space" attached.
I didn't know when building it. Attributes I'd added thinking "this'll look nice" created empty space when there were few entries. Things you only see after it's finished.
And the most confusing problem: the Git structure.
Inside the project folder there were two .git directories. One at the root, one inside site/. Both pointed to the same GitHub repository, but each was tracking code from a different point in time. Some edits were applied to the site/site/ path, some to site/.
This was a problem born from not properly setting up the structure when I first created the project. In Episode 02 I learned "planning comes before code," and that lesson repeated itself here.
Today I deleted site/.git and cleaned up the duplicate files. Three older prototype versions, three completed work orders, seven duplicated documents, empty folders, cache files. Altogether, over twenty unnecessary files had piled up in the project.
There's one thing I realized in this process.
Building is exciting work. You add a feature, something appears on screen, you press the deploy button and it's released to the world. There's a sense of achievement in this.
But inspecting is tedious work. Fixing type errors, security validation, removing empty space, organizing folders. This isn't making something new but tidying what's already made. Sometimes there's no visible change on screen.
For someone with only evenings, setting aside this tedious time separately is hard. There's the temptation to make one more new feature in the limited time.
So I decided to make it a rule. For every three new features, take one round of inspection time. The 3:1 rule.
If you've built a house, you sometimes have to look up at the roof.
🔧 Technical Terms in This Episode
ignoreBuildErrors A Next.js setting that forces the build to pass even when TypeScript type errors exist. Convenient in early development, but a dangerous setting at deployment because it prevents runtime errors from being caught at build time.
Input Validation / Whitelist The procedure by which a server inspects data received from outside. A whitelist "only lets through what's allowed." The opposite is a blacklist (only blocks what's forbidden), but in security, whitelisting is safer.
Git (.git)
A version control system for code. Records all change history. If there are two .git folders inside a project, two independent histories collide.
flex-1 / min-h
Attributes of CSS (a web styling language). flex-1 means "take up all remaining space," min-h means "maintain at least this height." When content is scarce, they can create unintended empty space.
Commit The act of saving code changes as a single unit. It means "record the state of the code at this point." Ten commits means there were ten meaningful changes.