diff --git a/flake.nix b/flake.nix index 3ba17f4..d0ddda0 100644 --- a/flake.nix +++ b/flake.nix @@ -20,6 +20,7 @@ system: let pkgs = import inputs.nixpkgs { inherit system; }; + inherit (pkgs) lib; typixLib = inputs.typix.lib.${system}; @@ -34,12 +35,20 @@ ''; }; - src = typixLib.cleanTypstSource ./.; + src = lib.fileset.toSource { + root = ./.; + fileset = lib.fileset.unions [ + (lib.fileset.fromSource (typixLib.cleanTypstSource ./.)) + ./src/info.toml + ]; + }; commonArgs = { typstSource = "src/main.typ"; typstOutput = "out/main.pdf"; - fontPaths = [ ]; + fontPaths = [ + "${pkgs.work-sans}/share/fonts/opentype" + ]; virtualPaths = [ ]; }; diff --git a/src/info.toml b/src/info.toml new file mode 100644 index 0000000..a8816e4 --- /dev/null +++ b/src/info.toml @@ -0,0 +1,13 @@ +[personal] +name = "Felix Schröter" +title = "Senior Software Engineer & Tech Lead" +location = "Lüneburg, Germany" +email = "dev@felschr.com" +github = "github.com/felschr" +linkedin = "linkedin.com/in/schroeter" +website = "felschr.com" + +[layout] +font = "Work Sans" +paper = "a4" +accent_color = "#246a48" diff --git a/src/lib/main.typ b/src/lib/main.typ new file mode 100644 index 0000000..1743285 --- /dev/null +++ b/src/lib/main.typ @@ -0,0 +1,333 @@ +#import "@preview/scienceicons:0.0.6": ( + email-icon, + github-icon, + linkedin-icon, + orcid-icon, + website-icon, +) + +// based on https://github.com/stuxf/basic-typst-resume-template + +#let common-doc( + author: "", + font: "Work Sans", + paper: "a4", + accent-color: "#000000", + body, +) = { + // Sets document metadata + set document(author: author, title: author) + + // Document-wide formatting, including font and margins + set text( + // LaTeX style font + font: font, + size: 10pt, + lang: "en", + // Disable ligatures so ATS systems do not get confused when parsing fonts. + ligatures: false, + ) + + set page( + margin: 1.5cm, + paper: paper, + ) + + // Link styles + show link: underline + + + // Small caps for section titles + show heading.where(level: 2): it => [ + #pad(top: 0pt, bottom: -10pt, [#smallcaps(it.body)]) + #line(length: 100%, stroke: 1pt) + ] + + // Accent Color Styling + show heading: set text(fill: rgb(accent-color)) + + show link: set text(fill: rgb(accent-color)) + + // Name will be aligned left, bold and big + show heading.where(level: 1): it => [ + #set align(left) + #set text( + weight: 700, + size: 20pt, + ) + #pad(it.body) + ] + + body +} + +// Personal Info Helper +#let contact-item(value, icon: "", prefix: "", link-type: "") = { + if value != "" { + if icon != "" { + icon + " " + } + if link-type != "" { + link(link-type + value)[#(prefix + value)] + } else { + value + } + } +} + +// Personal Info +#let personal-info( + position: left, + with-icons: false, + separator: " | ", + pronouns: "", + phone: "", + location: "", + email: "", + github: "", + linkedin: "", + personal-site: "", + orcid: "", +) = { + pad( + top: 0.25em, + align(position)[ + #{ + let items = ( + contact-item(pronouns), + contact-item(phone), + contact-item(location), + contact-item( + email, + icon: if with-icons { email-icon() } else { "" }, + link-type: "mailto:", + ), + contact-item( + github, + icon: if with-icons { github-icon() } else { "" }, + link-type: "https://", + ), + contact-item( + linkedin, + icon: if with-icons { linkedin-icon() } else { "" }, + link-type: "https://", + ), + contact-item( + personal-site, + icon: if with-icons { website-icon() } else { "" }, + link-type: "https://", + ), + contact-item( + orcid, + icon: orcid-icon(color: rgb("#AECD54")), + prefix: "orcid.org/", + link-type: "https://orcid.org/", + ), + ) + items.filter(x => x != none).join(separator) + } + ], + ) +} + +#let resume( + author: "", + pronouns: "", + location: "", + email: "", + github: "", + linkedin: "", + phone: "", + personal-site: "", + orcid: "", + accent-color: "#000000", + font: "Work Sans", + paper: "a4", + body, +) = { + show: common-doc.with( + author: author, + font: font, + paper: paper, + accent-color: accent-color, + ) + + // Level 1 Heading + [= #(author)] + + personal-info( + position: left, + pronouns: pronouns, + location: location, + email: email, + phone: phone, + github: github, + linkedin: linkedin, + personal-site: personal-site, + orcid: orcid, + ) + + // Main body. + set par(justify: true) + + body +} + +#let cover-letter( + author: "", + title: "", + pronouns: "", + location: "", + email: "", + github: "", + linkedin: "", + phone: "", + personal-site: "", + orcid: "", + accent-color: "#000000", + font: "Work Sans", + paper: "a4", + body, +) = { + show: common-doc.with( + author: author, + font: font, + paper: paper, + accent-color: accent-color, + ) + + grid( + columns: (70%, auto), + [ + #[= #(author)] + #if (title != "") { + [#text(title, fill: rgb(accent-color), size: 12pt)] + } \ + #location + ], + personal-info( + with-icons: true, + position: left, + separator: "\n", + pronouns: pronouns, + email: email, + phone: phone, + github: github, + linkedin: linkedin, + personal-site: personal-site, + orcid: orcid, + ), + ) + + body +} + +// Generic two by two component for resume +#let generic-two-by-two( + top-left: "", + top-right: "", + bottom-left: "", + bottom-right: "", +) = { + [ + #top-left #h(1fr) #top-right \ + #bottom-left #h(1fr) #bottom-right + ] +} + +// Generic one by two component for resume +#let generic-one-by-two( + left: "", + right: "", +) = { + [ + #left #h(1fr) #right + ] +} + +// Cannot just use normal --- ligature becuase ligatures are disabled for good reasons +#let dates-helper( + start-date: "", + end-date: "", +) = { + start-date + " " + $dash.em$ + " " + end-date +} + +// Section components below +#let edu( + institution: "", + dates: "", + degree: "", + gpa: "", + location: "", +) = { + generic-two-by-two( + top-left: strong(institution), + top-right: location, + bottom-left: emph(degree), + bottom-right: emph(dates), + ) +} + +#let work( + title: "", + dates: "", + company: "", + location: "", +) = { + generic-two-by-two( + top-left: strong(title), + top-right: dates, + bottom-left: emph(company), + bottom-right: emph(location), + ) +} + +#let project( + role: "", + name: "", + url: "", + dates: "", +) = { + generic-one-by-two( + left: { + if role == "" { + [*#name* #if url != "" and dates != "" [ (#link("https://" + url)[#url])]] + } else { + [*#role*, #name #if url != "" and dates != "" [ (#link("https://" + url)[#url])]] + } + }, + right: { + if dates == "" and url != "" { + link("https://" + url)[#url] + } else { + dates + } + }, + ) +} + +#let certificates( + name: "", + issuer: "", + url: "", + date: "", +) = { + [ + *#name*, #issuer + #if url != "" { + [ (#link("https://" + url)[#url])] + } + #h(1fr) #date + ] +} + +#let extracurriculars( + activity: "", + dates: "", +) = { + generic-one-by-two( + left: strong(activity), + right: dates, + ) +} diff --git a/src/main.typ b/src/main.typ index 15ad7cc..3c53e65 100644 --- a/src/main.typ +++ b/src/main.typ @@ -1,24 +1,17 @@ -#import "@preview/basic-resume:0.2.3": * +#import "lib/main.typ": * -#let name = "Felix Schröter" -#let location = "Lüneburg, Germany" -#let email = "dev@felschr.com" -#let github = "github.com/felschr" -#let linkedin = "linkedin.com/in/schroeter" -#let personal-site = "felschr.com" +#let info = toml("info.toml") #show: resume.with( - author: name, - location: location, - email: email, - github: github, - linkedin: linkedin, - personal-site: personal-site, - accent-color: "#26428b", - font: "New Computer Modern", - paper: "a4", - author-position: left, - personal-info-position: left, + author: info.personal.name, + location: info.personal.location, + email: info.personal.email, + github: info.personal.github, + linkedin: info.personal.linkedin, + personal-site: info.personal.website, + accent-color: info.layout.accent_color, + font: info.layout.font, + paper: info.layout.paper, ) == Work Experience @@ -42,8 +35,8 @@ - Full-Stack Architecture, Development, Infrastructure & DevOps for Cloud-native solutions - Main technologies: C\#, Rust, Nix, Kubernetes, Terraform / OpenTofu, React, MongoDB, GitLab CI, GCP - Adopted Nix for reproducible builds & environments used both locally for development and for CI/CD -- Expanded Observability using Sentry and integrations with Rust, C\#, React & Google Kubernetes Engine (GKE) -- Adopted Rust as core part of our tech stack due to its strong type system, excellent tooling, safety & performance +- Expanded Observability using Sentry and integrations with Rust, C\#, React & Kubernetes +- Adopted Rust into our tech stack due to its strong type system, excellent tooling, safety & performance - Established reference architecture using Rust, Google Cloud Run, MongoDB Atlas, Nix & GitLab CI with scalability and evolution from monolith to microservices in mind #work( @@ -65,7 +58,7 @@ - Main technologies: C\#, ASP.NET Core, TypeScript, Service Fabric, Cosmos DB, Azure, AWS - Created a microservice-based backend with ASP.NET Core & Azure Cosmos DB - Implemented frontends in React & Angular for different projects -- Built serverless backends for various client projects with AWS Lambda, DynamoDB & Serverless framework +- Built serverless backends for various client projects with AWS Lambda & Serverless framework - Migrated Windows containers to Linux containers to improve performance - Migrated from Azure Service Fabric to Kubernetes for container orchestration @@ -93,7 +86,8 @@ dates: dates-helper(start-date: "May 2024", end-date: "Present"), degree: "Master of Science in Computer Science", ) -- Relevant Coursework: Data Structures and Algorithms, Software Architecture for Big Data, Network Systems +- Current GPA: 4.0 / 4.0 (14 credits) +- Relevant Courses: Data Structures and Algorithms, Software Architecture for Big Data, Network Systems #edu( institution: "Berufsbildende Schulen I Lüneburg", @@ -110,7 +104,7 @@ url: "codeberg.org/felschr/nixos-config", ) - Maintaining my personal & work computers as well as a homelab via a declarative NixOS configuration -- I self-host various services for single sign-On (SSO), home automation, git forge, build server & more +- I self-host various services for single sign-on (SSO), home automation, git forge, build server & more #project( name: "Pheno-Inspect Plant Analyzer Web", @@ -118,7 +112,7 @@ url: "youtu.be/JMkj8vP0eJw", ) - Client project associated with upsquared GmbH -- Developed a web-based frontend for Pheno-Inspect's Digital Phenotyping platform powered by Computer Vision +- Developed web-based frontend for Digital Phenotyping platform powered by Computer Vision - Large drone images can be rendered & annotated efficiently with pixel-perfect accuracy - Main technologies: Next.js, Redux, MUI, fp-ts, OpenLayers, Rust (WASM), WebGL @@ -150,7 +144,7 @@ dates: dates-helper(start-date: "Nov 2018", end-date: "Aug 2019"), // url: "web.archive.org/web/20191021030141/https://www.letzte-werbung.de/melder", ) -- Allows users to report companies that send mail advertising despite a "No advertising please" sticker on the mailbox +- Allows users to report companies that send mail advertising despite "No advertising" sticker on mailbox - Main technologies: TypeScript, Node.js, React, AWS Lambda, Serverless framework, DynamoDB #project( @@ -204,7 +198,7 @@ - *Industry Knowledge*: Software Architecture, Cloud-native Architecture, DevOps, Infrastructure as Code (IaC), Reproducibility, Scalability, Functional Programming, Open Source Development - *Programming Languages*: Rust, Nix, TypeScript, C\#, HCL, Bash, Nushell -- *Backend*: Podman, Docker, gRPC, MongoDB, OpenAPI, GraphQL, buf, tokio, tonic, prost, axum, ASP.NET Core +- *Backend*: Podman, gRPC, MongoDB, OpenAPI, GraphQL, buf, tokio, tonic, prost, axum, ASP.NET Core - *Frontend*: React, Next.js, Redux, emotion, MUI, storybook, webpack, fp-ts - *Infrastructure & DevOps*: Kubernetes, OpenTofu, GitLab CI, Linux, direnv, treefmt, git-hooks.nix - *Cloud Providers*: Google Cloud Platform (GCP), Firebase, Amazon Web Services (AWS), Azure