The Problem
This repository lacks automated quality gates: no test suite, no CI/CD pipeline, and no dependency lockfile means changes ship without signal that existing behavior is preserved, and builds are non-reproducible across environments.
What This Does
TerraInk is a cartographic poster engine that generates custom city map posters from OpenStreetMap data. Users search locations via geocoding, select or build themes through a color palette system, and export high-resolution PNG posters at defined dimensions. The source lives primarily in src/ (130 files), with 117 TypeScript and 42 TSX files handling theming (src/features/theme/), map rendering (src/features/map/), markers (src/features/markers/), and export pipelines (src/features/export/). Poster generation flows through src/core/http/index.ts for API calls and src/core/cache/ for local storage. Two functions make outbound network calls (nominatimAdapter.searchLocations, nominatimAdapter.geocodeLocation) and one writes files (pdfExporter pipeline). The project uses Bun as its runtime, Vite for dev/build, and MapLibre GL for vector tile rendering.
How It Is Wired
Execution starts at src/App.tsx:65 (AppShell), which is called from nothing else in the repo, and src/App.tsx:27 (SettingsDrawer), also uncall ed from internal callers. The primary export path is compositeExport at src/features/poster/infrastructure/renderer/index.ts:15, which reaches 8 functions and is itself called from 1 place. The internal call graph shows 314 resolved call edges; clamp is called from 20 places, normalizeHexColor from 13, and usePosterContext from 11. The most connected hub is src/shared/utils/color.ts (14 functions, 2 classes, called from 9 files) defining normalizeHexColor, toUniqueHexColors, parseHex. Deep nesting of 3 levels appears in src/features/map/ui/MapDimensionFields.tsx, src/features/markers/ui/MarkersSection.tsx, and src/features/poster/ui/PreviewPanel.tsx, with max indentation depth of 6. Oversized files include src/features/map/infrastructure/maplibreStyle.ts and src/features/markers/ui/MarkersSection.tsx at 631 lines each, making changes hard to hold and reason about. No circular dependencies exist across 120 analyzed modules, but 109 repeated 6-line blocks across 25 files indicate duplicated logic that should be extracted.
How To Use It
Setup: bun install (bun.lock present; project uses Bun as runtime). Configuration: No environment variables are required for basic operation; src/core/config.ts centralizes project config. Running it: bun run dev (via vite.config.js) starts the development server; bun run build produces a production build. The app runs at http://localhost:5173. Exporting: Use the export UI (src/features/export/ui/) or invoke compositeExport programmatically from src/features/poster/infrastructure/renderer/index.ts.
Note: The README documents these commands verbatim.
Real-World Use
A user opens the app, searches “Austin, TX” via the geocoder (src/features/location/infrastructure/nominatimAdapter.ts), selects a curated theme or defines a custom palette using the src/features/theme/ui/ColorPicker.tsx, adjusts map layer visibility and typography controls, then clicks “Export Poster.” The system geocodes the location, renders the MapLibre vector map with selected styles, overlays text with chosen Google Fonts, and writes a PNG file via the pdfExporter/pngExporter pipeline. The result is a print-ready city map poster at the specified dimensions.
Code Health & Issues
- [HIGH] Add a test suite — 120 source files, no test files; any change reaches production without signal that behavior is preserved.
- [HIGH] Add a CI/CD workflow — no automated build/test gate; across this estate this pattern appears in 499 repositories.
- [HIGH] Add a build gate for Docker artifacts — deployment artifacts exist with no workflow validating the image or manifests.
- [MEDIUM] Enable Dependabot or Renovate — one manifest, no update bot; across 1,322 repositories this means advisories sit unpatched.
- [MEDIUM] Pin container base image by digest —
oven/bun:1-alpineandnginx:1.29-alpineare mutable; today’s build and last month’s contain different libc and CVE sets with no record. - [LOW] Add convention files — missing
.editorconfig,.gitattributes, formatter config.
These findings come from static analysis of the repository structure and source code.
The Bottom Line
The codebase is functional and well-structured for a solo developer project, with a clear feature set and a working map-rendering pipeline. However, the absence of tests, CI, and a lockfile makes it unsuitable for team or production use without significant investment in quality gates. It’s appropriate for individual exploration or forking with the intention to add those gates; teams should expect to implement a test suite, CI workflow, and pinned Docker bases before shipping changes confidently.