Sample report  Real analysis of the project "codedictate" — 4,260 lines of code, 47 findings reviewed Get your own report
VibeCodeDoktor

Your Personal Code Guide for codedictate

Report ID: VCD-SAMPLE-codedictate Date: August 20, 2026 Lines of Code: 4,260 Language: Python Tech Stack: Flask, Whisper, SQLAlchemy

codedictate is a Flask-based dictation solution using OpenAI Whisper for speech recognition. The project shows solid foundational architecture but has significant security gaps (hardcoded secrets, missing authentication), insufficient test coverage, and several dead code paths.

Some dependencies are outdated with known vulnerabilities.

Think of this report as a guide, not a grade. Every hint includes a concrete next step — often a single AI prompt is enough.

Top Findings

Ranked by importance — work through them from the top

1
CRITICAL Major Effort

God Function: transcribe_and_process (380 lines)

server/transcribe.py:45
What's Happening

A single function handles audio decoding, chunking, Whisper API calls, post-processing, punctuation, and database writes — all in 380 lines.

What Happens if You Don't Fix This

Virtually untestable, extremely error-prone to modify. Any bug fix can have unintended side effects.

How to Fix
  1. Split into dedicated steps: decode_audio, chunk_audio, call_whisper, postprocess, save_result
  2. Make each step independently testable
  3. Implement a pipeline pattern (step by step)
AI Fix Prompt

"Refactor transcribe_and_process() in server/transcribe.py into 5 smaller functions: decode_audio(), chunk_audio(), call_whisper(), postprocess_text(), save_transcription(). Wire them together in a pipeline function."

Code
def transcribe_and_process(audio_file, user_id, language="de"):
    # ... 380 lines of nested logic
    # audio decoding, chunking, API calls, text cleanup, DB writes
What to Remember

Functions over 50 lines are a smell. Over 100 is dangerous. Over 300 is a maintenance nightmare. Split along responsibility boundaries.

2
CRITICAL Major Effort

Only 8% Test Coverage (2 Tests for 4260 LOC)

tests/test_transcribe.py:1
What's Happening

The entire project has only 2 tests in a single test file. Core functionality like upload, transcription, and authentication is untested.

What Happens if You Don't Fix This

Any change can silently break existing functionality. Refactoring becomes a gamble.

How to Fix
  1. Set up test framework (pytest, pytest-flask)
  2. Test at least every API endpoint
  3. Cover critical business logic with unit tests
  4. Set up CI pipeline with test execution
AI Fix Prompt

"Set up pytest with pytest-flask. Create test files: tests/test_api.py (endpoint tests), tests/test_transcribe.py (transcription logic), tests/test_models.py (database operations). Target 60% coverage minimum."

Code
# tests/test_transcribe.py — ENTIRE test suite:
def test_whisper_returns_text():
    assert transcribe("hello.wav") != ""

def test_empty_audio():
    assert transcribe("empty.wav") == ""
What to Remember

Test coverage below 40% means you are flying blind. Prioritize testing critical paths: auth, payment, data persistence.

3
CRITICAL Medium

Tests Use Production Database

tests/test_transcribe.py:5
What's Happening

Existing tests connect to the same database as production because no test configuration exists.

What Happens if You Don't Fix This

Tests can modify or delete production data. An accidental test run can destroy real user data.

How to Fix
  1. Configure separate test database connection in conftest.py
  2. Use SQLite in-memory for fast unit tests
  3. Create fixtures for test data setup and teardown
AI Fix Prompt

"Create tests/conftest.py with a test database fixture using SQLite in-memory. Update tests to use the fixture instead of importing from server.config directly."

Code
# tests/test_transcribe.py
from server.config import DATABASE_URL  # same as production!
from server.models import db

def test_save_transcription():
    db.session.add(...)  # writes to production DB!
What to Remember

Tests must never touch production databases. Use separate test databases, fixtures, and cleanup.

