Files
gabrielkaszewski-next/docs/superpowers/plans/2026-04-24-experience-timeline.md
Gabriel Kaszewski c34d069d54
All checks were successful
Build and Deploy Gabriel Kaszewski Portfolio / build-and-deploy-local (push) Successful in 1m8s
rework of experience
2026-04-24 13:09:27 +02:00

10 KiB
Raw Blame History

Experience Timeline Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Replace the horizontal experience card carousel with a full-width vertical timeline that surfaces job descriptions and sub-phase breakdowns from static data.

Architecture: Extend the Job type with optional summary and sub_phases fields, update data.ts with CV content, then replace the card carousel with a new ExperienceTimeline server component. No client-side JS — all content is statically rendered.

Tech Stack: Next.js (App Router), TypeScript, TailwindCSS


File Map

Action File Responsibility
Modify lib/types.ts Add JobSubPhase, extend Job
Modify lib/data.ts Add summary + sub_phases to WPP and GIAP entries
Create components/experience-timeline.tsx Renders the full vertical timeline (server component)
Modify components/experience.tsx Swap card loop for <ExperienceTimeline>
Delete components/experience-card.tsx Replaced by timeline component

Task 1: Extend types

Files:

  • Modify: lib/types.ts

  • Step 1: Add JobSubPhase and extend Job

Replace the entire contents of lib/types.ts with:

export interface Skill {
  name: string;
}

export interface JobSubPhase {
  label: string;
  start_date: string;
  end_date: string | null;
  bullets: string[];
}

export interface Job {
  id: number;
  position: string;
  company: string;
  still_working: boolean;
  start_date: string;
  end_date: string | null;
  technologies: string[];
  summary?: string;
  sub_phases?: JobSubPhase[];
}

export interface Project {
  id: number;
  name: string;
  short_description: string;
  description: string;
  technologies: string[];
  thumbnails: string[];
  category: 'Web' | 'Mobile' | 'Desktop' | 'Api' | 'Game';
  github_url?: string | null;
  visit_url?: string | null;
  download_url?: string | null;
  commercial?: boolean;
}
  • Step 2: Verify TypeScript is happy
npx tsc --noEmit

Expected: no errors (existing job entries have no sub_phases yet, so optional fields are fine).

  • Step 3: Commit
git add lib/types.ts
git commit -m "feat: add JobSubPhase type and extend Job with summary and sub_phases"

Task 2: Update job data

Files:

  • Modify: lib/data.ts

  • Step 1: Update the WPP entry (id: 8)

Replace the WPP job object in the jobs array:

{
  id: 8,
  position: "Software Engineer",
  company: "WPP Media | Choreograph | Wavemaker",
  still_working: true,
  start_date: "2023-09-13",
  end_date: null,
  summary:
    "Advanced from frontend UI development to backend systems engineering, leading infrastructure-agnostic design initiatives.",
  sub_phases: [
    {
      label: "Backend & Infrastructure",
      start_date: "2025-03-01",
      end_date: null,
      bullets: [
        "Engineered and optimized backend applications and internal tools using Python, FastAPI, and Django.",
        "Streamlined CI/CD workflows and containerized applications with GitLab Pipelines, Docker, and Kubernetes across GCP and Azure environments.",
      ],
    },
    {
      label: "Frontend Architecture",
      start_date: "2023-09-13",
      end_date: "2025-03-01",
      bullets: [
        "Architected scalable microfrontends utilizing Angular and Module Federation, seamlessly integrating standalone internal tools into a unified enterprise shell application.",
        "Ensured seamless integration of UI components with Kubernetes-based deployments and Azure Pipelines.",
      ],
    },
  ],
  technologies: [
    "Angular",
    "Azure",
    "Azure Pipelines",
    "Django",
    "Docker",
    "FastAPI",
    "GCP",
    "Gitlab CI",
    "Gitlab Pipelines",
    "Kubernetes",
    "PostgreSQL",
    "Python",
    "React",
    "SCSS",
    "TailwindCSS",
    "Typescript",
  ],
},
  • Step 2: Update the GIAP entry (id: 2)

Replace the GIAP job object:

{
  id: 2,
  position: "Full Stack Developer",
  company: "GIAP",
  still_working: false,
  start_date: "2021-05-19",
  end_date: "2023-02-03",
  sub_phases: [
    {
      label: "Desktop / Backend",
      start_date: "2021-05-19",
      end_date: "2022-02-01",
      bullets: [
        "Architected and optimized complex PostGIS/PostgreSQL cross-database comparison queries utilizing Common Table Expressions (CTEs), drastically reducing execution time from over 5 minutes to under 15 seconds.",
        "Developed a robust GIS data assertion module using Python and Qt to automatically validate spatial data against strict compliance standards.",
      ],
    },
    {
      label: "Frontend",
      start_date: "2022-02-01",
      end_date: "2023-02-03",
      bullets: [
        "Engineered a comprehensive, public-facing web application for the City of Gdańsk (geogdansk.pl) leveraging React, TypeScript, Redux, and the ArcGIS JS API.",
      ],
    },
  ],
  technologies: [
    "Python",
    "React",
    "Typescript",
    "PostgreSQL",
    "PostGIS",
    "ArcGIS JS API",
    "Redux",
    "Qt",
    "QGIS",
    "Git",
  ],
},
  • Step 3: Verify TypeScript is happy
