Module 3: Exporting, Normalizing, and Structuring the Repository
8. Project: from instance to documented repository
Description
By the end of this lesson you will have produced, end to end, the module's central deliverable: turning Cumbre's n8n instance —with its four workflows and its credentials— into the cumbre-automations repository, normalized, documented, with automated export via script, credentials out of the repo, and a correct .gitignore. The result is a repository that would pass another developer's review: exactly what job postings describe when they ask for "version-controlled, documented JSON."
This matters because it's proof that the seven previous lessons fit together. Up to now you practiced each piece separately: exporting, separating secrets, normalizing, structuring, documenting, automating. The project joins them in the right order and shows you the whole is more than the sum —a professional repository isn't "doing the seven things," it's doing them in the sequence that avoids the accidents. And it leaves you a real artifact: not an exercise to discard, but a repository you can show off in an interview and defend.
Connection to the module: this lesson doesn't introduce new concepts; it integrates every concept in the module. Each phase of the project is a previous lesson put in its place within the full flow. Pay attention to the order of the phases, because that's where the lesson no single lesson could give on its own lives: why the .gitignore comes before exporting, why documentation comes after structure, why the security check comes before the commit. When you're done, you close the first of the guide's three visual phases —"version workflows with Git"— and you're ready for Module 4, where that clean repository becomes the source for three isolated environments.
A project is a dress rehearsal of the real work
Before getting hands-on, a word about what this project is and isn't.
It isn't a toy exercise. It's a dress rehearsal of the real work, in the theatrical sense: the full performance, in order, of what you'd do on day one at a job asking you to deliver versioned automations. When a company hires you to "get n8n's workflows in order and leave them versioned and documented," you're going to do, almost step by step, what you do here with Cumbre. That's why it's worth doing seriously, as if the CRM were real and the key you're protecting were worth real money —because in the real job, it will be.
Think of it as the dress rehearsal of a play before opening night. In the dress rehearsal, you run the whole show, with costumes and lights, no audience. You're not learning a new scene; you're testing that all the scenes you already rehearsed separately flow together without stumbling. This project is your dress rehearsal: the show is "instance to documented repository," and the scenes are the seven lessons. If a scene trips up, that's where you discover what you hadn't fully understood —and better to discover it in rehearsal than on opening night.
There's a hidden reward in doing it in order and seriously: when you're done, you won't just "know about" versioning workflows, you'll have it done. The distance between those two things is huge in an interview. Anyone can say they understand .gitignore; very few can open a real repository, point at the line that protects the secrets, and explain why it's where it is. This project puts you on the second side.
A note about the starting point. The project assumes you already have, from Module 2, a cumbre-automations repository initialized with Git (with git init already done), and an n8n instance with Cumbre's workflows. If you're following the guide with your own instance, use your real workflows; the shape is identical. If you don't have an instance handy, read the whole project anyway: the sequence and its logic come through just the same, and you run them when you have the environment.
Worked example: the full project, phase by phase
Let's build cumbre-automations in eight phases. Each phase opens with where you are and closes with what to expect, so you always know if you're on track.
Phase 0 — Where you are: the instance and the empty repo
Starting point: an n8n instance with Cumbre's four workflows —order-triage, inventory-sync, weekly-report, support-autoresponder— and their credentials, plus a cumbre-automations folder with Git initialized and, for now, practically empty. Stand inside it:
cd cumbre-automations
What to expect: git status shows you a repository with nothing relevant yet (maybe a minimal README from Module 2). It's the blank canvas. From here we build.
Every command that follows assumes the guide's Docker scenario (docker exec -u node "$CONTAINER" ...). If your n8n is installed with npm on your machine, you already know from lesson 2 how to adapt them: drop the docker exec ... prefix and run n8n export:workflow directly, with no need for docker cp. The project's logic is identical in both scenarios; only how you call the CLI changes.
Phase 1 — Shield the secrets, BEFORE anything else
Where you are: empty repo, about to start adding files. This is the phase that goes first, and the order isn't negotiable. Before exporting a single workflow —and long before touching a credential— you put up the safety net, so no secret can slip in even by accident.
Create the .gitignore in the root, with lesson 3's content:
# --- Secrets: never to the repository ---
.env
.env.*
!.env.example
credentials/*.json
*.credentials.json
credentials-backup.json
*-decrypted.json
.n8n/
# --- System noise and temp files ---
node_modules/
.DS_Store
.export-raw/
(Notice two adjustments from lesson 3: credentials/*.json ignores any .json inside credentials/ but lets its README.md through; and we add .export-raw/, the temp folder lesson 7's export.sh uses.)
And lesson 4's .gitattributes, for line endings:
*.json text eol=lf
What to expect: two new files in the root, .gitignore and .gitattributes. There are no secrets to protect yet, and that's exactly the point: the net goes up before there's anything that could fall through. Putting the .gitignore first is the decision that makes the whole export phase that follows safe.
Phase 2 — Structure the skeleton
Where you are: the secrets are already shielded. Now you give the repo shape, with lesson 5's layout.
mkdir -p workflows credentials docs scripts
touch docs/.gitkeep
Create the .env.example in the root, with the secret variable names and no values:
# .env.example — copy to .env and fill in YOUR values. .env is NOT uploaded (see .gitignore).
CRM_API_KEY=
LLM_API_KEY=
STORE_API_KEY=
DB_CONNECTION_STRING=
SMTP_PASSWORD=
And the credentials inventory in credentials/README.md, without values:
# Required credentials
Real values do NOT live in this repo. Only what's needed is documented here.
| Workflow | Credential | Type | What for |
|---|---|---|---|
| order-triage | Cumbre CRM key | Header Auth | Reading customer data in the CRM |
| order-triage | Cumbre LLM key | (language model) | Classifying the order with the AI Agent |
| inventory-sync | Store API | Header Auth | Reading stock from the online store |
| weekly-report | Reporting DB | Postgres | Reading the week's sales |
| weekly-report | Ops mailbox | SMTP | Sending the report |
| support-autoresponder | Support mailbox | IMAP/SMTP | Reading and replying to emails |
| support-autoresponder | Cumbre LLM key | (language model) | Drafting the reply |
What to expect: four folders (workflows/, credentials/, docs/, scripts/), the .env.example, and credentials/README.md. The skeleton is standing, still with no content in workflows/. git status should show these new files and should not show any real .env (you didn't create one, but if it existed, it would be ignored).
Phase 3 — The export script
Where you are: skeleton ready, no workflows yet. Before exporting by hand, you put in place the machine that does it for you: lesson 7's export.sh. Create it at scripts/export.sh with that lesson's full content —including the dependency check— and make it executable:
chmod +x scripts/export.sh
What to expect: scripts/export.sh exists and is executable. You haven't run it yet; it's just ready. Putting it in place before the first export means even your first export is reproducible: you never do the process "by hand once and with a script afterward," you do it with a script from the start.
Phase 4 — Export and normalize in one pass
Where you are: the script ready, workflows/ empty. Now you run the script and watch the whole module's magic condensed into one command. From the repo's root:
./scripts/export.sh
What to expect: the terminal prints the four steps, and at the end workflows/ has the four files with readable, already-normalized names: order-triage.json, inventory-sync.json, weekly-report.json, support-autoresponder.json. Open them: no pinData, no versionId, no meta.instanceId, keys sorted. A glance at order-triage.json confirms its credentials block has only references (id and name), not values. The secrets are still out; the logic is in, clean.
This is the moment where the module "clicks": what in lesson 1 were five gaps in the editor's button, is now a command that produces reproducible, secret-free material with clean diffs.
Phase 5 — Document for handoff
Where you are: workflows exported and clean, but still unexplained. Now lesson 6: a README per workflow in docs/, plus the root README.
Create docs/order-triage.md with lesson 6's full template —purpose, trigger, dependencies, required credentials, variables, input contract, Mermaid diagram, and notes/assumptions. Repeat, more briefly, for the other three workflows: each deserves at least a purpose, trigger, dependencies, credentials, and a diagram. They don't have to be long; they have to be enough (remember the stranger test).
Add the root README.md with lesson 5's five answers: what it is, what's inside, how to get it running, how to maintain it, where the secrets are.
And, optionally but recommended, open each workflow in n8n's editor and add a header sticky note with its purpose and a pointer to its doc. On re-export, those notes travel in the JSON.
What to expect: docs/ with a .md per workflow, a root README.md that orients, and credentials/README.md from phase 2. A stranger opening the repo now can understand what each workflow does and how to start it. The .gitkeep in docs/ is now unnecessary —delete it, the folder has real content.
Phase 6 — Security check, before touching history
Where you are: all the content is in place. Before committing —never after— you do the security review. It's the last checkpoint before anything enters Git's permanent history.
git status
Review the list with an auditor's eye. These should appear: workflows/, docs/, credentials/README.md, scripts/export.sh, .env.example, .gitignore, .gitattributes, the README.md. These should not appear, under any circumstance: any .env with values, any credential exports (*-decrypted.json, credentials-backup.json), the .n8n/ folder, or the temp .export-raw/.
As a double-check, actively search for anything shaped like a secret in what you're about to commit:
git diff --cached
(If you haven't run git add yet, look with git diff first.) Read it looking for sk-, Bearer , password, long keys. If you find a secret, stop: remove it, and if it already made it into a file that got exported, consider rotating that credential. Better a minute of paranoia now than an incident later.
What to expect: git status's list contains only files that should travel, and no secrets. If something doesn't add up, the problem is almost always a missing pattern in .gitignore (phase 1) —fix it before continuing.
Phase 7 — Commit the deliverable
Where you are: verification passed, zero secrets in sight. Now, yes, you —not me, not the script— decide what enters history. Add the files you reviewed and commit with a clear message:
git add .
git commit -m "Initial repository: workflows exported, normalized, and documented"
(And if the repo has a GitHub remote from Module 2, git push backs it up and makes it shareable.)
What to expect: a commit that captures the whole repository. git log shows it; git show --stat HEAD lists which files went in —review it once more to confirm nothing improper slipped through. With this, cumbre-automations is a real deliverable.
Optional phase — Back up the credentials, outside the repo
Where you are: the repo committed, with the secrets correctly out. But "out of the repo" can't mean "without a backup": Cumbre's credentials also need a backup copy, just elsewhere. Close lesson 3's loop with an encrypted backup that lives far from the repository.
docker exec -u node "$CONTAINER" n8n export:credentials --all --output=/tmp/creds-backup.json
docker cp "$CONTAINER":/tmp/creds-backup.json ~/secure-backups/cumbre-creds-backup.json
Notice two deliberate decisions: it's without --decrypted (it comes out encrypted, not plaintext), and the destination is ~/secure-backups/, a folder outside the cumbre-automations tree, not inside. That encrypted backup, to be restored, needs the same N8N_ENCRYPTION_KEY that encrypted it, so save that key too in your password manager —separate from the backup, like the combination and the safe from lesson 3.
What to expect: an encrypted backup file in a secure spot, and zero trace of it in the repository. git status inside cumbre-automations should show nothing new: the backup lives in another universe. With this, your credentials are backed up and out of the repo, exactly the balance lesson 3 was chasing.
How it's reviewed: the other developer's rubric
The project's standard isn't "I did the eight phases"; it's "another developer would approve this repo." It's worth seeing it through their eyes, because that's the review that matters. This is the list a competent reviewer would judge cumbre-automations by, grouped by what each lesson contributed:
Security (lesson 3) — what gets reviewed first and most harshly:
- No credential value is in the repo, encrypted or plain.
-
.gitignorecovers.env, credential exports, and.n8n/. -
.env.examplehas the variable names but no values. - Git's history (not just the current state) is clean of secrets.
Export and cleanup (lessons 2 and 4):
- Workflows are exported via CLI, not downloaded by hand.
- The JSON is normalized: no
pinData,versionId,meta.instanceId; keys sorted. - A save with no logic changes would produce an empty diff after normalizing.
Structure (lesson 5):
- Clear layout:
workflows/,credentials/,docs/,scripts/, config files in the root. - Readable
kebab-casefilenames, not ids. - The repo's organization mirrors the instance's.
Documentation (lesson 6):
- A README per workflow with purpose, trigger, dependencies, credentials, and diagram.
- A root README that lets you get started without asking the author.
- The stranger test passes: someone could get a workflow running with just the docs.
Reproducibility (lesson 7):
- An
export.sh(or equivalent) exists that reproduces the repo's state from one command. - The script is documented in the README as the way to maintain the repo.
If your cumbre-automations checks all these boxes, it isn't an exercise: it's a portfolio artifact. The box most people fail is the fourth security one —"the history is clean"— because they review the current state and forget that a committed-then-deleted secret is still in the history. Review it carefully.
Defending the repo in an interview
This repository isn't just a finished exercise: it's a portfolio artifact, something concrete you can show and defend when someone asks you "do you know how to deliver automations like a professional?" It's worth thinking ahead about how you'd present it, because the questions you'd get asked are the same ones this module answered.
If an interviewer opens your cumbre-automations and asks you, you should be able to answer without hesitating:
- "How do you guarantee a credential doesn't leak?" — You show the
.gitignorein place since the first commit, explain that not even encrypted credentials go into the repo (the other half of the lock, the permanent history), and that the reference in the JSON is a pointer, not a secret. That answer alone sets you apart from most candidates. - "Why are your diffs so clean?" — You explain normalization: the volatile fields you remove and the stable key order, and demonstrate that a save with no logic changes produces an empty diff. Very few people can give this answer, and it reveals you understand what's inside the JSON.
- "How do you keep this up to date?" — You show
export.shand explain that one command reproduces the repo's state, and why reproducibility is what makes automating it possible. - "Could someone else pick this up without you?" — You apply the stranger test live: you open a workflow README and show that someone could start it with just that.
Notice the pattern: every question a good interviewer would ask, this module turned into a design decision you can point to in your own repo. You're not describing theory; you're showing evidence. That's the difference between saying "I know how to use n8n" and demonstrating "I own an automation system" —and it's, word for word, what the best job postings ask for.
Keep this repo. Polish it. When you finish the whole guide —with Module 4's environments, Module 5's tests, and Module 6's promotion— it's going to be the project you show off, and each module adds a layer that answers another interview question.
Common mistakes
Exporting before setting up the .gitignore (practical, and the most serious ordering mistake). What happens: someone, excited to get started, runs export.sh or exports credentials before creating the .gitignore, and the very first export generates a file that, with no net in place, a git add . catches. Why it happens: it seems natural to "bring in the content first, organize it later." With secrets, that order is dangerous. How to spot it: if your first commit includes something that should have been ignored, you swapped the order. How to fix it: .gitignore is always phase 1, before generating any file. The project's sequence is designed precisely so the net exists before anything that could fall through it.
Committing without the verification phase (practical). What happens: someone jumps from "I finished documenting" straight to git add . && git commit, skipping the audit git status and git diff, and drags a secret or a temp file into history. Why it happens: verification feels like an optional step when you're in a hurry. How to spot it: if you commit without explicitly looking at what you're committing, you're missing the verification. How to fix it: phase 6 isn't optional; it's the quality control before touching history. Always look at what's going in before it goes in. Reviewing is cheaper than repairing.
Documenting the four workflows with the same depth as the JSON, adding no value (conceptual). What happens: someone, to "document completely," describes each workflow node by node, repeating what the JSON already says, and never writes the purposes or the assumptions. Why it happens: describing the how is easy; thinking through the why takes effort. How to spot it: if your documentation can be reconstructed just by looking at the canvas, it isn't adding anything. How to fix it: focus on what the JSON doesn't say —purpose, assumptions, what to watch— and leave the how for the diagram. The stranger test is your judge: where that person gets stuck, docs are missing; where they get bored, there's excess.
Duplicating the workflows per environment "to get ahead of Module 4" (conceptual). What happens: someone, knowing three environments are coming, creates workflows-dev/, workflows-staging/, and workflows-prod/ with copies of the same order-triage.json. Why it happens: they confuse "three environments" with "three copies of the logic." How to spot it: if the same workflow is in your repo three times, this is it. How to fix it: the logic gets versioned once; what changes per environment is the configuration, not the workflow, and Module 4 handles that with a separate folder. One workflow, many environments. Duplicating the logic guarantees that one day you'll fix a bug in one copy and leave it in the other two.
Exercises
Exercise 1 — Self-assess with the rubric. Take your finished cumbre-automations (or the one you built following the project) and go through it with the other developer's rubric, box by box. Note which ones you can check confidently and which you can't. For each box you can't check, write in one sentence what's missing.
See solution
There's no single answer; the result is your diagnosis. What most people discover is that the security and structure boxes get checked easily, and the two that stay weak are: the clean history one (because people review the state, not the history) and the stranger test one (because you document from the knowledge you already have in your head).
If you can't check a box, that's exactly your next task, and it's small and concrete: not "improve the repo" in the abstract, but "add the purpose to weekly-report's README" or "confirm with git log there are no secrets in the history." The rubric turns "is my repo okay?" into a list of specific actions.
Why it works: learning to review yourself through someone else's eyes is the skill this whole module chases. The rubric is the scaffold for doing it before someone actually reviews you —in an interview, in a pull request. Every box you fix is a comment they won't have to make.
Exercise 2 — Justify the order of the phases. Without looking back at the project, explain in one or two sentences why each of these orders is correct: (a) the .gitignore (phase 1) before exporting (phase 4); (b) the structure (phase 2) before documenting (phase 5); (c) the security check (phase 6) before the commit (phase 7).
See solution
(a) The .gitignore goes before exporting because exporting can generate files with secrets (especially if you touch credentials), and .gitignore only protects the future, not the past: put in place afterward, it doesn't remove from history what already slipped through. The net goes up before there's anything that could fall through it.
(b) Structure goes before documentation because documentation lives inside the structure —the READMEs go in docs/, which has to exist first— and because documenting makes sense once you already know where everything lives. Skeleton first, then flesh.
(c) Verification goes before the commit because the commit is what makes the content permanent in Git's history. Verifying after committing is reviewing when it's already too late: a committed secret is already in the history even if you delete it. Quality control goes before the line that can't be undone, not after.
Why it works: the order of the phases isn't chronological by chance; it's causal. Each phase enables or protects the next. Understanding why that order —and not another— is what lets you improvise with judgment when a real project doesn't match Cumbre's exactly. The sequence is the lesson; the individual phases are just tasks.
Exercise 3 — Simulate a change and its full cycle. Imagine that tomorrow you change order-triage's threshold in the editor from 1500 to 2000. Write the exact sequence of steps you'd follow so that change reaches the repository cleanly, from saving in the editor to the commit.
See solution
The sequence: (1) you save the change in n8n's editor; (2) from the repo's root, you run ./scripts/export.sh, which re-exports and normalizes the four workflows; (3) you run git diff to review the change —and here's normalization's payoff: the diff shows only the threshold line, 1500 → 2000, and nothing else; (4) if the logic change affects the documentation (here, the PRIORITY_THRESHOLD variable in docs/order-triage.md), you update it in the same cycle; (5) git status to confirm nothing improper slipped through; (6) git add and git commit -m "order-triage: raise the urgent-shipping threshold to 2000".
The elegant part is that this cycle —edit, run the script, review the clean diff, update the doc, verify, commit— is the same for any change, small or large. It's the habit the whole module built, condensed into six steps that become automatic.
Why it works: a project doesn't end when you deliver it; it starts living. This exercise moves you from "I set up the repo once" to "I maintain the repo every time something changes," which is where the real work happens. A professional repository isn't the one that was born organized, it's the one that stays organized after fifty changes, and that only happens with a repeatable cycle like this one.
Summary and next step
In this lesson you integrated the whole module into a real deliverable. You turned Cumbre's instance into the cumbre-automations repository, in eight phases whose order is the lesson: first you shielded the secrets with .gitignore (because it protects the future, not the past), then you structured the skeleton, set up export.sh, exported and normalized in one pass, documented for handoff, checked security with an auditor's eye —before touching history— and only then committed, deciding yourself what goes in. And you saw the project through the eyes of whoever reviews it, via a rubric grouped by security, export, structure, documentation, and reproducibility, with the warning that the most-forgotten box is the clean history one, not just the state.
With this you close Module 3 and the guide's first phase: "version workflows with Git." You already know how to build workflows (previous guides), version them with Git (Modules 1 and 2), and —now— export, clean, structure, document, and automate all of that into a repository another developer can pick up. You crossed over from "workflow builder" to someone who delivers a system.
Module 4 opens the second phase. Up to here, cumbre-automations is a repository; starting with Module 4 it becomes the source of truth for three isolated environments —dev, staging, and prod— each a separate n8n instance, brought up with Docker Compose, with its own N8N_ENCRYPTION_KEY and its own test or production credentials. You're going to see why a real environment isn't "another browser tab," how one gets isolated from another, and how the separation between "shared logic" and "per-environment configuration" you already started designing here becomes the backbone of a professional deployment. The repository you just delivered is exactly what Module 4 needs to get started.
Resources
- Export and import workflows — n8n Docs — the export and import reference, the basis for the project's export phase.
- Use the command line — n8n Docs — every CLI command
export.shorchestrates, to consult while you build. - Set a custom encryption key — n8n Docs — the
N8N_ENCRYPTION_KEYyou shielded in this module and that Module 4 will use per environment. - git commit — Git Documentation — the reference for the command that closes out the project, for writing clear commit messages.
- About READMEs — GitHub Docs — how GitHub presents your root
READMEas the cover of the repository you just delivered. - gitignore — Git Documentation — the
.gitignorereference you shielded in phase 1, for fine-tuning patterns if a secret slips intogit status. - Docker installation — n8n Docs — how n8n runs on Docker, useful for confirming your container's name and volumes while running the project.