Professional Portfolio Site
This is the portfolio you're looking at right now — built entirely in Flask, backed by PostgreSQL, and deployed on Railway with a custom domain. It's not a template or a no-code builder; it's a real web application I designed and built from scratch. The whole thing is maintained through a custom admin dashboard I built myself, so adding or updating projects never means touching the codebase. It's the kind of system I'd build professionally — and that's exactly the point.
Quick Facts
Overview
Problem
Most developer portfolios are static HTML pages thrown together with a CSS template. That gets the job done, but it doesn't actually demonstrate anything about how the developer writes software. I wanted my portfolio to be the proof of skill, not just a holder for links to other projects. Beyond that, maintaining a static site gets tedious fast — every update means editing HTML by hand, pushing manually, and hoping nothing breaks. I needed something I could actually run like a real product.
Solution
I built a full-stack Flask application structured around three blueprints: public routes, an admin blueprint, and a REST API. All project data lives in PostgreSQL via SQLAlchemy, and the admin dashboard handles everything — full CRUD on projects, media uploads, tag management, contact messages, and automated JSON backups before every write. A GitHub Actions CI/CD pipeline runs the full test suite on every push and deploys to Railway only when tests pass. The snapshot sync system keeps local and production databases in sync by treating admin_snapshot.json as the authoritative source of truth — deletions on the live site commit an updated snapshot to GitHub, which the local dev environment picks up on the next pull and restart.
Challenges
The trickiest part was making the snapshot sync genuinely reliable. Early on, deleting a project on the live site wouldn't stick — the next deploy would restore it because the sync only ever upserted and never deleted. I had to redesign it as authoritative: any project in the database that isn't in the snapshot gets removed on startup. Getting the CI/CD pipeline stable also took a few iterations — Railway token naming conventions, GitHub Actions path filters, and the interaction between Railway's own auto-deploy and the Actions workflow all needed careful untangling before deploys were consistent.
Results / Metrics
The portfolio is live at xavieroc.dev and demonstrates the full stack I worked through during 100 Days of Code — Flask, SQLAlchemy, REST API design, admin tooling, media handling, testing with pytest, and deployment with Docker and Railway. Building the admin dashboard from scratch instead of reaching for Flask-Admin was absolutely the right call — it forced me to implement auth, CSRF protection, file handling, and backup logic myself, which is where the real learning happened. If I rebuilt it today I'd add richer media editing and role-based admin permissions, but as a capstone it covers everything I set out to prove.
Screenshots
Click to enlarge.
Click to enlarge.
Videos
No videos available yet.