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

379 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:
```typescript
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**
```bash
npx tsc --noEmit
```
Expected: no errors (existing job entries have no `sub_phases` yet, so optional fields are fine).
- [ ] **Step 3: Commit**
```bash
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:
```typescript
{
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:
```typescript
{
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**
```bash
npx tsc --noEmit
```
Expected: no errors.
- [ ] **Step 4: Commit**
```bash
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**
```tsx
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**
```bash
npx tsc --noEmit
```
Expected: no errors.
- [ ] **Step 3: Commit**
```bash
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`**
```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**
```bash
rm components/experience-card.tsx
```
- [ ] **Step 3: Verify no remaining imports of ExperienceCard**
```bash
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**
```bash
npx tsc --noEmit
```
Expected: no errors.
- [ ] **Step 5: Start dev server and visually verify the timeline renders correctly**
```bash
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**
```bash
git add components/experience.tsx
git commit -m "feat: replace experience card carousel with vertical timeline"
```