About Cody

I'm a software engineer in New Brunswick, Canada, building practical web software from the interface down to deployment.

I like clear user flows, readable code, and systems I can operate with confidence. Most of my work sits where product details, backend logic, and infrastructure all have to line up.

Portrait of Cody Woolaver

How I Work

I usually start by making sure I understand the actual problem, not just the requested change. From there I care most about correctness, maintainability, and leaving the next developer with enough context to keep moving.

This site is also a working example of that. It is an older Pyramid app that I am modernizing piece by piece, which makes it a useful place to show how I handle tradeoffs, migrations, dependency updates, UI cleanup, and deployment work over time.

What I Bring

  • Patient debugging and a habit of finding the root cause before widening the fix.
  • Care for existing systems, especially when modernizing code that already works.
  • Comfort moving between backend Python, templates, JavaScript, CSS, Docker, and deployment details.
  • Product sense: asking what the user actually needs and keeping the implementation grounded in that.

Featured Project

Why Minesweeper?

Minesweeper has stuck with me for a long time. When I was younger, I would work through boards on paper just to find the next logical move. I liked that a small grid could turn into a real reasoning problem: what is known, what is implied, what is safe, and where probability starts once logic runs out?

The version on this site keeps game state on the server and includes a solver-assisted hint system. The solver looks at the visible board, evaluates neighbouring cells, and identifies moves that are logically forced. It is a small project, but it pulls together constraints, state, interaction, and algorithmic thinking in a way I still enjoy.

The board itself is intentionally simple: a fixed-length string plus row and column counts. The dimensions map each index back to an x, y position, and the backend expands that representation into a grid when it needs to reason about neighbours.

A separate uncovered mask controls what the player can see. The full field knows where every mine and number lives, while the mask lets the UI reveal only the current state. When a player uncovers a zero, the server walks outward through adjacent safe cells and updates the mask to produce the familiar cascade.

It represents the kind of work I like: clear rules, visible logic, and a usable experience built around a small but interesting core.

Try the Minesweeper project

About This Site

How This Website Is Built

What powers the backend?

This site is a Python web application built with Pyramid and served by Gunicorn. Pyramid maps routes to view functions, builds the request and response objects, and gives the application a small core without prescribing every other layer. Most pages are rendered on the server with Jinja, so navigation works as ordinary HTML and JavaScript is added only where a feature needs it.

SQLAlchemy provides the application models, queries, connection pooling, and transaction integration. Alembic versions the schema separately from the application code, while PyMySQL connects the app to its MySQL database.

What powers the frontend?

The frontend is intentionally modest: Bootstrap 3 provides the base layout, Less holds the application styles, and CoffeeScript plus jQuery power the older interactive behavior. There is no client-side application shell; Pyramid and Jinja own the page, while page-specific scripts handle things such as games, uploads, and admin tools.

Webpack 5 compiles the Less and CoffeeScript, extracts the CSS, and separates shared browser code from page bundles. The resulting versioned static assets are built once in the container image rather than compiled while the application is serving requests. CoffeeScript made sense when the first parts of the site were written; I would choose modern JavaScript or TypeScript for a new project and am gradually modernizing this layer.

What happens when a page is requested?

Public traffic crosses a Cloudflare Tunnel to SWAG, the Nginx-based reverse proxy at the edge of my private network. SWAG forwards the request to Gunicorn, which runs the Pyramid WSGI application. Pyramid matches the route, loads data through SQLAlchemy when needed, renders a Jinja template, and returns HTML to the browser.

The application accepts forwarded client and scheme information only from explicitly trusted proxy addresses. Authentication uses signed cookies, state-changing forms use CSRF protection, and production cookies are restricted with secure, HTTP-only, and SameSite settings.

Why Pyramid?

Pyramid was the main framework I worked with at SurveyMonkey, and it shaped how I think about web applications. I originally came from Django, where the framework gives you a large built-in stack, including the ORM. Pyramid is smaller and more explicit: it handles routing, views, configuration, requests, and responses well, while leaving room to choose the rest of the application structure.

That fit this site well. The app could stay small, but I could still wire together the pieces I wanted: SQLAlchemy models, explicit migrations, server-rendered pages, admin tools, a few interactive projects, and deployment code I understand end to end.

How is the data handled?

The site has its own production database on a centralized MySQL instance shared by my personal projects. Other projects use the same database service, but not the same database. Development has a separate database, so I can test changes without touching production data.

Schema changes are managed with Alembic in both development and production. The container applies pending migrations before Gunicorn starts, which keeps the deployed code and database schema aligned. User-uploaded ShareX files live on a separate persistent Docker volume, so replacing an application container does not replace its stored files.

How is the application packaged?

A multi-stage Docker build keeps the concerns separate. A Node stage installs the exact packages from the npm lockfile and builds the browser assets; a Python stage creates a virtual environment from the pinned Python requirements; and the final runtime image copies in only those results and the application source.

The runtime container starts as root only long enough to copy file-backed secrets into a private temporary location and prepare persistent storage. It then drops to a dedicated unprivileged user, runs Alembic, and starts Gunicorn. A built-in HTTP health check verifies that the application is answering inside the container.

How is it hosted and deployed?

I build changes on a separate local machine and push them to a self-hosted Gitea instance. The release workflow publishes an immutable image for that exact commit, records its digest in my infrastructure repository, and updates the managed Docker stack on a dedicated VM in my Proxmox cluster. Public traffic enters through Cloudflare Tunnel and then SWAG, which routes the request to the portfolio's private origin.

The current deploy process has a short downtime window. That is fine for this portfolio, but for a production service I would move toward blue-green or rolling deployment, health-gated container replacement, and traffic shifting only after the new instance is ready.

How is the site observed?

The application writes bounded access and application logs to its container output. Grafana Alloy collects those records and sends them to Loki, while Docker health and runtime metrics are stored in Prometheus. Grafana provides the private dashboards and query interface for both.

Access records omit query strings, client addresses, referrers, user agents, cookies, and authenticated identity, and the site does not send browser analytics. I keep the response model proportionate to a personal site: useful logs, metrics, health signals, and conservative alerts without a paging rotation. For a service with a formal reliability target, I would add stricter service-level objectives, escalation runbooks, and an owned incident response path.

What I Am Looking For

I am interested in teams that value clear communication, practical ownership, and steady improvement. I do my best work where correctness matters, maintainability is treated as part of the product, and engineers are encouraged to understand the business problem behind the ticket.

If that sounds useful for your team, I would be happy to talk.

Contact me