Introduction
Hello from Japan! π―π΅
This article was originally published in Japanese on Qiita and has been translated and adapted for DEV Community.
I am a working truck driver teaching myself Python.
I try to bring two habits from logistics into web application development:
- Do not leave any cargo behind
- Inspect everything before shipment
This was Day 69 of my Python-learning journey, with a total of 148 study hours.
This time, I did not add a new feature to my bakery sales management application, sales_data_app.
Instead, I spent five hours on:
- Repository cleanup
- Full inspection
- Removal of obsolete code
- Synchronizing documentation and configuration with the current application
The inspection covered much more than application code.
I reviewed:
- README files
- Screenshots
- Demo videos
- Thumbnails
.gitignore.dockerignore- Old Excel-related logic
- Unused imports
- Unnecessary dependencies
- Unused CSS
- Outdated UI text
- Git conflict markers
- pytest
- Synchronization with GitHub
The application itself was working.
However, a working application and a repository that accurately represents the current specification are not the same thing.
As development continues, small leftovers begin to accumulate:
- Old specifications
- Outdated images
- Obsolete settings
- Unused CSS
- Dependencies that no longer have a purpose
In logistics terms, the delivery may have been completed successfully, while old materials and paperwork are still sitting in the corner of the truck.
Before loading the next shipment, I decided to inspect and clear the entire cargo area.
Main idea
This article is not only about organizing files.
A working application does not necessarily mean that the code, dependencies, UI, documentation, Docker configuration, and Git state all match the current specification.
What This Article Covers
This article explains:
- How to inspect an entire Flask repository
- A safe order for reviewing deletion candidates
- The difference between
.gitignoreand.dockerignore - How to find unused imports, dependencies, and CSS
- How to interpret an empty
grepresult - Why searching for Git conflict markers produced false positives
- How to decide whether changes belong in one commit
- Why I checked both pytest and
working tree clean - A reusable repository inspection checklist
This is a long article.
You can read it from beginning to end, jump directly to a section that interests you, or use the repository inspection checklist near the end during your own maintenance work.
The Application
sales_data_app is a web application that combines:
- Bakery product registration
- Daily sales entry
- Sales analysis
- Business advice generated through the Gemini API
The main technology stack is:
Python 3.12
Flask
PostgreSQL
SQLAlchemy
Flask-Migrate / Alembic
Docker / Docker Compose
Gunicorn
Render
pytest
GitHub Actions
Gemini API
The application supports the following workflow:
Register products and prices
β
Enter or update today's sales quantities
β
Review sales rankings and charts
β
Receive business advice from Gemini
Thinking About the Inspection in Five Layers
Looking back, the inspection targets could be divided into five layers.
1. Runtime code
Unused imports, obsolete logic, old settings, unused CSS
2. Dependencies
Libraries that remained in requirements.txt unnecessarily
3. UI and documentation
HTML wording, README files, screenshots, and demo assets
4. Delivery scope
.gitignore and .dockerignore
5. Shipment status
pytest, git diff, git status, and GitHub synchronization
Dividing the repository into these five layers made the inspection scope much clearer than simply searching for βunnecessary files.β
A repository inspection is not only about deleting files.
It is the process of aligning the current specification with the code, dependencies, UI, documentation, and delivery state.
Work Completed During the Five Hours
The main tasks were:
- Organize demo videos, thumbnails, and screenshots
- Correct image paths in the README
- Capture screenshots of the current UI
- Clean up
.gitignore - Clean up
.dockerignore - Remove obsolete Excel-related logic
- Remove unused imports
- Remove the
openpyxldependency - Remove unused CSS
- Correct outdated page titles
- Search for remnants of old specifications
- Search for Git conflict markers
- Commit changes by purpose
- Run pytest
- Verify synchronization with GitHub
- Record the work in two README files
The following sections describe the actual order of work.
1. Organizing Images and Videos by Purpose
I started by organizing the demo assets in the repository.
The final structure became:
sales_data_app/
βββ demo_mp4/
βββ demo_thumbnail/
βββ screenshot/
βββ static/
βββ templates/
βββ README.md
Each directory now has a clear responsibility.
demo_mp4/
βββ Demo videos
demo_thumbnail/
βββ YouTube thumbnails
screenshot/
βββ Screenshots used in the README
Previously, videos and images were mixed across the repository root and other locations.
This did not directly affect application behavior.
However, it made it difficult for another person to answer questions such as:
What is this image used for?
Is this file still required?
Is it necessary to run the application?
Is it documentation material?
Organizing files by both directory name and location makes their purpose easier to understand without opening them.
Folder organization is not merely cosmetic.
It is part of the information architecture of the repository.
Update README Paths After Moving Files
When files move into new directories, the README references must also change.
For example, after moving a screenshot into the screenshot directory:

