From Vibe Code to Enterprise Software: The Production Readiness Checklist

#production readiness checklist
Sandor Farkas - Founder & Lead Developer at Wolf-Tech

Sandor Farkas

Founder & Lead Developer

Expert in software development and legacy code optimization

Your AI-assisted prototype works. Users are onboarding, revenue is trickling in, and a serious enterprise buyer just asked for a security questionnaire and a reference architecture diagram. This is the moment every founder building with Cursor, Claude, or Copilot eventually reaches — and it is where a demo-grade codebase has to become something an enterprise procurement team will actually sign off on.

That transition has a name. It is called production readiness, and it is the gap between "it runs" and "it runs reliably, observably, and auditable under hostile conditions." The production readiness checklist below is the one we walk through in every vibe-code rescue engagement we take on at Wolf-Tech. It is deliberately opinionated, written for Symfony/PHP and Next.js/TypeScript stacks, and it exists because AI-generated code consistently leaves the same gaps in the same places.

Thirty items, grouped into six areas. You will not pass every one on day one. The goal is to know where you stand, prioritise ruthlessly, and close gaps in the order that matters most to your specific customers.

Security and secrets: the non-negotiables

Enterprise buyers start their evaluation here. Failing this section ends procurement conversations before they begin.

1. All secrets live outside the repository. Environment variables, loaded from a secret manager (AWS Secrets Manager, HashiCorp Vault, Doppler). No .env committed, no hardcoded API keys, no fallback defaults in source. Run git log -p -S "sk_" or trufflehog across your history and rotate anything it finds.

2. Authentication uses a vetted library. Symfony Security Bundle, NextAuth, or an identity provider like Auth0 or Clerk. Never hand-rolled session logic. AI tends to reinvent authentication; it tends to do so badly.

3. Password storage uses Argon2id or bcrypt with cost ≥ 12. MD5 and SHA-1 are instant disqualifiers. Symfony's PasswordHasher uses sane defaults — confirm the algorithm in security.yaml.

4. All inputs are validated server-side. Client-side validation is UX, not security. In Symfony, use Validator constraints on DTOs. In Next.js API routes, validate with Zod or a similar schema library before the data ever touches your business logic.

5. SQL uses parameterised queries or an ORM, always. Grep for string concatenation in queries:

grep -r "->query(\"SELECT.*\".*\$" src/
grep -r "db.execute(`SELECT.*\${" app/

Every match is a potential SQL injection vector. AI-generated code frequently produces the second pattern when a developer describes a query in natural language.

6. CSRF and CORS are explicitly configured. Symfony has CSRF tokens built into forms — use them. Next.js API routes need explicit CORS policy; the default of allowing all origins is wrong for any B2B SaaS.

7. A dependency scanner runs on every pull request. composer audit, npm audit, Dependabot, or Snyk. AI-generated package.json files frequently pull old, vulnerable versions because the training data predates recent CVEs.

Observability: if you cannot see it, you cannot sell it

Enterprise customers will ask how you debug incidents. "We read the logs on the server" is not a satisfying answer.

8. Structured logging is in place. JSON logs via Monolog (PHP) or Pino (Node), with a consistent schema: timestamp, level, message, trace_id, user_id, tenant_id. Plain console.log and error_log() do not count.

9. A single request has a correlation ID across services. Generate it at the edge, propagate via headers (X-Request-Id), include it in every log line and every outbound API call. Without this, you cannot follow a bug across a distributed system.

10. Errors are captured in Sentry, Rollbar, or equivalent. Unhandled exceptions should page someone, not disappear into a log file rotated weekly.

11. Application metrics are exposed. Request rate, error rate, p95/p99 latency, queue depth. Prometheus is free; Grafana Cloud has a generous free tier. There is no excuse for flying blind.

12. Health checks exist and mean something. A /healthz endpoint that returns 200 if the database, Redis, and critical upstream services are reachable — not just "the web server is alive."

13. Audit logs record who did what. For any action that modifies customer data, log the actor, the resource, the before/after state, and the timestamp, with an append-only store. SOC 2 requires this. Enterprise buyers ask for sample audit log entries in due diligence.

Reliability and performance under load

This is where the code quality audit findings concentrate in almost every vibe-code rescue we run.

14. Background work runs in queues, not inside request handlers. Symfony Messenger with a Redis or RabbitMQ transport. Email sends, file processing, webhook deliveries, AI inference calls — all asynchronous, all with retry and dead-letter handling.

15. Database queries have been profiled. Enable the slow query log, run EXPLAIN ANALYZE on your ten most-executed queries, add the missing indexes. N+1 detection in Doctrine:

