Analyze Flow is a starter cross-platform CLI and reusable Java library for finding backend performance bottlenecks and architecture smells. The current implementation targets Java/Spring Boot projects with JavaParser. The architecture is intentionally split so Go, Python, and TypeScript analyzers can be added without changing the CLI contract, public API, or JSON report shape.
- Repeated database calls, including repository/JdbcTemplate/EntityManager-style calls.
- Repeated third-party/API calls, including RestTemplate/WebClient/HttpClient-style calls.
- Calls inside loops where batching, request-scope memoization, Redis, or Caffeine can reduce latency.
- Pure function candidates that can be memoized.
- Similar Java method bodies using token normalization, n-gram Jaccard similarity, and LCS ratio.
- Long
if/switchlogic that may be better expressed as Strategy or Factory. - Direct client construction that should move behind an injected Proxy/Adapter/Gateway.
- Unused private methods, unused local variables/parameters, and unreachable statements.
- Loop hotspots such as nested loops and large loop-heavy methods.
- Folder/package structure smells such as controller-to-repository shortcuts and missing test source folders.
mvn test
mvn packageThe shaded executable jar is produced at:
target/analyze-flow.jarRun it directly from any project:
java -jar target/analyze-flow.jar /path/to/spring-boot-projectOr use the local script after packaging:
./bin/analyze-flow /path/to/spring-boot-project
./bin/analyze-flow
./bin/analyze-flow --fastThe project path is optional. With no path, Analyze Flow scans the current directory and auto-detects a Java/Spring Boot codebase.
Use --fast for large repositories when you want the quickest feedback loop.
analyze-flow ./project-path \
--config ./project-path/analyze-flow.yaml \
--output ./analyze-flow-report.json \
--html-output ./analyze-flow-dashboard.htmlBy default, the CLI writes both a JSON report and a self-contained local HTML dashboard. Use --no-dashboard for JSON-only CI mode.
Start a local dashboard/API server:
./bin/analyze-flow --serve --port 8765Endpoints:
GET /dashboardGET /api/reportGET /api/summaryGET /api/analyticsGET /api/findingsGET /api/mcp
If --config is omitted, the tool looks for:
analyze-flow.yamlanalyze-flow.ymlanalyze-flow.jsonanalyze-flow.propertiessrc/main/resources/application.propertiessrc/main/resources/application.yamlsrc/main/resources/application.yml
Spring Boot teams can put properties in application.properties with the analyzeFlow. prefix:
analyzeFlow.sourceIncludes=src/main/java
analyzeFlow.repeatedCallThreshold=2
analyzeFlow.dbCallPatterns=.*Repository\\.(find|get|query|save|delete|count).*
analyzeFlow.externalCallPatterns=.*RestTemplate\\.(getForObject|postForObject|exchange).*YAML/JSON config can use the same field names as AnalyzeFlowConfig.
flowchart LR
CLI["analyze-flow CLI"] --> Config["ConfigLoader<br/>properties/yaml/json"]
CLI --> Engine["AnalysisEngine"]
Engine --> Java["JavaProjectAnalyzer<br/>JavaParser AST"]
Engine -. future .-> Go["Go Analyzer<br/>tree-sitter/go parser"]
Engine -. future .-> Python["Python Analyzer<br/>libcst/ast"]
Engine -. future .-> TS["TypeScript Analyzer<br/>ts-morph/compiler API"]
Java --> Detectors["Detectors<br/>redundancy/purity/patterns"]
Detectors --> Report["JSON Report<br/>local UI input"]
com.analyzeflow.api: public reusable library API.com.analyzeflow.cli: terminal command and JSON writing.com.analyzeflow.config: default rules, config discovery, rule matching.com.analyzeflow.core: language-neutral analyzer interface and dispatch.com.analyzeflow.java: JavaParser scanner and detectors.com.analyzeflow.model: stable JSON report DTOs for a local UI.com.analyzeflow.report: JSON and offline dashboard writers.
Use the library from Java after publishing to an internal Maven repository:
import com.analyzeflow.api.AnalyzeFlow;
import com.analyzeflow.model.AnalysisReport;
import java.nio.file.Path;
AnalysisReport report = AnalyzeFlow.scan(Path.of("."));Or write both artifacts:
AnalyzeFlow.builder()
.projectRoot(Path.of("."))
.jsonOutput(Path.of("analyze-flow-report.json"))
.htmlOutput(Path.of("analyze-flow-dashboard.html"))
.build()
.analyze();The generated analyze-flow-dashboard.html is an offline UI with summary cards, latency before/after bars, severity charts, top impact findings, searchable finding cards, existing-code snippets, improved-shape suggestions, and estimated improvement percentages.
It also includes dedicated cards for query/API problems, loop hotspots, unused code, folder structure, the Analytics API, and MCP/AI assist status.
More detail:
The detector works in four passes:
- Parse source files into ASTs.
- Build a
MethodProfilefor each Java method:- class and method name
- source location
- normalized token stream
- method calls
- call category: DB, external API, or unknown
- loop/branch context
- Group DB/API calls by semantic key:
- normalized scope
- method name
- argument shape
- literal endpoint/path values when present
- Emit findings when:
- the same DB/API call appears more than
repeatedCallThreshold - the call appears inside a loop
- the same semantic call appears across multiple methods
- two method bodies exceed the similarity threshold
- the same DB/API call appears more than
For latency, v0 uses configurable estimates:
current = observed_operations * configured_backend_latency
optimized = first_backend_call + duplicate_operations * configured_cache_latency
saving = current - optimized
This is intentionally conservative and UI-friendly. Later, dynamic tracing can replace estimates with production-like timings from OpenTelemetry spans, Java Flight Recorder, or application logs.
Two code blocks are compared like this:
- Tokenize source into identifiers, literals, keywords, and operators.
- Normalize literals to
LIT. - Normalize identifiers to stable placeholders per block:
ID1,ID2,ID3. - Compute token 3-gram Jaccard similarity.
- Compute longest common subsequence ratio.
- Final score:
score = 0.60 * jaccard_3gram + 0.40 * lcs_ratio
This catches code that is not text-identical but has the same structure, for example two methods that call different repositories but perform the same validation, transformation, and response building flow.
The report is designed for a local UI:
{
"toolName": "analyze-flow",
"version": "0.1.0",
"generatedAt": "2026-05-14T00:00:00Z",
"projectPath": "/path/to/project",
"summary": {
"filesScanned": 12,
"methodsScanned": 80,
"findingsCount": 6,
"estimatedCurrentLatencyMs": 900,
"estimatedOptimizedLatencyMs": 220,
"estimatedSavingMs": 680
},
"findings": [
{
"id": "AF-0001",
"ruleId": "redundant-io-call",
"category": "Performance",
"severity": "HIGH",
"title": "Repeated remote/data call inside loop",
"locations": [],
"evidence": {},
"recommendation": {},
"latencyEstimate": {}
}
]
}Keep the CLI and report model stable. Add one analyzer per language:
- Go: parse with
go/parserin a small helper binary or use tree-sitter from Java. - Python: parse with
libcstor Pythonast, emit method/function profiles as JSON. - TypeScript: use
ts-morphor the TypeScript compiler API to extract call expressions and control flow.
Each analyzer should output the same internal concepts:
- function/method profile
- call sites
- semantic call key
- loop/branch context
- normalized token stream
That lets the same redundancy and similarity algorithms work across languages.
Before publishing, replace placeholder coordinates and metadata with your real namespace, GitHub URL, license, developer, and SCM information. Maven Central also requires sources, Javadocs, signatures, checksums, and valid POM metadata.
Suggested release path:
- Register at Sonatype Central Portal and verify your namespace.
- Generate a Central publishing token.
- Add
maven-source-plugin,maven-javadoc-plugin,maven-gpg-plugin, andcentral-publishing-maven-plugin. - Configure token credentials in
~/.m2/settings.xmlunder server idcentral. - Release with a non-SNAPSHOT version.
- Run
mvn clean deploy. - Validate and publish in the Central Portal, or enable auto-publish after you trust the pipeline.
Useful official docs: