Skip to content
Metric VaultHelp Center
Open app

Repository structure

Every top-level file and directory in the production repository, what it is for, whether it ships, and which ones must never be edited directly.

Last updated 2026-08-06

Summary#

The production repository is flat by design. The worker, the customer app, the marketing pages and the admin console all sit at the root; supporting assets live in a small number of directories. Nothing is generated at build time except the staged dist/ copy, so what you see in the tree is very close to what is served.

This page enumerates the whole tree. Use it to answer three questions: what is this file for, does it ship, and is it safe to edit directly.

Overview#

Four rules explain most of the layout.

Root means "shipped as a page or a top-level asset". The deploy workflow stages every top-level *.html plus a named list of root files. If a file is at the root and is not in that list and is not HTML, it does not ship.

Directories ship whole or not at all. The workflow copies icons free-tools reports legal js css images recursively. Any other directory (partials/, i18n/, tests/, docs/, cron-worker/, chrome-extension/) is a source or tooling directory and never reaches production.

Three files are generated or mirrored and must not be hand-edited in their destination. LOGIN_HTML inside _worker.js mirrors login.html. The navbar and footer inside 21 public pages mirror partials/. js/mv-i18n-dict.<lang>.js is emitted by the translation generator. Editing the destination is silently overwritten by the next sync.

dist/ is a lie locally. It is git-ignored, rebuilt by CI on every deploy, and your local copy is whatever you last put there. It currently holds files CI would never ship.

Root files#

FileSizeShips?What it is
_worker.js1,710,142 B / 28,268 linesYesThe entire backend. Router, every /api handler, the inlined login page, the schema creators, the cron jobs. See The worker (_worker.js)
_headerssmallYesCache-Control overrides. no-cache, no-store, must-revalidate for /login.html, /login, /dashboard.html, /dashboard, /sw.js, /index.html, /. The first four also get Pragma: no-cache and Expires: 0
_routes.jsonsmallYesWhich paths invoke the worker. include: ["/*"] with 15 excluded paths that are served as pure static assets
.assetsignore196 BNoRoot copy is inert for the CI deploy: the workflow writes an empty dist/.assetsignore instead, and wrangler reads the one in the output directory
wrangler.tomlsmallNo (config)Pages-format config: name, pages_build_output_dir = "dist", compatibility_date, and the D1/KV/R2/AI bindings. Never port this file between repositories
dashboard.html7,223,279 B / 64,435 linesYesThe customer application. CRLF line endings. Owned by branch main
admin.html302,928 BYesThe operator console. English by design, excluded from the i18n pipeline
login.html75,840 BYes, but not servedThe sign-in page. _worker.js intercepts /login and /login.html and returns the inlined LOGIN_HTML copy instead
index.html242,812 BYesMarketing homepage. Owned by branch redesign
pricing.html210,307 BYesPricing page and the plan feature lists
blog.html, blog-post.html~40 KB eachYesPublic blog shell and post template
legal.html54,548 BYesLegal hub, CRLF line endings
404.html5,961 BYesDeliberately chrome-less. Served by the worker with a real 404 status
ext-preview.html41,842 BYesInternal extension preview page
manifest.json644 BYesPWA manifest. Excluded from the worker by _routes.json
sw.js3,155 BYesService worker. CACHE_NAME is bumped to evict stale client caches after a deploy
robots.txt, sitemap.xmlsmallYesAlso emitted inline by the worker at /robots.txt and /sitemap.xml
chat-widget.js79,671 BYesThe Metric Vault Assistant. One engine, three surfaces. Loaded by index, pricing and dashboard. Shared file, in the design-lint targets
pwa-install.js13,826 BYesInstall banner
blog-embed.js14,835 BYesThird-party embed script for customer blogs
chatbot.js584 BYesA deliberate no-op stub. Pages auto-injects a <script src="/chatbot.js"> tag; shipping a valid empty file stops that resolving to an HTML 404 body
admin-supabase-setup.sql, admin-supabase-full-setup.sql-NoManual Supabase schema, run by hand in the SQL editor. Nothing applies them automatically
CLAUDE.md-NoProject instructions loaded by AI sessions
README.md-NoRepository readme
metricvault-extension*.zip14-45 KB eachNoChrome Web Store build archives, produced by the zip command in chrome-extension/README.md. -v2.1.1 matches the current manifest.json version and is the artifact that was uploaded; the unversioned copy is byte-identical to it. Not staged

