Built With Purpose
A Symfony Retrospective on Building Real Software for Real Ministry
Why I Built It
Some projects are just projects. This one was different — and it started before I wrote a single line of code. In August 2022, I attended Men’s Encounter for the first time. I didn’t go as a developer, a volunteer, or a leader. I went as someone who needed it. What happened that weekend is its own story, but the short version is that it reoriented things — the way I thought about vocation, about where my skills were supposed to go, about what work was actually for. I left different than I arrived.
So when my local area leader reached out and asked if I’d be willing to build the registration platform for Men’s Encounter, I didn’t hesitate. He had worked with me before and knew what I could do — but what he may not have fully known was how much that ask meant to me personally. Encounter wasn’t just an event I’d heard about. It was an event that had genuinely changed the direction of my life.
Being invited to give something back to it felt less like a work opportunity and more like a full-circle moment. I had spent years developing skills in web development — skills I’d built through a decade-long IT career — and here was a chance to put them to use for something that mattered in a completely different way. A gift I had developed over years, now used for something beyond a paycheck.
And the deeper I got into the project, the more connected I became. Around the same time, I stepped into a leadership role at the event’s tech booth — filling in when the primary lead needed to be away. That experience didn’t shape the platform directly, but it deepened my relationship with the other leaders and grew my investment in the ministry itself. I wasn’t just a developer handed a spec sheet. I was someone who was showing up, building trust, and genuinely caring about what this event was trying to do.
That combination — personal history with the event, technical experience, and a growing connection to the leadership — made this more than a freelance build. It made it personal.
The Non-Standard Decisions
Not every project gets a clean slate. This one came with constraints baked in from the start — and that’s fine. Real-world development rarely looks like the ideal setup from a tutorial.
The most significant constraint was hosting. The organization already had a provider they were comfortable with — a shared cPanel environment — and moving elsewhere simply wasn’t on the table. That decision had downstream effects I didn’t fully anticipate. To make things work, I had to create a custom kernel — one that lived where the host expected it, but pointed to a completely different directory where the real application kernel actually ran. It’s not something you’d find in the Symfony docs under “recommended setup,” but it solved a real problem, and there’s a certain satisfaction in that.
That same hosting constraint shaped my approach to deployment. I wanted something as close to autonomous as possible — push code, let the system handle the rest. I got close. Not all the way there, but close enough that the manual steps remaining are minimal. It’s one of those things where “90% automated” still feels like a win compared to where it started.
The frontend story is a little more interesting. The project didn’t start with a single, deliberate asset strategy — it evolved. Initially the JavaScript went one direction, but as Symfony’s Asset Mapper matured I wanted to give it a real try, so the project shifted with it. To be clear: I’m not here to crown Asset Mapper over Webpack Encore. Both are solid tools. But this project gave me a natural opportunity to experiment with the newer approach, and I also used it to take Turbo for a spin. Here was a project I owned, with real stakes but also some runway to try things. That combination doesn’t come along often.
The rest of the stack — Doctrine ORM, Symfony Security — stayed squarely conventional. No need to reinvent the wheel when the wheel already fits.
Design Limitations and Drawbacks
Every project has a gap between what you shipped and what you wished you’d shipped. This one is no different — and I’d rather name those gaps honestly than pretend they don’t exist.

The most visible limitation is the UI. The platform works. Registrations go through, the flow is clear, the important stuff is in the right place. But polished? Not quite. Design kept getting pushed down the priority stack in favor of getting features functional and stable. That’s a trade-off I made consciously under time pressure, but it’s still a trade-off. When you’re a solo developer juggling both backend and frontend, something usually gives — and in this case it was visual refinement.
The code structure tells a similar story. The project grew organically, which is another way of saying it didn’t always grow neatly. Early decisions that seemed fine in isolation created inconsistencies that compounded over time. The patterns aren’t always uniform across the codebase, and there are areas where the architecture would look noticeably different if I were starting from scratch today.
The entity structure is where that drift is most apparent. What started as a reasonably clean data model got harder to navigate as features were added along the way. Each addition made sense in the moment, but the cumulative effect is a set of entities that are more confusing than they should be — relationships that aren’t immediately obvious, responsibilities that have blurred. It’s the kind of thing that slows you down when you return to the code after time away.

As for features that still have room to grow: user account management is one area that hasn’t fully taken shape yet, though that’s less a technical limitation and more a matter of waiting for the right direction from the team. Some features need stakeholder input before they’re worth building out, and this is one of them. The admin and reporting side is a different story — the bones are there, but the registration and event assignment workflows need to be built out further before meaningful reporting becomes possible. The data exists; the path to surfacing it cleanly just isn’t complete yet.
None of this is a dismissal of the work. It’s an honest accounting of it.
What I’d Do Differently
Retrospectives are only useful if you’re honest about them. So here’s what I’d actually change.
The entity structure would get a lot more thought before a single line of code got written. It’s easy to underestimate how much a data model shapes everything downstream — the queries, the relationships, the way features get layered in later. I know that now in a way I didn’t fully appreciate at the start. A few extra hours of modeling upfront would have saved a lot of untangling later.
I’d also push harder for stakeholder input on features much earlier in the process. Some of the gaps in the platform today aren’t technical problems — they’re direction problems. Building before you have clarity on what’s actually needed is a fast way to build the wrong thing, or to build something that just sits unfinished because the requirements never fully materialized. Getting the right people in the room earlier, even briefly, matters more than I gave it credit for.
That connects to something harder to solve: keeping stakeholder engagement alive when the people you need are already stretched thin. Ministry leadership volunteers their time, carries real responsibilities, and is pulled in more directions than anyone should be. That’s not a criticism — it’s just reality. But I’d approach it differently next time. Shorter feedback loops, smaller asks, more asynchronous ways to get input. The goal is making it easy for busy people to stay involved, rather than hoping they’ll find the space to.
And UI — I’d give it an actual seat at the table from the beginning rather than treating it as something to come back to later. Later has a way of never arriving.
As for where things are headed: the platform isn’t done. The entity structure needs a thoughtful re-evaluation, the admin and reporting workflows need to be built out properly, and the UI deserves the attention it didn’t get the first time around. There’s also still room to push the deployment pipeline closer to fully autonomous. The foundation is solid — what’s left is mostly the work of refinement, completion, and making something functional into something genuinely polished. That work is still in progress, and I’m still invested enough to see it through.
What’s Still Coming
Some features didn’t make it into the current version of the platform — not because they were forgotten, but because they weren’t ready. These are active plans, not wishlist items.
Payment processing is the biggest one. Right now, registration and payment are disconnected experiences, and that creates friction that shouldn’t exist. The goal is an integrated online payment workflow that ties directly into the event registration flow — so that signing up and paying happen together, cleanly. Getting there requires more than just dropping in a payment gateway. It means thinking through how payments connect to event capacity, registration status, and the reporting that leadership depends on. It’s the kind of feature that touches everything, so it has to be done right.
Framework and PHP upgrades are also on the roadmap. Running on older versions isn’t a crisis, but it’s technical debt with a clock on it — security patches, compatibility concerns, and eventually features you simply can’t use. Upgrading on shared hosting requires some care, but it’s planned and it’s coming.
All three of these depend, to some degree, on stakeholder alignment. That’s a lesson already learned and one I’m carrying forward intentionally — shorter feedback loops, smaller asks, and staying in front of the people who need to be part of the decisions. The platform has real momentum, and these next steps are how it gets from functional to complete.
The foundation is there. The work continues.
If you’re curious about the career shift that brought me from a decade in IT into ministry work — and why projects like this one sit at the intersection of both — you can read more about me.