If the files are moved but the README paths are not updated, the images stop appearing on GitHub.
I checked the work in this order:
Move the files
β
Update the README paths
β
Confirm that the images display on GitHub
2. Aligning the README with the Current UI
Some screenshots in the README no longer matched the applicationβs current screens.
I started the latest version of the application and captured new screenshots.
The main updated screens were:
- Product master registration
- Menu registration completion
- Daily sales entry
- Sales analysis dashboard
README screenshots are not merely decoration.
When someone opens a repository, they may inspect the screenshots before reading the code.
If the screenshots are outdated, an improved application may still appear to be using its old UI.
An Outdated HTML Title
While reviewing the screens, I also found an outdated title in the HTML.
Before:
<title>Sales Aggregation Complete</title>
However, the current screen represents completed product-menu registration, not sales aggregation.
I changed it to:
<title>Menu Registration Complete</title>
The browser-tab title is also part of the application specification visible to users.
Updating the page heading while leaving the tab title outdated still creates inconsistency.
Even when the application works correctly, outdated wording may mislead users or developers reading the code.
UI wording should be synchronized with the current specification just like application logic.
3. Updating .gitignore for the Current Development Environment
Next, I reviewed files that Git does not need to track.
The cleaned-up .gitignore became:
# Python
.venv/
__pycache__/
*.pyc
.pytest_cache/
# Raw operational data and sensitive files
ιε»ε£²δΈι«/
*.xlsx
*.db
.env
# Other unnecessary files
*.bak
sales_data_app_android_demo.mp4
Do Not Track Virtual Environments or Caches
.venv/
__pycache__/
*.pyc
.pytest_cache/
These files are generated separately in each development environment.
They can be recreated and do not need to be stored on GitHub.
Do Not Track Secrets
.env
An .env file may contain sensitive values such as Gemini API keys.
It should be explicitly excluded to reduce the risk of accidentally pushing secrets to a public repository.
Do Not Track Local Data
*.db
*.xlsx
ιε»ε£²δΈι«/
The production application uses PostgreSQL.
Local SQLite files and old Excel documents do not need to be stored in GitHub.
However, an important point is:
A file looks old
β
It is safe to delete immediately
I checked local.db and confirmed that the configuration still referenced it.
Therefore, I excluded it from Git tracking but did not immediately delete it from my local environment.
4. Using .dockerignore to Decide What Goes into Production
Files that Git should not track and files that Docker should not receive serve different purposes.
I therefore reviewed .dockerignore separately.
# Git
.git
.gitignore
# Environment variables and virtual environments
.env
.venv/
venv/
# Python and test caches
__pycache__/
*.pyc
.pytest_cache/
# Local data and obsolete documents
*.db
*.xlsx
ιε»ε£²δΈι«/
*.bak
# Development and documentation files
README.md
test_prompts.py
demo_mp4/
demo_thumbnail/
screenshot/
# Operating-system and log files
*.log
.DS_Store
README files, screenshots, demo videos, and tests are valuable on GitHub.
However, they were not required in this production Docker image.
.gitignoreand.dockerignorehave different responsibilities.
.gitignore: decides what Git does not track.dockerignore: decides what Docker does not send into the build context
In logistics terms:
Documents worth storing in the warehouse
β
Cargo that belongs on the delivery truck
GitHub may preserve development history and documentation.
Docker should carry only what the running application needs.
Two Questions for Classifying Files
When deciding where a file belongs, I used two questions:
1. Is this file worth preserving on GitHub?
2. Is this file needed when the production application runs?
| File | GitHub | Docker | Reason |
|---|---|---|---|
| Application code | Yes | Yes | Required to run |
| HTML and CSS | Yes | Yes | Required for the UI |
| README | Yes | No | Documentation |
| Screenshots | Yes | No | Used for repository explanation |
| Demo videos | Yes | No | Not required at runtime |
| Test files | Yes | No in this image | Used for CI and development |
.env |
No | No | Sensitive information |
.venv |
No | No | Recreated per environment |
| SQLite database | No | No | Local development data |
This approach is more useful than copying ignore files from another project without understanding them.
5. Searching for Leftovers from the Old Excel Implementation
The early version of this application used Excel.
The architecture later moved toward PostgreSQL, but some Excel-era code remained.
I found the following leftovers.
Old Folder Configuration in config.py
PAST_FOLDER_NAME = "ιε»ε£²δΈι«"
PAST_FOLDER = os.path.join(
BASE_DIR,
PAST_FOLDER_NAME,
)
Old Directory-Creation Logic in app.py
os.makedirs(
config.PAST_FOLDER,
exist_ok=True,
)
Unused Imports
from flask import send_file
from google.genai import types
Unnecessary Dependency
openpyxl
The current application stores sales data in PostgreSQL.
It no longer generates or sends Excel files.
After confirming the references, I removed the obsolete code and dependency.
6. Do Not Delete a Candidate Immediately
An important part of the inspection was avoiding immediate deletion when something looked obsolete.
I used the following sequence:
Search for the name
β
Check where it is referenced
β
Compare it with the current specification
β
Delete it
β
Search for the same name again
β
Run tests
For example, finding openpyxl in requirements.txt was not enough reason to remove it immediately.
I first checked whether the code still used it.
I applied the same process to:
- Configuration variables
- Imports
- CSS classes
- Old folder names
Deleting code because it βlooks oldβ is risky.
Treat the search before and after deletion as one complete verification process.
7. Final Diff: 23 Lines Removed and 2 Changed
After removing the old Excel logic, unused imports, unnecessary dependencies, unused CSS, and outdated UI text, the diff looked like this:
app.py | 10 +---------
config.py | 4 ----
requirements.txt | 1 -
static/style.css | 8 --------
templates/success.html | 2 +-
5 files changed, 2 insertions(+), 23 deletions(-)
I did not add a large amount of new code.
Instead, I removed 23 lines that were no longer needed by the current specification.
Development does not only mean increasing the amount of code.
Reducing unused code with a clear reason is also an improvement.
Less code is not automatically better.
However, removing unnecessary code can:
- Make the current behavior easier to understand
- Reduce the risk of accidentally reusing obsolete logic
- Clarify the purpose of dependencies
- Reduce future maintenance targets
- Make it easier to keep the README and implementation consistent
8. Finding and Removing Unused CSS
I used grep to check whether CSS remained that was no longer used by HTML or JavaScript.
grep -Rni "ai-loading" \
templates \
static \
app.py
The first search found only the CSS definition:
static/style.css:680:.input-page .ai-loading {
The class was not referenced by the templates or JavaScript.
I removed the entire CSS block.
.input-page .ai-loading {
/* Unused styles */
}
I then ran the same search again.
grep -Rni "ai-loading" \
templates \
static \
app.py
The result contained zero matches.
No output
I also removed an old .btn-back style that the current dashboard no longer used.
A CSS Definition Does Not Prove That the Class Is Used
A class existing in a stylesheet and a class being used by the application are different things.
Both sides must be checked:
Does the CSS definition exist?
Is it referenced by HTML or JavaScript?
When only the definition remains and there are no references, it becomes a deletion candidate.
However, JavaScript may apply classes dynamically, so checking HTML alone is not sufficient.
9. A Red Cross from grep Did Not Mean an Error
When I searched for old wording and class names, the command displayed no matches.
However, my terminal showed a red cross.
At first, I thought the command had failed.
The grep exit statuses mean:
0: A matching line was found
1: No matching line was found
2 or higher: The command itself failed
In this case, exit code 1 meant that the old text was not found.
That was the expected result.
No match
=
No obsolete remainder
Do not judge success or failure only from terminal colors or symbols.
Check what the commandβs exit status actually means.
Zero Search Results Are Still a Valid Result
Searches are not only useful for finding problems.
They can also verify that something no longer exists.
After deletion, searching for the same name and receiving zero matches confirms:
The deleted identifier no longer remains
In that case, no output is the result.
You do not need to memorize every command in this article.
What matters is understanding:
- What you are searching for
- What a match or no match means
- How to reuse the command later from your shell history or notes
The regular expression used below can simply be understood as a condition that searches for Git conflict markers one complete line at a time.
10. Searching for Git Conflict Markers Produced Many CSS Matches
I next searched for leftover Git conflict markers.
When Git produces a merge conflict, files may contain:
<<<<<<< HEAD
Current content
=======
Other content
>>>>>>> branch-name
My first search was:
grep -RniE \
'<<<<<<<|=======|>>>>>>>' \
--exclude-dir=.git \
--exclude-dir=.venv \
--exclude-dir=__pycache__ \
--exclude-dir=.pytest_cache \
.
This produced many matches from divider comments in static/style.css.
/* ========================================
Section heading
======================================== */
The search term ======= matched the decorative CSS separator.
Restricting the Search to the Start of a Line Was Still Not Enough
I then restricted the pattern to the beginning of a line.
grep -RniE \
'^(<<<<<<< |=======|>>>>>>> )' \
--exclude-dir=.git \
--exclude-dir=.venv \
--exclude-dir=__pycache__ \
--exclude-dir=.pytest_cache \
.
However, the CSS divider lines also began with equal signs.
They were still detected.
Matching Only the Actual Git Conflict Format
Finally, I restricted the pattern using both the beginning and end of each line.
grep -RniE \
'^(<<<<<<< .+|=======$|>>>>>>> .+)$' \
--exclude-dir=.git \
--exclude-dir=.venv \
--exclude-dir=__pycache__ \
--exclude-dir=.pytest_cache \
.
The result was zero matches.
No output
This confirmed that no Git conflict markers remained.
Many Search Results Do Not Necessarily Mean Many Problems
This experience showed that:
Many search results
β
Many actual problems
A broad pattern may match normal comments or code.
In this example:
Goal: Find Git conflict markers
β
Search for lines containing =======
β
Normal CSS divider comments also match
Before interpreting the results, ask:
What normal code could also match this search condition?
11. Use Search Commands for Hypothesis Testing
I did not use grep only as a text-finding tool.
I used it to test hypotheses such as:
Old Excel logic may still remain
Unused CSS may still remain
Outdated UI wording may still remain
Git conflict markers may still remain
The process was:
Form a hypothesis
β
Search
β
Inspect the results
β
Decide whether they are real issues or false positives
β
Adjust the code or search condition
β
Search again
The important part is not memorizing the command.
It is knowing what you are trying to verify.
12. Group Related Changes and Commit Before Another Purpose Gets Mixed In
The changes affected five files:
app.py
config.py
requirements.txt
static/style.css
templates/success.html
Although several files changed, all changes served one purpose:
Remove obsolete specifications and unused code
I therefore recorded them in one commit.
git commit -m "Remove old Excel logic and unused code"
Too Many Small Commits and One Huge Commit Are Both Hard to Read
Creating a commit for every changed line can fragment the work unnecessarily.
On the other hand, combining many unrelated changes makes the diff difficult to understand later.
I used the following rule:
Group related changes
Commit before a different purpose becomes mixed in
In logistics terms:
Cargo for the same destination
β
Load it together
Cargo for a different destination
β
Ship before the loads become mixed
Checks Before Committing
Before committing, I ran:
git status
git diff --stat
git status showed which files had changed.
git diff --stat showed the approximate scale of the changes.
app.py | 10 +---------
config.py | 4 ----
requirements.txt | 1 -
static/style.css | 8 --------
templates/success.html | 2 +-
5 files changed, 2 insertions(+), 23 deletions(-)
At this stage, I confirmed that no unrelated files had been included.
13. Running the Final Tests
After committing and pushing the changes, I ran pytest.
pytest
The result was:
================================================== test session starts ==================================================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0
rootdir: /home/tosane/sales_data_app
plugins: anyio-4.13.0
collected 3 items
test_prompts.py ... [100%]
=================================================== 3 passed in 0.20s ===================================================
All three tests passed.
3 passed in 0.20s
However, the current pytest suite consists of only three tests focused mainly on prompt-generation logic.
Therefore:
pytest passed
β
Every part of the application is guaranteed
I combined the tests with:
- Search verification
- Diff inspection
- UI inspection
- Git status checks
Having tests and sufficiently protecting every important behavior are not the same thing.
It is necessary to understand which parts of the application are actually covered.
14. Checking working tree clean
Finally, I checked the Git state.
git status
The result was:
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
This confirmed:
No uncommitted changes remained
The local main branch matched GitHub
No unfinished files remained
Fixing the Code Is Not the End of the Task
For this inspection, I defined completion as:
Modify the code
β
Review the diff
β
Run the tests
β
Commit the changes
β
Push to GitHub
β
Confirm synchronization with GitHub
β
Confirm that no unfinished changes remain
In other words:
The code was fixed
β
The task is complete
working tree cleanis not merely a status message.It means the next task can begin without mixing in unfinished changes from the previous task.
In logistics terms, the delivery is not finished until the truck returns and the cargo area is checked for anything left behind.
15. Recording the Work in the README Files
After cleaning up the code and repository, I updated two README files:
- The
sales_data_appREADME - My GitHub profile README
The sales_data_app README
I added the following items to the update history:
- Organized demo videos, thumbnails, and screenshots
- Updated README image paths
- Cleaned up
.gitignore - Cleaned up
.dockerignore - Removed obsolete Excel processing
- Removed unused imports, dependencies, and CSS
- Updated an outdated page title
- Confirmed that all three pytest tests passed
- Confirmed that the Git working tree was clean
My GitHub Profile README
I recorded the repository-wide inspection as a milestone for July 19, 2026.
I also updated my total study time:
143 total hours
β
148 total hours
The README update was recorded with:
git commit -m "Document repository inspection and 148 study hours"
16. Results of the Five-Hour Inspection
The final results were:
Work time 5 hours
Total study time 148 hours
Changed code files 5 files
Diff 23 lines removed, 2 lines changed
Old specification 0 remaining matches
Git conflict markers 0 matches
pytest 3 passed
Difference from GitHub None
Final state working tree clean
No new feature was added.
However, I aligned all of the following with the current specification:
Code
Dependencies
HTML text
CSS
README
Screenshots
Directory structure
.gitignore
.dockerignore
Git state
What I Learned
1. Working Applications Can Still Contain Old Parts
Even if an application runs correctly, code and dependencies from older architectures may remain.
In this project:
Excel-centered architecture
β
Migration to PostgreSQL
β
Old Excel directory settings and openpyxl become unnecessary
When feature development continues without maintenance, old specifications can quietly remain.
The repository should therefore be inspected periodically to confirm that it matches the current architecture.
2. README Files and Images Are Part of the Software
Even when the code is current, outdated README text or screenshots present an outdated version of the project.
In a public repository, all of the following are part of the deliverable:
Code
README
Screenshots
Demo videos
Directory structure
Commit history
The README is not an optional attachment outside the codebase.
It is often the entry point through which users, recruiters, and other developers understand the project.
3. GitHub Contents and Docker Contents Are Different
README files and tests belong on GitHub.
They may not belong in the production Docker image.
GitHub
βββ Stores documentation, tests, and development history
Docker
βββ Contains the files required to run the application in production
.gitignore and .dockerignore should not automatically contain the same rules.
Each file must be evaluated according to its purpose.
4. Deletion Requires Evidence
Deleting code merely because it appears unused is dangerous.
I used the following sequence:
Search
β
Inspect references
β
Compare with the current specification
β
Delete
β
Search again
β
Test
Deletion is not simply the act of reducing code.
It should be performed only after you can explain why the code is no longer required.
5. Zero Search Results Can Be Important
When confirming that obsolete code no longer remains, no matches from grep can be the expected result.
Search intended to find a problem
Matches found β Something needs inspection
Search intended to confirm removal
No matches β Expected state
The meaning of a search result depends on the purpose of the search.
6. Search Conditions Can Produce False Positives
Searching for ======= matched not only Git conflict markers but also CSS separator comments.
Many search results
β
Many problems
The search condition itself may be too broad.
Do not judge only by the number of matches. Inspect why each result matched.
7. Divide Commits by Purpose, Not File Count
The cleanup changed five files.
However, every change served the same purpose:
Removing obsolete specifications and unused code
I therefore grouped them into one commit.
A useful commit boundary is based less on:
How many files changed?
and more on:
Why were these files changed?
8. working tree clean Is the Starting Condition for the Next Task
Starting new work while uncommitted changes remain can mix unrelated purposes:
Current changes
+
Next changes
=
A commit whose purpose is difficult to understand
By confirming working tree clean, the next task can begin with an empty cargo area.
Reusable Repository Inspection Checklist
The following checklist summarizes the process in a form that can be reused in other projects.
Runtime Code
- [ ] Are there unused imports?
- [ ] Do settings from retired specifications remain?
- [ ] Are unused functions or processes still present?
- [ ] Do references to old directories or filenames remain?
- [ ] Are there unused CSS classes?
- [ ] Could any apparently unused class be added dynamically by JavaScript?
Dependencies
- [ ] Are unused libraries still listed?
- [ ] Did you search the code before removing a dependency?
- [ ] Could another library depend on it indirectly?
- [ ] Does the application still run after removing it?
- [ ] Do the tests still pass?
README and UI
- [ ] Does the README match the current implementation?
- [ ] Are the screenshots current?
- [ ] Do image paths match the current directory structure?
- [ ] Does the demo video still match the interface?
- [ ] Do outdated UI labels or HTML
titlevalues remain? - [ ] Does the README describe any feature that no longer exists?
File Structure
- [ ] Are videos, images, and documents organized by purpose?
- [ ] Are unnecessary files scattered in the repository root?
- [ ] Do backup files remain?
- [ ] Can the purpose of a file be understood from its name?
Git
- [ ] Does
.gitignoreexclude sensitive information? - [ ] Are virtual environments and caches excluded?
- [ ] Are local databases and raw data excluded?
- [ ] Did you review the changed files with
git status? - [ ] Did you review the diff with
git difforgit diff --stat? - [ ] Are unrelated changes mixed together?
- [ ] Do Git conflict markers remain?
- [ ] Did you push the changes to GitHub?
- [ ] Is the working tree clean?
Docker
- [ ] Does
.dockerignoreexclude.git? - [ ] Is
.envexcluded from the build context? - [ ] Are virtual environments and caches excluded?
- [ ] Are local databases and Excel files excluded?
- [ ] Are production-unnecessary README files, images, and videos excluded?
- [ ] Have you distinguished files that belong on GitHub from files required by Docker?
Final Verification
- [ ] Did you search again for deleted names?
- [ ] Did you check whether search results were false positives?
- [ ] Did the tests pass?
- [ ] Do you understand what the tests cover?
- [ ] Did you visually inspect the necessary screens?
- [ ] Did you update the README with the work performed?
- [ ] Are the local repository and GitHub synchronized?
Conclusion
I did not add a new feature during these five hours.
Even so, I brought the repository to the following state:
- The code matches the current specification
- Obsolete dependencies have been removed
- The README matches the latest UI
- The purpose of videos and images is easier to understand
- Files stored on GitHub are organized
- Unnecessary documentation is not included in the production Docker image
- The tests pass
- The repository is synchronized with GitHub
- The working tree is clean
In logistics, loading cargo is not the only responsibility.
The following also matter:
Is unnecessary cargo mixed in?
Is the loading location easy to understand?
Do the cargo and shipping documents match?
Was anything left behind after delivery?
Can the next trip begin with an empty truck?
Software development was similar:
Add code
β
Unload unnecessary code
β
Align the documentation with the current state
β
Organize the files included in production
β
Run tests
β
Ship to GitHub
β
Confirm working tree clean
The strongest lesson from this inspection was:
A repository-wide inspection is not a task for deleting unnecessary files.
It is the process of aligning the current specification with the code, dependencies, UI, documentation, and delivery state.
Before loading the next feature, inspect the current cargo area.
These five hours became maintenance time that made the next stage of development safer.
Related Links
GitHub
https://github.com/tosane932/sales_data_app
Live Demo
https://bakery-salesdata.onrender.com/
Top comments (0)