ProfileDeck: one database for the profile and the CV

For years my public profile and my CV drifted apart in the most boring way possible. A role ended, a project shipped, a company renamed itself — and I would update one document, then forget the other until the next time someone asked for a PDF.

biplob.dev is the writing site. biplob.me is the career site. I wanted the second one to be as calm as the first, and I wanted the downloadable CV to be a view of the same data, not a third copy I maintain by hand.

That is ProfileDeck: a self-hosted portfolio and CV CMS. Enter the work once. Publish a profile, an HTML CV, and an A4 PDF from one database.

Editorial wordmark for ProfileDeck a lime highlight on DECK beside a terminal card that reads whoami one database

The problem was never “I need another portfolio template”

Templates are easy. The painful part is the content model.

A career is not a single hero paragraph. It is employers who rebrand, projects that should be featured or quietly archived, skills that belong in groups, certifications with dates, and a number of years that should not be hardcoded in three places. I also did not want a SaaS résumé builder holding the canonical copy of my work history.

So ProfileDeck is opinionated in a small way: the database is the source of truth. The public site, the CV preview, and the PDF are just presentations.

Diagram an admin table and a website plus CV document all connected through one database

Admin writes records. The homepage, the project archive, and the CV all read them.

What you get in the browser

The public profile is a long, editorial page rather than a dashboard of widgets. It has the pieces I actually need when someone lands on the site:

  • A hero with name, headline, location, and a short terminal-style card
  • Light and dark themes that follow the system preference and remember a manual toggle
  • Work history, selected projects, skills, education, certifications, training, and interests
  • View all projects path to /projects when there is more published work than the featured set
  • Kind filters (professional, personal, package) and pagination on that archive
  • A downloadable CV, plus a printable HTML preview

The screenshots below use the fictional demo seed — Alex Morgan in Portland — so the GitHub README and this post do not leak a real résumé.

Dark theme. The lime block is the surname; the card on the right is the same “whoami” idea as this journal.

Light theme. Same layout, paper and ink instead of charcoal.

The live installation is biplob.me. The writing stays here on biplob.dev. Two destinations, two jobs.

The admin is Filament, not a custom back office

I did not want to invent another CMS UI. ProfileDeck uses Filament resources for every content type: profile, companies, roles, projects, skills, education, and the rest.

Projects were the resource that needed the most care. There are far more published items than I want on the homepage, so featured vs visible matters, and the table has to be sortable. The list now has ID, company, start and end dates, kind, and filters — including company — so I can find a row without scrolling a hundred thumbnails.

The real panel is Filament. This is the idea: treat the archive like data, not like a mood board.

Uploads live on Laravel’s public disk. A project without a thumbnail gets a monogram tile instead of a broken image. Companies have a former-name field so a rebrand does not split one employer into two timelines.

Small details that save me from myself

:years is not a magic number in copy. Tagline, summary, and bio can contain a :years token. At render time it becomes the full years since the oldest visible role. When the next anniversary passes, the sentences stay true without a find-and-replace.

The email address is not sitting in the homepage HTML. The “Email me” control stores a base64 payload and builds mailto: in JavaScript. It will not stop a determined scraper, but it keeps the obvious harvest out of the markup.

Demo data and personal data are separated on purpose. DemoSeeder is what you get on clone: fictional, complete, safe to screenshot. Personal seeders and media are gitignored so I can rebuild my site without publishing my history to GitHub.

Stack and requirements

  • PHP 8.3+
  • Laravel 13, Filament 4, Tailwind, Vite
  • Dompdf for the A4 CV
  • SQLite to start, MySQL when you want a production-shaped database

Quickest path:

git clone https://github.com/biplobice/profiledeck.git
cd profiledeck
composer install
cp .env.example .env
php artisan key:generate
touch database/database.sqlite
php artisan migrate --seed
php artisan storage:link
npm install && npm run build
php artisan serve

The profile is /. The admin is /admin. Demo login is admin@example.com / password — public by design. Change it before the box faces the internet.

What I am not claiming

ProfileDeck is not a page builder, not a blog, and not a multi-tenant SaaS. It is one person’s career CMS that happened to be general enough to open-source. If you want a journal, keep a journal (this site exists for that). If you want a profile and a CV that cannot disagree, this is the shape I settled on.

The code is MIT-licensed: github.com/biplobice/profiledeck.

If you try it, the useful bug reports are the boring ones: a date that sorts wrong, a PDF that drops a thumbnail, a project that should be visible but is not. Those are the same class of problems I built it to stop having twice.

Conversation

Leave the first comment

Join the discussion

Thoughtful, constructive comments are welcome.

Keep reading

Related notes