Introduction
Hello from Japan! 🇯🇵
This article was originally published in Japanese on Qiita and has been translated and adapted for DEV Community.
My name is tosane932. I work as a professional truck driver in logistics while teaching myself Python and web application development.
I began studying on May 12, 2026, and my total learning time has now reached 152 hours.
This time, I used Codex in VS Code to perform a static review of a Flask application I am developing.
The target was sales_data_app, a sales management application for bakery stores.
It currently supports:
- Product registration
- Daily sales quantity entry
- Sales rankings
- Chart.js visualizations
- Business advice through the Gemini API
- PostgreSQL data management
- Docker-based runtime environments
- Testing with pytest and GitHub Actions
I had already reviewed the code myself several times.
This time, however, I asked Codex to inspect the entire project and identify potential improvements.
My conclusion was that Codex is extremely fast and highly capable at investigation.
At the same time, asking it to fix every reported issue at once could damage existing features or the database.
To me, Codex felt like:
An experienced veteran employee transferred from another department who does not yet understand how this particular workplace operates.
Its inspection ability is excellent.
However, a human who understands the actual workplace still needs to decide what is a defect and what is intentional behavior.
Installing Codex in VS Code
I installed the official Codex extension in VS Code.
Codex can inspect files in the currently opened project and help with tasks such as:
- Explaining code
- Investigating problems
- Editing files
- Running tests
- Executing terminal commands
However, my first instruction prevented the investigation from moving forward.
Please inspect the structure of this project.
Do not modify files or run terminal commands.
Codex responded that it had no way to inspect the file list or file contents without using terminal commands.
I therefore revised the instruction to allow read-only commands while still prohibiting changes.
You may run read-only terminal commands required
to inspect the project structure.
However, the following actions are prohibited:
- Creating, modifying, or deleting files
- Installing packages
- Modifying the database
- Performing Git write operations
- Starting the application
After this change, Codex could inspect the entire project in read-only mode.
Rules I Set for Codex
Giving Codex unrestricted access felt dangerous, so I added explicit working rules to the custom instructions.
Working rules:
- Do not begin making changes without my explicit permission.
- First explain the facts you can confirm, possible causes,
proposed fixes, affected areas, and required tests.
- Separate investigation from implementation.
In principle, handle only one issue at a time.
- Do not mix unrelated changes into the same task.
- Do not run Git commit, push, reset, or rebase
without explicit permission.
- Confirm with me before creating or deleting databases,
running migrations, or modifying data.
- Confirm with me before deleting files,
updating dependencies, or performing actions
that may affect production.
- Read-only investigation commands are allowed.
- After making changes, report the modified files,
the reason for each change, the affected areas,
and the verification results.
I also configured Codex to request approval before performing operations instead of giving it full access.
Custom instructions describe expected behavior, but they are not a hard access-control system.
For that reason, I used both configuration restrictions and written instructions.
Performing a Static Review of the Entire Project
I asked Codex to review the whole project from several perspectives.
Inspect this entire project in read-only mode.
Report improvement candidates from the following perspectives:
- Obvious defects
- Security
- Maintainability
- Missing tests
- Unnecessary files or obsolete processing
- Differences between the README and implementation
Conditions:
- Do not create, modify, or delete files
- Do not modify the database
- Do not perform Git write operations
- Do not start the application or run tests yet
- Separate confirmed facts from assumptions
- Classify severity as high, medium, or low
- For each item, provide the relevant filename
and location as evidence
Codex reported a total of 18 improvement candidates.
The main findings were as follows.
High Severity
- Migrations that might fail when building from an empty database
- Stored XSS in the dynamically rendered ranking section
- Public data modification without authentication
- Missing validation between sale dates, product dates, and sales status
- File permissions for
.env
Medium Severity
- Repeated Gemini API execution without authentication
- Invalid input being treated as a server error or even a successful request
- No database-level prevention of duplicate sales for the same product and date
- Insufficient tests for important behavior
- Sales aggregation based only on product names
- Unpinned Chart.js version
- Containers running as the root user
- Development dependencies included in production
Low Severity
- Year selection fixed to 2026
- Images and videos no longer referenced from the README
- Local build artifacts and outdated documents
- Placeholder URLs remaining in JSON-LD
- Unclear relationship between CI and Render deployment conditions
Codex organized the findings with:
- Filenames
- Relevant lines
- Confirmed facts
- Possible effects
- Suggested improvements
The number of findings surprised me.
However, asking Codex to fix all 18 issues at once would have been risky.
Do Not Accept AI Findings Without Verification
In the first review, Codex classified the .env file permissions as high severity.
I asked it to investigate the issue again.
Codex then checked additional facts:
-
/home/tosanehad0750permissions -
.envwas excluded from Git -
.envwas not included in the Docker image - Render did not directly use the local
.envfile - The additional risk was small in a single-user environment
After this investigation, Codex revised its own severity rating from high to low or medium.
This demonstrated why the first AI response should not automatically be accepted.
Even when an AI answer is detailed and confidently written, it may still be wrong or incomplete.
I used the following process:
- Perform a static review of the entire project
- Recheck only the high-severity findings
- Separate reproducibility conditions from current practical impact
- Confirm the required specification before making changes
- Select only one issue as the first fix
Choosing Stored XSS as the First Fix
Of the 18 findings, I selected stored XSS in the dashboard’s dynamic ranking display as the first issue to fix.
I chose it because:
- The change could be limited to one file
- It did not affect the database or authentication design
- Normal product-name display could be preserved
- The security benefit was clear
- Manual verification would be straightforward
The problematic code inserted a product name retrieved from an API directly into an HTML string.
<div class="prod-name">${item[0]}</div>
The generated HTML string was later assigned to innerHTML.
rankContainer.innerHTML = htmlContent;
item[0] contained a product name entered by a user.
If the name contained HTML or event attributes, the browser could interpret it as markup instead of plain text.
Jinja2 auto-escaping protected the initial server-rendered page.
However, after data was fetched through the Fetch API, the ranking was updated in JavaScript using innerHTML.
That created a separate stored XSS risk.
Asking Codex for the Design Before Allowing Changes
I did not immediately allow Codex to edit the file.
First, I asked it to explain the proposed design.
Of the high-severity findings,
handle only the stored XSS issue
in the product-name ranking display.
Do not modify any files yet.
Explain the following:
1. The exact code location that requires modification
2. How to preserve the same display without using innerHTML
3. The files that would need to change
4. The impact on the existing ranking display
5. The expected behavior when product names contain
Japanese text, symbols, or HTML-like strings
6. The tests required after the change
Do not handle the AI response display,
CSP, authentication, database,
or any other improvement in this task.
Codex proposed the following approach:
- Stop using
innerHTML - Create elements with
document.createElement() - Assign product names through
textContent - Use a
DocumentFragmentto append multiple rows efficiently - Preserve the existing CSS classes and DOM structure
- Generate the empty-data message through the DOM API as well
It explained that the change could be completed entirely inside:
templates/dashboard.html
Allowing Codex to Implement the Fix
After reviewing the scope, I gave Codex permission to implement only that fix.
Implement only the stored XSS protection
for the dynamically generated product ranking.
Conditions:
- Modify only templates/dashboard.html
- Change only the ranking-update logic
- Do not touch the AI response, Chart.js,
API, CSS, backend, or database
- Preserve existing class names and DOM structure
- Stop generating the ranking with innerHTML
- Use DOM APIs and textContent
- Do not run Git commit or push
- Do not run tests or start the application yet
After making the change, report:
1. The exact range changed
2. The difference before and after
3. Confirmation that no out-of-scope changes were made
Codex completed the change in approximately 47 seconds.
The Updated Code
The product name was assigned through textContent.
const productName = document.createElement('div');
productName.className = 'prod-name';
productName.textContent = item[0];
textContent does not interpret the value as HTML.
For example, even if the following product name is stored:
<b>Melon Bread</b>
the browser displays it as text instead of creating a bold b element.
Each ranking element is now created with the DOM API.
const rankingItem = document.createElement('div');
rankingItem.className = 'ranking-item';
const rankBadge = document.createElement('div');
rankBadge.className = 'rank-badge';
if (rank <= 3) {
rankBadge.classList.add(`rank-${rank}`);
}
rankBadge.textContent = String(rank);
The quantity and unit are also created as separate elements instead of HTML strings.
const productQuantity = document.createElement('div');
productQuantity.className = 'prod-qty';
productQuantity.append(
document.createTextNode(String(item[1]))
);
const productUnit = document.createElement('span');
productUnit.className = 'prod-unit';
productUnit.textContent = 'items';
productQuantity.append(productUnit);
Finally, the generated elements are appended together.
rankingItem.append(
rankBadge,
productName,
productQuantity
);
fragment.append(rankingItem);
The previous ranking content is removed with:
rankContainer.replaceChildren();
Because the existing CSS classes and DOM structure were preserved, the display logic became safer without changing the appearance.
Manual Verification
After the fix, I registered test products, entered sales quantities, and verified the results.
The local environment and Render production environment use separate databases.
For that reason, I registered the same test products again in Render and checked the behavior from my smartphone.
Normal Product Name
Melon Bread
It displayed normally.
Product Name Containing an HTML Tag
<b>Melon Bread</b>
It was not displayed in bold.
The browser treated it as plain text rather than HTML.
Product Name Containing Japanese Text and Symbols
あんぱん <限定> & コーヒー
The characters <, >, and & displayed correctly.
I found no problems with:
- Product registration
- Sales quantity entry
- Dynamic ranking updates
- Dashboard charts
Final Check on the Render Demo from a Smartphone
After deployment, I operated the public Render demo from my smartphone.
I registered:
<b>メロンパン</b>あんぱん <限定> & コーヒー
I then entered daily sales quantities and confirmed that the products appeared correctly in both the ranking and chart.
The HTML tags were not executed or rendered as formatting.
The special characters <, >, and & were not lost.
The existing sales-entry workflow, ranking, and charts also continued to work normally.
Reviewing the Diff
Codex reported that only templates/dashboard.html had changed.
I also reviewed the change manually with git diff.
git diff -- templates/dashboard.html
The git diff output was displayed through the less pager.
To exit the pager, press:
q = quit
This does not close the terminal.
It only closes the diff viewer and returns to the normal command prompt.
Can Codex Be Used in Real Development?
In this case, Codex did much more than generate code.
It handled:
- Inspection of the entire project structure
- Comparison between the README and implementation
- Identification of security risks
- Identification of the relevant files and lines
- Separation of confirmed facts from assumptions
- Clarification of reproduction conditions
- Analysis of the impact on existing features
- Suggestions for required tests
- A narrowly scoped implementation
- Reporting of the final changes
The ability to perform all of this quickly felt extremely powerful.
A few years ago, a person would have needed to open files one by one, record the relevant line numbers, and prepare a report manually.
Static-analysis tools and linters have existed for a long time.
However, explaining a problem in Japanese while considering project context, likely impact, and possible fixes would still have required substantial human effort.
That said, asking Codex to fix all 18 findings in one operation would have been dangerous.
Some findings required business decisions before any code change.
Examples included:
- Whether edits to historical sales should be allowed
- Whether discontinued products should allow corrections to past records
- Whether anyone should be able to operate the public demo
- Whether authentication should be mandatory
- How to repair migrations for an empty database
- How migration changes could affect the existing Render database
A technically reasonable change could still break the purpose of the application.
A Veteran Inspector from Another Department
The best logistics analogy I found was:
Codex is an experienced veteran employee transferred from another department who does not yet understand this workplace.
It can quickly identify dangerous equipment, questionable procedures, and suspicious code.
Its reports are fast and detailed.
However, it does not automatically know:
- Why the current workflow exists
- Which requirements have priority
- Which exceptions are necessary
- What the public demo is intended to allow
- Which existing behaviors must be preserved
A human reviewing the findings still needs to decide:
- Is this truly a defect?
- Is it an intentional specification?
- Is it a future improvement?
- Does it need to be fixed immediately?
- What scope can be changed safely?
- Could the fix break another workflow?
Before allowing Codex to modify the code, I followed this process:
- Inspect the whole project in read-only mode
- Recheck the high-severity findings
- Correct the severity of an overestimated item
- Limit the first fix to one stored XSS issue
- Review the design and impact before implementation
- Limit the change to one file
- Allow Codex to implement the fix
- Review the diff with
git diff - Register the test products locally and verify sales entry and dashboard display
- Commit the change and push it to GitHub
- Confirm completion of the Render deployment
- Register the same products again in Render because its database is separate
- Verify sales entry, rankings, and charts from a smartphone
- Confirm that both the local and production environments behaved normally
Codex changed the code in approximately 47 seconds.
However, making those 47 seconds safe required a human to read the findings, understand the specification, and define the allowed scope.
What AI Can Handle and What Humans Must Decide
I organized the responsibilities as follows.
Tasks That Are Easy to Delegate to Codex
- Inspecting files in the project
- Identifying possible code issues
- Showing evidence and relevant locations
- Comparing possible fixes
- Making narrowly scoped code changes
- Reporting what changed
- Suggesting test cases
Decisions That Still Belong to Humans
- The purpose of the application
- Business rules
- Priorities
- Acceptable risk
- Public demo operation policies
- Database and production-change decisions
- Which findings to adopt or postpone
- Final verification and release decisions
Codex works quickly when instructions are clear.
However, giving it full access with vague instructions such as:
Fix everything.
could lead to a serious incident.
The faster the worker, the more clearly the work area and stopping conditions must be defined.
Conclusion
I used Codex in VS Code to perform a static review of a Flask application and fix one stored XSS issue.
The final implementation changed only the dynamic ranking-generation logic in:
templates/dashboard.html
The fix included:
- Removing ranking generation through
innerHTML - Creating DOM elements with
createElement() - Assigning product names through
textContent - Preserving the existing CSS classes and DOM structure
- Manually testing Japanese text, symbols, and HTML-like product names
- Confirming that normal product registration, sales entry, and ranking display still worked
Codex demonstrated investigation and implementation speed that could be highly useful in real development.
However, fixing every issue identified by AI is not automatically the correct decision.
The important process is:
Investigate
Recheck
Define the specification
Limit the change
Review the diff
Verify the actual behavior
Codex is an extremely fast and capable worker.
However, the decision about what to fix, what not to fix, and when the application is ready to ship still belongs to the human developer.
My total learning time has now reached 152 hours.
I will continue using AI without handing over the entire project blindly.
My goal is to remain able to explain the cause, affected area, and reason for each change in my own words.
Related Links
GitHub
https://github.com/tosane932/sales_data_app

Top comments (0)