4
CRITICAL Medium

No Error Handling on Whisper API Calls

server/transcribe.py:156
What's Happening

API calls to the Whisper service have no timeout, no retry, and no specific error handling. A 500 or timeout crashes the entire request handler.

What Happens if You Don't Fix This

Transient API errors cause complete transcription failure. Users lose their recording without an error message.

How to Fix
  1. Set timeout for API calls (e.g., 30 seconds)
  2. Implement retry logic with exponential backoff
  3. Catch specific errors and return user-friendly messages
AI Fix Prompt

"Wrap Whisper API calls in server/transcribe.py with tenacity retry decorator: @retry(stop=stop_after_attempt(3), wait=wait_exponential(min=1, max=10)). Add timeout=30 to requests."

Code
response = openai.audio.transcriptions.create(
    model=WHISPER_MODEL,
    file=audio_chunk,
    language=language
)  # no timeout, no retry, no error handling
What to Remember

All external API calls need timeout, retry, and error handling. Assume the network will fail.

5
CRITICAL Quick Fix

Secret Key Uses Predictable Default

server/config.py:8
What's Happening

The Flask SECRET_KEY has a hardcoded fallback "dev-key-change-me" that gets used in production when the environment variable is not set.

What Happens if You Don't Fix This

With a known secret key, attackers can sign session cookies and gain admin access.

How to Fix
  1. Remove fallback — application should not start without SECRET_KEY
  2. Use secrets.token_hex(32) for production
  3. Add startup check that aborts on missing key
AI Fix Prompt

"In server/config.py, change SECRET_KEY to raise an error if not set: SECRET_KEY = os.environ["FLASK_SECRET_KEY"] # no fallback, must be set."

Code
SECRET_KEY = os.getenv("FLASK_SECRET_KEY", "dev-key-change-me")  # predictable!
What to Remember

Never provide default values for security-critical configuration. Fail loudly instead of running insecurely.

6
CRITICAL Medium

Flask 2.2.3 Has Known Security Vulnerability (CVE-2023-30861)

requirements.txt:1
What's Happening

Flask 2.2.3 is vulnerable to session cookie manipulation (CVE-2023-30861). The current version is 3.1.x.

What Happens if You Don't Fix This

Attackers can manipulate session cookies and impersonate other users.

How to Fix
  1. Update Flask to >= 3.0.0
  2. Review breaking changes in Flask 3.0 migration guide
  3. Run all tests after update
AI Fix Prompt

"In requirements.txt, update Flask from 2.2.3 to 3.1.0. Review the Flask 3.0 migration guide for breaking changes. Run tests after update."

Code
# requirements.txt
Flask==2.2.3  # CVE-2023-30861: session cookie vulnerability
Werkzeug==2.2.3  # also outdated, update together
What to Remember

Run pip-audit or safety check regularly. Pinned versions require active maintenance to stay secure.

7
CRITICAL Quick Fix

Hardcoded API Key in Source Code

server/config.py:14
What's Happening

The OpenAI API key is hardcoded directly in the source code and gets committed to the repository with every push.

What Happens if You Don't Fix This

Attackers can extract the API key from git history and make API calls at your expense.

How to Fix
  1. Move API key to environment variables
  2. Create .env file and add to .gitignore
  3. Rotate the existing key immediately
AI Fix Prompt

"Replace the hardcoded OPENAI_API_KEY in server/config.py with os.environ.get("OPENAI_API_KEY") and add a .env.example file."

Code
OPENAI_API_KEY = "sk-proj-abc123def456ghi789"
What to Remember

Never commit API keys or secrets to version control. Use environment variables or a secrets manager.

8
CRITICAL Medium

SQL Injection via Raw Query

server/models.py:87
What's Happening

User input is directly interpolated into a SQL query without parameterization or escaping.

What Happens if You Don't Fix This

Attackers can execute arbitrary SQL commands, steal data, or drop the entire database.