npx tsc --noEmit

Expected: no errors.

  • Step 4: Commit
git add lib/data.ts
git commit -m "feat: add sub_phases and summary to WPP and GIAP job entries"

Task 3: Create ExperienceTimeline component

Files:

  • Create: components/experience-timeline.tsx

  • Step 1: Create the component

import { Job } from "@/lib/types";
import Chip from "./chip";
import formatDate from "@/utils/format-date";

const ExperienceTimeline = ({ jobs }: { jobs: Job[] }) => (
  <div className="relative w-full max-w-3xl mx-auto flex flex-col gap-0">
    <div className="absolute left-[9px] top-3 bottom-3 w-px bg-gradient-to-b from-white/30 to-white/0" />
    {jobs.map((job) => (
      <div key={job.id} className="flex gap-6 pb-10 last:pb-0">
        <div className="flex flex-col items-center shrink-0 w-5 pt-1.5 z-10">
          <div className="w-3 h-3 rounded-full bg-white/40 border border-white/20 shadow-[0_0_8px_rgba(255,255,255,0.2)]" />
        </div>
        <div className="flex-1 bg-white/5 border border-white/10 rounded-2xl p-5 hover:border-white/20 transition-colors">
          <div className="flex justify-between items-start flex-wrap gap-1 mb-1">
            <h4 className="text-lg font-semibold text-white">{job.position}</h4>
            <span className="text-xs text-white/40">
              {formatDate(job.start_date)} {" "}
              {job.still_working ? "Present" : formatDate(job.end_date!)}
            </span>
          </div>
          <p className="text-sm text-white/60 mb-4">{job.company}</p>

          {job.summary && (
            <p className="text-sm text-white/50 italic mb-4">{job.summary}</p>
          )}

          {job.sub_phases && job.sub_phases.length > 0 && (
            <div className="flex flex-col gap-3 mb-4">
              {job.sub_phases.map((phase) => (
                <div
                  key={phase.label}
                  className="bg-white/[0.03] border border-white/[0.07] rounded-xl px-4 py-3"
                >
                  <div className="flex justify-between items-center flex-wrap gap-1 mb-2">
                    <span className="text-[11px] font-semibold uppercase tracking-widest text-white/50">
                      {phase.label}
                    </span>
                    <span className="text-[10px] text-white/30">
                      {formatDate(phase.start_date)} {" "}
                      {phase.end_date ? formatDate(phase.end_date) : "Present"}
                    </span>
                  </div>
                  <ul className="list-disc list-inside space-y-1">
                    {phase.bullets.map((b) => (
                      <li key={b} className="text-xs text-white/50 leading-relaxed">
                        {b}
                      </li>
                    ))}
                  </ul>
                </div>
              ))}
            </div>
          )}

          <div className="border-t border-white/10 pt-4 mt-2">
            <p className="text-[10px] uppercase tracking-widest text-white/30 mb-2">
              Technologies
            </p>
            <div className="flex flex-wrap gap-2">
              {job.technologies.map((tech) => (
                <Chip key={tech} text={tech} />
              ))}
            </div>
          </div>
        </div>
      </div>
    ))}
  </div>
);

export default ExperienceTimeline;
  • Step 2: Verify TypeScript is happy
npx tsc --noEmit

Expected: no errors.

  • Step 3: Commit
git add components/experience-timeline.tsx
git commit -m "feat: add ExperienceTimeline server component"

Task 4: Wire up timeline in Experience section and remove old card

Files:

  • Modify: components/experience.tsx

  • Delete: components/experience-card.tsx

  • Step 1: Replace experience.tsx

import { Job } from "@/lib/types";
import ExperienceTimeline from "@/components/experience-timeline";

const Experience = ({ jobs }: { jobs: Job[] }) => (
  <div
    id="experience"
    className="flex flex-col items-center gap-8 p-4 w-full"
  >
    <h3 className="mt-4 text-5xl font-bold tracking-tight text-white">
      Experience
    </h3>
    <ExperienceTimeline jobs={jobs} />
  </div>
);

export default Experience;
  • Step 2: Delete the old card component
rm components/experience-card.tsx
  • Step 3: Verify no remaining imports of ExperienceCard
grep -r "experience-card\|ExperienceCard" /mnt/drive/dev/gabrielkaszewski-next --include="*.tsx" --include="*.ts" | grep -v node_modules

Expected: no output.

  • Step 4: Verify TypeScript is happy
npx tsc --noEmit

Expected: no errors.

  • Step 5: Start dev server and visually verify the timeline renders correctly
npm run dev

Open http://localhost:3000 and scroll to the Experience section. Verify:

  • Vertical line and dots are visible

  • WPP shows summary + two sub-phase blocks with bullets

  • digimonkeys.com shows only dates + chips (no sub-phases)

  • GIAP shows two sub-phase blocks with bullets

  • Tech chips render under each entry

  • Step 6: Commit

git add components/experience.tsx
git commit -m "feat: replace experience card carousel with vertical timeline"