#+TITLE: README for ogit #+AUTHOR: Marius Peter #+DATE: <2025-05-13 Tue> * Objective A lightweight, mobile-friendly alternative to cgit. * Architecture The executable in =bin/main.ml= loads configuration and delegates to =lib/main.ml=. Startup fails visibly when an explicitly selected configuration file is missing or when configuration cannot be parsed or validated. Requests flow through the following layers: 1. =Routes= defines bidirectional, type-safe paths used for both Dream route registration and generated links. 2. =Handlers= opens and validates one repository context per request, maps application errors to HTTP statuses, and coordinates data access with rendering. 3. =Resolvers= provides repository discovery and Git data access. An opened repository context owns its Git store, resolved metadata, and default-branch policy so operations in one request reuse the same store. 4. =Views= renders data supplied by handlers. Views do not access the filesystem or load configuration. 5. =Static_handler= serves assets embedded at build time by =ocaml-crunch=. Resolver failures retain their category until the HTTP boundary: malformed input becomes =400 Bad Request=, missing repositories or Git objects become =404 Not Found=, and storage or filesystem failures become =500 Internal Server Error=. ** View layer The view layer is split into three levels so that page code stays declarative: 1. =Ui= is the only module that names HTML elements. It is generic: it knows nothing about Git or ogit's routes, and every function takes plain strings and already-built nodes. It supplies links, lists, disclosures, breadcrumbs, toolbars, pagination, line-numbered code listings, a diff viewer, and document scaffolding. The class names it emits are its contract with =styles.css=. Its public surface is fixed by =ui.mli=, which also carries the module's documentation; attribute plumbing stays private, so callers compose blocks rather than assembling attributes. 2. =Components= names ogit's page parts — navigation bars, repository rows, tree rows, commit-type badges — and wires them to =Routes=, so URLs are never written by hand. =Layout= composes the page shell. 3. =Root= and =Repo= describe pages: they say which parts a page is made of and hand them to =Layout=. Neither contains markup. Supporting logic lives beside them rather than inside the page descriptions: =Syntax= guesses a blob's language for highlighting, and =Time_fmt= formats Git dates. =Charts= generates standalone SVG. * Documentation API documentation is generated with odoc: #+begin_src sh dune build @doc #+end_src The entry point is =_build/default/_doc/_html/index.html=. =scripts/docs.sh= runs the same build and opens that file in a browser; =scripts/docs.sh --print= prints the path instead. The landing page at =doc/index.mld= orders the modules by the request flow described above. =doc/conventions.mld= records where documentation is expected to live. Unresolved type links pointing into Dream, Toml, Git or dream-html are expected: those packages' own documentation is not built here. * Configuration Ogit reads the path named by =OGIT_CONFIG=. Otherwise it checks =$XDG_CONFIG_HOME/ogit/config.toml= and finally =/etc/ogit/config.toml=. When no explicit =OGIT_CONFIG= is selected, a missing file uses environment-derived defaults; malformed or invalid files never silently fall back. See =config.toml= at the project root for a reference of all available variables with their defaults and documentation. The =commits_max_displayed= value controls commit list lengths on all-commit and branch pages. =default_branch= is tried after =HEAD= and before the conventional =main= and =master= fallbacks. * Deployment ** Repository layout Git repositories are expected under =/srv/git= (the default =git_project_root=), owned by a dedicated =git= user: #+begin_example /srv/git/ git:git 750 /srv/git/repo.git/ git:git 750 #+end_example The ogit service runs as a separate user (e.g. =ogit=) with group =git= for read access. This allows =ProtectHome=yes= in systemd hardening. ** SSH push access Push access uses the =git= user over SSH. Place authorized public keys in =/srv/git/.ssh/authorized_keys=. Set the =git= user's shell to =/usr/bin/git-shell= to restrict interactive login. ** systemd A sample unit file is provided in =deploy/ogit.service=. * Alternatives - =cgit= - Very fast page renders. - Unwieldy appearance on mobile. - Extensive use of Git terminology; not beginner-friendly. - codemadness' =stagit= - Minimalist. - Uses less Git terminology and more plain English identifiers.