parent
e2ff82b759
commit
9afd5f51c5
5 changed files with 486 additions and 31 deletions
79
flake.nix
79
flake.nix
|
@ -34,57 +34,74 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
src = typixLib.cleanTypstSource ./.;
|
mkTypst = entry: rec {
|
||||||
commonArgs = {
|
src = typixLib.cleanTypstSource ./.;
|
||||||
typstSource = "src/main.typ";
|
commonArgs = {
|
||||||
typstOutput = "out/main.pdf";
|
typstSource = "src/${entry}.typ";
|
||||||
|
typstOutput = "out/${entry}.pdf";
|
||||||
|
|
||||||
fontPaths = [ ];
|
fontPaths = [
|
||||||
|
"${pkgs.inter}/share/fonts/truetype"
|
||||||
|
];
|
||||||
|
|
||||||
virtualPaths = [ ];
|
virtualPaths = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
commonBuildArgs = commonArgs // {
|
||||||
|
XDG_CACHE_HOME = typstPackagesCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
build-drv = typixLib.buildTypstProject (
|
||||||
|
commonBuildArgs
|
||||||
|
// {
|
||||||
|
inherit src;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
build-script = typixLib.buildTypstProjectLocal (
|
||||||
|
commonBuildArgs
|
||||||
|
// {
|
||||||
|
inherit src;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch-script = typixLib.watchTypstProject commonArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
commonBuildArgs = commonArgs // {
|
typstMain = mkTypst "main";
|
||||||
XDG_CACHE_HOME = typstPackagesCache;
|
typstWork = mkTypst "work";
|
||||||
};
|
|
||||||
|
|
||||||
build-drv = typixLib.buildTypstProject (
|
|
||||||
commonBuildArgs
|
|
||||||
// {
|
|
||||||
inherit src;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
build-script = typixLib.buildTypstProjectLocal (
|
|
||||||
commonBuildArgs
|
|
||||||
// {
|
|
||||||
inherit src;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
watch-script = typixLib.watchTypstProject commonArgs;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
checks = {
|
checks = {
|
||||||
inherit build-drv build-script watch-script;
|
inherit (typstMain) build-drv build-script watch-script;
|
||||||
|
# inherit (typstWork) build-drv build-script watch-script;
|
||||||
};
|
};
|
||||||
|
|
||||||
packages.default = build-drv;
|
packages = {
|
||||||
|
default = typstMain.build-drv;
|
||||||
|
work = typstWork.build-drv;
|
||||||
|
};
|
||||||
|
|
||||||
apps = rec {
|
apps = rec {
|
||||||
default = watch;
|
default = watch;
|
||||||
build = inputs.flake-utils.lib.mkApp {
|
build = inputs.flake-utils.lib.mkApp {
|
||||||
drv = build-script;
|
drv = typstMain.build-script;
|
||||||
};
|
};
|
||||||
watch = inputs.flake-utils.lib.mkApp {
|
watch = inputs.flake-utils.lib.mkApp {
|
||||||
drv = watch-script;
|
drv = typstMain.watch-script;
|
||||||
|
};
|
||||||
|
build-work = inputs.flake-utils.lib.mkApp {
|
||||||
|
drv = typstWork.build-script;
|
||||||
|
};
|
||||||
|
watch-work = inputs.flake-utils.lib.mkApp {
|
||||||
|
drv = typstWork.watch-script;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
devShells.default = typixLib.devShell {
|
devShells.default = typixLib.devShell {
|
||||||
inherit (commonArgs) fontPaths virtualPaths;
|
inherit (typstMain.commonArgs) fontPaths virtualPaths;
|
||||||
packages = [
|
packages = [
|
||||||
watch-script
|
typstMain.watch-script
|
||||||
pkgs.typstyle
|
pkgs.typstyle
|
||||||
pkgs.tinymist
|
pkgs.tinymist
|
||||||
|
|
||||||
|
|
247
src/lib/work.typ
Normal file
247
src/lib/work.typ
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
#let dates-helper(
|
||||||
|
start-date: "",
|
||||||
|
end-date: "",
|
||||||
|
) = {
|
||||||
|
start-date + " - " + end-date
|
||||||
|
}
|
||||||
|
|
||||||
|
#let job_entry(date, company, position, description, experiences) = {
|
||||||
|
grid(
|
||||||
|
columns: (22%, 33%, auto),
|
||||||
|
gutter: 12pt,
|
||||||
|
// Column 1: Date Range
|
||||||
|
box(
|
||||||
|
fill: rgb(242, 242, 242, 255),
|
||||||
|
width: 100%,
|
||||||
|
inset: 10pt,
|
||||||
|
text(date),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Column 2: Company Info
|
||||||
|
box()[
|
||||||
|
#text(company) \
|
||||||
|
#text(weight: "bold", position) \
|
||||||
|
#text(description)
|
||||||
|
],
|
||||||
|
|
||||||
|
// Column 3: Work Experiences
|
||||||
|
for exp in experiences {
|
||||||
|
box(
|
||||||
|
fill: rgb(242, 242, 242, 255),
|
||||||
|
width: 100%,
|
||||||
|
inset: 10pt,
|
||||||
|
[
|
||||||
|
#text(exp.role) \
|
||||||
|
#text(weight: "bold", exp.heading) \
|
||||||
|
#text(size: 10pt, exp.description)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let resume(
|
||||||
|
name: "",
|
||||||
|
position: "",
|
||||||
|
address: none,
|
||||||
|
birth_date: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
profile-picture: image,
|
||||||
|
company-logo: image,
|
||||||
|
font: "Inter",
|
||||||
|
paper: "a4",
|
||||||
|
body,
|
||||||
|
) = {
|
||||||
|
set document(author: name, title: name)
|
||||||
|
|
||||||
|
set text(font: font, lang: "en")
|
||||||
|
show heading: set text(rgb(0, 194, 255, 255))
|
||||||
|
|
||||||
|
grid(
|
||||||
|
columns: 100%,
|
||||||
|
align: (right),
|
||||||
|
[
|
||||||
|
#company-logo
|
||||||
|
\ \ \ \
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
grid(
|
||||||
|
columns: (60%, 180pt),
|
||||||
|
align: (top, right),
|
||||||
|
[
|
||||||
|
#text(size: 30pt, weight: "bold", name) \
|
||||||
|
\
|
||||||
|
#text(size: 13pt, weight: "bold", position) \
|
||||||
|
\ \
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
set text()
|
||||||
|
grid(
|
||||||
|
columns: (50%, auto),
|
||||||
|
gutter: 100pt,
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#heading(level: 2, "Personal Data")
|
||||||
|
|
||||||
|
#grid(
|
||||||
|
columns: (50%, 50%),
|
||||||
|
gutter: 20pt,
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold", "Name:") \
|
||||||
|
#text(name)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold", "Birth date:") \
|
||||||
|
#text(birth_date)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold", "Address:") \
|
||||||
|
#text(address.street)
|
||||||
|
#text(address.city)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold", "Contact:") \
|
||||||
|
#text(email)
|
||||||
|
#{
|
||||||
|
if phone != "" {
|
||||||
|
text(phone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
profile-picture,
|
||||||
|
)
|
||||||
|
|
||||||
|
linebreak()
|
||||||
|
linebreak()
|
||||||
|
|
||||||
|
body
|
||||||
|
}
|
||||||
|
|
||||||
|
#let work_experience(body) = {
|
||||||
|
set text(fill: black)
|
||||||
|
|
||||||
|
set text(fill: rgb(0, 194, 255, 255))
|
||||||
|
grid(
|
||||||
|
columns: (60%, auto),
|
||||||
|
heading(level: 2, "Work Experience"), heading(level: 2, "Case Studies"),
|
||||||
|
)
|
||||||
|
|
||||||
|
set text(fill: black)
|
||||||
|
body
|
||||||
|
}
|
||||||
|
|
||||||
|
#let education_entry(date, university, degree, subject) = {
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold", date) \
|
||||||
|
#text(weight: "bold", university) \
|
||||||
|
#text(degree + " in " + subject)
|
||||||
|
\ \
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let certification_entry(date, issuer, certificate) = {
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold", date) \
|
||||||
|
#text(weight: "bold", certificate) \
|
||||||
|
#text(weight: "bold", issuer)
|
||||||
|
\ \
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let language_levels = (
|
||||||
|
(0, 25, "Beginner"),
|
||||||
|
(26, 50, "Intermediate"),
|
||||||
|
(51, 75, "Advanced"),
|
||||||
|
(76, 99, "Fluent"),
|
||||||
|
(100, 100, "Native"),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let lang_level_text = score => {
|
||||||
|
let result = "Unknown"
|
||||||
|
|
||||||
|
for (min, max, label) in language_levels {
|
||||||
|
if score >= min and score <= max {
|
||||||
|
result = label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#let language_entry(lang, score) = {
|
||||||
|
grid(
|
||||||
|
columns: (40%, auto),
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#text(weight: "bold")[#lang]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
box(
|
||||||
|
width: 100%,
|
||||||
|
[
|
||||||
|
#lang_level_text(score)
|
||||||
|
#box(
|
||||||
|
width: 105pt,
|
||||||
|
height: 6pt,
|
||||||
|
fill: rgb(220, 220, 220),
|
||||||
|
inset: 0pt,
|
||||||
|
[
|
||||||
|
#rect(
|
||||||
|
width: (105pt * score / 100),
|
||||||
|
height: 6pt,
|
||||||
|
fill: rgb(0, 194, 255, 255),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let bottom_grid(sections) = {
|
||||||
|
linebreak()
|
||||||
|
linebreak()
|
||||||
|
linebreak()
|
||||||
|
|
||||||
|
set text(fill: rgb(0, 194, 255, 255))
|
||||||
|
grid(
|
||||||
|
columns: (60%, auto),
|
||||||
|
gutter: 3pt,
|
||||||
|
..sections.map(s => {
|
||||||
|
if s != none {
|
||||||
|
heading(level: 2, s.title)
|
||||||
|
|
||||||
|
set text(fill: black)
|
||||||
|
s.content
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
set text(fill: black)
|
||||||
|
}
|
BIN
src/photo.jpg
Normal file
BIN
src/photo.jpg
Normal file
Binary file not shown.
After ![]() (image error) Size: 307 KiB |
BIN
src/upsquared.png
Normal file
BIN
src/upsquared.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 9.8 KiB |
191
src/work.typ
Normal file
191
src/work.typ
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
#import "lib/work.typ": *
|
||||||
|
|
||||||
|
#let name = "Felix Schröter"
|
||||||
|
#let position = "Senior Software Engineer & Tech Lead"
|
||||||
|
#let address = (street: "Salzwedeler Str. 1", city: "21339 Lüneburg")
|
||||||
|
#let birth_date = "26.09.1995"
|
||||||
|
#let email = "fs@upsquared.com"
|
||||||
|
|
||||||
|
#let profile-picture = image("photo.jpg", width: 115pt, height: 135pt)
|
||||||
|
#let company-logo = image("upsquared.png", width: 220pt, height: auto)
|
||||||
|
|
||||||
|
#show: resume.with(
|
||||||
|
name: name,
|
||||||
|
position: position,
|
||||||
|
address: address,
|
||||||
|
birth_date: birth_date,
|
||||||
|
email: email,
|
||||||
|
profile-picture: profile-picture,
|
||||||
|
company-logo: company-logo,
|
||||||
|
)
|
||||||
|
|
||||||
|
#show: work_experience.with()
|
||||||
|
|
||||||
|
#job_entry(
|
||||||
|
dates-helper(start-date: "Jun 2024", end-date: "Present"),
|
||||||
|
"upsquared GmbH",
|
||||||
|
"Senior Software Engineer & Tech Lead",
|
||||||
|
"Leading Cloud-native Development, Infrastructure & DevOps solutions",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
role: "Tech Lead",
|
||||||
|
heading: "Grow engineering team",
|
||||||
|
description: "Onboard, mentor & lead new team of engineers.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
role: "Software & Cloud Architect",
|
||||||
|
heading: "Cloud-native solutions",
|
||||||
|
description: "Architect solutions built on Rust, Kubernetes, OpenTofu & GCP",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#job_entry(
|
||||||
|
dates-helper(start-date: "Oct 2019", end-date: "May 2024"),
|
||||||
|
"upsquared GmbH",
|
||||||
|
"Senior Software Engineer",
|
||||||
|
"Full-Stack Architecture, Development, Infrastructure & DevOps for Cloud-native solutions",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
role: "Software & Cloud Architect",
|
||||||
|
heading: "Cloud-native solutions",
|
||||||
|
description: "Architect solutions built on Rust, C#, Kubernetes, Terraform & GCP",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
role: "DevOps Engineer",
|
||||||
|
heading: "Full-stack Observability",
|
||||||
|
description: "Enhanced Observability with Sentry, Rust, C#, React & GKE",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
role: "Frontend Engineer",
|
||||||
|
heading: "Plant Analyzer Web",
|
||||||
|
description: "Built web-based frontend for digital phenotyping platform",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
role: "DevOps Engineer",
|
||||||
|
heading: "Reproducible CI/CD",
|
||||||
|
description: "Established reproducible builds & dev environments using Nix",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#job_entry(
|
||||||
|
dates-helper(start-date: "Apr 2019", end-date: "Sep 2019"),
|
||||||
|
"Digital Spring",
|
||||||
|
"Senior Software Engineer",
|
||||||
|
"Full-Stack Architecture, Development, Infrastructure & DevOps for Cloud-native solutions",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
role: "DevOps Engineer",
|
||||||
|
heading: "GitLab CI/CD",
|
||||||
|
description: "Set up GitLab CI/CD pipeline for .NET microservices",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#job_entry(
|
||||||
|
dates-helper(start-date: "Oct 2016", end-date: "Mar 2019"),
|
||||||
|
"Digital Spring",
|
||||||
|
"Software Engineer",
|
||||||
|
"Full-Stack Development, Infrastructure & DevOps for Cloud-native solutions",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
role: "Backend & Cloud Architect",
|
||||||
|
heading: "Cloud-native solutions",
|
||||||
|
description: "Built microservices & Kubernetes cluster from scratch",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
role: "Backend & Cloud Engineer",
|
||||||
|
heading: "Serverless solutions",
|
||||||
|
description: "Built serverless backends with AWS Lambda",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
role: "Frontend Engineer",
|
||||||
|
heading: "Modern web apps",
|
||||||
|
description: "Implemented frontends in React & Angular for different projects",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#job_entry(
|
||||||
|
dates-helper(start-date: "Jun 2015", end-date: "Sep 2016"),
|
||||||
|
"Werum IT Solutions GmbH (now Körber Pharma Software GmbH)",
|
||||||
|
"Software Engineer",
|
||||||
|
"",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
role: "Software Engineer",
|
||||||
|
heading: "Interface development",
|
||||||
|
description: "DCS/PCS and ERP interface development with .NET & PL/SQL",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#job_entry(
|
||||||
|
dates-helper(start-date: "Aug 2012", end-date: "Jun 2015"),
|
||||||
|
"Werum IT Solutions GmbH (now Körber Pharma Software GmbH)",
|
||||||
|
"Trainee",
|
||||||
|
"",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
role: "Software Engineer",
|
||||||
|
heading: "Process automation",
|
||||||
|
description: "Process automation (DCS/PCS) interface development with .NET",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let education = (
|
||||||
|
(
|
||||||
|
dates-helper(start-date: "May 2024", end-date: "Present"),
|
||||||
|
"University of Colorado Boulder",
|
||||||
|
"Master of Science",
|
||||||
|
"Computer Science",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
dates-helper(start-date: "Aug 2012", end-date: "Jun 2015"),
|
||||||
|
"Berufsbildende Schulen I Lüneburg",
|
||||||
|
"Computer Science Expert",
|
||||||
|
"Software Development",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
#let certifications = (
|
||||||
|
(
|
||||||
|
"Feb 2024",
|
||||||
|
"CompTIA",
|
||||||
|
"CompTIA Cloud+",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Feb 2024",
|
||||||
|
"Cloud Security Alliance",
|
||||||
|
"Certificate of Cloud Security Knowledge v.4",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
#let languages = (
|
||||||
|
("English", 90),
|
||||||
|
("German", 100),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let sections = (
|
||||||
|
(
|
||||||
|
title: "Education",
|
||||||
|
content: education.map(e => education_entry(..e)).join("\n"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Languages",
|
||||||
|
content: languages.map(l => language_entry(..l)).join("\n"),
|
||||||
|
),
|
||||||
|
none,
|
||||||
|
// (
|
||||||
|
// title: "Certifications",
|
||||||
|
// content: certifications.map(c => certification_entry(..c)).join("\n"),
|
||||||
|
// ),
|
||||||
|
(
|
||||||
|
title: "Interests",
|
||||||
|
content: "reading, tea, Nix, NixOS, Linux, homelab, Doctor Who",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#bottom_grid(sections)
|
Loading…
Add table
Add a link
Reference in a new issue