// In dev, log every query with backtrace
$config->setSQLLogger(new DebugStack());
// Count queries per request; anything > 30 needs investigation

16. Connection pooling is configured. PgBouncer in front of PostgreSQL, ProxySQL in front of MySQL. Without it, your database hits its connection limit long before you hit your user limit.

17. Caching has an explicit policy. What is cached, for how long, and how is it invalidated? Redis with clear TTLs beats "we cache everything forever and restart when it breaks."

18. The service degrades gracefully. When Stripe is slow, checkout queues the charge rather than timing out. When search is down, the product page still loads without results. Circuit breakers in critical outbound paths.

19. A load test has been run recently. k6 or Locust at 3x expected peak, against a production-like environment. If you have never load tested, you do not know your real ceiling — you know your developer's laptop's ceiling.

Data protection and compliance

Non-negotiable for European B2B SaaS, and increasingly non-negotiable everywhere.

20. Backups run, and restores have been tested. Daily automated backups of the primary database with point-in-time recovery. Critically: a documented, rehearsed restore procedure. An untested backup is a theoretical backup.

21. PII is classified and minimised. You know which columns contain personal data, you encrypt them at rest, and you have a data retention policy that actually deletes records when required. GDPR Article 5(1)(e) is not optional in the EU.

22. A Data Processing Agreement is ready. Every enterprise customer will ask for one. Have it drafted, know your sub-processors, and maintain a list of where customer data flows.

23. TLS 1.2+ everywhere, HSTS enabled. Let's Encrypt is free, Traefik and Caddy automate it. There is no legitimate reason to ship plaintext HTTP to a production endpoint in 2026.

Deployment, rollback, and change management

24. Deployments are automated and repeatable. A CI/CD pipeline — GitHub Actions, GitLab CI, CircleCI — that runs tests, builds an image, and deploys. Not a Slack message to the developer asking them to push.

25. Every deployment is reversible in under ten minutes. Tag every release. Keep the previous Docker image. Practise the rollback; do not discover the procedure during an outage.

26. Database migrations are backwards compatible during rollout. Expand-contract pattern: add new columns, dual-write, migrate data, drop the old columns in a later release. Doctrine Migrations supports this workflow; the discipline has to come from the team.

27. Feature flags cover risky changes. LaunchDarkly, Unleash, or a small in-house implementation. New features ship dark, get toggled on for internal users, then a cohort, then everyone. The ability to turn a feature off without a deployment is an enterprise-grade capability.

Code quality, documentation, and process

The soft items that decide whether a second engineer can ever contribute to the codebase without starting over.

28. Static analysis runs in CI. PHPStan at level 5+ for PHP; tsc --noEmit with strict: true for TypeScript; ESLint with recommended rules. The AI-generated any types and suppressed warnings get caught here.

29. There are tests that mean something. Not 100% coverage — meaningful coverage. Integration tests for the critical user journeys (signup, checkout, data export) and unit tests for domain logic. A legacy code optimization engagement almost always starts by writing the tests that should have existed from the start.

30. A runbook exists for common incidents. "Database at 90% disk," "queue backlog over 10,000," "authentication provider outage." Two paragraphs each, kept in the repo. The first time on-call happens at 3am is not the right time to invent the response.

How to use this production readiness checklist

Do not attempt to close thirty gaps in parallel. A realistic sequence for most vibe-coded SaaS products looks like this: security items first, because a breach ends the business; observability next, because you cannot improve what you cannot measure; then reliability items, prioritised by what your load testing reveals; compliance items driven by your specific customer contracts; and finally the process items, which compound over time but rarely cause acute incidents.

A fair internal target is to close the security, observability, and reliability sections within six to eight weeks of a serious growth event. That is an aggressive timeline but an achievable one with a focused senior developer or a short external engagement.

Enterprise readiness is not a single project. It is a transition from one mode of building — fast, exploratory, AI-assisted — to another mode that adds the discipline AI tools do not enforce on their own. The checklist above is a map of the gap, not a recipe for despair. Most vibe-coded applications we see are closer to enterprise-ready than their founders believe, because the core product logic is often sound. What is missing is the operational envelope around that logic.

If you are looking at this list and counting the gaps in your own codebase, that is useful information. The next step is a structured review that turns the gaps into a prioritised remediation plan with concrete effort estimates. Wolf-Tech offers a free initial consultation for exactly this kind of assessment. Contact us at hello@wolf-tech.io or visit wolf-tech.io to start the conversation.