In this article
- What I set out to build
- Codex built a useful foundation
- The architecture started drifting
- A routing problem exposed the mismatch
- Git became part of the safety system
- Keeping a simple stack simple
- What Codex is good at in this project
- What I’m changing in my prompts
- Would I still use Codex for the rest of the app?
Question: What’s it actually like building a football club manager with Codex while keeping the app on a plain PHP and MySQL stack?
Building the football club manager with Codex has been faster than I expected, but also much stranger. It has helped me put together a proper multi-club application with teams, seasons, permissions, fixtures, training sessions and private calendar feeds. I’ve also spent a surprising amount of time reminding it that the project is a server-rendered PHP app, not a React project waiting to happen.
That tension has become the real build diary story. Codex is doing useful work, and the app is moving forward, but keeping the architecture simple now takes active effort.
What I set out to build
The original idea was a practical football club management system. I want it to handle the work that happens around a real club: clubs, seasons, teams, players, fixtures, training sessions, availability, attendance, registrations, payments and history.
That makes it more than an information site or a small fixture list. The app needs to keep each club’s data separate, give different users the right level of access and stay understandable as more workflows join together.
I chose the stack early:
- plain PHP and MySQL
- server-rendered pages
- Apache with a normal virtual host
- Tabler for the application interface
- no React, Node, SPA architecture or extra build tooling
I didn’t end up with that stack because I was avoiding a harder option. I chose it because it suits the app and I know how to maintain it. I can follow a request through PHP, inspect the database and understand what Apache is serving without adding a separate frontend application and development server.
A football club manager needs dependable forms, permissions, calendars and admin screens. It doesn’t gain much from looking like a startup demo. That’s the same reason I still think not every side project needs a modern JavaScript stack.
Codex built a useful foundation
The early work went well. Codex helped build multi-club separation, an active-club switcher, seasons, teams, user roles and permissions. Fixtures and training sessions followed, including recurring events and private calendar feeds.
The test coverage has grown with the app. I now have more smoke checks around the connected parts, which matters because a change to permissions, routing or club context can break something that looked unrelated in the prompt.
Availability and attendance are the next major piece. Once those are in place, the calendar side of the app will connect to the people using it. Coaches and managers will be able to see who can attend, who has replied and who turned up.
By this point the repository contains a substantial application, and Codex has helped me get there. The glitches matter because they interrupt useful progress rather than proving the whole experiment was a mistake.
The architecture started drifting
The oddest problems haven’t been normal coding mistakes. Bugs are expected, and most of them can be traced, tested and fixed.
The harder problem appears when Codex stops respecting a decision that was already settled. The repository already contained a PHP application with its own structure, routes, Apache setup and UI conventions. Even so, Codex began behaving as though it had been asked to start a new frontend project.
React-shaped assumptions crept into the work. The Sites workflow appeared. I had to make prompts increasingly explicit about not initialising React, Next.js, Vite, Node, Cloudflare tooling or an SPA starter.
Eventually, the architecture warning became almost as detailed as the feature request:
This is an existing server-rendered PHP and MySQL application running through Apache. Inspect the repository first, follow the current conventions and preserve the existing architecture. Don’t initialise React, Next.js, Vite, Node, Cloudflare tooling or a new SPA project.
Repeating that instruction helps, but it also tells me something about the tool. When Codex sees a dashboard, calendar, users and teams, it can reach for common modern frontend patterns even when the repository points somewhere else.
Common frontend patterns can be useful, but they don’t belong in a repository that has already chosen a different shape. I still like using Codex for old-stack work. I wrote about that in Codex Makes Old-School Web Development Feel New Again, and this project hasn’t changed my mind. It has made me more careful about where the tool’s defaults can lead.
A routing problem exposed the mismatch
The clearest example was the local login URL. I wanted the app to live at:
http://football/login
Instead, it started sending me to:
http://football/football-manager/public/login
The extra path showed that the app’s URL generation, its public directory and the WAMP virtual host no longer agreed about where the application lived. The PHP could still be valid and the login page could still exist, but redirects and links were being built from the wrong base. A framework project with its own development server might expect a public directory in the URL setup. My Apache virtual host already pointed at the public directory, so exposing the internal folder path made no sense.
Fixing it meant looking at the whole request rather than patching the visible URL. I had to check the Apache document root, the virtual-host configuration, the application’s base URL and the code generating links and redirects. I also had to ask whether an earlier Codex change had introduced assumptions from a different project shape.
That last check now comes up often. The error on screen can sit several steps away from the decision that caused it.
Git became part of the safety system
As the changes grew broader, Git stopped feeling like background housekeeping. I started using it as the boundary around each Codex task.
My working loop now looks like this:
- Inspect the repository and nearby files.
- Confirm the branch and working tree.
- Describe one contained change.
- Run the relevant tests and smoke checks.
- Review the diff before moving on.
- Commit only when the result fits the app.
Repository inspection is now a standing requirement in my prompts. Codex needs to see the application that exists, not fill gaps with the application it expects to find.
There’s a big difference between asking it to “build a football calendar” and asking it to “add availability to the existing event workflow, using the current permission checks, PHP controllers and Tabler forms, without changing routing or frontend architecture.” The second prompt gives it fewer chances to invent a new project around the feature.
This is close to the process I used for TerraLog: give the assistant the latest repository context, keep the patch focused, test it myself and commit only what works. I described that in the safer AI coding workflow I’m using to build TerraLog. The football manager is a bigger test of the same habit because more features now depend on shared permissions, club context and routing.
Keeping a simple stack simple
I used to think of simple architecture as something you got by leaving things out. This project has made it feel more like a decision that needs regular maintenance.
A calendar feature can pull in a frontend framework. A routing fix can add a new base-path abstraction. A form improvement can introduce a build process. Each choice may look reasonable on its own, yet together they can move the repository away from the app I intended to maintain.
That’s where the human part of AI-assisted development matters. Codex can write a sound implementation for a different architecture. Unless I understand the current one, I may not notice the drift until a route changes, the local setup breaks or a simple feature starts depending on a new toolchain.
The token tax of new tech applies here too. Every extra layer needs more explanation, more context and more checking. A familiar PHP structure gives Codex less to learn, but only when I keep the repository and prompts consistent enough for that advantage to hold.
The football club manager doesn’t need to impress someone reading its package file. It needs to make sense to me and, eventually, to the people running a club.
What Codex is good at in this project
Codex works best when the repository already contains a pattern it can follow. Asking it to add another resource using the same permissions, forms and layouts as an existing resource usually produces something I can review and improve.
It also handles repetitive application work well. Database-backed forms, validation, role checks and tests take time when you’re working alone. Starting from a decent first implementation makes it easier to keep moving, even when that first implementation needs correction.
The trouble starts when the task is broad enough for Codex to choose the architecture as well as the code. “Build the club administration area” leaves too many decisions open. A smaller request tied to existing files gives me a much better result.
For me, Codex earns its place by shortening the distance between a clear task and a reviewable patch. I still make the architectural decisions and decide whether the patch belongs in the app.
What I’m changing in my prompts
Architectural constraints now sit beside the feature requirements. I no longer assume Codex will treat the current stack as settled background context.
For substantial tasks, I tell it to inspect the repository first, preserve server-rendered PHP pages, use the existing Tabler UI and avoid introducing a JavaScript application framework. I also tell it not to change routing, deployment assumptions or unrelated files unless the feature needs that work.
I ask for a summary of the files changed and anything it wasn’t sure about. That makes review easier and sometimes reveals a bad assumption before I start testing.
I’m also more willing to revert a patch. A large generated change can create the feeling that I should rescue it because the work already exists. Starting again with a smaller prompt is often quicker than reshaping the rest of the application around a decision I didn’t want.
Would I still use Codex for the rest of the app?
Yes. It has helped me build more of the football club manager than I would have completed in the same period on my own, and the next milestone is clear.
Availability and attendance will make the app feel less like a collection of administration screens. They’ll connect fixtures and training sessions to the day-to-day question a coach actually has: who can make it?
I expect Codex to help with that work. I’ll give it the current repository, keep the task narrow, run the tests and inspect the diff before I move on. I’ll probably remind it that the app still doesn’t need React.