Developer Onboarding
Quick-start guide for new Ledgerline contributors.
Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Node.js | 20+ | node -v to verify |
| pnpm | 9+ | corepack enable && corepack prepare pnpm@latest --activate |
| Docker | Latest | Required for local MongoDB and Valkey |
Setup
git clone <repo-url> && cd ledgerline
pnpm install
pnpm dev:infra # starts Mongo + Valkey via Docker Compose
pnpm dev # starts the API with tsx watch (hot reload)
The API listens on http://localhost:<PORT> (default 3000). AdminJS mounts at /admin, the data API at /api.
Render cache config note
In production, cache config can come from VALKEY_URL, REDIS_URL, or
REDIS_HOST + REDIS_PORT.
For Render deploys, use the Key Value internal connection details. In
production, if a configured cache URL still points to localhost, startup
prefers REDIS_HOST/REDIS_PORT when available so the API does not try
127.0.0.1:6379.
When both dotenv defaults and platform env vars exist, platform values are used
for cache connection settings.
If external cache is unreachable at boot, API startup now falls back to
in-memory cache so the service can come up for recovery operations.
AdminJS frontend bundles are served with explicit path fallbacks during boot to
avoid pnpm/Render path-resolution issues for app.bundle.js,
global.bundle.js, and related assets.
AdminJS theme bundling also requires @adminjs/themes to be installed in app
dependencies; missing it causes startup failure with
Cannot find module '@adminjs/themes'.
Admin sidebar resources are grouped into four collapsible sections (Users &
Identity, Commerce, Configuration, Monitoring) via src/types/admin.navigation.ts.
Per-user theming works by populating req.session.adminUser.theme before AdminJS
routes handle the request. System themes define universal layout tokens (sidebar,
container, sectionBg, text) and seedSystemThemes updates existing system theme overrides
on each deploy. The top-right user dropdown (overridden LoggedIn component)
shows the user's display name and links to the User Settings page. The User
Settings page uses theme-aware contrast (grey100 for text, sectionBg for inner boxes, filterBg for nested UI) for readability across light and dark themes.
The LoggedIn override injects ThemeAwareGlobals (createGlobalStyle)
that forces html, body, #app, input, textarea, select to use theme.colors.text
and input::placeholder to use theme.colors.grey60, overriding AdminJS's hardcoded
dark text color in the layout template. Every custom text element also sets an
explicit theme-aware color token (grey100/grey80) to prevent CSS cascade issues. Custom AdminJS
components (UserSettingsPage, LoggedIn override) are pre-built
at build time via scripts/build-admin-components.mjs and shipped with the
deploy. In development, admin.watch() bundles and watches for changes.
Key Commands
| Command | Purpose |
|---|---|
pnpm dev | Start dev server with hot reload |
pnpm dev:infra | Start local Mongo + Valkey containers |
pnpm dev:down | Stop local infra containers |
pnpm typecheck | Run TypeScript type checking |
pnpm lint | Run ESLint |
pnpm test | Run unit tests (Vitest) |
pnpm run e2e | Run end-to-end API tests |
pnpm check:contracts-coverage | Verify dependency contract test coverage |
pnpm check:cycles | Detect circular imports (Madge) |
pnpm format | Auto-format with Prettier + ESLint fix |
pnpm semgrep | Security/correctness scan (optional, requires Semgrep CLI) |
pnpm release:dry | Preview semantic-release next version/notes without publishing |
| pnpm stripe-mock --scenario=<name> | Run Stripe mock harness (local webhook simulator, port 4001) |
| pnpm taxjar-mock | Run TaxJar mock harness (local tax API simulator, port 4004) |
| pnpm easypost-mock --scenario=<name> | Run EasyPost mock harness (label + tracker webhook simulator, port 4003) |
Recommended pre-push order: pnpm typecheck → pnpm lint → pnpm test → pnpm run e2e → pnpm check:contracts-coverage → pnpm check:cycles
Architecture Overview
Ledgerline uses hexagonal (ports/adapters) architecture:
- Types (
src/types/) — pure shared contracts, no runtime logic. - Ports (
src/ports/) — app-facing capability interfaces (logging, DB, cache, auth). - Adapters (
src/adapters/) — concrete infrastructure implementations (Pino, Mongoose, Sentry). - App code (
src/data/,src/endpoints/) — domain services, validators, endpoints. - Bootstrap (
src/bootstrap/) — wires adapters into ports, mounts transport surfaces. - Init (
src/init/) — composition roots that build the full app context. - Registries (
src/registries/) — per-entrypoint module wiring (endpoints, admin, commands, events).
Key rule: app code imports ports, never adapters. Only bootstrap/init may import adapters.
Where to Find Things
| What | Where |
|---|---|
| Architecture rules & layering table | docs/ARCHITECTURE.md |
| Contribution conventions & tooling | docs/CONTRIBUTING.md |
| Auth flow documentation | docs/AUTH.md |
| Config / environment variables | docs/CONFIG.md |
| Agent/AI operating guidance | docs/AGENTS.md |
| Feature module source | src/data/<feature>/ |
| API reference docs | docs/api/ |
| Feature reference docs | docs/reference/ |
| Feature documentation | src/data/<feature>/<feature>.documentation.md |
| Release process + changelog | docs/releases/README.md |
| Docs automation rule mapping | docs/ai-ecosystem/documentation-types-and-rules.md |
Feature Module Structure
Each feature in src/data/<feature>/ follows a consistent layout:
<feature>.model.ts # Mongoose schema/model
<feature>.validators.ts # Zod schemas and DTO validation
<feature>.repository.ts # Repository port (interface)
<feature>.repository.mongoose.ts # Repository adapter (Mongoose)
<feature>.service.ts # Business logic
<feature>.endpoint.ts # Express route handler
<feature>.admin.ts # AdminJS resource config
<feature>.command.ts # Discord/CLI command handler
<feature>.events.ts # Event bus handlers
<feature>.spec.ts # Unit tests (co-located)
<feature>.documentation.md # Feature documentation
Next Steps
- Read
docs/ARCHITECTURE.mdfor the full layering rules. - Read
docs/CONTRIBUTING.mdfor commit conventions and review expectations. - Read
docs/releases/README.mdfor semantic-release and versioning flow. - Pick a feature module (e.g.
src/data/customer/) and trace the flow from endpoint → service → repository. - Run the test suite to confirm your environment is working.
Pre-commit docs automation flow
Before each commit, Husky runs pnpm docs:pre-commit-update first:
- It inspects staged files and maps them to affected doc types using
scripts/docs/documentation-types.rules.json. - It auto-runs generators where available (e.g. AI Ecosystem reference).
- For AI-backed doc types, it either:
- calls
DOC_UPDATE_CMDautomatically, or - writes
scripts/docs/.pre-commit-doc-prompt.mdand blocks commit until docs are updated/staged.
- calls