"The app is 80% done, the previous developer stopped answering, can you finish it?" If you freelance long enough, you get this message. Sometimes the project is in good shape. Sometimes the last 20% is really 70%. And sometimes the repository itself is a risk to your own machine.

I'm a freelance Flutter and WordPress developer in Famagusta, North Cyprus. This is the checklist I go through before I quote, in the order I do it.

1. Don't run it yet: read it in isolation

The first rule: a repository from a stranger is untrusted code. Fake "fix this bug in our repo" tasks are a known way to steal SSH keys, browser cookies and saved passwords from developers. So the first pass is reading, not running, and anything that executes happens in a throwaway environment (a GitHub Codespace on a separate account, or a VM), never on the laptop that holds my client logins.

Things I read before any flutter pub get or gradle task:

  • android/build.gradle, android/app/build.gradle and settings.gradle: anything that calls exec, commandLine or downloads scripts at build time.
  • android/gradle/wrapper/gradle-wrapper.properties and the wrapper JAR: does the distribution URL point to services.gradle.org?
  • ios/Podfile and any "Run Script" build phases in the Xcode project.
  • pubspec.yaml: git dependencies pointing to unknown forks, or path dependencies outside the repo.
  • .vscode/tasks.json: a task with "runOn": "folderOpen" runs the moment you open the folder. Open unknown projects in Restricted Mode.
  • Any package.json (web tooling, Firebase functions): preinstall / postinstall scripts.

Only when that looks clean do I build, and still in the isolated environment. The APK it produces can then be tested on a spare phone or a cloud emulator.

2. Secure what belongs to the client

Before touching code, I make sure the client actually owns their project:

  • Git repo in their organisation, not the previous developer's personal account.
  • Google Play Console and Apple Developer accounts in the client's name.
  • Owner access to Firebase / Supabase / the backend, plus API keys for maps, payments and push notifications.
  • The Figma file and assets.

If any of this is missing, that is the first milestone, because without it nothing else is safe to build on.

3. Measure the real state

Then the honest part. I run through:

  • flutter analyze and the number of warnings (and whether analysis_options.yaml silences everything).
  • Flutter / Dart SDK constraints vs. current stable, and flutter pub outdated.
  • State management: one consistent approach, or three mixed together?
  • Secrets in source: API keys or passwords committed in Dart files or google-services.json for the wrong project.
  • Tests: any at all? Do they pass?
  • Every screen on a real device: which features work, and which only look finished.

The output is a short written report for the client in plain language: what works, what needs fixing, what is missing.

4. Finish, refactor or rebuild

Most rescues end up in one of three buckets:

Situation Recommendation
Clean structure, missing features Finish as is
Works, but features break each other Refactor key modules first, then finish
Weak foundation or very old SDK Rebuild, keeping designs, backend and data

Rebuilding sounds expensive, but it is often cheaper than fighting a codebase where every change breaks two other screens.

5. Make the next handover painless

Whatever happens, I set the project up so the client is never stuck again: weekly pushes to their repo, regular test builds they can install, store accounts and keys in their name, and a short README that explains how to build and release.

I wrote a non-technical version of this for business owners here: Unfinished App? How to Rescue a Half-Built App and Launch It. If you've taken over a project that turned out to be a trap, I'd love to hear what you check first.