How to Fix
  1. Replace string interpolation with parameterized queries
  2. Use SQLAlchemy ORM methods instead of raw SQL
  3. Add input validation as an additional layer of defense
AI Fix Prompt

"In server/models.py line 87, replace the f-string SQL query with a parameterized SQLAlchemy query using bindparams or ORM methods."

Code
db.execute(f"SELECT * FROM transcriptions WHERE user_id = '{user_id}' AND title LIKE '%{search}%'")
What to Remember

Always use parameterized queries. Never interpolate user input into SQL strings.

Your Roadmap

The three most important next steps

1
God Function: transcribe_and_process (380 lines)
Complexity
Virtually untestable, extremely error-prone to modify. Any bug fix can have unintended side effects.
2
Only 8% Test Coverage (2 Tests for 4260 LOC)
Tests
Any change can silently break existing functionality. Refactoring becomes a gamble.
3
No Error Handling on Whisper API Calls
Code Quality
Transient API errors cause complete transcription failure. Users lose their recording without an error message.

You're on the right track. Every fix makes your code better for you and for AI. Keep going!

I analyzed these areas:

Overview

6
Quick Fixes
Small changes, often a single AI prompt
10
Important Improvements
Need a bit more attention, but worth it
2
Strategic Upgrades
Larger refactors for long-term stability

Appendix: Further Findings

These findings are less urgent but remain fully documented

Complexity

Why This Matters

AI assistants pack everything into one big function. Works until you change something — then everything breaks. If a function has >50 lines or >3 nesting levels, ask AI to split it.

MAJOR Medium

Deeply Nested Error Handling (5 Levels)

server/transcribe.py:128
What's Happening

Five nested try/except blocks make the control flow nearly impossible to follow.

What Happens if You Don't Fix This

Errors get caught at the wrong level, leading to silent failures and hard-to-find bugs.

How to Fix
  1. Extract each try/except block into its own function
  2. Use specific exceptions instead of generic ones
  3. Use early-return pattern for error paths
AI Fix Prompt

"In server/transcribe.py starting at line 128, flatten the 5 nested try/except blocks by extracting each into a separate function that raises specific exceptions."

Code
try:
    try:
        try:
            result = whisper.transcribe(chunk)
        except APIError:
            try:
                result = whisper.transcribe(chunk, model="base")
            except:
                ...
What to Remember

Flatten nested error handling by extracting functions. Each function handles one concern and its specific errors.

MAJOR Significant

Circular Import Between app.py and models.py

server/app.py:8
What's Happening

app.py imports models.py, and models.py imports app.py for the db instance. This is worked around with delayed imports, making the code fragile.

What Happens if You Don't Fix This

Any restructuring can lead to ImportError. The code is hard to test because import order is critical.

How to Fix
  1. Move database instance to its own module (db.py)
  2. Both modules import from db.py instead of each other
  3. Introduce Flask Application Factory pattern
AI Fix Prompt

"Create server/db.py exporting the SQLAlchemy db instance. Update server/app.py and server/models.py to import from server/db.py instead of each other."

Code
# server/app.py
from server.models import User, Transcription

# server/models.py
from server.app import db  # circular!
What to Remember

Circular imports indicate poor module boundaries. Extract shared dependencies into a separate module.

MAJOR Medium

Configuration Scattered Across 6 Files

server/config.py:1
What's Happening

Configuration values are spread across config.py, app.py, models.py, transcribe.py, whisper_api.py, and setup.py with sometimes conflicting defaults.

What Happens if You Don't Fix This

Inconsistent configuration leads to hard-to-reproduce bugs, especially between development and production.

How to Fix
  1. Centralize all configuration in config.py
  2. Use environment-dependent config classes (Development, Production, Testing)
  3. Other modules import from config.py
AI Fix Prompt

"Consolidate all configuration into server/config.py with Development/Production/Testing classes. Update all other files to import from config."

