Using ChatGPT in an Existing Web Project: A Repeatable Development Workflow

A useful ChatGPT web development workflow starts with a change you can verify. In an existing application, the challenge is not producing another code snippet: it is making the requested change while preserving the behavior the project already depends on.

This guide follows one bounded example: tightening pagination validation for a list endpoint. You will prepare relevant context, ask for a plan, inspect a small implementation, test boundary cases, and record the decision. The example uses plain JavaScript so that the review process is visible without assuming a particular web framework or database.

If you have not yet tried a small task with ChatGPT, begin with your first guided web development task with ChatGPT. Here, the starting point is an application you already maintain.

Define a change with observable acceptance criteria

Suppose an endpoint accepts page and limit query parameters. Its current parsing is permissive: a value such as 10abc may become 10 when passed to parseInt. You want to reject malformed values without changing filtering, authentication, database access, or the response format.

Write the intended behavior before requesting code:

  • Missing page defaults to 1; missing limit defaults to 20.
  • Supplied values must be positive decimal integers without leading zeros.
  • page must not exceed 10,000; limit must not exceed 100.
  • Empty strings, signs, fractions, spaces, suffixes, and repeated parameters are rejected.
  • The helper returns page, limit, and a zero-based offset.
  • The existing route remains responsible for mapping invalid input to the application's established client-error response.

The upper bounds are example application rules, not universal recommendations. Replace them with limits justified by your own endpoint. This task improves parsing; it does not make offset pagination efficient for every database or dataset.

Prepare a minimal context packet

Give ChatGPT the information needed to understand the boundary of the change:

  • The runtime and framework versions actually used by your project.
  • The existing parsing helper and the route code that calls it.
  • A representative test and the command used to run that test.
  • The established error-response convention.
  • Requirements that must stay unchanged, including authorization and filtering.

Do not send the entire repository by default. Remove credentials and personal data, and use invented request examples. Check the data controls and organizational policy for the particular product and workspace you use before sharing private project material.

For the example in this article, the input is explicitly a URLSearchParams instance. An Express, Next.js, or other route may expose a different query representation. Show that representation rather than silently passing a framework-specific object to an unrelated helper.

Ask for a plan before asking for code

A useful first request might be:

We need to tighten pagination parsing for one existing list endpoint. The helper receives URLSearchParams and the route handles its errors using our existing client-error response. Here are the current helper, caller and relevant test. Use the acceptance criteria below. First identify assumptions and propose the smallest change. Do not alter filtering, authentication, database queries, response shape or dependencies.

Review the plan against the code you supplied. If it proposes replacing the router or installing a validation package, ask why that is necessary for this bounded task. If it assumes duplicate parameters can be ignored, point back to the explicit rejection requirement.

Once the plan fits the scope, request the implementation and focused tests. Keeping these steps separate gives you a chance to correct an assumption before it becomes a larger patch.

Inspect a small implementation

The following helper illustrates one implementation of the stated rules:

export function parsePagination(params) {
  function readPositiveInteger(name, fallback, maximum) {
    const values = params.getAll(name);
    if (values.length === 0) return fallback;
    if (values.length !== 1 || !/^[1-9]\d*$/.test(values[0])) {
      throw new RangeError(`${name} must be one positive decimal integer`);
    }
    const value = Number(values[0]);
    if (!Number.isSafeInteger(value) || value > maximum) {
      throw new RangeError(`${name} is outside the supported range`);
    }
    return value;
  }

  const page = readPositiveInteger('page', 1, 10000);
  const limit = readPositiveInteger('limit', 20, 100);
  return { page, limit, offset: (page - 1) * limit };
}

Review what the helper does before integrating it. getAll makes duplicate detection explicit. The regular expression checks the entire string before numeric conversion, and the numeric checks enforce the stated bounds. Defaults apply to absent parameters; an explicitly empty value is not treated as absent.

The function does not query a database, perform authorization, or create an HTTP response. Keeping those responsibilities outside the helper makes the change easier to inspect. Its caller must translate RangeError into the project's established client-input error without exposing internal details.

