413 lines
12 KiB
Vue
413 lines
12 KiB
Vue
<template>
|
||
<div class="page">
|
||
<section class="card about">
|
||
<div class="left">
|
||
<div class="portrait">
|
||
<img src="@/assets/profile-avatar.jpg" alt="Brad Stein" />
|
||
</div>
|
||
<div class="contact">
|
||
<div class="name">Brad Stein</div>
|
||
<div class="role">{{ about.role }}</div>
|
||
<div class="role">{{ about.focusLine }}</div>
|
||
<div class="meta">US Citizen · Remote</div>
|
||
<div class="links">
|
||
<a href="https://www.linkedin.com/in/steinbradley/" target="_blank" rel="noopener noreferrer">LinkedIn</a>
|
||
<a href="https://scm.bstein.dev/bstein" target="_blank" rel="noopener noreferrer">Gitea</a>
|
||
<a href="https://metrics.bstein.dev" target="_blank" rel="noopener noreferrer">Metrics</a>
|
||
<a href="mailto:brad@bstein.dev">brad@bstein.dev</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="right">
|
||
<h1>About Me</h1>
|
||
<div class="copy">
|
||
<p v-for="paragraph in about.summary.slice(0, 2)" :key="paragraph">{{ paragraph }}</p>
|
||
<p>
|
||
Public platform work is visible in the
|
||
<a href="https://scm.bstein.dev/bstein/titan-iac" target="_blank" rel="noopener noreferrer">Titan IaC repo</a>,
|
||
<a href="https://scm.bstein.dev/bstein" target="_blank" rel="noopener noreferrer">scm.bstein.dev</a> and
|
||
<a href="https://metrics.bstein.dev" target="_blank" rel="noopener noreferrer">metrics.bstein.dev</a>.
|
||
</p>
|
||
</div>
|
||
<div class="skill-groups" aria-label="Résumé skill summary">
|
||
<div v-for="group in about.skillGroups" :key="group.label" class="skill-group">
|
||
<h2>{{ group.label }}</h2>
|
||
<div class="highlights">
|
||
<div v-for="skill in group.items" :key="skill" class="pill mono">{{ skill }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<div class="section-head">
|
||
<h2>Experience</h2>
|
||
<span class="pill mono">Summary</span>
|
||
</div>
|
||
<div class="timeline">
|
||
<div v-for="item in timeline" :key="item.id" class="entry">
|
||
<div class="dot"></div>
|
||
<div>
|
||
<div class="entry-title">{{ item.title }}</div>
|
||
<div class="entry-sub">
|
||
<a v-if="item.companyUrl" :href="item.companyUrl" target="_blank" rel="noopener noreferrer">
|
||
{{ item.company }}
|
||
</a>
|
||
<span v-else>{{ item.company }}</span>
|
||
<span> · {{ item.dates }}</span>
|
||
</div>
|
||
<ul>
|
||
<li v-for="point in item.points" :key="point">{{ point }}</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="divider"></div>
|
||
<p class="note">
|
||
Web version aligned to <span class="mono">Stein.Brad.Resume.2026.06.pdf</span>. Phone and street address are
|
||
intentionally omitted from the public site.
|
||
</p>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<div class="section-head">
|
||
<h2>Titan Lab</h2>
|
||
<span class="pill mono">atlas platform</span>
|
||
</div>
|
||
<div class="copy">
|
||
<p>
|
||
Titan Lab is the live platform behind bstein.dev. The core is <span class="mono">Atlas</span>, a GitOps-managed
|
||
<span class="mono">k3s</span> cluster where services are reconciled by <span class="mono">Flux</span> and operated
|
||
with the same habits I use professionally: source of truth, quality gates, observability, identity, storage,
|
||
recovery paths, and documented handoff.
|
||
</p>
|
||
<p>
|
||
The platform runs identity, source control, CI/CD, container delivery, observability, storage, member services,
|
||
and experimental AI workloads. It is also where I build automation around bootstrap, recovery, service health,
|
||
and operator workflows instead of leaving them as manual notes.
|
||
</p>
|
||
<p>
|
||
<span class="mono">Oceanus</span> and <span class="mono">Tethys</span> are now part of Atlas capacity instead of separate public status surfaces.
|
||
The dedicated non-cluster hosts are the control-plane database node and the jumphost. <span class="mono">Cassandra</span>,
|
||
the MTG AI playtester, is deployed at
|
||
<a href="https://cassandra.bstein.dev/" target="_blank" rel="noopener noreferrer">cassandra.bstein.dev</a>.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<div class="section-head">
|
||
<h2>Education</h2>
|
||
<span class="pill mono">UT Austin</span>
|
||
</div>
|
||
<div class="copy">
|
||
<p>
|
||
Studied Mechanical Engineering and Applied Math at the University of Texas at Austin, including Java, C++,
|
||
probability, statistics, complex analysis, numerical methods, number theory, and differential equations.
|
||
</p>
|
||
<p>
|
||
Participated in the Emerging Scholars honors calculus program and later served as an assistant for it.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed } from "vue";
|
||
import { useRoute } from "vue-router";
|
||
import { homepageContentForMode, homepageModeFromRoute } from "../data/homepageContent";
|
||
|
||
const route = useRoute();
|
||
const content = computed(() => homepageContentForMode(homepageModeFromRoute(route)));
|
||
const about = computed(() => content.value.about);
|
||
|
||
const timeline = [
|
||
{
|
||
id: "titan-lab-architect",
|
||
title: "Kubernetes Cluster Development",
|
||
company: "Titan Lab",
|
||
companyUrl: "https://scm.bstein.dev/bstein/titan-iac",
|
||
dates: "Apr 2020 – Present",
|
||
points: [
|
||
"Created and operate a local k3s cluster with metrics for home and self-hosted services.",
|
||
"Run personal SCM, CI/CD, password management, mail, cloud storage, movie streaming, video conferencing, AI chatbot, and cluster automation services.",
|
||
"Build automation around bootstrap, recovery, service health, operator workflows, identity, storage, and dashboards.",
|
||
],
|
||
},
|
||
{
|
||
id: "actalent-boeing-ptes",
|
||
title: "Software Development Engineer in Test",
|
||
company: "Boeing",
|
||
companyUrl: "https://www.boeing.com/",
|
||
dates: "Oct 2023 – Oct 2025",
|
||
points: [
|
||
"Consulted through Actalent on a complex communications program at the intersection of test engineering, DevSecOps, and infrastructure automation.",
|
||
"Created system and end-to-end tests using Python and Selenium to validate microservice and web UI interactions.",
|
||
"Built TaskWatcher tooling for key capture/decryption and Docker Compose drift protection on dedicated hosts.",
|
||
"Created Lanterna to visualize a Flux-driven monorepo with Mermaid charts rerun after merged changes.",
|
||
"Created promotion-pipeline quality gates for a system test suite and microservice release flow.",
|
||
],
|
||
},
|
||
{
|
||
id: "tradehat-frontend",
|
||
title: "Frontend Engineer",
|
||
company: "TradeHat",
|
||
companyUrl: "https://www.tradehat.com/",
|
||
dates: "Mar 2020 – Mar 2021",
|
||
points: [
|
||
"Worked as one of four engineers building the startup product from scratch.",
|
||
"Selected Vue.js and Quasar as the frontend foundation for multi-architecture support.",
|
||
"Helped build the alpha deployment infrastructure using redundant ThinkPads hosted at each engineer's home in Dallas.",
|
||
"Built reporting and dashboard pages in Vue with Tailwind CSS and FusionCharts.",
|
||
],
|
||
},
|
||
{
|
||
id: "ibm-sdet",
|
||
title: "Software Development Engineer in Test",
|
||
company: "IBM",
|
||
companyUrl: "https://www.ibm.com/cloud",
|
||
dates: "Nov 2018 – May 2023",
|
||
points: [
|
||
"Authored and planned automated end-to-end and system tests for IBM Cloud systems in Python, Go, and Terraform.",
|
||
"Served as a consultant before accepting a full-time role in 2020; documented contributions and hosted feature demos and knowledge transfers.",
|
||
"Automated platform validation for a remote data center, including RHEL and SUSE functionality, licensing, repository availability, and performance.",
|
||
"Automated A100 and V100 GPU resource tests for CUDA functionality and data security in accelerated-computing environments.",
|
||
"Created a Zabbix health dashboard for Cloud APIs and planned key feature testing in Python.",
|
||
"Created Terraform and Go system tests for microservice interactions and platform scalability/autoscaling.",
|
||
],
|
||
},
|
||
{
|
||
id: "unifocus-survey-programmer",
|
||
title: "Lead Survey Programmer",
|
||
company: "UniFocus",
|
||
companyUrl: "https://www.unifocus.com/",
|
||
dates: "Aug 2014 – Nov 2018",
|
||
points: [
|
||
"Transformed a configuration role into an automation role using Python and SQL for online surveys and reports.",
|
||
"Served as team lead, recruiting staff and mentoring junior engineers.",
|
||
"Converted Python automation scripts into a CLI tool and built a VBA-driven Excel workbook for business contacts.",
|
||
"Automated responsive design updates for web surveys with Python and added JavaScript/CSS mobile support.",
|
||
"Created a Python XML parser to restore survey data that could otherwise be lost.",
|
||
"Won UniFocus Excellence Award (2015) and Innovation Award (2016).",
|
||
],
|
||
},
|
||
];
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page {
|
||
max-width: 1260px;
|
||
margin: 0 auto;
|
||
padding: 32px 22px 72px;
|
||
}
|
||
|
||
.about {
|
||
display: grid;
|
||
grid-template-columns: minmax(220px, 0.48fr) minmax(0, 2fr);
|
||
gap: 30px;
|
||
}
|
||
|
||
.portrait {
|
||
width: 120px;
|
||
height: 120px;
|
||
flex: 0 0 120px;
|
||
aspect-ratio: 1 / 1;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
display: grid;
|
||
place-items: center;
|
||
background: linear-gradient(135deg, rgba(0, 229, 197, 0.5), rgba(127, 124, 255, 0.45));
|
||
}
|
||
|
||
.portrait img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.left {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 14px;
|
||
padding-top: 8px;
|
||
}
|
||
|
||
.contact .name {
|
||
font-weight: 800;
|
||
color: var(--text-strong);
|
||
}
|
||
|
||
.contact .role {
|
||
color: var(--text-muted);
|
||
max-width: 220px;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
.contact .meta {
|
||
color: var(--text-muted);
|
||
font-size: 13px;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.badges {
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.links {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.links a {
|
||
color: var(--accent-cyan);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.links a:hover {
|
||
color: var(--accent-rose);
|
||
}
|
||
|
||
.right h1 {
|
||
margin: 0 0 8px;
|
||
}
|
||
|
||
.skill-groups {
|
||
display: grid;
|
||
gap: 0;
|
||
margin-top: 18px;
|
||
}
|
||
|
||
.skill-group {
|
||
display: grid;
|
||
grid-template-columns: minmax(130px, 160px) minmax(0, 1fr);
|
||
gap: 16px;
|
||
align-items: start;
|
||
padding: 11px 0;
|
||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
.skill-group h2 {
|
||
margin: 5px 0 0;
|
||
color: var(--text-strong);
|
||
font-size: 15px;
|
||
}
|
||
|
||
.section-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.copy {
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.copy p {
|
||
margin: 0 0 10px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.copy p:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.highlights {
|
||
display: flex;
|
||
gap: 6px;
|
||
flex-wrap: wrap;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.highlights .pill {
|
||
min-height: 30px;
|
||
padding: 5px 9px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.note {
|
||
color: var(--text-muted);
|
||
margin: 0;
|
||
}
|
||
|
||
.note a {
|
||
color: var(--text-muted);
|
||
text-decoration: none;
|
||
border-bottom: 1px dashed rgba(255, 255, 255, 0.18);
|
||
padding-bottom: 1px;
|
||
}
|
||
|
||
.note a:hover {
|
||
color: var(--accent-cyan);
|
||
border-bottom-color: rgba(0, 229, 197, 0.5);
|
||
}
|
||
|
||
.timeline {
|
||
display: grid;
|
||
gap: 12px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.entry {
|
||
display: grid;
|
||
grid-template-columns: auto 1fr;
|
||
gap: 10px;
|
||
}
|
||
|
||
.dot {
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 50%;
|
||
border: 2px solid var(--accent-cyan);
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.entry-title {
|
||
font-weight: 800;
|
||
}
|
||
|
||
.entry-sub {
|
||
color: var(--text-muted);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.entry-sub a {
|
||
color: var(--accent-cyan);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.entry-sub a:hover {
|
||
color: var(--accent-rose);
|
||
}
|
||
|
||
ul {
|
||
margin: 0;
|
||
padding-left: 16px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
@media (max-width: 820px) {
|
||
.about {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.left {
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.skill-group {
|
||
grid-template-columns: 1fr;
|
||
gap: 8px;
|
||
}
|
||
}
|
||
</style>
|