Code
# config.py: WHISPER_MODEL = "medium"
# transcribe.py: MODEL = os.getenv("MODEL", "small")  # conflicts!
# whisper_api.py: DEFAULT_MODEL = "base"  # another conflict!
What to Remember

Configuration should live in one place. A single source of truth eliminates configuration drift.

Tests

Why This Matters

In vibe coding, testing is the only guarantee. Every new prompt can break old code. Golden rule: write a test proving current state works BEFORE asking AI to change anything.

MAJOR Significant

No Integration Tests for API Endpoints

server/app.py:1
What's Happening

Not a single API endpoint is tested with HTTP requests. Neither upload, transcription, nor admin routes have integration tests.

What Happens if You Don't Fix This

Routing errors, wrong HTTP status codes, and serialization issues are only discovered in production.

How to Fix
  1. Use Flask test client (app.test_client())
  2. Test happy path + error cases for each endpoint
  3. Validate request/response format and status codes
AI Fix Prompt

"Create tests/test_api.py using Flask test client. Test all routes: GET /health, POST /upload, POST /transcribe, GET /transcriptions, /admin/* with both valid and invalid inputs."

Code
# No integration tests exist. Example of what should be:
# def test_upload_invalid_file(client):
#     response = client.post("/upload", data={"audio": (BytesIO(b"not audio"), "test.exe")})
#     assert response.status_code == 400
What to Remember

Every API endpoint needs at least a happy-path and an error-case integration test using the framework test client.

MAJOR Medium

No Test Fixtures or Factories

tests/test_transcribe.py:1
What's Happening

Test data is created inline without reusable fixtures. Every new test must write its own setup code.

What Happens if You Don't Fix This

Duplicated setup code leads to inconsistent test data and makes tests hard to maintain.

How to Fix
  1. Create pytest fixtures in conftest.py
  2. Factory functions for commonly needed test objects
  3. Provide fixtures for app instance, DB session, test client
AI Fix Prompt

"Create tests/conftest.py with fixtures: app (Flask test app), client (test client), db_session (test database), sample_audio (test audio file). Create tests/factories.py for User and Transcription factories."

Code
# Current: no fixtures, each test duplicates setup
def test_something():
    app = create_app()  # duplicated
    db.create_all()  # duplicated
    user = User(email="test@test.com")  # duplicated
What to Remember

Good test infrastructure (fixtures, factories, helpers) pays for itself within weeks by making tests easy to write and maintain.

Dead Code

Why This Matters

Dead code accumulates from AI sessions — old approaches left behind. It confuses both you and future AI prompts. Keep code clean: what's not needed gets deleted.

MAJOR Quick Fix

Entire Module server/whisper_api.py is Unused

server/whisper_api.py:1
What's Happening

server/whisper_api.py is not imported by any other module. The Whisper integration is done directly in transcribe.py.

What Happens if You Don't Fix This

Dead module confuses new developers and gets accidentally modified during refactoring.

How to Fix
  1. Delete the module since it is unused
  2. If desired: refactor transcribe.py to actually use whisper_api.py
AI Fix Prompt

"Delete server/whisper_api.py — it is not imported anywhere. Run grep -r "whisper_api" to confirm no references exist."

Code
# server/whisper_api.py — 180 lines, imported by nobody
class WhisperClient:
    def __init__(self, api_key, model="medium"):
        ...
    def transcribe(self, audio_path, language="de"):
        ...
What to Remember

Dead code is not free. It costs attention, creates confusion, and can introduce bugs when accidentally modified.

MAJOR Quick Fix

14 Unused Imports Across 5 Files

server/app.py:3
What's Happening

14 imported modules or functions are never used: json, sys, re in app.py, hashlib and hmac in auth.py, among others.

What Happens if You Don't Fix This

Unused imports slow down startup, increase memory footprint, and obscure real dependencies.