The helper also assumes that its argument implements URLSearchParams. Add a conversion at an appropriate boundary only if the actual route needs it, and test that conversion with the framework's real query representation. Do not infer that integration from this isolated example.

Test accepted input and rejected boundaries

Use explicit input-output examples when reviewing ChatGPT's tests:

Query stringExpected result
Empty querypage 1, limit 20, offset 0
page=3&limit=10page 3, limit 10, offset 20
page=10000&limit=100page 10000, limit 100, offset 999900
page=0Reject
limit=101Reject
limit=10abcReject
page=1.5Reject
page=01Reject
limit=Reject
page=1&page=2Reject

Include negative values, encoded whitespace, and an integer larger than JavaScript can represent safely as additional rejection cases. Tests should exercise the contract, not merely assert that the helper returns an object.

Then test the route itself. Confirm that invalid input produces the existing client-error response, authorized valid requests retain their filtering and response shape, and the helper is called with the intended input type. Passing helper tests alone does not prove that the route is integrated correctly.

Debug with reproducible evidence

When a test fails, report its exact input, observed output, and expected output. For example:

The acceptance criteria reject repeated page parameters. The test for page=1&page=2 currently returns page 1 instead of raising the input error. Here is the helper and failing assertion. Identify the cause and propose a minimal correction; keep the single-value and default cases unchanged.

Only use that follow-up if it describes a failure you actually observed. If the test already passes, do not ask the model to fix a hypothetical failure in the working implementation.

After a correction, run the previously failing case and the related boundary cases. If ChatGPT proposes weakening an assertion to make the suite pass, compare the assertion with the agreed contract before accepting that change.

Review the patch before accepting it

Read the diff independently of the explanation. Check whether the modification changes files outside the agreed scope, introduces dependencies, suppresses errors, or removes tests that protect existing behavior.

For this pagination example, inspect the caller as carefully as the helper. A correct parser can still be integrated incorrectly if exceptions become server errors, query arrays are flattened before duplicate detection, or a refactor accidentally bypasses filtering.

Run the project's relevant checks and inspect the endpoint behavior. Test results reduce uncertainty; they do not turn a generated explanation into a guarantee. If the patch changes a security boundary or a shared abstraction, expand the review to match that actual change.

Record reusable context and decisions

After accepting the patch, record the rules that will matter next time: the query input type, the chosen bounds, how the route maps errors, and which tests cover the behavior. Keep a short prompt template with slots for the actual files and acceptance criteria.

That record is more useful than copying a long chat transcript into every future request. When the project or task changes, replace the stale context rather than assuming that previous answers still describe the codebase.

A completed workflow leaves a focused diff, checks you ran, and a clear account of what remains outside scope. For this example, database pagination strategy and broader API redesign remain separate tasks.

Frequently Asked Questions

How much project context should I provide?

Start with the relevant helper, caller, runtime details, existing error convention, and a representative test. Add more only when a concrete uncertainty requires it, and remove credentials and personal data.

Should I accept a patch when its helper tests pass?

Review the diff and test the integration too. Helper tests do not establish that the route handles errors, authorization, filtering, and response formatting correctly.

Why does the example reject leading zeros and repeated parameters?

Those are explicit rules of this example application. Your project may choose another contract, but its implementation and tests should agree on how to handle those inputs.

What should I do when a generated change fails a test?

Provide the exact input, observed result, expected result, and relevant code. Request a minimal correction and rerun the affected checks without weakening the agreed behavior.

Does this helper improve database pagination performance?

Not by itself. It validates input and bounds the example request. Query planning, indexes, dataset size, and alternatives to offset pagination need a separate assessment.


Transparency note: This article contains no affiliate links. The pagination limits are illustrative application rules, not a production API specification.

Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Necessary

Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.

Analytics

This website uses Google Analytics to collect anonymous information such as the number of visitors to the site, and the most popular pages.

Keeping this cookie enabled helps us to improve our website.