4.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Integreat is a full-stack web application for accounts payable (AP) and accounting automation. It integrates with multiple financial data sources (Plaid, Yodlee, Square, Intuit QBO) to manage invoices, bank accounts, transactions, and vendor information.
Tech Stack:
- Backend: Clojure 1.10.1 with Ring (Jetty), Datomic database, GraphQL (Lacinia, in process of depracation)
- Frontend, two versions:
- ClojureScript with Reagent, Re-frame, (almost depracated)
- Server side: HTMX, TailwindCSS, alpinejs (current)
- Java: Amazon Corretto 11 (required for Clojure 1.10.1)
Development Commands
Build:
lein build # Create uberjar
lein uberjar # Standalone JAR
npm install # Install Node.js dependencies (for frontend build)
Development
docker-compose up -d # Start Datomic, Solr services
lein repl # Start Clojure REPL (nREPL on port 9000), typically one will be running for you already
lein cljfmt check # Check code formatting
lein cljfmt fix # Auto-format code
clj-paren-repair [FILE ...] # fix parentheses in files
clj-nrepl-eval -p PORT "(+ 1 2 3)" # evaluate clojure code
Often times, if a file won't compile, first clj-paren-repair on the file, then try again. If it doesn't wor still, try cljfmt check.
Running the Application:
As Web Server:
INTEGREAT_JOB="" lein run # Default: port 3000
# Or with custom port:
PORT=3449 lein run
As Background Job:
Set INTEGREAT_JOB environment variable to one of:
square-import-job- Square POS transaction syncyodlee2- Yodlee bank account syncplaid- Plaid bank linkingintuit- Intuit QBO syncimport-uploaded-invoices- Process uploaded invoice PDFsezcater-upsert- EZcater PO syncledger_reconcile- Ledger reconciliationbulk_journal_import- Journal entry import- (no job) - Run web server + nREPL
Architecture
Request Flow:
- Ring middleware pipeline processes requests
- Authentication/authorization middleware (Buddy) wraps handlers
- Bidi routes dispatch to handlers
- SSR (server-side rendering) generates HTML with Hiccup for main views
- For interactive pages, HTMX handles partial updates
- Client-side uses alpinejs as a bonus
Multi-tenancy:
- Client-based filtering via
:client/codeand:client/groups - Client selection via
X-Clientsheader or session - Role-based permissions: admin, standard user, vendor
Key Directories:
src/clj/auto_ap/- Backend Clojure codesrc/clj/auto_ap/server.clj- Main entry point, job dispatcher, Mount lifecyclesrc/clj/auto_ap/handler.clj- Ring app, middleware stacksrc/clj/auto_ap/datomic/- Datomic schema and queriessrc/clj/auto_ap/ssr/- Server-side rendered page handlers (Hiccup templates)src/clj/auto_ap/routes/- HTTP route definitionssrc/clj/auto_ap/jobs/- Background batch jobssrc/clj/auto_ap/graphql/- GraphQL type definitions and resolverssrc/cljs/auto_ap/- Frontend ClojureScript for old, depracated versiontest/clj/auto_ap/- Unit/integration tests
Database
- Datomic schema defined in
resources/schema.edn - Key entity patterns:
:client/code,:client/groupsfor multi-tenancy:vendor/*,:invoice/*,:transaction/*,:account/*for standard entities:db/type/reffor relationships, many with:db/cardinality :db.cardinality/many
Configuration
- Dev config:
config/dev.edn(set via-Dconfig=config/dev.edn) - Env vars:
INTEGREAT_JOB,PORT - Docker: Uses Alpine-based Amazon Corretto 11 image
Important Patterns
- Middleware stack in
handler.clj: route matching → logging → client hydration → session/auth → idle timeout → error handling → gzip - Client context added by middleware:
:identity,:clients,:client,:matched-route - Job dispatching in
server.clj: checksINTEGREAT_JOBenv var to run specific background jobs or start web server - Test selectors: namespaces ending in
integrationorfunctionalare selected bylein test :integration/lein test :functional
Clojure REPL Evaluation
The command clj-nrepl-eval is installed on your path for evaluating Clojure code via nREPL.
Discover nREPL servers:
clj-nrepl-eval --discover-ports
Evaluate code:
clj-nrepl-eval -p <port> "<clojure-code>"
With timeout (milliseconds)
clj-nrepl-eval -p <port> --timeout 5000 "<clojure-code>"
The REPL session persists between evaluations - namespaces and state are maintained.
Always use :reload when requiring namespaces to pick up changes.