How to Fix
  1. Use ruff or autoflake to automatically remove unused imports
  2. Set up isort for consistent import sorting
  3. Set up pre-commit hook for import checks
AI Fix Prompt

"Run ruff check --select F401 --fix server/ to auto-remove all unused imports. Then run ruff check --select I --fix server/ to sort remaining imports."

Code
import json  # unused
import sys  # unused
import re  # unused
from flask import Flask, request, jsonify, redirect  # redirect unused
What to Remember

Use an auto-formatter (ruff, autoflake) to catch unused imports. Configure as a pre-commit hook to prevent accumulation.

Code Quality

Why This Matters

AI repeats itself between prompts. Inconsistent naming, duplicate functions. Each issue is small but together code becomes unmaintainable. Check regularly.

MAJOR Quick Fix

Bare except Catches SystemExit and KeyboardInterrupt

server/transcribe.py:198
What's Happening

except: without a specific exception catches everything including SystemExit, KeyboardInterrupt, and MemoryError.

What Happens if You Don't Fix This

Process cannot be cleanly terminated. Severe system errors are swallowed and go unnoticed.

How to Fix
  1. Replace except: with except Exception:
  2. Even better: catch specific exceptions (requests.Timeout, openai.APIError)
  3. Add logging for caught exceptions
AI Fix Prompt

"In server/transcribe.py, replace all bare except: clauses with except Exception as e: and add logging.exception("...") calls."

Code
try:
    result = process_audio(chunk)
except:  # catches EVERYTHING
    result = ""  # silently returns empty string
What to Remember

Never use bare except:. Always catch specific exceptions or at minimum except Exception.

Security

Why This Matters

AI-generated code often contains security holes — hardcoded keys, missing validation, SQL concatenation. These are invisible: the code "works" but is like an unlocked front door. For every AI-generated code, check input validation and whether secrets ended up in the source.

CRITICAL Significant

Missing Authentication on Admin Endpoints

server/app.py:203
What's Happening

Admin routes (/admin/users, /admin/stats) are accessible without any authentication whatsoever.

What Happens if You Don't Fix This

Anyone can view user data, delete accounts, and modify system settings.

How to Fix
  1. Implement authentication middleware
  2. Add JWT or session-based auth for admin routes
  3. Introduce role-based access control (RBAC)
AI Fix Prompt

"Add a @require_admin decorator to all /admin/* routes in server/app.py. Implement JWT-based authentication in server/auth.py."

Code
@app.route("/admin/users")
def admin_users():
    users = User.query.all()
    return jsonify([u.to_dict() for u in users])
What to Remember

Every admin endpoint must require authentication and authorization. Defense in depth means checking at every layer.

CRITICAL Quick Fix

Flask Debug Mode Enabled in Production Config

server/app.py:312
What's Happening

The application starts with debug=True, enabling the interactive debugger and code reload in production.

What Happens if You Don't Fix This

The Werkzeug debugger allows remote code execution. Attackers can run arbitrary Python code on your server.

How to Fix
  1. Control debug=True via environment variable
  2. Set FLASK_DEBUG=0 in production
  3. Use Gunicorn or uWSGI as production WSGI server
AI Fix Prompt

"In server/app.py line 312, replace app.run(debug=True) with app.run(debug=os.environ.get("FLASK_DEBUG", "0") == "1")."

Code
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)
What to Remember

Never enable debug mode in production. It exposes an interactive debugger that allows arbitrary code execution.

A further 29 lower-priority hints were reviewed but not written out individually — they would have padded this report without making it more useful.

Does this look familiar?

Your code probably has similar spots. AI agents find them for you — usually in under an hour.

Get a report for your project — EUR 19

Ready for your own report?

47 findings in this project. How many does yours have?

Analyse your code — EUR 19 Back to homepage

One-time EUR 19 incl. VAT · no subscription · report usually within an hour by e-mail