The Great Reshuffling

obscura breaking change architecture

Every project gets its first breaking change eventually. Most wait until they're mature, battle-tested, widely adopted. Obscura? We couldn't even make it to version 1.0 before rearranging the furniture. In our defence, the furniture was in the wrong rooms.

What Changed

All user-owned content now lives under a single site/ directory:

site/
  config/        ← was config/
  content/       ← was content/
  themes/        ← new: your custom themes go here

Everything else in the repository — src/, themes/, docs/ — is Obscura's engine code. The line is drawn. One side is yours, the other side is ours. No more guessing.

If you're on an existing setup, run:

npm run migrate

It detects the old layout and moves things into place. That's it. If you prefer to do it by hand: mkdir site && mv config content site/. Either way, it's a one-time operation.

Why We Did This

Three reasons, in order of how much they annoyed us.

1. Custom Themes Had Nowhere to Live

This was the trigger. If you wanted to tweak the editorial theme — change a colour, adjust a layout — you had to modify files in themes/editorial/. The same themes/editorial/ that ships with Obscura. The same one that gets overwritten when you pull upstream updates. Oops.

Now there's a proper place: site/themes/. Drop a theme there, and Obscura checks it first before falling back to the built-in one. Fork the editorial theme, go wild, and never worry about git pull stomping your changes.

2. The Mental Model Was Muddy

In the old layout, your config sat next to Obscura's source code. Your photos lived at the same level as TypeScript files and CI configs. It worked — but you had to know which directories were yours and which belonged to the engine.

Now it's one rule: site/ is yours, everything else is Obscura's. That's the whole mental model. You can explain it in a sentence, which is exactly how many sentences a directory layout should require.

3. The .gitignore Was Getting Weird

Here's a question that tripped up more people than we'd like to admit (well, honestly, I have to admit there aren't that many people yet): "Can I commit my config to git?" The old answer was a hesitant "well, those directories aren't tracked by default, but they're not gitignored either, except for photo binaries, which are gitignored by extension inside content/photos/, but sidecar YAMLs next to those photos are fine, and—"

The new answer: everything under site/ is committable, except photo binaries (because a portfolio of RAW files doesn't belong in a git repository, and your hosting provider's storage limits agree). Config, posts, pages, sidecar metadata — all fair game. The .gitignore is short, obvious, and doesn't require a flowchart to understand.

What This Means for You

New users: Nothing. npm run init already scaffolds into site/. You're starting with the right layout.

Existing users: Run npm run migrate. Update any personal scripts or shortcuts that reference the old config/ or content/ paths. If you've been building Obscura from a fork, this is the cleanest upstream merge you'll ever get — your content is in site/, ours stays outside it, and the two don't collide.

Theme tinkerers: You now have a home. Copy a built-in theme to site/themes/, rename it, and make it yours. Obscura resolves site/themes/ first, built-in themes/ second. No patches, no workarounds.

The ADR

If you're the type who wants the full reasoning — trade-offs, alternatives considered, consequences — we wrote it all down in ADR-014. Architectural Decision Records are how we make sure future-us remembers why past-us did something. Especially useful when past-us decided to ship a breaking change before lunch.

Was This Worth a Breaking Change?

Honestly? Yes. The old layout was a source of friction — small, constant friction that would only compound as more people started using Obscura and customising themes. One migration command now saves everyone a hundred future headaches.

Besides, if you're going to break things, do it early — before the crowd shows up.