Icons and images at the root that do ship: favicon.ico, favicon-16x16.png, favicon-32x32.png, apple-touch-icon.png, icon-192.png, icon-192.svg, icon-512.png, icon-512.svg, logo-dark.png, logo-light.png, og-image.png.

Directories#

DirectoryShips?Contents
css/Yes24 stylesheets plus a README. tokens.css is the only place tokens may be defined; legacy-mvx.css (1.05 MB, 12,046 lines) is frozen and may only shrink
js/Yes24 classic scripts plus vendor/supabase-2.38.0.umd.js. No modules, no bundling, no defer by convention
free-tools/Yesindex.html plus 11 public tool pages
legal/Yesprivacy.html, terms.html, gdpr.html, security.html
reports/Yes9 static sample reports used by marketing
icons/, images/YesSidebar icons and platform imagery
partials/Nosite-nav.html, site-footer.html and extras/. Source for the centralized chrome, stamped into pages by tests/site-chrome-sync.mjs
i18n/Nostrings.en.json and dict.{es,fr,pt,de,ru}.json. Pipeline inputs; the shipped dictionaries are js/mv-i18n-dict.<lang>.js, one per language
tests/No19 Node verification scripts plus design-lint-baseline.json and a README. See Verification scripts
docs/NoDESIGN-CONSTITUTION.md, handoffs, guides, and docs/kb/ (this knowledge base)
cron-worker/NoA separate Cloudflare Worker with its own wrangler.toml and its own deploy
chrome-extension/NoExtension source
dist/git-ignoredThe staged copy CI assembles. Locally it is whatever you last copied there
.wrangler/git-ignoredLocal wrangler state: state/v3/{cache,d1,kv,r2,workflows}
.github/Noworkflows/deploy.yml and workflows/cron.yml. Never port deploy.yml between repositories

css/ in full#

FileBytesScope
tokens.css4,051The single source of truth for color, spacing, radius, shadow and type tokens. Light :root, dark under [data-theme="dark"]
app.css105,939Dashboard chrome: the 3-column shell, rail, sidebar, topbar, cards. Re-declares :root with the dark palette and puts light behind [data-theme="light"]
legacy-mvx.css1,050,377The frozen .mvx stylesheet. Holds the 11 forked token definitions the ratchet tracks
mvr.css44,883The .mvr-* result-panel component system
mvr-premium.css9,192Additive premium layer, loaded last in <head>
site-chrome.css24,088Public navbar and footer, namespaced .mv-*
chapter-demos.css20,723Homepage mini-dashboards, .cd-*. Index only
blog.css72,633Blog Studio, .mvblog-*
tool-explainer.css23,767In-app explainers, .mvte-*
rec-panel.css16,832Recommendations panel, .mvrec-*
psi.css23,194PageSpeed report, .psi-*. Outside the design-lint targets so it can keep Google's exact palette
library.css13,231Library timeline, .mvlib-*
library-saved.css18,023Saved-results prompt, .mvsv-*
responsive-analyzer.css24,068.ra-*
image-tool.css27,069.it-*
content-checks.css14,379.mvcc-*
content-decay.css3,049.cd-* scoped under #view-contentdecay. Shares a prefix with chapter-demos.css but the two are never on the same page
advtech.css8,730.mvat-*
social.css12,214.mv-soc-*. Brand colors live here deliberately, outside the ratchet
notifhub.css3,252.nh-*
merge-tabs.css1,050.mvmg-*
tech-guide.css5,129.mvtg-*
gbp.css2,889.gbp-*
dev-placeholder.css1,809.mvdev-*, for announced-but-unbuilt tools

