# What You’ll Learn#
A technical due diligence for a legacy web or mobile app is not a code review. It is a structured assessment that answers three executive questions: is it secure, is it maintainable, and what will it cost to evolve.
This guide shows a step-by-step process to run a legacy code audit web mobile for a Next.js and React app or a Flutter app. You’ll get a checklist, a risk scoring rubric, and a way to convert findings into a phased modernization plan that leadership can fund.
# When You Actually Need Due Diligence#
You typically need this audit when one of these triggers occurs:
- 1Acquisition or investment due diligence, where technical risk affects valuation.
- 2A new agency or internal team takeover, where you need predictable delivery timelines.
- 3The roadmap is blocked by bugs, regressions, or slow releases.
- 4Security or compliance requirements increased, including SOC 2, ISO 27001, or PCI-related controls.
In practice, teams underestimate compounding maintenance cost. Multiple industry benchmarks put annual maintenance at roughly 15 to 25 percent of initial build cost, and legacy systems trend toward the high end when test coverage and dependency hygiene are weak. The goal of this audit is to quantify risk, not just complain about old code.
# Scope and Deliverables: Define What “Done” Means#
Before touching the repo, set a concrete scope so the audit does not turn into open-ended refactoring advice.
Audit Scope Checklist#
| Area | Web: Next.js and React | Mobile: Flutter | Evidence you should collect |
|---|---|---|---|
| Security | Auth flows, API calls, secrets, headers, dependency CVEs | Auth flows, deep links, storage, dependency CVEs | Threat list, CVE report, top fixes |
| Performance | Core Web Vitals, bundle size, server response, caching | Startup time, jank, memory, battery | Metrics snapshot and bottleneck list |
| DX and Maintainability | Build reproducibility, linting, tests, CI time | Build flavors, code gen, tests, CI time | Build steps, quality gates, pain points |
| Architecture | Data flow, routing, state, boundaries | State management, navigation, modularity | Diagram and key risks |
| Dependency Health | npm lockfile, major versions, transitive risk | pubspec lock, plugin stability | Upgrade plan and risk log |
| Ops and Observability | Logs, errors, tracing, SLOs | Crash reporting, analytics, release monitoring | Monitoring gaps and action list |
Minimum Deliverables That Stakeholders Understand#
- A one-page risk summary with a numeric score and top 10 issues.
- A prioritized backlog with estimates and acceptance criteria.
- A phased modernization roadmap with timelines and “no rewrite” options.
- A short technical readout, ideally 45 minutes with Q and A.
ℹ️ Note: A due diligence report without estimates and sequencing is not actionable. If you cannot assign a rough size, leadership cannot budget or plan a release train.
# Step-by-Step Audit Process for Legacy Next.js, React, and Flutter#
This process is designed for 5 to 10 days. If your app is large, keep the same steps but time-box each to avoid boiling the ocean.
# Step 1: Access, Inventory, and Reproducible Builds#
Your first goal is to answer one question: can a new engineer build and run the app in under 60 minutes.
What to Collect in the First Day#
| Asset | Why it matters | What good looks like |
|---|---|---|
| Repository list | Hidden dependencies derail timelines | All repos documented, including infra |
| Environments | Bugs often live in config | Dev, staging, prod described and reachable |
| Secrets management | Leaked keys create incidents | Vault or managed secrets, least privilege |
| Build instructions | Onboarding time becomes cost | Single command start, consistent tooling |
| CI pipeline | Release speed and stability | Reproducible builds, cached dependencies |
Fast Build Repro Checks#
For Next.js and React:
node -v
npm -v
npm ci
npm run build
npm run testFor Flutter:
flutter --version
flutter doctor -v
flutter pub get
flutter test
flutter build apk --debugIf any step fails, capture the error and the time spent. That time becomes part of your maintainability score.
💡 Tip: Ask one developer who has never touched the project to run the setup from scratch while screen-recording. You will get a precise list of missing docs, implicit assumptions, and flaky steps.
# Step 2: Architecture and Codebase Map#
You want to quickly understand where change is safe and where change is risky.
What to Document#
For Next.js and React:
- Routing model and data fetching patterns across pages and components.
- State management approach, including where server state and UI state live.
- API layer conventions and error handling.
- SSR, SSG, and caching decisions, including edge deployment if used.
For Flutter:
- State management library and its boundaries.
- Navigation structure and deep link handling.
- Layering, for example presentation, domain, data.
- Platform channels and native code touchpoints.
Signals of Hidden Complexity#
| Signal | Why it matters | Typical remediation |
|---|---|---|
| Shared global state mutated everywhere | Bugs become non-local | Introduce boundaries and typed events |
| No module boundaries | Refactors become risky | Modularize by feature or domain |
| Business logic in UI layer | Testing becomes expensive | Extract services and domain layer |
| Direct API calls from widgets or components | Hard to secure and cache | Central API client and interceptors |
# Step 3: Security Audit Checklist for Web and Mobile#
Security is usually the highest-impact part of technical due diligence because it can create immediate business risk. Your goal is not to find every issue, but to identify systemic exposure.
Use this as a companion to our deeper security guide: Web Application Security Checklist.
Web: Next.js and React Security Checklist#
| Check | What to verify | Evidence |
|---|---|---|
| Authentication | Token lifecycle, refresh, logout | Flow diagram and test cases |
| Authorization | Role checks are server-side | Policy list and API enforcement proof |
| Input validation | Server validates, client only assists | Validation schema and error mapping |
| XSS protections | Escaping and safe rendering | Review dangerous rendering usage |
| CSRF | Cookies with proper protections | Header and cookie attributes |
| Security headers | CSP, HSTS, X-Frame-Options equivalents | Deployed headers snapshot |
| Secrets | No secrets in client bundle | grep results and CI checks |
| Dependency vulnerabilities | npm audit is not enough | CVE report with severity and exploitability |
Practical checks you can run:
npm audit --audit-level=high
npx depcheck
npx license-checker --summaryMobile: Flutter Security Checklist#
| Check | What to verify | Evidence |
|---|---|---|
| Secure storage | Tokens not stored in plain prefs | Storage library usage review |
| Deep links | Validation, no auth bypass | Test cases for malicious links |
| TLS and API trust | No accepting bad certificates | Http client configuration |
| Jailbreak and root signals | If needed for threat model | Decisions documented |
| Crash logs | No PII in logs | Sampling from crash tool |
| Dependency vulnerabilities | Plugin provenance and versions | Plugin list and maintenance status |
A fast scan of dependencies:
flutter pub deps --style=compact
flutter pub outdated⚠️ Warning: A common due diligence failure is auditing only the client code. If the API and identity provider are out of scope, explicitly document assumptions, because most real authorization bugs are server-side.
# Step 4: Performance Audit with Real Metrics, Not Opinions#
Performance findings should be tied to numbers. On web, the most defensible metrics are Core Web Vitals and bundle sizes. On Flutter, focus on jank, memory, and startup time.
Use this for deeper tactics and tooling: Website Performance Optimization.
Web Metrics to Capture#
| Metric | Target for most products | How to measure |
|---|---|---|
| LCP | less than 2.5 seconds | Lighthouse, CrUX, RUM |
| INP | less than 200 milliseconds | RUM and field data |
| CLS | less than 0.1 | Lighthouse and field data |
| TTFB | less than 800 milliseconds | RUM, server logs |
| JS bundle size | keep critical path minimal | build analyzer and source maps |
Quick Next.js checks:
npm run build
npx next build --profile
npx @next/bundle-analyzerIf you cannot run a bundle analyzer, at least capture the /_next/static output sizes and the number of chunks.
Flutter Metrics to Capture#
| Metric | Practical target | How to measure |
|---|---|---|
| Cold start | less than 2 seconds on mid-range device | Profile mode, real device |
| Jank | keep frames under budget | Flutter DevTools frame chart |
| Memory | stable under typical flows | DevTools memory timeline |
| Network | avoid chatty APIs | Proxy logs and request counts |
Basic profiling command:
flutter run --profile🎯 Key Takeaway: Performance audits are credible when you provide a baseline, a top 5 bottleneck list, and an estimate of expected improvement, for example “reduce initial JS by 35 percent by removing unused dependencies and splitting routes”.
# Step 5: Developer Experience and Delivery Pipeline Audit#
DX issues are not “nice to have”. They show up as longer cycle times, more regressions, and higher staffing cost.
What to Measure#
| DX Area | What to measure | Why it matters |
|---|---|---|
| Onboarding time | minutes to first successful run | hiring and handover risk |
| CI duration | minutes per PR | throughput and cost |
| Flakiness | reruns per week | morale and predictability |
| Code quality gates | lint, format, types | regression prevention |
| Test coverage | unit, integration, e2e | confidence to change |
Practical checks:
- Is TypeScript strict mode enabled in a React and Next.js app.
- Is there a single source of truth for environment variables.
- Are Flutter build flavors documented and reproducible.
- Is code generation stable, and are generated files committed or not, consistently.
# Step 6: Dependency Health and Upgrade Risk#
Legacy apps tend to accumulate “dependency debt”. A single unmaintained package can block major upgrades, and major upgrades can block security patches.
Dependency Health Checklist#
| Dimension | Web: npm | Mobile: pub | What to flag as risk |
|---|---|---|---|
| Lockfile | package-lock or pnpm-lock | pubspec.lock | missing lockfile, frequent drift |
| Outdated majors | next, react, node | flutter, dart sdk | multiple major jumps required |
| Abandonware | low downloads, no commits | discontinued plugins | replacement required |
| Transitive risk | nested packages with CVEs | nested packages | patching complexity |
| Licenses | GPL, AGPL exposure | restrictive licenses | legal and distribution risk |
Commands that produce actionable output:
npm outdated
npm ls --depth=0flutter pub outdated --mode=null-safetyIf the Flutter app still has non-null-safe dependencies, treat it as a modernization priority. Null safety migration reduces runtime crashes and improves tooling, and most active packages have supported it for years.
# Step 7: Testing Strategy and Quality Signals#
You are not aiming for 100 percent test coverage. You are aiming for “safe change” in the highest-risk areas.
Minimum Test Baseline for Legacy Apps#
| Layer | Web recommendation | Flutter recommendation | Why |
|---|---|---|---|
| Unit tests | critical utils and domain logic | domain and services | fast regression protection |
| Integration tests | API client and auth flows | repositories and state | catches contract breakage |
| E2E tests | top 3 revenue flows | top 3 user flows | protects business outcomes |
| Visual checks | snapshot or visual diff for key pages | golden tests for key widgets | prevents UI regressions |
A good due diligence output is a list of “test gaps” tied to the roadmap. Example: “Add E2E coverage for checkout login flow before refactoring auth”.
# Risk Scoring Rubric: Make Findings Comparable#
A risk score turns subjective concerns into a decision tool. Use a weighted model so leadership can see what drives the result.
Scoring Model#
Score each category from 0 to 5, then multiply by weight. Higher is worse.
| Category | Weight | Score meaning |
|---|---|---|
| Security | 30 | 0 is robust controls, 5 is exploitable and unmonitored |
| Reliability and Observability | 20 | 0 is strong SLOs and monitoring, 5 is blind incidents |
| Performance | 15 | 0 meets targets, 5 misses targets severely |
| Maintainability and Architecture | 15 | 0 modular and readable, 5 tightly coupled |
| Dependency Health | 10 | 0 current and maintained, 5 blocked upgrades |
| DX and Delivery | 10 | 0 fast CI and strong gates, 5 slow and flaky |
Overall risk score formula:
Risk Score = sum(category_score * weight) / sum(weights)
Severity and Effort Matrix for Each Finding#
In addition to the overall score, each issue should have two ratings:
- Impact from 1 to 5, where 5 is user data risk or revenue impact.
- Effort from 1 to 5, where 5 is multi-sprint change with cross-team coordination.
This lets you prioritize by “impact per effort”.
Example Risk Scorecard#
| Area | Score 0-5 | Weight | Weighted |
|---|---|---|---|
| Security | 4 | 30 | 120 |
| Reliability and Observability | 3 | 20 | 60 |
| Performance | 2 | 15 | 30 |
| Maintainability and Architecture | 4 | 15 | 60 |
| Dependency Health | 5 | 10 | 50 |
| DX and Delivery | 3 | 10 | 30 |
| Total | — | 100 | 350 |
Overall Risk Score = 350 / 100 = 3.5
Interpretation:
| Score range | Risk level | Typical decision |
|---|---|---|
| 0.0 to 1.5 | Low | Normal iteration, small improvements |
| 1.6 to 2.9 | Moderate | Plan a modernization quarter |
| 3.0 to 4.0 | High | Stabilization first, pause big features |
| 4.1 to 5.0 | Critical | Immediate security and reliability response |
# Turning Findings Into a Phased Modernization Roadmap#
A roadmap is where most audits fail. You need sequencing that reduces risk early while keeping the product shipping.
Phase 0: Stabilize and Make Change Safe, 1 to 3 Weeks#
Goals:
- Make builds reproducible.
- Add basic monitoring and crash reporting.
- Patch high-severity vulnerabilities with known exploits.
Typical tasks:
| Task | Applies to | Outcome |
|---|---|---|
| Pin runtime versions | Web and mobile | fewer environment-only bugs |
| CI caching and deterministic installs | Web and mobile | faster builds, fewer flakes |
| Add error reporting and alerts | Web and mobile | less time to detect incidents |
| Patch critical CVEs | Web and mobile | reduced breach risk |
Deliverable: a “green pipeline” and an incident visibility baseline.
Phase 1: Security and Dependency Health, 2 to 6 Weeks#
This phase reduces the risk of being blocked by future upgrades.
For Next.js and React:
- Upgrade Node.js to an active LTS and align Next.js and React versions.
- Replace abandoned libraries, especially auth, routing, and form libs if unmaintained.
- Add security headers and enforce server-side authorization checks.
For Flutter:
- Migrate to a modern Flutter and Dart baseline supported by your plugins.
- Replace deprecated plugins and remove unmaintained platform wrappers.
- Standardize secure storage and network stack.
Deliverable: “supported stack” status plus a dependency upgrade playbook.
Phase 2: Performance and UX Improvements, 2 to 8 Weeks#
This phase is where teams see visible customer impact.
For Next.js and React:
- Split bundles by route and remove unused dependencies.
- Fix waterfall requests and caching gaps.
- Introduce image optimization and predictable SSR and SSG rules.
For Flutter:
- Remove expensive rebuild patterns and isolate widgets.
- Optimize lists, images, and JSON parsing.
- Reduce startup work and lazy-load heavy features.
Deliverable: measured improvements, for example “LCP improved from 3.8 seconds to 2.3 seconds” or “cold start reduced by 35 percent”.
Phase 3: Architecture Modernization, Ongoing#
Do this last, after you can safely change things.
Examples:
- Introduce a feature-based module structure in React and Next.js.
- Standardize state management and API boundaries.
- Extract shared domain logic and add contract tests.
- For Flutter, enforce clean architecture boundaries where it matters, not everywhere.
Deliverable: reduced lead time per feature and lower defect rate.
💡 Tip: Use a “strangler” approach: modernize one flow at a time behind stable interfaces. This keeps risk local and avoids the multi-month rewrite trap.
# How to Estimate Cost and Timeline From Audit Data#
Leadership needs rough order-of-magnitude estimates, not perfect numbers.
A Practical Estimation Method#
- 1Group findings into epics by phase.
- 2For each epic, estimate in “small, medium, large” tied to weeks.
- 3Add a coordination factor if multiple repos or teams are involved.
Example sizing model:
| Size | Typical time | Suitable for |
|---|---|---|
| Small | 0.5 to 2 days | config, lint, small refactors |
| Medium | 3 to 7 days | library replacements, new test suite |
| Large | 2 to 6 weeks | major upgrades, architecture boundaries |
If your due diligence is for outsourcing or handover, also include a transition plan. This reduces the “unknown unknowns” that often inflate delivery timelines after takeover. For a practical framework, see Outsourcing Web Development Guide.
# Recommended Audit Artifacts You Can Reuse#
You will move faster in future audits if you standardize templates.
Artifacts to Produce#
| Artifact | Format | Who uses it |
|---|---|---|
| System map | one page diagram | engineering and product |
| Risk register | table with scores | leadership and security |
| Dependency upgrade plan | milestones by version | engineering |
| Performance baseline | metrics snapshot | engineering and marketing |
| Roadmap | phases with dates | leadership |
A solid risk register row should include:
- Finding summary
- Impact and likelihood
- Evidence, including file paths or metrics
- Recommendation
- Effort estimate
- Owner and phase
# Common Pitfalls in Legacy App Due Diligence#
- 1No runtime validation — reviewing code without running flows misses real bottlenecks and crashes.
- 2Using only static scanners — tools find symptoms, not systemic causes.
- 3Treating modernization as a rewrite — you lose momentum and usually ship later with the same unknown risks.
- 4Ignoring observability — without logs and metrics, you cannot prove improvements or catch regressions.
- 5Skipping stakeholder readout — if leadership does not understand risk, the backlog will not get funded.
# Key Takeaways#
- Time-box your legacy code audit web mobile to 5 to 10 days and require reproducible builds as the first gate.
- Score risk with a weighted rubric so security, reliability, and dependency health are not drowned out by subjective opinions.
- Tie performance findings to measurable baselines like Core Web Vitals for web and startup and jank metrics for Flutter.
- Convert findings into phases: stabilize first, then security and dependencies, then performance, then architecture modernization.
- Deliver a roadmap with estimates and acceptance criteria, or the audit will not translate into funded work.
# Conclusion#
Technical due diligence is the fastest way to turn a legacy Next.js, React, or Flutter app from “risky and expensive” into “predictable and upgradeable”. A structured audit plus a scored risk register gives leadership clarity, and a phased modernization plan avoids the rewrite trap while still delivering measurable improvements.
If you want Samioda to run a legacy code audit and deliver a modernization roadmap your team can execute, contact us with repo access and a staging build. We’ll return a scored report, a prioritized backlog, and a phased plan aligned with your release schedule.
FAQ
Founder & Senior Developer at Samioda. 8+ years building React, Next.js, Flutter and n8n automation solutions for clients across Europe.
More in Agency & Business
All →From MVP to V1: A Roadmap for Scaling Product, Team, and Tech (Next.js + Flutter)
A practical MVP to V1 roadmap for the next 90–180 days: refactoring strategy, analytics, reliability, security, prioritization, and a framework for deciding what to rebuild, automate, and hire versus outsource.
The Maintenance Checklist After Launch: Web, Mobile, and Automation Systems That Don’t Rot
A practical web app maintenance checklist with weekly, monthly, and quarterly routines for security, dependencies, monitoring, backups, and automation health.
After Launch: Our Agency Handoff Playbook for a Software Project Handoff After Launch
A practical playbook for a software project handoff after launch: access management, runbooks, SLAs, monitoring, incident response, and clear ownership.
Need help with your project?
We build custom solutions using the technologies discussed in this article. Senior team, fixed prices.
Related Articles
From MVP to V1: A Roadmap for Scaling Product, Team, and Tech (Next.js + Flutter)
A practical MVP to V1 roadmap for the next 90–180 days: refactoring strategy, analytics, reliability, security, prioritization, and a framework for deciding what to rebuild, automate, and hire versus outsource.
Our Testing Strategy: How We Ship Web + Mobile Faster with QA, Automation, and Observability
A practical look at Samioda’s software testing strategy agency approach for React, Next.js, Flutter, and n8n workflows using risk-based QA, automation, and observability.
How We Estimate Next.js and Flutter Projects: From Unknowns to a Defensible Scope
A practical guide to web and mobile app project estimation for Next.js and Flutter: discovery inputs, assumptions, risk buffers, milestones, and scope control.