Project metrics

A snapshot of the size and shape of the Mercator port. Numbers as of 2026-10-16 (after commit 2954f97, the end of phase 10), measured as described at the end.

History

First commit 2026-10-13 12:18
Latest commit 2026-10-16 11:11
Commits 295 (90 on 10-13, 90 on 10-14, 79 on 10-15, 36 on 10-16)
Working sessions (logs in docs/sessions/) 8 (one of two minutes without a log)
Working time 24 h 10 min active (35 h 8 min from first to last message)
Questions decided (#N) #1–#150
Phases 1–10 done
Demo live at https://biber.mittenin.at since 2026-10-15

Work sessions

From the timestamps of the Claude Code transcripts (local time). Active counts the time between messages, leaving out pauses longer than 15 minutes.

Session Date From – to Span Active Main topics
2a53ba5b 2026-10-13 11:57 – 18:52 6:55 5:36 analysis of the Rails app, roadmap, foundation, catalogue, checkout (first steps)
87be7c65 2026-10-13 19:13 – 19:19 0:05 0:05 setting up the session log export
3c7d3d68 2026-10-14 08:15 – 19:30 11:14 6:00 checkout completion, CMS, guided selling (chat, offers, emails, print)
4c06f629 2026-10-15 06:26 – 09:15 2:48 2:48 backlog, incidents, online payment, Docker
fafce14e 2026-10-15 11:21 – 17:50 6:29 3:47 demo mode, home server deployment, metrics, rate limits, Mollie
5090fc35 2026-10-15 18:44 – 22:28 3:44 2:01 Mollie test, back office payments, backlog, phase 9 documentation
998a2b77 2026-10-15 22:36 – 22:38 0:02 0:02 a question about the help links (no log)
d377cff1 2026-10-16 07:24 – 11:15 3:51 3:51 backlog, LiveDashboard, checkout address dialog, Docker docs, phase 10 video advice
Total 35:08 24:10

Code size

Line counts include blank lines and comments. LiveView templates are inline ~H in .ex files, so they are counted under lib.

Area Files Lines
lib/ (Elixir, incl. templates) 274 36,848
↳ lib/mercator/ (domains, resources, seeds) 17,126
↳ lib/mercator_web/ (LiveViews, components, controllers) 19,599
test/ (.exs tests + .ex support) 127 12,243
Migrations (priv/repo/migrations/) 42 2,623
Config (config/) 6 728
JavaScript (assets/js/, without colocated hooks) 5 616
CSS (assets/css/) 1 278
Typst document template (priv/typst/) 1 112
Translations (.po, de + en) 6 12,039
In-app documentation (priv/docs/, de + en) 59 1,759
Documentation (docs/, incl. session logs) 19 10,469

Without blank lines lib/ has 32,127 lines; tests are about 33 % of the application code. The repository tracks 821 files; the demo photos (assets/img/) are 105 MB. (The documentation is written one paragraph per line, so its line counts say little; see the word counts below.)

Structure

Ash domains 6
Ash resources 35
↳ Catalog / Sales / Content / Consulting / Accounts / Operations 13 / 7 / 5 / 5 / 3 / 2
Actions 204
Attributes 404
Relationships 82
Resources with policies 33
Resources with a state machine 8 (Category, Product, Order, Page, Conversation, Call, Offer, Incident)
Resources with history (AshPaperTrail) 1 (Page)
Database tables 40
Elixir modules 355
LiveViews 42 (22 in the admin area)
LiveComponents 6
Function component modules 16
Routes 80 (61 LiveView)
Oban workers 11 (3 cron jobs)
Direct dependencies (mix.exs) 45

Video advice (phase 10)

Self-hosted audio, video and screen sharing with Elixir WebRTC, from the design draft (09:00) to the documented, deployed and tested phase (11:11) in 17 commits on 2026-10-16:

Part Lines
Media relay (Calls.Room), call API (Calls), Call resource, watcher 774
Call area component 119
Browser side (call.js, ringtone.js) 378
Tests (incl. FakeBrowser, an ExWebRTC peer playing a browser) 702

Tests

Tests 732
Doctests 16
describe blocks 95
Test files 118
Full run (mix test) about 40–65 s

mix precommit runs all of them, plus compile with warnings as errors, format check, Credo --strict and Sobelow.

Translations

Domain Messages
default (UI) 1,038
errors 58
auth (sign-in pages) 26

German is complete; English uses the msgids, which are English.

Demo data (seeds)

A clean seed (Mercator.Seeds.run/0 on an empty database), plus the demo photos:

Products Variants Categories Properties Images CMS pages Orders Conversations (messages) Calls Offers Demo users
90 136 40 13 130 8 7 5 (34) 2 5 7

(The earlier snapshot counted the dev database, which also held data made by hand: 10 pages, 15 orders, 9 conversations, 12 offers.)

Documentation

The documentation compiled into the app (Mercator.Docs), counted as shown there (plain text, without front matter). The session logs as exported during the work, before the final export of the last session.

Part Language Chapters Words
Back office manual (by role) de / en 17 / 17 4,099 / 4,293
Operating guide de / en 6 / 6 1,608 / 1,716
Shop help de / en 5 / 5 1,142 / 1,218
Developers: overview and workflow en 2 853
Developers: design documents and roadmap en 10 18,779
Making-of: introduction and metrics en 2 901
Making-of: session logs en 7 87,640
Total 77 122,249

About 350 printed pages at 350 words each, nearly three quarters of it the session logs. Every admin page (27 routes) has a manual chapter behind its "?".

Compared with the Rails original

The Rails/Hobo shop (mercator-src/mercator), for orientation only. It also contains parts that are not ported (ERP, Icecat and Bechlem integrations, importer), and Hobo generates much of its UI.

Rails/Hobo (2013–2017) Phoenix/Ash (2026)
Commits 1,947 over 4 years 295 over 4 days
Models / resources 53 35
Model code 4,715 17,126 (lib/mercator/, incl. seeds)
Controllers, views (incl. DRYML), JS 17,303 20,493 (lib/mercator_web/, JS, CSS)
Test code 33,763 (spec/) 12,243

How measured

git rev-list --count HEAD                                  # commits
git log --format=%ad --date=short | sort | uniq -c         # commits per day
find lib -name '*.ex' | xargs cat | wc -l                  # lines (same for other dirs)
grep -rE '^\s*test "' test | wc -l                         # tests
grep -c '^msgid' priv/gettext/*.pot                        # messages (+1 header each)

The Ash numbers come from introspection in the running app (Tidewave project_eval or iex -S mix):

domains = Application.get_env(:mercator, :ash_domains)
resources = Enum.flat_map(domains, &Ash.Domain.Info.resources/1)
length(resources)
resources |> Enum.flat_map(&Ash.Resource.Info.actions/1) |> length()
Phoenix.Router.routes(MercatorWeb.Router) |> length()
# LiveViews and LiveComponents: the app's modules by their __live__ kind
{:ok, mods} = :application.get_key(:mercator, :modules)
Enum.count(mods, &(function_exported?(&1, :__live__, 0) and &1.__live__()[:kind] == :view))

Demo data counts come from a test that runs Mercator.Seeds.run/0 in the sandbox and counts the tables (rolled back afterwards); the images from the dev database after mix run priv/repo/seeds.exs.

The documentation numbers come from Mercator.Docs (words of each chapter's plain text, chapters in their own language only):

admin = %{roles: [:administrator]}
for part <- Mercator.Docs.parts(), locale <- ["de", "en"] do
  chapters = part |> Mercator.Docs.chapters(locale, admin) |> Enum.filter(&(&1.locale == locale))
  {part, locale, length(chapters), chapters |> Enum.map(&length(String.split(&1.text))) |> Enum.sum()}
end

Session durations come from the timestamp of every entry in the transcripts (~/.claude/projects/<project>/*.jsonl): the span is first to last entry; active time sums the gaps between consecutive entries that are at most 15 minutes long.