js/ in full#

FileBytesPurpose
mv-i18n-dict.<lang>.jses 2,949,060 … ru 3,990,234 (one downloaded per visitor)Generated. window.MV_I18N keyed by English source string. Loaded lazily on first non-English language
tool-samples.js467,002window.MV_TOOL_SAMPLES, captured real results for the "See example" preview. Data, not UI; excluded from the i18n scanner
mv-blog.js239,357Blog Studio, a multi-site CMS inside the app
mv-library.js62,383Library and Saved Work
mv-guide-rules.js39,313The "Get recommendations" rule table
mv-export.js31,071Shared PDF/Excel/CSV/JSON export engine
mv-psi.js31,081PageSpeed report renderer, shared with the free tool page
rec-panel.js22,868Recommendations panel controller
mv-charts.js20,909Shared chart wrappers over Chart.js
mv-content-checks.js19,941Plagiarism and fact checking
mv-modal.js16,499mvAlert, mvConfirm, mvPrompt. Shared file
mv-advtech.js14,864Advanced Technical Checks
mv-polyfills.js13,470Globals the premium renderers reference by bare name. Do not reorder
mv-i18n-runtime.js11,742The shared translation runtime for every page except dashboard.html
tool-explainer.js9,861Motion for .mvte explainers
mv-combined.js7,954Merged tools: run a primary view and its siblings together
mv-particles.js7,087Vanilla particles background
chapter-demos.js6,720Homepage chapter animations
mv-merge-tabs.js5,640Tab strip for merged tools
mv-site-chrome.js5,478Mobile hamburger for the shared navbar
mv-helpers.js5,348Extracted utilities such as mvRelativeTime and mvDownloadCsv
mv-reveal.js4,632Scroll-reveal, disabled under reduced motion
export-gate.js2,107Disables export controls until a tool has a result
kgap-vs.js2,075Gap Finder dual-field sync
vendor/supabase-2.38.0.umd.js98,746Self-hosted Supabase SDK

Files that must not be edited in place#

DestinationReal sourceSync command
const LOGIN_HTML in _worker.jslogin.htmlnode tests/login-inline-sync.mjs --write
Navbar and footer inside 21 public pagespartials/site-nav.html, partials/site-footer.htmlnode tests/site-chrome-sync.mjs --write
js/mv-i18n-dict.<lang>.js (five)i18n/strings.en.json and i18n/dict.*.jsonnode tests/i18n-generate.mjs --emit
help/docs/kb/**/*.mdnode tests/kb-build.mjs --write
dist/the repository rootthe deploy workflow, or a manual copy for local dev

Each of the first three has a no-argument drift check that exits 1 when the two sides disagree. Run them before committing.

File-ownership rules#

Two developers share this repository, and the split is by file rather than only by branch, because git merges cleanly when two branches touch different files.

FileOwnerRule
index.htmlbranch redesignDo not edit from any other branch
dashboard.htmlbranch mainDo not edit from redesign. 7.2 MB and CRLF; two simultaneous editors produce an unusable merge
css/tokens.csssharedA change for one page restyles every page. Say so explicitly before editing
css/app.css, js/mv-modal.js, chat-widget.jssharedLoaded by both the marketing site and the app
The site footercopy-pasted into 20+ pagesAny edit is a 20-file diff. Do the whole set in one commit or not at all

Full detail, including the pre-commit checklist, is in Code conventions and file ownership.

Line endings#

dashboard.html and legal.html use CRLF. A search-and-replace written for \n matches nothing in them; use \r?\n. login.html is also CRLF, but ECMAScript normalises CRLF to LF inside a template literal, so the inlined copy is LF and login-inline-sync.mjs compares line-ending agnostically. Several public pages have mixed endings, so site-chrome-sync.mjs preserves untouched regions byte for byte and inserts using each file's dominant EOL.

See also

Was this article helpful?