Now, with services!
Some checks failed
ci/woodpecker/pr/ci Pipeline failed

This commit is contained in:
2026-03-09 18:09:12 -03:00
parent 164ba69010
commit 1e0afb103c
64 changed files with 2365 additions and 2562 deletions

8
.dockerignore Normal file
View File

@@ -0,0 +1,8 @@
# Preview-only 410 path artifacts (copy-410-paths.mjs).
# Deploy uses pnpm run build (no copy step); nginx serves 410 via error_page.
# These dirs exist only when running build-preview for local serve dist.
dist/pt
dist/feed
dist/2024
dist/category
dist/comments

View File

@@ -10,7 +10,7 @@ This file helps LLM agents work in this repo without introducing anti-patterns.
## Stack and architecture ## Stack and architecture
- **Framework**: SvelteKit with **adapter-static**. All routes are prerendered; there is no client-side router or hydration (`csr: false` in `src/routes/+layout.ts`). - **Framework**: SvelteKit with **adapter-static**. All routes are prerendered; there is no client-side router or hydration (`csr: false` in `src/routes/+layout.ts`).
- **Build**: `pnpm run build` = `vite build``node scripts/critters.mjs``node scripts/minify-static-js.mjs``node scripts/copy-410-paths.mjs`. Output is `dist/` (static files only). - **Build**: `pnpm run build` = `vite build``node scripts/critters.mjs``node scripts/generate-sitemap.mjs``node scripts/minify-static-js.mjs`. Output is `dist/` (static files only). Deploy uses this; no 410 path copies. For local preview with 410 URLs working, use `pnpm run build-preview` (adds `copy-410-paths.mjs`). The 410 path dirs are in `.dockerignore` so they are never included in the image.
- **Runtime**: nginx serves `dist/` (mounted as `/usr/share/nginx/html` in the container). No Node at runtime. - **Runtime**: nginx serves `dist/` (mounted as `/usr/share/nginx/html` in the container). No Node at runtime.
- **Theming**: CSS only. Light/dark follows **system preference** via `@media (prefers-color-scheme: dark)` in `src/app.css`. There is no JS theme toggle or `data-theme`; do not add one unless explicitly requested. - **Theming**: CSS only. Light/dark follows **system preference** via `@media (prefers-color-scheme: dark)` in `src/app.css`. There is no JS theme toggle or `data-theme`; do not add one unless explicitly requested.
- **Fonts**: **Local only.** Inter and Fraunces are served from `static/assets/fonts/` (e.g. `inter-v20-latin-*.woff2`, `fraunces-v38-latin-*.woff2`). Preloads are in `src/routes/+layout.svelte`. Do not add Google Fonts or other external font URLs for the main site or error pages. - **Fonts**: **Local only.** Inter and Fraunces are served from `static/assets/fonts/` (e.g. `inter-v20-latin-*.woff2`, `fraunces-v38-latin-*.woff2`). Preloads are in `src/routes/+layout.svelte`. Do not add Google Fonts or other external font URLs for the main site or error pages.
@@ -29,7 +29,7 @@ This file helps LLM agents work in this repo without introducing anti-patterns.
| `static/` | Copied as-is into `dist/` by SvelteKit. Favicon, robots.txt, fonts, images, **404.html**, **410.html**, and **assets/error-pages.css** live here. | | `static/` | Copied as-is into `dist/` by SvelteKit. Favicon, robots.txt, fonts, images, **404.html**, **410.html**, and **assets/error-pages.css** live here. |
| `scripts/critters.mjs` | Post-build: inlines critical CSS into **every** `dist/*.html` (including 404 and 410). Resolves stylesheet URLs relative to `dist/`. | | `scripts/critters.mjs` | Post-build: inlines critical CSS into **every** `dist/*.html` (including 404 and 410). Resolves stylesheet URLs relative to `dist/`. |
| `scripts/minify-static-js.mjs` | Post-build: minifies JS in `dist/assets/`. | | `scripts/minify-static-js.mjs` | Post-build: minifies JS in `dist/assets/`. |
| `scripts/copy-410-paths.mjs` | Post-build: copies `410.html` to each 410 URL path as `index.html` so static preview (e.g. `serve dist`) shows the 410 page at those URLs; nginx still returns 410 via explicit location blocks. | | `scripts/copy-410-paths.mjs` | Run by `build-preview` only: copies `410.html` to each 410 URL path as `index.html` so static preview (e.g. `serve dist`) shows the 410 page at those URLs. Production uses `build` (no copy); nginx returns 410 via explicit location blocks and `error_page 410 /410.html`. |
| `nginx.conf` | Serves static files; `try_files $uri $uri/ /index.html` for SPA-style fallback; `error_page 404 /404.html` and `error_page 410 /410.html` for custom error pages. | | `nginx.conf` | Serves static files; `try_files $uri $uri/ /index.html` for SPA-style fallback; `error_page 404 /404.html` and `error_page 410 /410.html` for custom error pages. |
## Static error pages (404, 410) ## Static error pages (404, 410)
@@ -41,7 +41,7 @@ This file helps LLM agents work in this repo without introducing anti-patterns.
- **Do not** add error-page-only CSS in `src/app.css`; the app bundle is not loaded on error pages. - **Do not** add error-page-only CSS in `src/app.css`; the app bundle is not loaded on error pages.
- **Theme alignment**: When changing light/dark colors or typography in `src/app.css`, update **`static/assets/error-pages.css`** so 404/410 stay visually consistent (same `--ep-*` tokens and, if needed, `@media (prefers-color-scheme: dark)`). - **Theme alignment**: When changing light/dark colors or typography in `src/app.css`, update **`static/assets/error-pages.css`** so 404/410 stay visually consistent (same `--ep-*` tokens and, if needed, `@media (prefers-color-scheme: dark)`).
- **Local fonts**: Error pages use the same font paths as the main site (`/assets/fonts/...`) via `@font-face` in `error-pages.css`. Do not use Google Fonts or other external font URLs on error pages. - **Local fonts**: Error pages use the same font paths as the main site (`/assets/fonts/...`) via `@font-face` in `error-pages.css`. Do not use Google Fonts or other external font URLs on error pages.
- **Preview vs production**: In preview (`serve dist`), the 410 URLs (e.g. `/pt/`, `/feed/`) are served by copying `410.html` to each path as `index.html` (see `scripts/copy-410-paths.mjs`). In production, nginx returns HTTP 410 for those paths and serves the same content via `error_page 410 /410.html`. If you add or remove 410 paths, update both `nginx.conf` and the `PATHS` array in `scripts/copy-410-paths.mjs`. - **Preview vs production**: Deploy runs `pnpm run build` (no 410 path copies); the image stays minimal and nginx serves 410 via `error_page 410 /410.html`. For local preview with 410 URLs working, run `pnpm run build-preview` then `serve dist`; the copied `index.html` files under each 410 path are in `.dockerignore` so they are never copied into the image. If you add or remove 410 paths, update `nginx.conf` and the `PATHS` array in `scripts/410-paths.mjs`.
## Anti-patterns to avoid ## Anti-patterns to avoid

View File

@@ -7,7 +7,8 @@
"description": "mifi Ventures landing site — SvelteKit static build with critical CSS inlining", "description": "mifi Ventures landing site — SvelteKit static build with critical CSS inlining",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "vite build && node scripts/critters.mjs && node scripts/generate-sitemap.mjs && node scripts/minify-static-js.mjs && node scripts/copy-410-paths.mjs", "build": "vite build && node scripts/critters.mjs && node scripts/generate-sitemap.mjs && node scripts/minify-static-js.mjs",
"build-preview": "pnpm run build && node scripts/copy-410-paths.mjs",
"dev": "vite dev", "dev": "vite dev",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",

View File

@@ -492,6 +492,152 @@ a {
} }
} }
.content-list--ordered {
list-style: decimal;
padding-left: var(--space-xl);
}
.content-list--ordered li {
padding-left: var(--space-sm);
}
.content-list--ordered li::before {
content: none;
}
/* ========================================
Service Pages: Credibility Strip, Who Grid, FAQ
======================================== */
.service-credibility {
background-color: var(--color-bg-subtle);
}
.service-credibility__list {
list-style: none;
margin: 0;
padding: 0;
max-width: var(--max-width);
margin: 0 auto;
display: grid;
gap: var(--space-md);
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.service-credibility__list li {
position: relative;
padding-left: var(--space-lg);
font-size: var(--font-size-base);
line-height: var(--line-height-relaxed);
color: var(--color-text-secondary);
}
.service-credibility__list li::before {
content: '→';
position: absolute;
left: 0;
color: var(--color-primary);
font-weight: var(--font-weight-semibold);
}
.who-grid {
display: grid;
gap: var(--space-xxl);
grid-template-columns: 1fr 1fr;
}
@media (max-width: 768px) {
.who-grid {
grid-template-columns: 1fr;
}
}
.who-block h2,
.who-block .list-heading {
font-size: var(--font-size-xl);
margin-bottom: var(--space-md);
}
/* ========================================
Services Landing: Card Grid, Engagements, Ideal
======================================== */
.services-grid-section {
background-color: var(--color-bg);
}
.services-card-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-xl);
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.services-card {
padding: var(--space-xl);
background-color: var(--color-bg-alt);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-medium);
display: flex;
flex-direction: column;
}
.services-card__title {
margin-bottom: var(--space-md);
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
}
.services-card__desc {
flex: 1;
margin-bottom: var(--space-lg);
font-size: var(--font-size-base);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.services-card__link {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-weight: var(--font-weight-semibold);
}
.services-card__link span {
margin-left: var(--space-xs);
}
.engagements-list {
margin: var(--space-lg) 0;
}
.engagements-list dt {
font-weight: var(--font-weight-semibold);
color: var(--color-text);
margin-top: var(--space-lg);
margin-bottom: var(--space-xs);
}
.engagements-list dt:first-child {
margin-top: 0;
}
.engagements-list dd {
margin: 0 0 0 var(--space-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.services-intro {
background-color: var(--color-bg-alt);
}
.services-ideal {
background-color: var(--color-bg-alt);
}
/* ======================================== /* ========================================
Nav Item and Footer Links Common Styles Nav Item and Footer Links Common Styles
======================================== */ ======================================== */

View File

@@ -0,0 +1,37 @@
<script lang="ts">
import type { EngagementItem } from '$lib/types/service-page';
const {
items,
sectionId = 'how-engagements-work',
headingId = 'engagements-heading',
heading = 'How engagements work',
intro,
outro,
}: {
items: EngagementItem[];
sectionId?: string;
headingId?: string;
heading?: string;
intro?: string;
outro?: string;
} = $props();
</script>
<section id={sectionId} class="section" aria-labelledby={headingId}>
<div class="container container--narrow">
<h2 id={headingId}>{heading}</h2>
{#if intro}
<p>{intro}</p>
{/if}
<dl class="engagements-list">
{#each items as item}
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
{/each}
</dl>
{#if outro}
<p>{outro}</p>
{/if}
</div>
</section>

View File

@@ -6,7 +6,9 @@
/** Page slug for body class: "page-home" | "page-services" | "page-services-hands-on-saas-architecture-consultant" etc. Set at build time per route; no client JS. */ /** Page slug for body class: "page-home" | "page-services" | "page-services-hands-on-saas-architecture-consultant" etc. Set at build time per route; no client JS. */
const bodyClass = $derived( const bodyClass = $derived(
path === '/' ? 'page-home' : 'page-' + path.replace(/^\/|\/$/g, '').replace(/\//g, '-') path === '/'
? 'page-home'
: 'page-' + path.replace(/^\/|\/$/g, '').replace(/\//g, '-'),
); );
interface NavigationItem { interface NavigationItem {
@@ -27,7 +29,10 @@
hidden hidden
/> />
<div class="mobile-nav-header"> <div class="mobile-nav-header">
<span class="mobile nav-header-logo"> <span class={[
'mobile nav-header-logo',
{ 'page-home': bodyClass === 'page-home' }
]}>
<Wordmark /> <Wordmark />
</span> </span>
<button <button
@@ -53,7 +58,12 @@
</button> </button>
</div> </div>
<div id="nav-menu" class="nav-menu container"> <div id="nav-menu" class="nav-menu container">
<span class={['nav-header-logo desktop', { 'page-home': bodyClass === 'page-home' }]}> <span
class={[
'nav-header-logo desktop',
{ 'page-home': bodyClass === 'page-home' },
]}
>
{#if page !== 'home'} {#if page !== 'home'}
<a href="/"> <a href="/">
<Wordmark /> <Wordmark />

View File

@@ -7,7 +7,9 @@
bookingLinkTitle, bookingLinkTitle,
bookingLinkUrl = 'https://cal.mifi.ventures/the-mifi/30min', bookingLinkUrl = 'https://cal.mifi.ventures/the-mifi/30min',
showEmailLink = false, showEmailLink = false,
showServicesLink = false showServicesLink = false,
sectionId = 'contact',
headingId = 'contact-heading',
}: { }: {
title: string; title: string;
subtitle: string; subtitle: string;
@@ -15,16 +17,14 @@
bookingLinkUrl?: string; bookingLinkUrl?: string;
showEmailLink?: boolean; showEmailLink?: boolean;
showServicesLink?: boolean; showServicesLink?: boolean;
sectionId?: string;
headingId?: string;
} = $props(); } = $props();
</script> </script>
<section <section id={sectionId} class="section schedule-section" aria-labelledby={headingId}>
id="contact"
class="section schedule-section"
aria-labelledby="contact-heading"
>
<div class="container"> <div class="container">
<h2 id="contact-heading" class="section-title">{title}</h2> <h2 id={headingId} class="section-title">{title}</h2>
<p class="schedule-text">{subtitle}</p> <p class="schedule-text">{subtitle}</p>
<div class="cta-group"> <div class="cta-group">
<a <a

View File

@@ -0,0 +1,82 @@
<script lang="ts">
import type { ServiceSectionContent } from '$lib/types/service-page';
const {
section,
}: {
section: ServiceSectionContent;
} = $props();
const headingId = $derived(section.headingId ?? `${section.id}-heading`);
const sectionClasses = $derived(
['section', section.sectionClass].filter(Boolean).join(' '),
);
const containerClass = $derived(
section.narrowContainer === false ? 'container' : 'container container--narrow',
);
const listClass = $derived(
[section.bulletsListClass, 'content-list'].filter(Boolean).join(' '),
);
</script>
<section id={section.id} class={sectionClasses} aria-labelledby={headingId}>
<div class={containerClass}>
<h2 id={headingId} class:sr-only={section.headingSrOnly ?? false}>
{section.heading}
</h2>
{#if section.lede}
<p>{section.lede}</p>
{/if}
{#each section.paragraphs ?? [] as p}
<p>{p}</p>
{/each}
{#each section.subsections ?? [] as sub, subIndex}
{@const subId = sub.headingId ?? `${section.id}-sub-${subIndex}`}
<h3 id={subId}>{sub.heading}</h3>
{#each sub.paragraphs ?? [] as p}
<p>{p}</p>
{/each}
{#if (sub.bullets?.length ?? 0) > 0}
<ul class="content-list">
{#each sub.bullets as bullet}
<li>{bullet}</li>
{/each}
</ul>
{/if}
{/each}
{#if (section.bullets?.length ?? 0) > 0}
<ul class={listClass}>
{#each section.bullets as bullet}
<li>{bullet}</li>
{/each}
</ul>
{/if}
{#if (section.orderedBullets?.length ?? 0) > 0}
<ol class="content-list content-list--ordered">
{#each section.orderedBullets as bullet}
<li>{bullet}</li>
{/each}
</ol>
{/if}
{#each section.trailingParagraphs ?? [] as p}
<p>{p}</p>
{/each}
{#if (section.footerLinks?.length ?? 0) > 0}
<p>
{#each section.footerLinks as link, i}
{#if i > 0}
<span aria-hidden="true"> · </span>
{/if}
<a href={link.href}>{link.label}</a>
{/each}
</p>
{/if}
</div>
</section>

View File

@@ -0,0 +1,38 @@
<script lang="ts">
import type { ServiceCard } from '$lib/types/service-page';
const {
services,
sectionId = 'services-grid',
headingId = 'services-heading',
heading = 'Services',
}: {
services: ServiceCard[];
sectionId?: string;
headingId?: string;
heading?: string;
} = $props();
</script>
<section id={sectionId} class="section services-grid-section" aria-labelledby={headingId}>
<div class="container">
<h2 id={headingId} class="section-title">{heading}</h2>
<ul class="services-card-list">
{#each services as service (service.href)}
<li class="services-card">
<h3 class="services-card__title">{service.title}</h3>
<p class="services-card__desc">{service.description}</p>
<a
href={service.href}
class="services-card__link"
data-umami-event="service link"
data-umami-event-label={service.href}
>
Learn more
<span aria-hidden="true"></span>
</a>
</li>
{/each}
</ul>
</div>
</section>

View File

@@ -4,11 +4,15 @@
title = 'Who this is for', title = 'Who this is for',
whoForList, whoForList,
whoNotList, whoNotList,
whoForHeading = 'Good fit',
whoNotHeading = 'Who this is not for',
}: { }: {
title?: string; title?: string;
showTitle?: boolean; showTitle?: boolean;
whoForList: string[]; whoForList: string[];
whoNotList: string[]; whoNotList: string[];
whoForHeading?: string;
whoNotHeading?: string;
} = $props(); } = $props();
</script> </script>
@@ -17,7 +21,7 @@
<h2 id="who-for-heading" class={{ 'sr-only': !showTitle }}>{title}</h2> <h2 id="who-for-heading" class={{ 'sr-only': !showTitle }}>{title}</h2>
<div class="who-grid"> <div class="who-grid">
<div class="who-block"> <div class="who-block">
<h3 id="who-for-list-heading"class="list-heading">Good fit</h3> <h3 id="who-for-list-heading" class="list-heading">{whoForHeading}</h3>
<ul class="content-list" aria-labelledby="who-for-list-heading"> <ul class="content-list" aria-labelledby="who-for-list-heading">
{#each whoForList as item, index (index)} {#each whoForList as item, index (index)}
<li>{item}</li> <li>{item}</li>
@@ -25,7 +29,7 @@
</ul> </ul>
</div> </div>
<div class="who-block"> <div class="who-block">
<h3 id="who-not-list-heading" class="list-heading">Who this is not for</h3> <h3 id="who-not-list-heading" class="list-heading">{whoNotHeading}</h3>
<ul class="content-list" aria-labelledby="who-not-list-heading"> <ul class="content-list" aria-labelledby="who-not-list-heading">
{#each whoNotList as item, index (index)} {#each whoNotList as item, index (index)}
<li>{item}</li> <li>{item}</li>

View File

@@ -6,12 +6,14 @@
<header id="header" class="hero"> <header id="header" class="hero">
<div class="container"> <div class="container">
<Logo /> <Logo />
<h1 class="hero__headline">Hands-On Product Architecture for Early-Stage SaaS</h1> <h2 class="headline">Hands-On Product Architecture for Early-Stage SaaS</h2>
<p class="hero__subhead"> <p class="subhead">
I help SaaS teams ship quickly without creating frontend debt, architectural drift, or I help SaaS teams ship quickly without creating frontend debt, architectural
technical complexity that slows iteration later. drift, or technical complexity that slows iteration later.
</p>
<p class="supporting">
Mike Fitzpatrick — product architect and senior software engineer
</p> </p>
<p class="hero__supporting">Mike Fitzpatrick — product architect and senior software engineer</p>
<div class="cta-group"> <div class="cta-group">
<a <a
href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=hero" href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=hero"
@@ -53,7 +55,7 @@
} }
} }
.hero__headline { .headline {
margin-bottom: var(--space-lg); margin-bottom: var(--space-lg);
font-family: var(--font-family-heading); font-family: var(--font-family-heading);
font-size: var(--font-size-xxl); font-size: var(--font-size-xxl);
@@ -67,7 +69,7 @@
} }
} }
.hero__subhead { .subhead {
max-width: var(--max-narrow-width); max-width: var(--max-narrow-width);
margin: 0 auto var(--space-md) auto; margin: 0 auto var(--space-md) auto;
font-size: var(--font-size-large); font-size: var(--font-size-large);
@@ -76,7 +78,7 @@
line-height: var(--line-height-relaxed); line-height: var(--line-height-relaxed);
} }
.hero__supporting { .supporting {
margin: 0 auto var(--space-xl) auto; margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-base); font-size: var(--font-size-base);
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);

View File

@@ -21,18 +21,22 @@
{ {
title: 'Stage-Aligned Infrastructure', title: 'Stage-Aligned Infrastructure',
description: description:
'Infrastructure decisions that match your company\'s stage, without unnecessary SaaS sprawl or cloud complexity.', "Infrastructure decisions that match your company's stage, without unnecessary SaaS sprawl or cloud complexity.",
href: '/services/stage-aligned-infrastructure', href: '/services/stage-aligned-infrastructure',
}, },
]; ];
</script> </script>
<section id="services" class="section services-overview" aria-labelledby="services-overview-heading"> <section
id="services"
class="section services-overview"
aria-labelledby="services-overview-heading"
>
<div class="container"> <div class="container">
<h2 id="services-overview-heading" class="section-title">How I Help</h2> <h2 id="services-overview-heading" class="section-title">How I Help</h2>
<p class="services-overview__intro"> <p class="services-overview__intro">
I work with early-stage SaaS teams in four primary ways, depending on the stage of the I work with early-stage SaaS teams in four primary ways, depending on the
product and the type of technical support needed. stage of the product and the type of technical support needed.
</p> </p>
<ul class="services-overview__list"> <ul class="services-overview__list">
{#each services as service (service.href)} {#each services as service (service.href)}

View File

@@ -1,5 +1,8 @@
<script lang="ts"> <script lang="ts">
import { whatIHelpTeamsFixIntro, whatIHelpTeamsFixItems } from '$lib/data/home/content'; import {
whatIHelpTeamsFixIntro,
whatIHelpTeamsFixItems,
} from '$lib/data/home/content';
</script> </script>
<section id="what-i-help-fix" class="section" aria-labelledby="what-i-help-fix-heading"> <section id="what-i-help-fix" class="section" aria-labelledby="what-i-help-fix-heading">

View File

@@ -1,42 +0,0 @@
/**
* FAQ for the fractional CTO for early-stage SaaS service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'What does "fractional CTO" actually mean?',
answer:
'A fractional CTO is a part-time technical leader who provides CTO-level guidance without the cost of a full-time executive. You get senior architectural direction, decision review, and technical oversight on a retainer basis—typically 1040 hours per month depending on your stage.',
},
{
question: 'How involved are you in day-to-day engineering?',
answer:
'I stay close enough to the code to keep decisions grounded. That means architecture reviews, participation in product and roadmap discussions, and hands-on refactoring when it matters. Im not a slide-deck CTO—I operate as a technical partner who can both advise and implement.',
},
{
question: 'Can you still contribute code?',
answer:
'Yes. I contribute code when its the right leverage: critical refactors, foundation work, or examples that set standards for the team. The goal is to improve the system and transfer knowledge, not to become a permanent implementer.',
},
{
question: 'How long do engagements usually last?',
answer:
'Engagements are typically ongoing month-to-month. Some teams need fractional leadership for 612 months until they hire a full-time CTO; others stay on a retainer longer. We align on goals and revisit as your team grows.',
},
{
question: 'Can you help with hiring engineers?',
answer:
'Yes. I help define technical standards, review candidates, and advise on team structure. Hiring decisions are technical decisions—having a clear bar and someone who can assess it makes a big difference.',
},
{
question: 'What tech stacks do you work with?',
answer:
'I work with modern web and SaaS stacks—frontend, backend, and infrastructure. The principles of good architecture (separation of concerns, maintainability, stage-appropriate choices) transfer across stacks. We can discuss fit for your stack.',
},
];

View File

@@ -1,47 +0,0 @@
/**
* FAQ for the hands-on SaaS architecture consultant service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'Do you only do frontend?',
answer:
"No. I'm product-first with backend and infra awareness—but frontend foundations are often the bottleneck for early-stage teams. I focus where the friction is.",
},
{
question: 'Will this slow us down?',
answer:
'No. The goal is to make iteration cheaper. A solid foundation reduces rework and lets you ship faster over time.',
},
{
question: 'Do we need a full redesign?',
answer:
'Usually no. I take an incremental foundation approach: fix the architecture and systems first, then evolve the UI. Big-bang redesigns are rarely necessary.',
},
{
question: 'What tech stacks do you work with?',
answer:
'I work with modern web stacks—React, Vue, Svelte, and similar. The principles (CSS architecture, tokens, components, accessibility) transfer. We can discuss fit for your stack.',
},
{
question: 'How do you handle accessibility?',
answer:
'Baseline standards (semantic markup, keyboard, focus, ARIA where needed) plus components built accessibly from the start. It\'s baked into the system, not bolted on.',
},
{
question: 'Can you work with our designer?',
answer:
'Yes. Design tokens and a component system give designers and engineers a shared language. I can align with your design process and tools.',
},
{
question: 'Do you offer ongoing support?',
answer:
'Yes, via an advisory retainer: regular check-ins, optional PR review, and guidance as you grow. Bounded and lightweight—not a 24/7 MSP model.',
},
];

View File

@@ -2,7 +2,7 @@ export const whatIHelpTeamsFixIntro =
'Most early-stage SaaS products do not break because of lack of effort. They break because the foundation was rushed, the frontend was treated as secondary, or complexity arrived before the company was ready for it.'; 'Most early-stage SaaS products do not break because of lack of effort. They break because the foundation was rushed, the frontend was treated as secondary, or complexity arrived before the company was ready for it.';
export const whatIHelpTeamsFixItems = [ export const whatIHelpTeamsFixItems = [
'Backend-heavy products with frontend foundations that don\'t scale', "Backend-heavy products with frontend foundations that don't scale",
'CSS and component systems that slow iteration', 'CSS and component systems that slow iteration',
'MVPs built quickly but not structured to evolve', 'MVPs built quickly but not structured to evolve',
'Teams shipping features without architectural guardrails', 'Teams shipping features without architectural guardrails',

View File

@@ -1,47 +0,0 @@
/**
* FAQ for the MVP architecture and launch service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'Will this slow us down?',
answer:
'No. The goal is to make iteration cheaper. I work incrementally—fixing foundations while you keep shipping. No rewrite mandates, no velocity freeze.',
},
{
question: 'Do we need a full rewrite?',
answer:
'Usually no. Most MVPs need structural cleanup and a clear component/CSS strategy, not a from-scratch rebuild. We prioritize the highest-leverage fixes first.',
},
{
question: 'What tech stacks do you work with?',
answer:
'I work with modern web stacks—React, Vue, Svelte, and similar. The principles (separation of concerns, tokens, components, accessibility) transfer. We can discuss fit for your stack.',
},
{
question: 'How do you handle accessibility?',
answer:
'Accessibility is baked in incrementally: semantic markup, keyboard and focus behavior, and ARIA where needed. Doing it as we refactor is far cheaper than retrofitting later.',
},
{
question: 'Can you work alongside our existing devs?',
answer:
'Yes. I pair with your team, document decisions, and hand off so youre not dependent on me. Knowledge transfer is part of the engagement.',
},
{
question: 'How quickly will we see impact?',
answer:
'Most teams feel the difference within 12 weeks once foundational issues are addressed: faster feature work, fewer bugs, and safer refactors.',
},
{
question: 'Do you only focus on frontend?',
answer:
"I'm product-first. Frontend foundations are often the bottleneck for early MVPs, so that's where I focus—but I align with your backend boundaries and deployment so the whole system makes sense.",
},
];

View File

@@ -0,0 +1,187 @@
import type { ServiceDetailContent } from '$lib/types/service-page';
const discoveryCallUrl =
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=fractional_cto_page';
export const pageContent: ServiceDetailContent = {
hero: {
title: 'Fractional CTO for Early-Stage SaaS',
subtitle:
'At a certain point, early-stage SaaS teams need more than just developers shipping features. They need someone steering the technical decisions. I work alongside founders and engineers to keep architecture sane, prevent premature complexity, and help teams move fast without creating structural problems.',
bookingLinkTitle: 'Book a discovery call',
bookingLinkUrl: discoveryCallUrl,
secondaryCta: {
href: '#approach',
label: 'See how I work',
umamiEventLabel: 'see how i work',
},
},
tocItems: [
{ label: 'When teams need technical leadership', href: '#when-teams' },
{ label: 'The two common failure modes', href: '#failure-modes' },
{ label: 'What working with me looks like', href: '#approach' },
{ label: 'What engineering teams notice', href: '#what-changes' },
{ label: 'Engagement structure', href: '#engagement' },
{ label: "Who it's for", href: '#who-its-for' },
{ label: 'FAQ', href: '#faq' },
{ label: 'Get in touch', href: '#final-cta' },
],
navItems: [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'How I work', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'Engagement', href: '#engagement', umamiEventLabel: 'engagement' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
],
sections: [
{
id: 'when-teams',
headingId: 'when-teams-heading',
heading: 'When a team needs technical leadership—but not a full-time CTO',
paragraphs: [
'Most early-stage SaaS companies reach a moment where shipping features is no longer the only challenge. Architecture decisions start to compound. Tooling choices matter. Hiring decisions become technical decisions.',
'But hiring a full-time CTO is often premature.',
'A fractional CTO provides senior-level guidance without the cost and commitment of a full-time executive.',
'Typical signs a team is here:',
],
bullets: [
'The codebase is growing quickly and architectural decisions are becoming harder to reverse',
'Founders want a second opinion on technical tradeoffs',
'Engineering teams are shipping but lack architectural guardrails',
'Tooling and infrastructure decisions feel arbitrary',
'Hiring engineers without a clear technical standard',
],
},
{
id: 'failure-modes',
headingId: 'failure-modes-heading',
heading: 'The two ways early-stage teams usually get it wrong',
paragraphs: ['I see two patterns repeatedly.'],
subsections: [
{
heading: 'Over-building too early',
paragraphs: [
"Teams adopt infrastructure and services designed for companies ten times their size. They spend time and capital building systems they don't yet need.",
],
},
{
heading: 'Shipping chaos',
paragraphs: [
'Other teams rush an MVP by outsourcing development cheaply, producing something that works—but is extremely difficult to iterate on.',
],
},
],
trailingParagraphs: [
'Healthy early-stage engineering balances both pressures: lean spending with solid foundations.',
],
footerLinks: [
{
label: 'Hands-on SaaS architecture',
href: '/services/hands-on-saas-architecture-consultant',
},
{
label: 'MVP architecture and launch',
href: '/services/mvp-architecture-and-launch',
},
{
label: 'Stage-aligned infrastructure',
href: '/services/stage-aligned-infrastructure',
},
],
},
{
id: 'approach',
headingId: 'approach-heading',
heading: 'What working with me looks like',
paragraphs: [
'I operate as a technical partner for founders and engineering teams.',
'That means I help with both strategic decisions and practical implementation.',
'Typical involvement includes:',
],
bullets: [
'Reviewing architecture decisions before they become expensive mistakes',
'Participating in product and roadmap discussions',
'Setting architectural guardrails for the engineering team',
'Evaluating tooling and infrastructure choices',
'Mentoring developers and improving engineering practices',
'Refactoring critical parts of the codebase when necessary',
'Helping founders understand the technical tradeoffs behind decisions',
],
trailingParagraphs: [
'I am not a slide-deck CTO. I stay close enough to the code to keep decisions grounded in reality.',
],
},
{
id: 'what-changes',
headingId: 'what-changes-heading',
heading: 'What changes when technical leadership is present',
paragraphs: [
'When a team has clear technical leadership, several things happen quickly:',
],
bullets: [
'Architectural decisions become intentional instead of reactive',
'Developers move faster because the system has clearer structure',
'Tooling choices become consistent',
'Technical discussions shift from opinion to reasoning',
'Engineers spend more time building and less time debating direction',
],
trailingParagraphs: [
'The result is not just cleaner systems—but a calmer engineering culture.',
],
},
{
id: 'engagement',
headingId: 'engagement-heading',
heading: 'How fractional CTO engagements usually work',
paragraphs: [
'Engagements are typically structured as a monthly retainer with defined availability.',
"Typical involvement ranges between 1040 hours per month depending on the company's stage and needs.",
'This usually includes:',
],
bullets: [
'Regular founder check-ins',
'Engineering architecture reviews',
'Product roadmap discussions',
'Codebase and system reviews',
'Guidance on hiring and technical standards',
],
trailingParagraphs: [
'The goal is consistent oversight without becoming a bottleneck.',
],
},
],
who: {
whoForList: [
'Founder-led SaaS companies',
'115 engineers',
'Teams preparing to scale their product',
'Companies that want technical leadership without a full-time CTO',
],
whoNotList: [
'Companies that already have strong senior technical leadership',
'Enterprises needing full-time executive presence',
'Teams looking only for implementation without architectural guidance',
],
},
scheduleCta: {
sectionId: 'final-cta',
headingId: 'final-cta-heading',
title: 'Need a technical adult in the room?',
subtitle:
'If your team is shipping quickly but architectural decisions are starting to feel heavier, a fractional CTO engagement can provide the guidance needed to keep the system healthy while the product grows.',
bookingLinkTitle: 'Book a discovery call',
bookingLinkUrl: `${discoveryCallUrl}-schedule-section`,
showEmailLink: true,
},
meta: {
title: 'Fractional CTO for Early-Stage SaaS | mifi Ventures',
description:
'Technical leadership for early-stage SaaS teams that need architectural direction without hiring a full-time CTO. Hands-on guidance that keeps teams shipping while preventing structural mistakes.',
jsonLdServiceDescription:
'Fractional CTO and technical partner for early-stage SaaS: architectural direction, codebase and tooling guidance, and hands-on leadership without the cost of a full-time CTO. Monthly retainer engagements.',
},
};

View File

@@ -0,0 +1,36 @@
/**
* FAQ for the fractional CTO for early-stage SaaS service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'What does "fractional CTO" actually mean?',
answer: 'A fractional CTO is a part-time technical leader who provides CTO-level guidance without the cost of a full-time executive. You get senior architectural direction, decision review, and technical oversight on a retainer basis—typically 1040 hours per month depending on your stage.',
},
{
question: 'How involved are you in day-to-day engineering?',
answer: 'I stay close enough to the code to keep decisions grounded. That means architecture reviews, participation in product and roadmap discussions, and hands-on refactoring when it matters. Im not a slide-deck CTO—I operate as a technical partner who can both advise and implement.',
},
{
question: 'Can you still contribute code?',
answer: 'Yes. I contribute code when its the right leverage: critical refactors, foundation work, or examples that set standards for the team. The goal is to improve the system and transfer knowledge, not to become a permanent implementer.',
},
{
question: 'How long do engagements usually last?',
answer: 'Engagements are typically ongoing month-to-month. Some teams need fractional leadership for 612 months until they hire a full-time CTO; others stay on a retainer longer. We align on goals and revisit as your team grows.',
},
{
question: 'Can you help with hiring engineers?',
answer: 'Yes. I help define technical standards, review candidates, and advise on team structure. Hiring decisions are technical decisions—having a clear bar and someone who can assess it makes a big difference.',
},
{
question: 'What tech stacks do you work with?',
answer: 'I work with modern web and SaaS stacks—frontend, backend, and infrastructure. The principles of good architecture (separation of concerns, maintainability, stage-appropriate choices) transfer across stacks. We can discuss fit for your stack.',
},
];

View File

@@ -0,0 +1,230 @@
import type { ServiceDetailContent } from '$lib/types/service-page';
const discoveryCallUrl =
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=hands_on_saas_arch_page';
export const pageContent: ServiceDetailContent = {
hero: {
title: 'Hands-On Product Architecture for Early-Stage SaaS',
subtitle:
"Most early-stage teams obsess over backend performance and treat the frontend as a thin layer. That's backwards. The frontend is the product—and if its foundations aren't built to scale, iteration slows, bugs multiply, and shipping becomes stressful. I work inside your codebase to build frontend systems that enable velocity: clean CSS architecture, reusable components, tokenized design systems, and accessibility from day one.",
bookingLinkTitle: 'Book a discovery call',
bookingLinkUrl: discoveryCallUrl,
secondaryCta: {
href: '#approach',
label: 'See my approach',
umamiEventLabel: 'see my approach',
},
},
tocItems: [
{ label: 'Credibility', href: '#credibility' },
{ label: 'Why this matters', href: '#why-this-matters' },
{ label: 'The frontend is the product', href: '#frontend-is-product' },
{ label: 'What goes wrong', href: '#what-goes-wrong' },
{ label: 'My approach', href: '#approach' },
{ label: 'Outcomes', href: '#outcomes' },
{ label: 'Engagement options', href: '#engagement' },
{ label: "Who it's for", href: '#who-its-for' },
{ label: 'FAQ', href: '#faq' },
{ label: 'Get in touch', href: '#final-cta' },
],
navItems: [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'My approach', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'Outcomes', href: '#outcomes', umamiEventLabel: 'outcomes' },
{ label: 'Engagement', href: '#engagement', umamiEventLabel: 'engagement' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
],
sections: [
{
id: 'credibility',
heading: 'Credibility',
headingSrOnly: true,
sectionClass: 'service-credibility',
narrowContainer: false,
bulletsListClass: 'service-credibility__list',
bullets: [
'Product developer at heart; systems-minded by default',
'Frontend foundations: CSS architecture, design tokens, component libraries',
'Accessibility-first (bolting it on later is always expensive)',
'Stage-aware decisions that preserve runway without slowing shipping',
],
},
{
id: 'why-this-matters',
headingId: 'why-heading',
heading: "Shipping slows down quietly—until it suddenly doesn't",
paragraphs: [
"Early-stage SaaS rarely fails because the backend can't handle load. It fails because iteration becomes painful.",
'When the frontend is ad hoc—CSS drift, inconsistent components, no tokens, accessibility bolted on later—every new feature costs more than it should. Engineers hesitate to touch code. Small changes break unrelated screens. Design becomes inconsistent. Velocity drops.',
'This is not a "design problem." It\'s an architecture problem.',
],
},
{
id: 'frontend-is-product',
headingId: 'frontend-heading',
heading: 'The frontend is the product',
paragraphs: [
"Your customers don't experience your database schema. They experience your UI.",
"A performant backend matters—but it's not more important than a frontend built for iteration. The frontend drives conversion, communicates trust, and determines how quickly your team can ship new features without breaking old ones.",
'If you want to move fast later, you have to build a foundation now.',
],
},
{
id: 'what-goes-wrong',
headingId: 'wrong-heading',
heading: 'What I see most often',
bullets: [
'Backend-crafted frontends: functional, but brittle and inconsistent',
'"CSS as an afterthought": global overrides, magic numbers, creeping specificity wars',
"Component sprawl: dozens of one-off components that can't be reused",
'No design tokens: colors, spacing, typography duplicated everywhere',
'Accessibility postponed: expensive retrofits, inconsistent semantics',
'Rebuilding instead of composing: no "lego system," so iteration is slow and repetitive',
],
},
{
id: 'approach',
headingId: 'approach-heading',
heading: 'My approach: architecture through implementation',
paragraphs: [
"I'm not a diagram consultant. I'm hands-on. I get into the codebase and build the foundation your team can extend.",
'The goal is simple: make iteration cheap.',
],
subsections: [
{
heading: '1) Fix the CSS foundation first',
paragraphs: [
'Bad CSS makes everything inconsistent and makes change arduous. I start by establishing a maintainable CSS architecture that supports a coherent visual language and reduces the bug surface area.',
],
},
{
heading: '2) Build a reusable component system',
paragraphs: [
'I create a component library that lowers duplication and prevents developers from "re-solving" the same UI problems. This increases speed and improves consistency.',
],
},
{
heading: '3) Tokenize the design system',
paragraphs: [
'Design tokens (color, spacing, typography, radii, shadows) allow the brand to evolve without rewrites. You can iterate quickly as you discover what your product should feel like.',
],
},
{
heading: '4) Bake in accessibility from day one',
paragraphs: [
'Accessibility isn\'t optional and it isn\'t "later." Bolting it on later is always expensive. Doing it early saves time, improves UX, and strengthens SEO.',
],
},
{
heading: '5) Keep the whole system stage-aligned',
paragraphs: [
"I'm pragmatic about tooling. Some things can stay on free tiers early. Some choices should be intentional because migration later is painful. The point is to preserve runway without slowing shipping.",
],
},
],
footerLinks: [
{
label: 'Fractional CTO for early-stage SaaS',
href: '/services/fractional-cto-for-early-stage-saas',
},
{
label: 'MVP architecture and launch',
href: '/services/mvp-architecture-and-launch',
},
{
label: 'Stage-aligned infrastructure',
href: '/services/stage-aligned-infrastructure',
},
],
},
{
id: 'outcomes',
headingId: 'outcomes-heading',
heading: 'What changes when the foundation is right',
paragraphs: [
"It's all connected—speed, bugs, confidence, and morale are one big ball of yarn. When the frontend foundation is right, the whole system gets calmer.",
],
bullets: [
'Developers ship faster with less hesitation',
'Lower bug rate from fewer one-off implementations',
'Cohesive UI and clearer product identity',
'Faster design iteration without rewrites',
'Accessibility becomes the default, not a retrofit',
'SEO improves naturally via good structure and semantics',
'Higher release confidence and better team morale',
],
},
{
id: 'engagement',
headingId: 'engagement-heading',
heading: 'How we can work together',
subsections: [
{
heading: 'Architecture engagement (high-fee, fixed scope)',
bullets: [
'Codebase review focused on frontend foundations',
'CSS + component audit, prioritized action plan',
'Token strategy and incremental adoption plan',
'Accessibility baseline and standards',
'A roadmap your team can execute',
],
},
{
heading: 'Implementation (optional, bounded)',
bullets: [
'Hands-on refactors and foundation building',
'Component library creation and rollout',
'Tokenization and theming support',
"Documentation and handoff so you're not dependent on me",
],
},
{
heading: 'Advisory retainer (recurring, low-liability)',
bullets: [
'Regular check-ins to keep architecture clean as you ship',
'Review of component/API decisions and PRs (optional)',
'Guidance on tooling tradeoffs as you grow',
'No 24/7 pager-duty MSP model',
],
},
],
},
],
who: {
whoForHeading: 'Who this is for',
whoForList: [
'Founder-led SaaS teams',
'115 engineers (and growing)',
'Teams shipping fast but feeling UI/UX friction',
'Teams who want adult-level architecture without slowing down',
],
whoNotList: [
'Organizations looking for pure strategy decks and diagrams',
'Teams wanting a long-term embedded full-time DevOps engineer',
'Companies needing 24/7 managed hosting with strict SLAs',
],
},
scheduleCta: {
sectionId: 'final-cta',
headingId: 'final-cta-heading',
title: 'Want to ship faster without frontend debt?',
subtitle:
"If your UI feels brittle, inconsistent, or slow to evolve, you're not alone—and you don't need a massive rewrite. Let's build a foundation that makes iteration cheap.",
bookingLinkTitle: 'Book a discovery call',
bookingLinkUrl: `${discoveryCallUrl}-schedule-section`,
showEmailLink: true,
},
meta: {
title: 'SaaS Product Architecture Consultant | mifi Ventures',
description:
'I help early-stage SaaS teams ship faster by building scalable frontend foundations—clean CSS, component libraries, design tokens, and accessibility from day one—so iteration accelerates instead of slowing down.',
jsonLdServiceDescription:
'Hands-on product architecture for early-stage SaaS: frontend foundations, CSS architecture, component libraries, design tokens, and accessibility from day one. Architecture engagement, implementation support, and advisory retainer.',
},
};

View File

@@ -0,0 +1,40 @@
/**
* FAQ for the hands-on SaaS architecture consultant service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'Do you only do frontend?',
answer: "No. I'm product-first with backend and infra awareness—but frontend foundations are often the bottleneck for early-stage teams. I focus where the friction is.",
},
{
question: 'Will this slow us down?',
answer: 'No. The goal is to make iteration cheaper. A solid foundation reduces rework and lets you ship faster over time.',
},
{
question: 'Do we need a full redesign?',
answer: 'Usually no. I take an incremental foundation approach: fix the architecture and systems first, then evolve the UI. Big-bang redesigns are rarely necessary.',
},
{
question: 'What tech stacks do you work with?',
answer: 'I work with modern web stacks—React, Vue, Svelte, and similar. The principles (CSS architecture, tokens, components, accessibility) transfer. We can discuss fit for your stack.',
},
{
question: 'How do you handle accessibility?',
answer: "Baseline standards (semantic markup, keyboard, focus, ARIA where needed) plus components built accessibly from the start. It's baked into the system, not bolted on.",
},
{
question: 'Can you work with our designer?',
answer: 'Yes. Design tokens and a component system give designers and engineers a shared language. I can align with your design process and tools.',
},
{
question: 'Do you offer ongoing support?',
answer: 'Yes, via an advisory retainer: regular check-ins, optional PR review, and guidance as you grow. Bounded and lightweight—not a 24/7 MSP model.',
},
];

View File

@@ -0,0 +1,103 @@
import type { ServicesLandingContent } from '$lib/types/service-page';
const discoveryCallUrl =
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=services_landing';
export const pageContent: ServicesLandingContent = {
hero: {
title: 'Consulting Services',
subtitle:
'I work with early-stage SaaS teams to build products that ship quickly and evolve cleanly. Engagements range from hands-on architecture work inside your codebase to technical leadership for growing teams.',
bookingLinkTitle: 'Schedule a discovery call',
bookingLinkUrl: discoveryCallUrl,
secondaryCta: {
href: '/#process',
label: 'See how I work',
umamiEventLabel: 'see how i work',
},
},
navItems: [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'Services', href: '#services-grid', umamiEventLabel: 'services' },
{
label: 'How engagements work',
href: '#how-engagements-work',
umamiEventLabel: 'engagements',
},
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
],
introParagraphs: [
'Early-stage SaaS companies face different technical challenges as they grow. Some need help building their MVP correctly. Others need architectural guidance as complexity increases. Some teams simply need a senior engineer who can step in and stabilize a chaotic codebase.',
'The services below represent the most common ways I work with founders and engineering teams.',
],
services: [
{
title: 'Hands-On SaaS Architecture',
description:
'Build the foundations that allow SaaS products to evolve without accumulating structural debt. I work directly inside your codebase to improve frontend systems, establish reusable components, and create architecture that supports long-term iteration.',
href: '/services/hands-on-saas-architecture-consultant',
},
{
title: 'MVP Architecture & Launch',
description:
"Ship your product quickly without creating a fragile system you'll have to rewrite six months later. I help teams design and build MVPs that are simple, scalable, and structured for rapid iteration.",
href: '/services/mvp-architecture-and-launch',
},
{
title: 'Fractional CTO / Technical Partner',
description:
"Technical leadership for teams that need architectural direction but aren't ready for a full-time CTO. I work alongside founders and engineers to guide system design, evaluate technical decisions, and maintain long-term architectural clarity.",
href: '/services/fractional-cto-for-early-stage-saas',
},
{
title: 'Stage-Aligned Infrastructure',
description:
"Infrastructure decisions should match your company's stage. I help teams avoid unnecessary SaaS sprawl and cloud complexity while building infrastructure that can grow with the product.",
href: '/services/stage-aligned-infrastructure',
},
],
engagementsIntro: 'Most engagements fall into one of three patterns:',
engagements: [
{
term: 'Architecture engagements',
definition:
'Focused, fixed-scope projects designed to diagnose and correct structural issues in a codebase.',
},
{
term: 'Implementation work',
definition: 'Hands-on engineering to build or refactor core product systems.',
},
{
term: 'Advisory retainers',
definition:
'Ongoing architectural guidance for teams that need senior technical oversight.',
},
],
engagementsOutro:
'Engagements are typically consulting-led and scoped to deliver meaningful progress quickly.',
idealClients: [
'Founder-led SaaS startups',
'Engineering teams with 115 developers',
'Products that are actively shipping and evolving',
'Teams that value thoughtful engineering decisions',
],
scheduleCta: {
title: 'Not sure which service fits?',
subtitle:
'Many engagements start with a short conversation about your product and technical challenges. From there we can determine whether architecture work, MVP support, or ongoing technical leadership makes the most sense.',
bookingLinkTitle: 'Schedule a discovery call',
bookingLinkUrl: `${discoveryCallUrl}-schedule-section`,
showEmailLink: true,
},
meta: {
title: 'SaaS Architecture Services | mifi Ventures',
description:
'Hands-on SaaS architecture consulting for early-stage teams. Services include product architecture, MVP launch support, fractional CTO guidance, and stage-aligned infrastructure strategy.',
jsonLdServiceDescription:
'SaaS architecture consulting for early-stage teams: hands-on product architecture, MVP launch support, fractional CTO, and stage-aligned infrastructure strategy.',
},
};

View File

@@ -0,0 +1,195 @@
import type { ServiceDetailContent } from '$lib/types/service-page';
const discoveryCallUrl =
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=mvp_arch_launch_page';
export const pageContent: ServiceDetailContent = {
hero: {
title: 'MVP Architecture & Launch for Early-Stage SaaS',
subtitle:
'Shipping fast is good. Shipping chaos is expensive. I help early-stage SaaS teams build MVPs that move quickly without creating frontend debt, fragile CSS, or structural problems that slow iteration six months later.',
bookingLinkTitle: 'Book a discovery call',
bookingLinkUrl: discoveryCallUrl,
secondaryCta: {
href: '#approach',
label: 'See how I work',
umamiEventLabel: 'see how i work',
},
},
tocItems: [
{ label: 'The common MVP pattern', href: '#common-pattern' },
{ label: 'What a good MVP foundation looks like', href: '#good-foundation' },
{ label: 'My approach', href: '#approach' },
{ label: 'What changes within 12 weeks', href: '#what-changes' },
{ label: 'Engagement options', href: '#engagement' },
{ label: "Who it's for", href: '#who-its-for' },
{ label: 'FAQ', href: '#faq' },
{ label: 'Get in touch', href: '#final-cta' },
],
navItems: [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'My approach', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'Engagement', href: '#engagement', umamiEventLabel: 'engagement' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
],
sections: [
{
id: 'common-pattern',
headingId: 'common-pattern-heading',
heading: 'Most MVPs are built for speed—few are built for iteration',
paragraphs: [
'Early MVPs often prioritize backend logic and feature delivery. The frontend becomes an afterthought—functional, but brittle. Six months later, every new feature feels heavier than the last.',
'Common symptoms:',
],
bullets: [
'Poor separation of concerns',
'Backend-heavy architecture with fragile UI',
'Repeated components instead of reusable systems',
'Spaghetti CSS and specificity wars',
'Accessibility postponed',
'"We\'ll clean it up later" decisions compounding',
],
trailingParagraphs: ["Speed isn't the problem. Structure is."],
},
{
id: 'good-foundation',
headingId: 'good-foundation-heading',
heading: 'MVP does not mean throwaway',
paragraphs: ['A well-built MVP is minimal—but intentional.', 'It includes:'],
bullets: [
'Clear separation between layers',
'Reusable, composable frontend components',
'Tokenized design systems (color, spacing, typography)',
'Clean, maintainable CSS architecture',
'Accessibility baked in from day one',
'A simple, predictable deployment path',
],
trailingParagraphs: [
'You can move fast and build correctly at the same time.',
],
footerLinks: [
{
label: 'Hands-on SaaS architecture',
href: '/services/hands-on-saas-architecture-consultant',
},
{
label: 'Fractional CTO for early-stage SaaS',
href: '/services/fractional-cto-for-early-stage-saas',
},
{
label: 'Stage-aligned infrastructure',
href: '/services/stage-aligned-infrastructure',
},
],
},
{
id: 'approach',
headingId: 'approach-heading',
heading: 'Architecture through implementation',
paragraphs: [
"I don't deliver diagrams and disappear. I work inside your codebase.",
'My approach:',
],
orderedBullets: [
'Fix the CSS foundation first.',
'Extract and standardize reusable components.',
'Introduce design tokens to prevent duplication.',
'Align frontend and backend boundaries.',
'Improve accessibility and semantics incrementally.',
'Keep shipping while refactoring.',
],
trailingParagraphs: ['No rewrite mandates. No velocity freeze.'],
},
{
id: 'what-changes',
headingId: 'what-changes-heading',
heading: 'What teams notice quickly',
paragraphs: [
'In most cases, teams feel the difference within 12 weeks once foundational issues are corrected.',
"You'll see:",
],
bullets: [
'Faster feature implementation',
'Lower bug rates',
'More consistent UI',
'Safer refactors',
'Increased release confidence',
'Better team morale',
],
trailingParagraphs: [
"It's all one big ball of yarn—clean up the foundation and everything moves more smoothly.",
],
},
{
id: 'engagement',
headingId: 'engagement-heading',
heading: 'How we can work together',
subsections: [
{
heading: 'MVP Architecture Engagement (fixed scope)',
bullets: [
'Codebase review focused on frontend foundations',
'Structural audit and prioritized roadmap',
'Component system extraction plan',
'CSS cleanup and token strategy',
'Accessibility baseline',
],
},
{
heading: 'Hands-On Implementation (optional)',
bullets: [
'Direct refactoring and component system creation',
'Tokenized design system rollout',
'Pairing with your engineers',
'Documentation and knowledge transfer',
],
},
{
heading: 'Ongoing Advisory (optional)',
bullets: [
'Periodic architecture reviews',
'Guardrails as you scale',
'Guidance on feature/system tradeoffs',
],
},
],
},
],
who: {
whoForHeading: 'Ideal fit',
whoForList: [
'Founder-led SaaS teams',
'110 engineers',
'Recently launched MVP',
'Feeling UI friction or code fragility',
'Want adult-level architecture without slowing down',
],
whoNotList: [
'Teams who only want features shipped as fast as possible without regard for structure',
'Organizations looking purely for architecture slide decks',
'Large enterprises needing formal procurement processes',
],
},
scheduleCta: {
sectionId: 'final-cta',
headingId: 'final-cta-heading',
title: 'Ready to stabilize your MVP?',
subtitle:
"If your MVP shipped fast but now feels fragile, let's reinforce the foundation before iteration slows further.",
bookingLinkTitle: 'Schedule a discovery call',
bookingLinkUrl: `${discoveryCallUrl}-schedule-section`,
showEmailLink: true,
},
meta: {
title: 'MVP Architecture & Launch Consultant | mifi Ventures',
description:
'I help early-stage SaaS teams build and stabilize MVPs with clean frontend foundations, reusable components, and scalable architecture—so you can ship fast without creating chaos six months later.',
jsonLdServiceDescription:
'MVP architecture and launch for early-stage SaaS: clean foundations, reusable components, tokenized design systems, and accessibility from day one. Fixed-scope engagement, hands-on implementation, and optional advisory.',
},
};

View File

@@ -0,0 +1,40 @@
/**
* FAQ for the MVP architecture and launch service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'Will this slow us down?',
answer: 'No. The goal is to make iteration cheaper. I work incrementally—fixing foundations while you keep shipping. No rewrite mandates, no velocity freeze.',
},
{
question: 'Do we need a full rewrite?',
answer: 'Usually no. Most MVPs need structural cleanup and a clear component/CSS strategy, not a from-scratch rebuild. We prioritize the highest-leverage fixes first.',
},
{
question: 'What tech stacks do you work with?',
answer: 'I work with modern web stacks—React, Vue, Svelte, and similar. The principles (separation of concerns, tokens, components, accessibility) transfer. We can discuss fit for your stack.',
},
{
question: 'How do you handle accessibility?',
answer: 'Accessibility is baked in incrementally: semantic markup, keyboard and focus behavior, and ARIA where needed. Doing it as we refactor is far cheaper than retrofitting later.',
},
{
question: 'Can you work alongside our existing devs?',
answer: 'Yes. I pair with your team, document decisions, and hand off so youre not dependent on me. Knowledge transfer is part of the engagement.',
},
{
question: 'How quickly will we see impact?',
answer: 'Most teams feel the difference within 12 weeks once foundational issues are addressed: faster feature work, fewer bugs, and safer refactors.',
},
{
question: 'Do you only focus on frontend?',
answer: "I'm product-first. Frontend foundations are often the bottleneck for early MVPs, so that's where I focus—but I align with your backend boundaries and deployment so the whole system makes sense.",
},
];

View File

@@ -0,0 +1,185 @@
import type { ServiceDetailContent } from '$lib/types/service-page';
const discoveryCallUrl =
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=stage_aligned_infra_page';
export const pageContent: ServiceDetailContent = {
hero: {
title: 'Stage-Aligned Infrastructure for Early-Stage SaaS',
subtitle:
'Infrastructure should match the stage of your company. Many early SaaS teams inherit complex cloud architectures and SaaS stacks designed for companies ten times their size. The result is predictable: large monthly bills and operational complexity that slows engineering teams down. I help founders design infrastructure that is simple, predictable, and able to evolve as the product grows.',
bookingLinkTitle: 'Book a discovery call',
bookingLinkUrl: discoveryCallUrl,
secondaryCta: {
href: '#approach',
label: 'See my approach',
umamiEventLabel: 'see my approach',
},
},
tocItems: [
{ label: 'The early-stage infrastructure trap', href: '#trap' },
{ label: 'The real cost', href: '#real-cost' },
{ label: 'What stage-aligned looks like', href: '#what-it-looks-like' },
{ label: 'Seeded cloud', href: '#seeded-cloud' },
{ label: 'When cloud services make sense', href: '#when-cloud' },
{ label: 'How I help', href: '#approach' },
{ label: "Who it's for", href: '#who-its-for' },
{ label: 'FAQ', href: '#faq' },
{ label: 'Get in touch', href: '#final-cta' },
],
navItems: [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'My approach', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
],
sections: [
{
id: 'trap',
headingId: 'trap-heading',
heading: 'How early-stage companies end up with enterprise infrastructure',
paragraphs: [
'Many startups adopt infrastructure patterns designed for much larger organizations.',
'Common causes include:',
],
bullets: [
'Copying architectures from big tech companies',
'Following tutorials designed for enterprise-scale systems',
'Adding cloud services incrementally without a clear strategy',
'Believing that complex infrastructure signals maturity',
],
trailingParagraphs: [
'The result is often a patchwork of services that are expensive to run and difficult to reason about.',
],
},
{
id: 'real-cost',
headingId: 'real-cost-heading',
heading: 'The hidden cost of infrastructure complexity',
paragraphs: [
'Infrastructure complexity has two costs: money and cognitive load.',
'Founders frequently notice the first sign when monthly cloud or SaaS bills grow unexpectedly. But the second cost can be even more damaging.',
'Engineers begin spending time navigating infrastructure instead of building product. Debugging becomes harder. Deployments become fragile. Small teams are suddenly maintaining systems designed for companies with dedicated platform teams.',
'Infrastructure should enable product development, not compete with it.',
],
},
{
id: 'what-it-looks-like',
headingId: 'what-heading',
heading: 'Infrastructure that grows with the product',
paragraphs: [
'Stage-aligned infrastructure starts simple and becomes more sophisticated only when necessary.',
'For many early products, a straightforward deployment environment can support far more growth than founders expect. Simple environments are easier to understand, easier to maintain, and far less expensive.',
'As the product scales, infrastructure can evolve deliberately rather than reactively.',
'The goal is not minimalism for its own sake. The goal is intentional complexity.',
],
},
{
id: 'seeded-cloud',
headingId: 'seeded-cloud-heading',
heading: 'Seeded Cloud Infrastructure',
paragraphs: [
'I sometimes describe this approach as "seeded cloud."',
'Instead of inheriting a massive ecosystem of services from day one, companies plant a small, understandable infrastructure foundation that can grow over time.',
'This might include:',
],
bullets: [
'Simple compute environments',
'Predictable deployment pipelines',
'Minimal operational overhead',
'Tooling chosen for clarity and maintainability',
],
trailingParagraphs: [
'As the product grows, that foundation can expand naturally into more sophisticated architectures.',
'Infrastructure evolves when scale requires it—not before.',
],
},
{
id: 'when-cloud',
headingId: 'when-cloud-heading',
heading: 'When managed cloud services are the right choice',
paragraphs: [
'Cloud platforms and SaaS tools exist for good reasons. For some companies and stages they are absolutely the right decision.',
'Examples include:',
],
bullets: [
'Teams operating at significant scale',
'Organizations with compliance requirements',
'Products requiring specialized infrastructure capabilities',
'Companies with dedicated platform engineering teams',
],
trailingParagraphs: [
'The key is adopting these tools deliberately, not reflexively.',
],
},
{
id: 'approach',
headingId: 'approach-heading',
heading: 'How I help teams realign their infrastructure',
paragraphs: [
'My work typically focuses on helping founders and engineering teams simplify their infrastructure while preserving the ability to grow.',
'Typical engagements include:',
],
bullets: [
'Infrastructure audits and simplification',
'Evaluating cloud and SaaS tool usage',
'Identifying unnecessary complexity',
'Designing simpler deployment patterns',
'Aligning infrastructure with product stage',
'Planning transitions as scale increases',
],
trailingParagraphs: [
'The goal is not rebuilding everything. The goal is restoring clarity and intentionality.',
],
footerLinks: [
{
label: 'Hands-on SaaS architecture',
href: '/services/hands-on-saas-architecture-consultant',
},
{
label: 'MVP architecture and launch',
href: '/services/mvp-architecture-and-launch',
},
{
label: 'Fractional CTO for early-stage SaaS',
href: '/services/fractional-cto-for-early-stage-saas',
},
],
},
],
who: {
whoForHeading: 'Ideal clients',
whoForList: [
'Founder-led SaaS companies',
'Teams with 115 engineers',
'Startups experiencing growing infrastructure costs',
'Companies that feel their infrastructure is more complex than their product requires',
],
whoNotList: [
'Large enterprises with dedicated platform teams',
'Companies already operating at significant infrastructure scale',
'Organizations seeking fully managed hosting providers',
],
},
scheduleCta: {
sectionId: 'final-cta',
headingId: 'final-cta-heading',
title: 'Infrastructure should support your product—not compete with it',
subtitle:
'If your infrastructure feels more complicated than your product requires, it may be time to simplify. Stage-aligned infrastructure helps teams focus on building features instead of maintaining unnecessary systems.',
bookingLinkTitle: 'Schedule a discovery call',
bookingLinkUrl: `${discoveryCallUrl}-schedule-section`,
showEmailLink: true,
},
meta: {
title: 'Startup Infrastructure Strategy | mifi Ventures',
description:
"Infrastructure decisions should match your company's stage. I help early-stage SaaS teams avoid unnecessary cloud complexity and SaaS sprawl while building infrastructure foundations that scale with the product.",
jsonLdServiceDescription:
'Stage-aligned infrastructure for early-stage SaaS: infrastructure audits, simplification, and strategy so complexity matches company stage. Capital efficiency, reduced sprawl, and foundations that evolve with the product.',
},
};

View File

@@ -0,0 +1,36 @@
/**
* FAQ for the stage-aligned infrastructure service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'What does stage-aligned infrastructure mean?',
answer: 'Infrastructure complexity should grow with your companys stage—not ahead of it. Stage-aligned infrastructure starts simple and intentional, then evolves deliberately when scale, compliance, or team size justify it. The goal is to avoid overbuilding too early while keeping a foundation that can grow.',
},
{
question: 'Are you anti-cloud?',
answer: 'No. Cloud and managed services are the right choice for many companies at the right stage. Im pragmatic: the question is whether your current complexity matches your actual needs. Adopting cloud services deliberately, when theyre justified, is different from inheriting enterprise patterns by default.',
},
{
question: 'Can simple infrastructure really support a growing SaaS product?',
answer: 'Yes. Many early-stage products are surprised by how much a straightforward deployment environment can support. Simple systems are easier to maintain, cheaper to run, and leave more time for building product. You add complexity when scale or requirements demand it—not before.',
},
{
question: 'When should startups adopt more advanced cloud architectures?',
answer: 'When compliance, team size, availability requirements, or scale justify the cost and operational burden. Theres no single threshold—its about aligning infrastructure with real needs. The goal is to adopt advanced tooling intentionally, with clear reasons, rather than by default.',
},
{
question: 'Can you work with our existing infrastructure?',
answer: 'Yes. Most engagements focus on auditing and simplifying what you already have—identifying unnecessary complexity, consolidating tooling, and designing clearer deployment patterns. The goal is restoring clarity and intentionality, not rebuilding everything from scratch.',
},
{
question: 'How quickly can infrastructure complexity be reduced?',
answer: 'It depends on the current state, but many teams see a clear path within the first engagement. Simplification is often incremental: we prioritize the highest-impact changes first and plan transitions so the team can keep shipping while complexity is reduced.',
},
];

View File

@@ -1,42 +0,0 @@
/**
* FAQ for the stage-aligned infrastructure service page.
* Single source of truth for both the page content and FAQPage JSON-LD.
*/
export interface FaqItem {
question: string;
answer: string;
}
export const faqItems: FaqItem[] = [
{
question: 'What does stage-aligned infrastructure mean?',
answer:
'Infrastructure complexity should grow with your companys stage—not ahead of it. Stage-aligned infrastructure starts simple and intentional, then evolves deliberately when scale, compliance, or team size justify it. The goal is to avoid overbuilding too early while keeping a foundation that can grow.',
},
{
question: 'Are you anti-cloud?',
answer:
'No. Cloud and managed services are the right choice for many companies at the right stage. Im pragmatic: the question is whether your current complexity matches your actual needs. Adopting cloud services deliberately, when theyre justified, is different from inheriting enterprise patterns by default.',
},
{
question: 'Can simple infrastructure really support a growing SaaS product?',
answer:
'Yes. Many early-stage products are surprised by how much a straightforward deployment environment can support. Simple systems are easier to maintain, cheaper to run, and leave more time for building product. You add complexity when scale or requirements demand it—not before.',
},
{
question: 'When should startups adopt more advanced cloud architectures?',
answer:
'When compliance, team size, availability requirements, or scale justify the cost and operational burden. Theres no single threshold—its about aligning infrastructure with real needs. The goal is to adopt advanced tooling intentionally, with clear reasons, rather than by default.',
},
{
question: 'Can you work with our existing infrastructure?',
answer:
'Yes. Most engagements focus on auditing and simplifying what you already have—identifying unnecessary complexity, consolidating tooling, and designing clearer deployment patterns. The goal is restoring clarity and intentionality, not rebuilding everything from scratch.',
},
{
question: 'How quickly can infrastructure complexity be reduced?',
answer:
'It depends on the current state, but many teams see a clear path within the first engagement. Simplification is often incremental: we prioritize the highest-impact changes first and plan transitions so the team can keep shipping while complexity is reduced.',
},
];

View File

@@ -0,0 +1,132 @@
/**
* Shared types for service pages and services landing.
* Used by content modules and components for localization-ready structure.
*/
export interface ServiceHeroSecondaryCta {
href: string;
label: string;
umamiEventLabel: string;
}
export interface ServiceHeroContent {
title: string;
subtitle: string;
bookingLinkTitle: string;
bookingLinkUrl: string;
secondaryCta?: ServiceHeroSecondaryCta;
}
export interface ServiceTocItem {
label: string;
href: string;
}
export interface ServiceFooterLink {
label: string;
href: string;
}
export interface ServiceSectionContent {
id: string;
heading: string;
headingId?: string;
/** If true, heading is visually hidden (sr-only) for accessibility */
headingSrOnly?: boolean;
/** Extra class(es) for the section element (e.g. service-credibility) */
sectionClass?: string;
/** Use container--narrow; set false for full-width strips (e.g. credibility) */
narrowContainer?: boolean;
/** Optional class for the bullets ul (e.g. service-credibility__list) */
bulletsListClass?: string;
lede?: string;
paragraphs?: string[];
bullets?: string[];
orderedBullets?: string[];
/** Paragraph(s) rendered after bullets (e.g. "Speed isn't the problem. Structure is.") */
trailingParagraphs?: string[];
/** Inline links (e.g. cross-links to other services) rendered after content */
footerLinks?: ServiceFooterLink[];
/** Optional sub-sections: h3 + content (paragraphs and/or bullets) */
subsections?: Array<{
heading: string;
headingId?: string;
paragraphs?: string[];
bullets?: string[];
}>;
}
export interface WhoGridContent {
whoForList: string[];
whoNotList: string[];
title?: string;
showTitle?: boolean;
whoForHeading?: string;
whoNotHeading?: string;
}
export interface ServiceScheduleCta {
title: string;
subtitle: string;
bookingLinkTitle: string;
bookingLinkUrl: string;
showEmailLink?: boolean;
showServicesLink?: boolean;
sectionId?: string;
headingId?: string;
}
/** Nav item for service/landing page navigation */
export interface ServiceNavItem {
label: string;
href: string;
umamiEventLabel: string;
}
/** Service card for the services landing grid */
export interface ServiceCard {
title: string;
description: string;
href: string;
}
/** Term/definition for "How engagements work" dl on landing */
export interface EngagementItem {
term: string;
definition: string;
}
/** SEO meta for use in +page.ts (single source of truth with content) */
export interface ServicePageMeta {
title: string;
description: string;
/** Optional short description for JSON-LD ProfessionalService */
jsonLdServiceDescription?: string;
}
/** Content shape for the services landing page */
export interface ServicesLandingContent {
hero: ServiceHeroContent;
navItems: ServiceNavItem[];
introParagraphs: string[];
services: ServiceCard[];
engagements: EngagementItem[];
engagementsIntro?: string;
engagementsOutro?: string;
idealClients: string[];
scheduleCta: ServiceScheduleCta;
meta: ServicePageMeta;
}
/** Content shape for a service detail page */
export interface ServiceDetailContent {
hero: ServiceHeroContent;
tocItems: ServiceTocItem[];
navItems: ServiceNavItem[];
sections: ServiceSectionContent[];
who: WhoGridContent;
scheduleCta: ServiceScheduleCta;
/** Optional FAQ section title override */
faqTitle?: string;
meta: ServicePageMeta;
}

View File

@@ -2,9 +2,7 @@
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import { privacyPolicy } from '$lib/data/privacy-policy'; import { privacyPolicy } from '$lib/data/privacy-policy';
const navItems = [ const navItems = [{ label: 'Home', href: '/', umamiEventLabel: 'home' }];
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
];
</script> </script>
<Navigation items={navItems} page="privacy-policy" /> <Navigation items={navItems} page="privacy-policy" />
@@ -22,14 +20,22 @@
{/each} {/each}
{#each privacyPolicy.sections as section (section.id)} {#each privacyPolicy.sections as section (section.id)}
<section id={section.id} class="legal-section" aria-labelledby={`${section.id}-heading`}> <section
id={section.id}
class="legal-section"
aria-labelledby={`${section.id}-heading`}
>
<h2 id={`${section.id}-heading`}>{section.heading}</h2> <h2 id={`${section.id}-heading`}>{section.heading}</h2>
{#each section.body as para} {#each section.body as para}
<p> <p>
{#if section.id === 'contact' && para === 'legal@mifi.ventures'} {#if section.id === 'contact' && para === 'legal@mifi.ventures'}
<a href="mailto:legal@mifi.ventures">legal@mifi.ventures</a> <a href="mailto:legal@mifi.ventures"
>legal@mifi.ventures</a
>
{:else if section.id === 'contact' && para === 'https://mifi.ventures'} {:else if section.id === 'contact' && para === 'https://mifi.ventures'}
<a href="https://mifi.ventures" rel="noopener noreferrer">https://mifi.ventures</a> <a href="https://mifi.ventures" rel="noopener noreferrer"
>https://mifi.ventures</a
>
{:else} {:else}
{para} {para}
{/if} {/if}

View File

@@ -1,307 +1,44 @@
<script lang="ts"> <script lang="ts">
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import ExternalLinkIcon from '$lib/components/Icon/ExternalLink.svelte'; import Hero from '$lib/components/Hero.svelte';
import ScheduleSection from '$lib/components/ScheduleSection.svelte'; import ScheduleSection from '$lib/components/ScheduleSection.svelte';
import ServicesCardGrid from '$lib/components/ServicesCardGrid.svelte';
const discoveryCallUrl = import EngagementsDl from '$lib/components/EngagementsDl.svelte';
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=services_landing'; import { pageContent } from '$lib/data/services/landing/content';
const navItems = [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'Services', href: '#services-grid', umamiEventLabel: 'services' },
{ label: 'How engagements work', href: '#how-engagements-work', umamiEventLabel: 'engagements' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
];
const services = [
{
title: 'Hands-On SaaS Architecture',
description:
'Build the foundations that allow SaaS products to evolve without accumulating structural debt. I work directly inside your codebase to improve frontend systems, establish reusable components, and create architecture that supports long-term iteration.',
href: '/services/hands-on-saas-architecture-consultant',
},
{
title: 'MVP Architecture & Launch',
description:
'Ship your product quickly without creating a fragile system you\'ll have to rewrite six months later. I help teams design and build MVPs that are simple, scalable, and structured for rapid iteration.',
href: '/services/mvp-architecture-and-launch',
},
{
title: 'Fractional CTO / Technical Partner',
description:
'Technical leadership for teams that need architectural direction but aren\'t ready for a full-time CTO. I work alongside founders and engineers to guide system design, evaluate technical decisions, and maintain long-term architectural clarity.',
href: '/services/fractional-cto-for-early-stage-saas',
},
{
title: 'Stage-Aligned Infrastructure',
description:
'Infrastructure decisions should match your company\'s stage. I help teams avoid unnecessary SaaS sprawl and cloud complexity while building infrastructure that can grow with the product.',
href: '/services/stage-aligned-infrastructure',
},
];
</script> </script>
<Navigation items={navItems} page="services" /> <Navigation items={pageContent.navItems} page="services" />
<header id="header" class="services-hero"> <Hero {...pageContent.hero} />
<div class="container">
<h1 class="services-hero__title">Consulting Services</h1>
<p class="services-hero__subhead">
I work with early-stage SaaS teams to build products that ship quickly and evolve cleanly.
Engagements range from hands-on architecture work inside your codebase to technical
leadership for growing teams.
</p>
<div class="cta-group">
<a
href={discoveryCallUrl}
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a discovery call (opens in new tab)"
data-umami-event="schedule discovery call"
data-umami-event-location="services hero"
>
Schedule a discovery call
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<a
href="/#process"
class="btn btn-secondary"
data-umami-event="see how i work"
data-umami-event-location="services hero"
>
See how I work
</a>
</div>
</div>
</header>
<main id="main"> <main id="main">
<section class="section services-intro" aria-labelledby="intro-heading"> <section class="section services-intro" aria-labelledby="intro-heading">
<div class="container container--narrow"> <div class="container container--narrow">
<h2 id="intro-heading" class="sr-only">How we work together</h2> <h2 id="intro-heading" class="sr-only">How we work together</h2>
<p> {#each pageContent.introParagraphs as p}
Early-stage SaaS companies face different technical challenges as they grow. Some <p>{p}</p>
need help building their MVP correctly. Others need architectural guidance as
complexity increases. Some teams simply need a senior engineer who can step in and
stabilize a chaotic codebase.
</p>
<p>
The services below represent the most common ways I work with founders and
engineering teams.
</p>
</div>
</section>
<section id="services-grid" class="section services-grid-section" aria-labelledby="services-heading">
<div class="container">
<h2 id="services-heading" class="section-title">Services</h2>
<ul class="services-card-list">
{#each services as service (service.href)}
<li class="services-card">
<h3 class="services-card__title">{service.title}</h3>
<p class="services-card__desc">{service.description}</p>
<a
href={service.href}
class="services-card__link"
data-umami-event="service link"
data-umami-event-label={service.href}
>
Learn more
<span aria-hidden="true"></span>
</a>
</li>
{/each} {/each}
</ul>
</div> </div>
</section> </section>
<section id="how-engagements-work" class="section" aria-labelledby="engagements-heading"> <ServicesCardGrid services={pageContent.services} />
<div class="container container--narrow">
<h2 id="engagements-heading">How engagements work</h2> <EngagementsDl
<p>Most engagements fall into one of three patterns:</p> items={pageContent.engagements}
<dl class="engagements-list"> intro={pageContent.engagementsIntro}
<dt>Architecture engagements</dt> outro={pageContent.engagementsOutro}
<dd> />
Focused, fixed-scope projects designed to diagnose and correct structural issues
in a codebase.
</dd>
<dt>Implementation work</dt>
<dd>
Hands-on engineering to build or refactor core product systems.
</dd>
<dt>Advisory retainers</dt>
<dd>
Ongoing architectural guidance for teams that need senior technical oversight.
</dd>
</dl>
<p>Engagements are typically consulting-led and scoped to deliver meaningful progress quickly.</p>
</div>
</section>
<section class="section services-ideal" aria-labelledby="ideal-heading"> <section class="section services-ideal" aria-labelledby="ideal-heading">
<div class="container container--narrow"> <div class="container container--narrow">
<h2 id="ideal-heading">Ideal clients</h2> <h2 id="ideal-heading">Ideal clients</h2>
<ul class="content-list"> <ul class="content-list">
<li>Founder-led SaaS startups</li> {#each pageContent.idealClients as item}
<li>Engineering teams with 115 developers</li> <li>{item}</li>
<li>Products that are actively shipping and evolving</li> {/each}
<li>Teams that value thoughtful engineering decisions</li>
</ul> </ul>
</div> </div>
</section> </section>
<ScheduleSection <ScheduleSection {...pageContent.scheduleCta} />
title="Not sure which service fits?"
subtitle="Many engagements start with a short conversation about your product and technical challenges. From there we can determine whether architecture work, MVP support, or ongoing technical leadership makes the most sense."
bookingLinkTitle="Schedule a discovery call"
bookingLinkUrl={`${discoveryCallUrl}-schedule-section`}
showEmailLink
/>
</main> </main>
<style>
.services-hero {
padding: var(--space-xxxl) 0 var(--space-xxl) 0;
text-align: center;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
}
.services-hero__title {
margin-bottom: var(--space-lg);
font-family: var(--font-family-heading);
font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold);
letter-spacing: -0.03em;
}
.services-hero__subhead {
max-width: var(--max-narrow-width);
margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.cta-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
justify-content: center;
align-items: center;
margin-top: var(--space-lg);
}
@media (max-width: 768px) {
.cta-group {
flex-direction: column;
width: 100%;
}
}
.container--narrow {
max-width: var(--max-narrow-width);
}
.services-intro {
background-color: var(--color-bg-alt);
}
.services-grid-section {
background-color: var(--color-bg);
}
.services-card-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: var(--space-xl);
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.services-card {
padding: var(--space-xl);
background-color: var(--color-bg-alt);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-medium);
display: flex;
flex-direction: column;
}
.services-card__title {
margin-bottom: var(--space-md);
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
}
.services-card__desc {
flex: 1;
margin-bottom: var(--space-lg);
font-size: var(--font-size-base);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.services-card__link {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-weight: var(--font-weight-semibold);
}
.services-card__link span {
margin-left: var(--space-xs);
}
.engagements-list {
margin: var(--space-lg) 0;
}
.engagements-list dt {
font-weight: var(--font-weight-semibold);
color: var(--color-text);
margin-top: var(--space-lg);
margin-bottom: var(--space-xs);
}
.engagements-list dt:first-child {
margin-top: 0;
}
.engagements-list dd {
margin: 0 0 0 var(--space-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.services-ideal {
background-color: var(--color-bg-alt);
}
.schedule-section {
text-align: center;
background-color: var(--color-bg-subtle);
}
.schedule-text {
margin-bottom: var(--space-lg);
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
[id] {
scroll-margin-top: 6rem;
}
</style>

View File

@@ -1,14 +1,16 @@
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
import type { PageMeta } from '$lib/seo'; import type { PageMeta } from '$lib/seo';
import { defaultJsonLdGraph } from '$lib/data/home/json-ld'; import { defaultJsonLdGraph } from '$lib/data/home/json-ld';
import { pageContent } from '$lib/data/services/landing/content';
const BASE = 'https://mifi.ventures'; const BASE = 'https://mifi.ventures';
const PAGE_URL = `${BASE}/services/`; const PAGE_URL = `${BASE}/services/`;
const servicePageMeta: PageMeta = { export const load: PageLoad = () => {
title: 'SaaS Architecture Consulting Services | mifi Ventures', const { meta } = pageContent;
description: const servicePageMeta: PageMeta = {
'Hands-on SaaS architecture consulting for early-stage teams. Services include product architecture, MVP launch support, fractional CTO guidance, and stage-aligned infrastructure strategy.', title: meta.title,
description: meta.description,
jsonLd: [ jsonLd: [
...defaultJsonLdGraph, ...defaultJsonLdGraph,
{ {
@@ -16,8 +18,7 @@ const servicePageMeta: PageMeta = {
'@id': `${BASE}/services/#service`, '@id': `${BASE}/services/#service`,
name: 'mifi Ventures', name: 'mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
description: description: meta.jsonLdServiceDescription ?? meta.description,
'SaaS architecture consulting for early-stage teams: hands-on product architecture, MVP launch support, fractional CTO, and stage-aligned infrastructure strategy.',
serviceType: [ serviceType: [
'SaaS Architecture Consulting', 'SaaS Architecture Consulting',
'MVP Development Consulting', 'MVP Development Consulting',
@@ -28,8 +29,6 @@ const servicePageMeta: PageMeta = {
areaServed: { '@type': 'Country', name: 'United States' }, areaServed: { '@type': 'Country', name: 'United States' },
}, },
], ],
}; };
export const load: PageLoad = () => {
return { meta: servicePageMeta }; return { meta: servicePageMeta };
}; };

View File

@@ -1,186 +1,29 @@
<script lang="ts"> <script lang="ts">
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import { faqItems } from '$lib/data/fractional-cto-for-early-stage-saas/faq';
import ScheduleSection from '$lib/components/ScheduleSection.svelte';
import Hero from '$lib/components/Hero.svelte'; import Hero from '$lib/components/Hero.svelte';
import TOC from '$lib/components/TOC.svelte'; import TOC from '$lib/components/TOC.svelte';
import WnoGrid from '$lib/components/WhoGrid.svelte'; import ServiceSection from '$lib/components/ServiceSection.svelte';
import WhoGrid from '$lib/components/WhoGrid.svelte';
import FAQ from '$lib/components/FAQ.svelte'; import FAQ from '$lib/components/FAQ.svelte';
import ScheduleSection from '$lib/components/ScheduleSection.svelte';
const discoveryCallUrl = import { pageContent } from '$lib/data/services/fractional-cto-for-early-stage-saas/content';
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=fractional_cto_page'; import { faqItems } from '$lib/data/services/fractional-cto-for-early-stage-saas/faq';
const navItems = [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'How I work', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'Engagement', href: '#engagement', umamiEventLabel: 'engagement' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
];
</script> </script>
<Navigation items={navItems} page="fractional-cto-for-early-stage-saas" /> <Navigation items={pageContent.navItems} page="fractional-cto-for-early-stage-saas" />
<Hero
title="Fractional CTO for Early-Stage SaaS" <Hero {...pageContent.hero} />
subtitle="At a certain point, early-stage SaaS teams need more than just developers shipping features. They need someone steering the technical decisions. I work alongside founders and engineers to keep architecture sane, prevent premature complexity, and help teams move fast without creating structural problems."
bookingLinkTitle="Book a discovery call"
bookingLinkUrl={discoveryCallUrl}
secondaryCta={{
label: "See how I work",
href: "#approach",
umamiEventLabel: "see how i work"
}}
/>
<main id="main"> <main id="main">
<TOC <TOC items={pageContent.tocItems} />
items={[
{ label: "When teams need technical leadership", href: "#when-teams" },
{ label: "The two common failure modes", href: "#failure-modes" },
{ label: "What working with me looks like", href: "#approach" },
{ label: "What engineering teams notice", href: "#what-changes" },
{ label: "Engagement structure", href: "#engagement" },
{ label: "Who it's for", href: "#who-its-for" },
{ label: "FAQ", href: "#faq" },
{ label: "Get in touch", href: "#final-cta" }
]}
/>
<section id="when-teams" class="section" aria-labelledby="when-teams-heading"> {#each pageContent.sections as section (section.id)}
<div class="container container--narrow"> <ServiceSection {section} />
<h2 id="when-teams-heading"> {/each}
When a team needs technical leadership—but not a full-time CTO
</h2>
<p>
Most early-stage SaaS companies reach a moment where shipping features is no longer
the only challenge. Architecture decisions start to compound. Tooling choices
matter. Hiring decisions become technical decisions.
</p>
<p>But hiring a full-time CTO is often premature.</p>
<p>
A fractional CTO provides senior-level guidance without the cost and commitment of a
full-time executive.
</p>
<p>Typical signs a team is here:</p>
<ul class="content-list">
<li>The codebase is growing quickly and architectural decisions are becoming harder to reverse</li>
<li>Founders want a second opinion on technical tradeoffs</li>
<li>Engineering teams are shipping but lack architectural guardrails</li>
<li>Tooling and infrastructure decisions feel arbitrary</li>
<li>Hiring engineers without a clear technical standard</li>
</ul>
</div>
</section>
<section id="failure-modes" class="section" aria-labelledby="failure-modes-heading"> <WhoGrid {...pageContent.who} />
<div class="container container--narrow">
<h2 id="failure-modes-heading">The two ways early-stage teams usually get it wrong</h2>
<p>I see two patterns repeatedly.</p>
<h3>Over-building too early</h3>
<p>
Teams adopt infrastructure and services designed for companies ten times their size.
They spend time and capital building systems they don't yet need.
</p>
<h3>Shipping chaos</h3>
<p>
Other teams rush an MVP by outsourcing development cheaply, producing something
that works—but is extremely difficult to iterate on.
</p>
<p>
Healthy early-stage engineering balances both pressures: lean spending with solid
foundations.
</p>
<p>
<a href="/services/hands-on-saas-architecture-consultant">Hands-on SaaS architecture</a>
·
<a href="/services/mvp-architecture-and-launch">MVP architecture and launch</a>
·
<a href="/services/stage-aligned-infrastructure">Stage-aligned infrastructure</a>
</p>
</div>
</section>
<section id="approach" class="section" aria-labelledby="approach-heading">
<div class="container container--narrow">
<h2 id="approach-heading">What working with me looks like</h2>
<p>
I operate as a technical partner for founders and engineering teams.
</p>
<p>That means I help with both strategic decisions and practical implementation.</p>
<p>Typical involvement includes:</p>
<ul class="content-list">
<li>Reviewing architecture decisions before they become expensive mistakes</li>
<li>Participating in product and roadmap discussions</li>
<li>Setting architectural guardrails for the engineering team</li>
<li>Evaluating tooling and infrastructure choices</li>
<li>Mentoring developers and improving engineering practices</li>
<li>Refactoring critical parts of the codebase when necessary</li>
<li>Helping founders understand the technical tradeoffs behind decisions</li>
</ul>
<p>
I am not a slide-deck CTO. I stay close enough to the code to keep decisions
grounded in reality.
</p>
</div>
</section>
<section id="what-changes" class="section" aria-labelledby="what-changes-heading">
<div class="container container--narrow">
<h2 id="what-changes-heading">What changes when technical leadership is present</h2>
<p>
When a team has clear technical leadership, several things happen quickly:
</p>
<ul class="content-list">
<li>Architectural decisions become intentional instead of reactive</li>
<li>Developers move faster because the system has clearer structure</li>
<li>Tooling choices become consistent</li>
<li>Technical discussions shift from opinion to reasoning</li>
<li>Engineers spend more time building and less time debating direction</li>
</ul>
<p>The result is not just cleaner systems—but a calmer engineering culture.</p>
</div>
</section>
<section id="engagement" class="section" aria-labelledby="engagement-heading">
<div class="container container--narrow">
<h2 id="engagement-heading">How fractional CTO engagements usually work</h2>
<p>
Engagements are typically structured as a monthly retainer with defined availability.
</p>
<p>
Typical involvement ranges between <strong>1040 hours per month</strong> depending on
the company's stage and needs.
</p>
<p>This usually includes:</p>
<ul class="content-list">
<li>Regular founder check-ins</li>
<li>Engineering architecture reviews</li>
<li>Product roadmap discussions</li>
<li>Codebase and system reviews</li>
<li>Guidance on hiring and technical standards</li>
</ul>
<p>The goal is consistent oversight without becoming a bottleneck.</p>
</div>
</section>
<WnoGrid
whoForList={["Founder-led SaaS companies", "115 engineers", "Teams preparing to scale their product", "Companies that want technical leadership without a full-time CTO"]}
whoNotList={["Companies that already have strong senior technical leadership", "Enterprises needing full-time executive presence", "Teams looking only for implementation without architectural guidance"]}
/>
<FAQ faqList={faqItems} /> <FAQ faqList={faqItems} />
<ScheduleSection <ScheduleSection {...pageContent.scheduleCta} />
title="Need a technical adult in the room?"
subtitle="If your team is shipping quickly but architectural decisions are starting to feel heavier, a fractional CTO engagement can provide the guidance needed to keep the system healthy while the product grows."
bookingLinkTitle="Book a discovery call"
bookingLinkUrl={`${discoveryCallUrl}-schedule-section`}
showEmailLink
/>
</main> </main>

View File

@@ -1,7 +1,8 @@
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
import type { PageMeta } from '$lib/seo'; import type { PageMeta } from '$lib/seo';
import { defaultJsonLdGraph } from '$lib/data/home/json-ld'; import { defaultJsonLdGraph } from '$lib/data/home/json-ld';
import { faqItems } from '$lib/data/fractional-cto-for-early-stage-saas/faq'; import { pageContent } from '$lib/data/services/fractional-cto-for-early-stage-saas/content';
import { faqItems } from '$lib/data/services/fractional-cto-for-early-stage-saas/faq';
const BASE = 'https://mifi.ventures'; const BASE = 'https://mifi.ventures';
const PAGE_URL = `${BASE}/services/fractional-cto-for-early-stage-saas/`; const PAGE_URL = `${BASE}/services/fractional-cto-for-early-stage-saas/`;
@@ -21,10 +22,11 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = { export const load: PageLoad = () => {
title: 'Fractional CTO for Early-Stage SaaS | Hands-On Technical Leadership', const { meta } = pageContent;
description: const servicePageMeta: PageMeta = {
'Technical leadership for early-stage SaaS teams that need architectural direction without hiring a full-time CTO. Hands-on guidance that keeps teams shipping while preventing structural mistakes.', title: meta.title,
description: meta.description,
jsonLd: [ jsonLd: [
...defaultJsonLdGraph, ...defaultJsonLdGraph,
{ {
@@ -32,8 +34,7 @@ const servicePageMeta: PageMeta = {
'@id': `${BASE}/services/fractional-cto-for-early-stage-saas/#service`, '@id': `${BASE}/services/fractional-cto-for-early-stage-saas/#service`,
name: 'mifi Ventures', name: 'mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
description: description: meta.jsonLdServiceDescription ?? meta.description,
'Fractional CTO and technical partner for early-stage SaaS: architectural direction, codebase and tooling guidance, and hands-on leadership without the cost of a full-time CTO. Monthly retainer engagements.',
serviceType: [ serviceType: [
'Fractional CTO', 'Fractional CTO',
'Technical Leadership', 'Technical Leadership',
@@ -44,8 +45,6 @@ const servicePageMeta: PageMeta = {
}, },
buildFaqPageJsonLd(), buildFaqPageJsonLd(),
], ],
}; };
export const load: PageLoad = () => {
return { meta: servicePageMeta }; return { meta: servicePageMeta };
}; };

View File

@@ -1,462 +1,29 @@
<script lang="ts"> <script lang="ts">
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import ExternalLinkIcon from '$lib/components/Icon/ExternalLink.svelte'; import Hero from '$lib/components/Hero.svelte';
import { faqItems } from '$lib/data/hands-on-saas-architecture-consultant/faq'; import TOC from '$lib/components/TOC.svelte';
import ServiceSection from '$lib/components/ServiceSection.svelte';
import WhoGrid from '$lib/components/WhoGrid.svelte';
import FAQ from '$lib/components/FAQ.svelte';
import ScheduleSection from '$lib/components/ScheduleSection.svelte'; import ScheduleSection from '$lib/components/ScheduleSection.svelte';
import { pageContent } from '$lib/data/services/hands-on-saas-architecture-consultant/content';
const discoveryCallUrl = import { faqItems } from '$lib/data/services/hands-on-saas-architecture-consultant/faq';
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=hands_on_saas_arch_page';
const navItems = [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'My approach', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'Outcomes', href: '#outcomes', umamiEventLabel: 'outcomes' },
{ label: 'Engagement', href: '#engagement', umamiEventLabel: 'engagement' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
];
</script> </script>
<Navigation items={navItems} page="hands-on-saas-architecture-consultant" /> <Navigation items={pageContent.navItems} page="hands-on-saas-architecture-consultant" />
<header id="header" class="service-hero"> <Hero {...pageContent.hero} />
<div class="container">
<h1 class="service-hero__title">
Hands-On Product Architecture for Early-Stage SaaS
</h1>
<p class="service-hero__subhead">
Most early-stage teams obsess over backend performance and treat the frontend as a thin
layer. That's backwards. The frontend is the product—and if its foundations aren't built
to scale, iteration slows, bugs multiply, and shipping becomes stressful. I work inside
your codebase to build frontend systems that enable velocity: clean CSS architecture,
reusable components, tokenized design systems, and accessibility from day one.
</p>
<div class="cta-group">
<a
href={discoveryCallUrl}
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Book a discovery call (opens in new tab)"
data-umami-event="book discovery call"
data-umami-event-location="hero"
>
Book a discovery call
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<a
href="#approach"
class="btn btn-secondary"
data-umami-event="see my approach"
data-umami-event-location="hero"
>
See my approach
</a>
</div>
</div>
</header>
<main id="main"> <main id="main">
<nav class="section service-toc" aria-label="Page contents"> <TOC items={pageContent.tocItems} />
<div class="container">
<h2 class="service-toc__title">On this page</h2>
<ul class="service-toc__list">
<li><a href="#credibility">Credibility</a></li>
<li><a href="#why-this-matters">Why this matters</a></li>
<li><a href="#frontend-is-product">The frontend is the product</a></li>
<li><a href="#what-goes-wrong">What goes wrong</a></li>
<li><a href="#approach">My approach</a></li>
<li><a href="#outcomes">Outcomes</a></li>
<li><a href="#engagement">Engagement options</a></li>
<li><a href="#who-its-for">Who it's for</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href="#final-cta">Get in touch</a></li>
</ul>
</div>
</nav>
<section {#each pageContent.sections as section (section.id)}
id="credibility" <ServiceSection {section} />
class="section service-credibility"
aria-labelledby="credibility-heading"
>
<div class="container">
<h2 id="credibility-heading" class="sr-only">Credibility</h2>
<ul class="service-credibility__list">
<li>Product developer at heart; systems-minded by default</li>
<li>Frontend foundations: CSS architecture, design tokens, component libraries</li>
<li>Accessibility-first (bolting it on later is always expensive)</li>
<li>Stage-aware decisions that preserve runway without slowing shipping</li>
</ul>
</div>
</section>
<section id="why-this-matters" class="section" aria-labelledby="why-heading">
<div class="container container--narrow">
<h2 id="why-heading">Shipping slows down quietly—until it suddenly doesn't</h2>
<p>
Early-stage SaaS rarely fails because the backend can't handle load. It fails because
iteration becomes painful.
</p>
<p>
When the frontend is ad hoc—CSS drift, inconsistent components, no tokens,
accessibility bolted on later—every new feature costs more than it should. Engineers
hesitate to touch code. Small changes break unrelated screens. Design becomes
inconsistent. Velocity drops.
</p>
<p>This is not a "design problem." It's an architecture problem.</p>
</div>
</section>
<section id="frontend-is-product" class="section" aria-labelledby="frontend-heading">
<div class="container container--narrow">
<h2 id="frontend-heading">The frontend is the product</h2>
<p>Your customers don't experience your database schema. They experience your UI.</p>
<p>
A performant backend matters—but it's not more important than a frontend built for
iteration. The frontend drives conversion, communicates trust, and determines how
quickly your team can ship new features without breaking old ones.
</p>
<p>If you want to move fast later, you have to build a foundation now.</p>
</div>
</section>
<section id="what-goes-wrong" class="section" aria-labelledby="wrong-heading">
<div class="container container--narrow">
<h2 id="wrong-heading">What I see most often</h2>
<ul class="content-list">
<li>Backend-crafted frontends: functional, but brittle and inconsistent</li>
<li>"CSS as an afterthought": global overrides, magic numbers, creeping specificity wars</li>
<li>Component sprawl: dozens of one-off components that can't be reused</li>
<li>No design tokens: colors, spacing, typography duplicated everywhere</li>
<li>Accessibility postponed: expensive retrofits, inconsistent semantics</li>
<li>
Rebuilding instead of composing: no "lego system," so iteration is slow and
repetitive
</li>
</ul>
</div>
</section>
<section id="approach" class="section" aria-labelledby="approach-heading">
<div class="container container--narrow">
<h2 id="approach-heading">My approach: architecture through implementation</h2>
<p>
I'm not a diagram consultant. I'm hands-on. I get into the codebase and build the
foundation your team can extend.
</p>
<p>The goal is simple: make iteration cheap.</p>
<h3>1) Fix the CSS foundation first</h3>
<p>
Bad CSS makes everything inconsistent and makes change arduous. I start by
establishing a maintainable CSS architecture that supports a coherent visual
language and reduces the bug surface area.
</p>
<h3>2) Build a reusable component system</h3>
<p>
I create a component library that lowers duplication and prevents developers from
"re-solving" the same UI problems. This increases speed and improves consistency.
</p>
<h3>3) Tokenize the design system</h3>
<p>
Design tokens (color, spacing, typography, radii, shadows) allow the brand to evolve
without rewrites. You can iterate quickly as you discover what your product should
feel like.
</p>
<h3>4) Bake in accessibility from day one</h3>
<p>
Accessibility isn't optional and it isn't "later." Bolting it on later is always
expensive. Doing it early saves time, improves UX, and strengthens SEO.
</p>
<h3>5) Keep the whole system stage-aligned</h3>
<p>
I'm pragmatic about tooling. Some things can stay on free tiers early. Some choices
should be intentional because migration later is painful. The point is to preserve
runway without slowing shipping.
</p>
<p>
<a href="/services/fractional-cto-for-early-stage-saas">Fractional CTO for early-stage SaaS</a>
·
<a href="/services/mvp-architecture-and-launch">MVP architecture and launch</a>
·
<a href="/services/stage-aligned-infrastructure">Stage-aligned infrastructure</a>
</p>
</div>
</section>
<section id="outcomes" class="section" aria-labelledby="outcomes-heading">
<div class="container container--narrow">
<h2 id="outcomes-heading">What changes when the foundation is right</h2>
<p>
It's all connected—speed, bugs, confidence, and morale are one big ball of yarn. When
the frontend foundation is right, the whole system gets calmer.
</p>
<ul class="content-list">
<li>Developers ship faster with less hesitation</li>
<li>Lower bug rate from fewer one-off implementations</li>
<li>Cohesive UI and clearer product identity</li>
<li>Faster design iteration without rewrites</li>
<li>Accessibility becomes the default, not a retrofit</li>
<li>SEO improves naturally via good structure and semantics</li>
<li>Higher release confidence and better team morale</li>
</ul>
</div>
</section>
<section id="engagement" class="section" aria-labelledby="engagement-heading">
<div class="container container--narrow">
<h2 id="engagement-heading">How we can work together</h2>
<h3>Architecture engagement (high-fee, fixed scope)</h3>
<ul class="content-list">
<li>Codebase review focused on frontend foundations</li>
<li>CSS + component audit, prioritized action plan</li>
<li>Token strategy and incremental adoption plan</li>
<li>Accessibility baseline and standards</li>
<li>A roadmap your team can execute</li>
</ul>
<h3>Implementation (optional, bounded)</h3>
<ul class="content-list">
<li>Hands-on refactors and foundation building</li>
<li>Component library creation and rollout</li>
<li>Tokenization and theming support</li>
<li>Documentation and handoff so you're not dependent on me</li>
</ul>
<h3>Advisory retainer (recurring, low-liability)</h3>
<ul class="content-list">
<li>Regular check-ins to keep architecture clean as you ship</li>
<li>Review of component/API decisions and PRs (optional)</li>
<li>Guidance on tooling tradeoffs as you grow</li>
<li>No 24/7 pager-duty MSP model</li>
</ul>
</div>
</section>
<section id="who-its-for" class="section" aria-labelledby="who-for-heading">
<div class="container">
<div class="who-grid">
<div class="who-block">
<h2 id="who-for-heading">Who this is for</h2>
<ul class="content-list">
<li>Founder-led SaaS teams</li>
<li>115 engineers (and growing)</li>
<li>Teams shipping fast but feeling UI/UX friction</li>
<li>Teams who want adult-level architecture without slowing down</li>
</ul>
</div>
<div class="who-block">
<h2 id="who-not-heading">Who this is not for</h2>
<ul class="content-list">
<li>Organizations looking for pure strategy decks and diagrams</li>
<li>Teams wanting a long-term embedded full-time DevOps engineer</li>
<li>Companies needing 24/7 managed hosting with strict SLAs</li>
</ul>
</div>
</div>
</div>
</section>
<section id="faq" class="section service-faq" aria-labelledby="faq-heading">
<div class="container container--narrow">
<h2 id="faq-heading">FAQ</h2>
<dl class="faq-list">
{#each faqItems as item (item.question)}
<dt>{item.question}</dt>
<dd>{item.answer}</dd>
{/each} {/each}
</dl>
</div>
</section>
<ScheduleSection <WhoGrid {...pageContent.who} />
title="Want to ship faster without frontend debt?"
subtitle="If your UI feels brittle, inconsistent, or slow to evolve, you're not alone—and you don't need a massive rewrite. Let's build a foundation that makes iteration cheap." <FAQ faqList={faqItems} />
bookingLinkTitle="Book a discovery call"
bookingLinkUrl={`${discoveryCallUrl}-schedule-section`} <ScheduleSection {...pageContent.scheduleCta} />
showEmailLink
/>
</main> </main>
<style>
.service-hero {
padding: var(--space-xxxl) 0 var(--space-xxl) 0;
text-align: center;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
}
.service-hero__title {
margin-bottom: var(--space-lg);
font-family: var(--font-family-heading);
font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold);
letter-spacing: -0.03em;
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
.service-hero__subhead {
max-width: var(--max-narrow-width);
margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.cta-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
justify-content: center;
align-items: center;
margin-top: var(--space-lg);
}
@media (max-width: 768px) {
.cta-group {
flex-direction: column;
width: 100%;
}
}
.container--narrow {
max-width: var(--max-narrow-width);
}
.service-toc {
padding: var(--space-xl) 0;
border-bottom: 1px solid var(--color-border);
}
.service-toc__title {
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--space-md);
}
.service-toc__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: var(--space-sm) var(--space-xl);
}
.service-toc__list a {
color: var(--color-text-secondary);
font-size: var(--font-size-medium);
}
.service-toc__list a:hover {
color: var(--color-primary);
}
.service-credibility {
background-color: var(--color-bg-subtle);
}
.service-credibility__list {
list-style: none;
margin: 0;
padding: 0;
max-width: var(--max-width);
margin: 0 auto;
display: grid;
gap: var(--space-md);
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.service-credibility__list li {
position: relative;
padding-left: var(--space-lg);
font-size: var(--font-size-base);
line-height: var(--line-height-relaxed);
color: var(--color-text-secondary);
}
.service-credibility__list li::before {
content: '→';
position: absolute;
left: 0;
color: var(--color-primary);
font-weight: var(--font-weight-semibold);
}
.who-grid {
display: grid;
gap: var(--space-xxl);
grid-template-columns: 1fr 1fr;
}
@media (max-width: 768px) {
.who-grid {
grid-template-columns: 1fr;
}
}
.who-block h2 {
font-size: var(--font-size-xl);
margin-bottom: var(--space-md);
}
.service-faq {
background-color: var(--color-bg-alt);
}
.faq-list {
margin: 0;
}
.faq-list dt {
font-weight: var(--font-weight-semibold);
color: var(--color-text);
margin-top: var(--space-xl);
margin-bottom: var(--space-sm);
}
.faq-list dt:first-child {
margin-top: 0;
}
.faq-list dd {
margin: 0 0 0 var(--space-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
}
.schedule-section {
text-align: center;
background-color: var(--color-bg-subtle);
}
.schedule-text {
margin-bottom: var(--space-lg);
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
/* Avoid anchor targets sitting under sticky nav */
[id] {
scroll-margin-top: 6rem;
}
</style>

View File

@@ -1,7 +1,8 @@
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
import type { PageMeta } from '$lib/seo'; import type { PageMeta } from '$lib/seo';
import { defaultJsonLdGraph } from '$lib/data/home/json-ld'; import { defaultJsonLdGraph } from '$lib/data/home/json-ld';
import { faqItems } from '$lib/data/hands-on-saas-architecture-consultant/faq'; import { pageContent } from '$lib/data/services/hands-on-saas-architecture-consultant/content';
import { faqItems } from '$lib/data/services/hands-on-saas-architecture-consultant/faq';
const BASE = 'https://mifi.ventures'; const BASE = 'https://mifi.ventures';
const PAGE_URL = `${BASE}/services/hands-on-saas-architecture-consultant/`; const PAGE_URL = `${BASE}/services/hands-on-saas-architecture-consultant/`;
@@ -21,10 +22,11 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = { export const load: PageLoad = () => {
title: 'Hands-On SaaS Architecture Consultant | Frontend Systems That Scale', const { meta } = pageContent;
description: const servicePageMeta: PageMeta = {
'I help early-stage SaaS teams ship faster by building scalable frontend foundations—clean CSS, component libraries, design tokens, and accessibility from day one—so iteration accelerates instead of slowing down.', title: meta.title,
description: meta.description,
jsonLd: [ jsonLd: [
...defaultJsonLdGraph, ...defaultJsonLdGraph,
{ {
@@ -32,8 +34,7 @@ const servicePageMeta: PageMeta = {
'@id': `${BASE}/services/hands-on-saas-architecture-consultant/#service`, '@id': `${BASE}/services/hands-on-saas-architecture-consultant/#service`,
name: 'mifi Ventures', name: 'mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
description: description: meta.jsonLdServiceDescription ?? meta.description,
'Hands-on product architecture for early-stage SaaS: frontend foundations, CSS architecture, component libraries, design tokens, and accessibility from day one. Architecture engagement, implementation support, and advisory retainer.',
serviceType: [ serviceType: [
'Product Architecture', 'Product Architecture',
'SaaS Engineering Consulting', 'SaaS Engineering Consulting',
@@ -44,8 +45,6 @@ const servicePageMeta: PageMeta = {
}, },
buildFaqPageJsonLd(), buildFaqPageJsonLd(),
], ],
}; };
export const load: PageLoad = () => {
return { meta: servicePageMeta }; return { meta: servicePageMeta };
}; };

View File

@@ -1,396 +1,29 @@
<script lang="ts"> <script lang="ts">
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import ExternalLinkIcon from '$lib/components/Icon/ExternalLink.svelte'; import Hero from '$lib/components/Hero.svelte';
import { faqItems } from '$lib/data/mvp-architecture-and-launch/faq'; import TOC from '$lib/components/TOC.svelte';
import ServiceSection from '$lib/components/ServiceSection.svelte';
import WhoGrid from '$lib/components/WhoGrid.svelte';
import FAQ from '$lib/components/FAQ.svelte';
import ScheduleSection from '$lib/components/ScheduleSection.svelte'; import ScheduleSection from '$lib/components/ScheduleSection.svelte';
import { pageContent } from '$lib/data/services/mvp-architecture-and-launch/content';
const discoveryCallUrl = import { faqItems } from '$lib/data/services/mvp-architecture-and-launch/faq';
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=mvp_arch_launch_page';
const navItems = [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'My approach', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'Engagement', href: '#engagement', umamiEventLabel: 'engagement' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
];
</script> </script>
<Navigation items={navItems} page="mvp-architecture-and-launch" /> <Navigation items={pageContent.navItems} page="mvp-architecture-and-launch" />
<header id="header" class="service-hero"> <Hero {...pageContent.hero} />
<div class="container">
<h1 class="service-hero__title">
MVP Architecture & Launch for Early-Stage SaaS
</h1>
<p class="service-hero__subhead">
Shipping fast is good. Shipping chaos is expensive. I help early-stage SaaS teams build
MVPs that move quickly without creating frontend debt, fragile CSS, or structural
problems that slow iteration six months later.
</p>
<div class="cta-group">
<a
href={discoveryCallUrl}
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Book a discovery call (opens in new tab)"
data-umami-event="book discovery call"
data-umami-event-location="hero"
>
Book a discovery call
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<a
href="#approach"
class="btn btn-secondary"
data-umami-event="see how i work"
data-umami-event-location="hero"
>
See how I work
</a>
</div>
</div>
</header>
<main id="main"> <main id="main">
<nav class="section service-toc" aria-label="Page contents"> <TOC items={pageContent.tocItems} />
<div class="container">
<h2 class="service-toc__title">On this page</h2>
<ul class="service-toc__list">
<li><a href="#common-pattern">The common MVP pattern</a></li>
<li><a href="#good-foundation">What a good MVP foundation looks like</a></li>
<li><a href="#approach">My approach</a></li>
<li><a href="#what-changes">What changes within 1&ndash;2 weeks</a></li>
<li><a href="#engagement">Engagement options</a></li>
<li><a href="#who-its-for">Who it's for</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href="#final-cta">Get in touch</a></li>
</ul>
</div>
</nav>
<section id="common-pattern" class="section" aria-labelledby="common-pattern-heading"> {#each pageContent.sections as section (section.id)}
<div class="container container--narrow"> <ServiceSection {section} />
<h2 id="common-pattern-heading">
Most MVPs are built for speed—few are built for iteration
</h2>
<p>
Early MVPs often prioritize backend logic and feature delivery. The frontend becomes
an afterthought—functional, but brittle. Six months later, every new feature feels
heavier than the last.
</p>
<p>Common symptoms:</p>
<ul class="content-list">
<li>Poor separation of concerns</li>
<li>Backend-heavy architecture with fragile UI</li>
<li>Repeated components instead of reusable systems</li>
<li>Spaghetti CSS and specificity wars</li>
<li>Accessibility postponed</li>
<li>"We'll clean it up later" decisions compounding</li>
</ul>
<p>Speed isn't the problem. Structure is.</p>
</div>
</section>
<section id="good-foundation" class="section" aria-labelledby="good-foundation-heading">
<div class="container container--narrow">
<h2 id="good-foundation-heading">MVP does not mean throwaway</h2>
<p>A well-built MVP is minimal—but intentional.</p>
<p>It includes:</p>
<ul class="content-list">
<li>Clear separation between layers</li>
<li>Reusable, composable frontend components</li>
<li>Tokenized design systems (color, spacing, typography)</li>
<li>Clean, maintainable CSS architecture</li>
<li>Accessibility baked in from day one</li>
<li>A simple, predictable deployment path</li>
</ul>
<p>You can move fast and build correctly at the same time.</p>
<p>
<a href="/services/hands-on-saas-architecture-consultant">Hands-on SaaS architecture</a>
·
<a href="/services/fractional-cto-for-early-stage-saas">Fractional CTO for early-stage SaaS</a>
·
<a href="/services/stage-aligned-infrastructure">Stage-aligned infrastructure</a>
</p>
</div>
</section>
<section id="approach" class="section" aria-labelledby="approach-heading">
<div class="container container--narrow">
<h2 id="approach-heading">Architecture through implementation</h2>
<p>I don't deliver diagrams and disappear. I work inside your codebase.</p>
<p>My approach:</p>
<ol class="content-list content-list--ordered">
<li>Fix the CSS foundation first.</li>
<li>Extract and standardize reusable components.</li>
<li>Introduce design tokens to prevent duplication.</li>
<li>Align frontend and backend boundaries.</li>
<li>Improve accessibility and semantics incrementally.</li>
<li>Keep shipping while refactoring.</li>
</ol>
<p>No rewrite mandates. No velocity freeze.</p>
</div>
</section>
<section id="what-changes" class="section" aria-labelledby="what-changes-heading">
<div class="container container--narrow">
<h2 id="what-changes-heading">What teams notice quickly</h2>
<p>
In most cases, teams feel the difference within 12 weeks once foundational issues
are corrected.
</p>
<p>You'll see:</p>
<ul class="content-list">
<li>Faster feature implementation</li>
<li>Lower bug rates</li>
<li>More consistent UI</li>
<li>Safer refactors</li>
<li>Increased release confidence</li>
<li>Better team morale</li>
</ul>
<p>
It's all one big ball of yarn—clean up the foundation and everything moves more
smoothly.
</p>
</div>
</section>
<section id="engagement" class="section" aria-labelledby="engagement-heading">
<div class="container container--narrow">
<h2 id="engagement-heading">How we can work together</h2>
<h3>MVP Architecture Engagement (fixed scope)</h3>
<ul class="content-list">
<li>Codebase review focused on frontend foundations</li>
<li>Structural audit and prioritized roadmap</li>
<li>Component system extraction plan</li>
<li>CSS cleanup and token strategy</li>
<li>Accessibility baseline</li>
</ul>
<h3>Hands-On Implementation (optional)</h3>
<ul class="content-list">
<li>Direct refactoring and component system creation</li>
<li>Tokenized design system rollout</li>
<li>Pairing with your engineers</li>
<li>Documentation and knowledge transfer</li>
</ul>
<h3>Ongoing Advisory (optional)</h3>
<ul class="content-list">
<li>Periodic architecture reviews</li>
<li>Guardrails as you scale</li>
<li>Guidance on feature/system tradeoffs</li>
</ul>
</div>
</section>
<section id="who-its-for" class="section" aria-labelledby="who-for-heading">
<div class="container">
<div class="who-grid">
<div class="who-block">
<h2 id="who-for-heading">Ideal fit</h2>
<ul class="content-list">
<li>Founder-led SaaS teams</li>
<li>110 engineers</li>
<li>Recently launched MVP</li>
<li>Feeling UI friction or code fragility</li>
<li>Want adult-level architecture without slowing down</li>
</ul>
</div>
<div class="who-block">
<h2 id="who-not-heading">Who this is not for</h2>
<ul class="content-list">
<li>
Teams who only want features shipped as fast as possible without regard
for structure
</li>
<li>Organizations looking purely for architecture slide decks</li>
<li>Large enterprises needing formal procurement processes</li>
</ul>
</div>
</div>
</div>
</section>
<section id="faq" class="section service-faq" aria-labelledby="faq-heading">
<div class="container container--narrow">
<h2 id="faq-heading">FAQ</h2>
<dl class="faq-list">
{#each faqItems as item (item.question)}
<dt>{item.question}</dt>
<dd>{item.answer}</dd>
{/each} {/each}
</dl>
</div>
</section>
<ScheduleSection <WhoGrid {...pageContent.who} />
title="Ready to stabilize your MVP?"
subtitle="If your MVP shipped fast but now feels fragile, let's reinforce the foundation before iteration slows further." <FAQ faqList={faqItems} />
bookingLinkTitle="Schedule a discovery call"
bookingLinkUrl={`${discoveryCallUrl}-schedule-section`} <ScheduleSection {...pageContent.scheduleCta} />
showEmailLink
/>
</main> </main>
<style>
.service-hero {
padding: var(--space-xxxl) 0 var(--space-xxl) 0;
text-align: center;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
}
.service-hero__title {
margin-bottom: var(--space-lg);
font-family: var(--font-family-heading);
font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold);
letter-spacing: -0.03em;
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
.service-hero__subhead {
max-width: var(--max-narrow-width);
margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.cta-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
justify-content: center;
align-items: center;
margin-top: var(--space-lg);
}
@media (max-width: 768px) {
.cta-group {
flex-direction: column;
width: 100%;
}
}
.container--narrow {
max-width: var(--max-narrow-width);
}
.service-toc {
padding: var(--space-xl) 0;
border-bottom: 1px solid var(--color-border);
}
.service-toc__title {
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--space-md);
}
.service-toc__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: var(--space-sm) var(--space-xl);
}
.service-toc__list a {
color: var(--color-text-secondary);
font-size: var(--font-size-medium);
}
.service-toc__list a:hover {
color: var(--color-primary);
}
.content-list--ordered {
list-style: decimal;
padding-left: var(--space-xl);
}
.content-list--ordered li {
padding-left: var(--space-sm);
}
.content-list--ordered li::before {
content: none;
}
.who-grid {
display: grid;
gap: var(--space-xxl);
grid-template-columns: 1fr 1fr;
}
@media (max-width: 768px) {
.who-grid {
grid-template-columns: 1fr;
}
}
.who-block h2 {
font-size: var(--font-size-xl);
margin-bottom: var(--space-md);
}
.service-faq {
background-color: var(--color-bg-alt);
}
.faq-list {
margin: 0;
}
.faq-list dt {
font-weight: var(--font-weight-semibold);
color: var(--color-text);
margin-top: var(--space-xl);
margin-bottom: var(--space-sm);
}
.faq-list dt:first-child {
margin-top: 0;
}
.faq-list dd {
margin: 0 0 0 var(--space-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
}
.schedule-section {
text-align: center;
background-color: var(--color-bg-subtle);
}
.schedule-text {
margin-bottom: var(--space-lg);
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
/* Avoid anchor targets sitting under sticky nav */
[id] {
scroll-margin-top: 6rem;
}
</style>

View File

@@ -1,7 +1,8 @@
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
import type { PageMeta } from '$lib/seo'; import type { PageMeta } from '$lib/seo';
import { defaultJsonLdGraph } from '$lib/data/home/json-ld'; import { defaultJsonLdGraph } from '$lib/data/home/json-ld';
import { faqItems } from '$lib/data/mvp-architecture-and-launch/faq'; import { pageContent } from '$lib/data/services/mvp-architecture-and-launch/content';
import { faqItems } from '$lib/data/services/mvp-architecture-and-launch/faq';
const BASE = 'https://mifi.ventures'; const BASE = 'https://mifi.ventures';
const PAGE_URL = `${BASE}/services/mvp-architecture-and-launch/`; const PAGE_URL = `${BASE}/services/mvp-architecture-and-launch/`;
@@ -21,10 +22,11 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = { export const load: PageLoad = () => {
title: 'MVP Architecture Consultant | Ship Fast Without Structural Debt', const { meta } = pageContent;
description: const servicePageMeta: PageMeta = {
'I help early-stage SaaS teams build and stabilize MVPs with clean frontend foundations, reusable components, and scalable architecture—so you can ship fast without creating chaos six months later.', title: meta.title,
description: meta.description,
jsonLd: [ jsonLd: [
...defaultJsonLdGraph, ...defaultJsonLdGraph,
{ {
@@ -32,8 +34,7 @@ const servicePageMeta: PageMeta = {
'@id': `${BASE}/services/mvp-architecture-and-launch/#service`, '@id': `${BASE}/services/mvp-architecture-and-launch/#service`,
name: 'mifi Ventures', name: 'mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
description: description: meta.jsonLdServiceDescription ?? meta.description,
'MVP architecture and launch for early-stage SaaS: clean foundations, reusable components, tokenized design systems, and accessibility from day one. Fixed-scope engagement, hands-on implementation, and optional advisory.',
serviceType: [ serviceType: [
'MVP Architecture', 'MVP Architecture',
'SaaS Engineering Consulting', 'SaaS Engineering Consulting',
@@ -44,8 +45,6 @@ const servicePageMeta: PageMeta = {
}, },
buildFaqPageJsonLd(), buildFaqPageJsonLd(),
], ],
}; };
export const load: PageLoad = () => {
return { meta: servicePageMeta }; return { meta: servicePageMeta };
}; };

View File

@@ -1,394 +1,29 @@
<script lang="ts"> <script lang="ts">
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import ExternalLinkIcon from '$lib/components/Icon/ExternalLink.svelte'; import Hero from '$lib/components/Hero.svelte';
import { faqItems } from '$lib/data/stage-aligned-infrastructure/faq'; import TOC from '$lib/components/TOC.svelte';
import ServiceSection from '$lib/components/ServiceSection.svelte';
import WhoGrid from '$lib/components/WhoGrid.svelte';
import FAQ from '$lib/components/FAQ.svelte';
import ScheduleSection from '$lib/components/ScheduleSection.svelte'; import ScheduleSection from '$lib/components/ScheduleSection.svelte';
import { pageContent } from '$lib/data/services/stage-aligned-infrastructure/content';
const discoveryCallUrl = import { faqItems } from '$lib/data/services/stage-aligned-infrastructure/faq';
'https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_content=stage_aligned_infra_page';
const navItems = [
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
{ label: 'My approach', href: '#approach', umamiEventLabel: 'approach' },
{ label: 'FAQ', href: '#faq', umamiEventLabel: 'faq' },
{
label: 'Book a call',
href: `${discoveryCallUrl}-navigation`,
umamiEventLabel: 'book-call',
},
];
</script> </script>
<Navigation items={navItems} page="stage-aligned-infrastructure" /> <Navigation items={pageContent.navItems} page="stage-aligned-infrastructure" />
<header id="header" class="service-hero"> <Hero {...pageContent.hero} />
<div class="container">
<h1 class="service-hero__title">
Stage-Aligned Infrastructure for Early-Stage SaaS
</h1>
<p class="service-hero__subhead">
Infrastructure should match the stage of your company. Many early SaaS teams inherit
complex cloud architectures and SaaS stacks designed for companies ten times their size.
The result is predictable: large monthly bills and operational complexity that slows
engineering teams down. I help founders design infrastructure that is simple, predictable,
and able to evolve as the product grows.
</p>
<div class="cta-group">
<a
href={discoveryCallUrl}
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Book a discovery call (opens in new tab)"
data-umami-event="book discovery call"
data-umami-event-location="hero"
>
Book a discovery call
<ExternalLinkIcon aria-label="Opens in new tab" size={17} />
</a>
<a
href="#approach"
class="btn btn-secondary"
data-umami-event="see my approach"
data-umami-event-location="hero"
>
See my approach
</a>
</div>
</div>
</header>
<main id="main"> <main id="main">
<nav class="section service-toc" aria-label="Page contents"> <TOC items={pageContent.tocItems} />
<div class="container">
<h2 class="service-toc__title">On this page</h2>
<ul class="service-toc__list">
<li><a href="#trap">The early-stage infrastructure trap</a></li>
<li><a href="#real-cost">The real cost</a></li>
<li><a href="#what-it-looks-like">What stage-aligned looks like</a></li>
<li><a href="#seeded-cloud">Seeded cloud</a></li>
<li><a href="#when-cloud">When cloud services make sense</a></li>
<li><a href="#approach">How I help</a></li>
<li><a href="#who-its-for">Who it's for</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href="#final-cta">Get in touch</a></li>
</ul>
</div>
</nav>
<section id="trap" class="section" aria-labelledby="trap-heading"> {#each pageContent.sections as section (section.id)}
<div class="container container--narrow"> <ServiceSection {section} />
<h2 id="trap-heading">
How early-stage companies end up with enterprise infrastructure
</h2>
<p>
Many startups adopt infrastructure patterns designed for much larger organizations.
</p>
<p>Common causes include:</p>
<ul class="content-list">
<li>Copying architectures from big tech companies</li>
<li>Following tutorials designed for enterprise-scale systems</li>
<li>Adding cloud services incrementally without a clear strategy</li>
<li>Believing that complex infrastructure signals maturity</li>
</ul>
<p>
The result is often a patchwork of services that are expensive to run and difficult
to reason about.
</p>
</div>
</section>
<section id="real-cost" class="section" aria-labelledby="real-cost-heading">
<div class="container container--narrow">
<h2 id="real-cost-heading">The hidden cost of infrastructure complexity</h2>
<p>Infrastructure complexity has two costs: money and cognitive load.</p>
<p>
Founders frequently notice the first sign when monthly cloud or SaaS bills grow
unexpectedly. But the second cost can be even more damaging.
</p>
<p>
Engineers begin spending time navigating infrastructure instead of building
product. Debugging becomes harder. Deployments become fragile. Small teams are
suddenly maintaining systems designed for companies with dedicated platform teams.
</p>
<p>Infrastructure should enable product development, not compete with it.</p>
</div>
</section>
<section id="what-it-looks-like" class="section" aria-labelledby="what-heading">
<div class="container container--narrow">
<h2 id="what-heading">Infrastructure that grows with the product</h2>
<p>
Stage-aligned infrastructure starts simple and becomes more sophisticated only when
necessary.
</p>
<p>
For many early products, a straightforward deployment environment can support far
more growth than founders expect. Simple environments are easier to understand,
easier to maintain, and far less expensive.
</p>
<p>
As the product scales, infrastructure can evolve deliberately rather than
reactively.
</p>
<p>
The goal is not minimalism for its own sake. The goal is <strong>intentional
complexity</strong>.
</p>
</div>
</section>
<section id="seeded-cloud" class="section" aria-labelledby="seeded-cloud-heading">
<div class="container container--narrow">
<h2 id="seeded-cloud-heading">Seeded Cloud Infrastructure</h2>
<p>I sometimes describe this approach as "seeded cloud."</p>
<p>
Instead of inheriting a massive ecosystem of services from day one, companies plant
a small, understandable infrastructure foundation that can grow over time.
</p>
<p>This might include:</p>
<ul class="content-list">
<li>Simple compute environments</li>
<li>Predictable deployment pipelines</li>
<li>Minimal operational overhead</li>
<li>Tooling chosen for clarity and maintainability</li>
</ul>
<p>
As the product grows, that foundation can expand naturally into more sophisticated
architectures.
</p>
<p>Infrastructure evolves when scale requires it—not before.</p>
</div>
</section>
<section id="when-cloud" class="section" aria-labelledby="when-cloud-heading">
<div class="container container--narrow">
<h2 id="when-cloud-heading">When managed cloud services are the right choice</h2>
<p>
Cloud platforms and SaaS tools exist for good reasons. For some companies and stages
they are absolutely the right decision.
</p>
<p>Examples include:</p>
<ul class="content-list">
<li>Teams operating at significant scale</li>
<li>Organizations with compliance requirements</li>
<li>Products requiring specialized infrastructure capabilities</li>
<li>Companies with dedicated platform engineering teams</li>
</ul>
<p>The key is adopting these tools deliberately, not reflexively.</p>
</div>
</section>
<section id="approach" class="section" aria-labelledby="approach-heading">
<div class="container container--narrow">
<h2 id="approach-heading">How I help teams realign their infrastructure</h2>
<p>
My work typically focuses on helping founders and engineering teams simplify their
infrastructure while preserving the ability to grow.
</p>
<p>Typical engagements include:</p>
<ul class="content-list">
<li>Infrastructure audits and simplification</li>
<li>Evaluating cloud and SaaS tool usage</li>
<li>Identifying unnecessary complexity</li>
<li>Designing simpler deployment patterns</li>
<li>Aligning infrastructure with product stage</li>
<li>Planning transitions as scale increases</li>
</ul>
<p>The goal is not rebuilding everything. The goal is restoring clarity and intentionality.</p>
<p>
<a href="/services/hands-on-saas-architecture-consultant">Hands-on SaaS architecture</a>
·
<a href="/services/mvp-architecture-and-launch">MVP architecture and launch</a>
·
<a href="/services/fractional-cto-for-early-stage-saas">Fractional CTO for early-stage SaaS</a>
</p>
</div>
</section>
<section id="who-its-for" class="section" aria-labelledby="who-for-heading">
<div class="container">
<div class="who-grid">
<div class="who-block">
<h2 id="who-for-heading">Ideal clients</h2>
<ul class="content-list">
<li>Founder-led SaaS companies</li>
<li>Teams with 115 engineers</li>
<li>Startups experiencing growing infrastructure costs</li>
<li>Companies that feel their infrastructure is more complex than their product requires</li>
</ul>
</div>
<div class="who-block">
<h2 id="who-not-heading">Who this is not for</h2>
<ul class="content-list">
<li>Large enterprises with dedicated platform teams</li>
<li>Companies already operating at significant infrastructure scale</li>
<li>Organizations seeking fully managed hosting providers</li>
</ul>
</div>
</div>
</div>
</section>
<section id="faq" class="section service-faq" aria-labelledby="faq-heading">
<div class="container container--narrow">
<h2 id="faq-heading">FAQ</h2>
<dl class="faq-list">
{#each faqItems as item (item.question)}
<dt>{item.question}</dt>
<dd>{item.answer}</dd>
{/each} {/each}
</dl>
</div>
</section>
<ScheduleSection <WhoGrid {...pageContent.who} />
title="Infrastructure should support your product—not compete with it"
subtitle="If your infrastructure feels more complicated than your product requires, it may be time to simplify. Stage-aligned infrastructure helps teams focus on building features instead of maintaining unnecessary systems." <FAQ faqList={faqItems} />
bookingLinkTitle="Schedule a discovery call"
bookingLinkUrl={`${discoveryCallUrl}-sechedule_section`} <ScheduleSection {...pageContent.scheduleCta} />
showEmailLink
/>
</main> </main>
<style>
.service-hero {
padding: var(--space-xxxl) 0 var(--space-xxl) 0;
text-align: center;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
}
.service-hero__title {
margin-bottom: var(--space-lg);
font-family: var(--font-family-heading);
font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold);
letter-spacing: -0.03em;
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
.service-hero__subhead {
max-width: var(--max-narrow-width);
margin: 0 auto var(--space-xl) auto;
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
}
.cta-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-md);
justify-content: center;
align-items: center;
margin-top: var(--space-lg);
}
@media (max-width: 768px) {
.cta-group {
flex-direction: column;
width: 100%;
}
}
.container--narrow {
max-width: var(--max-narrow-width);
}
.service-toc {
padding: var(--space-xl) 0;
border-bottom: 1px solid var(--color-border);
}
.service-toc__title {
font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--space-md);
}
.service-toc__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: var(--space-sm) var(--space-xl);
}
.service-toc__list a {
color: var(--color-text-secondary);
font-size: var(--font-size-medium);
}
.service-toc__list a:hover {
color: var(--color-primary);
}
.who-grid {
display: grid;
gap: var(--space-xxl);
grid-template-columns: 1fr 1fr;
}
@media (max-width: 768px) {
.who-grid {
grid-template-columns: 1fr;
}
}
.who-block h2 {
font-size: var(--font-size-xl);
margin-bottom: var(--space-md);
}
.service-faq {
background-color: var(--color-bg-alt);
}
.faq-list {
margin: 0;
}
.faq-list dt {
font-weight: var(--font-weight-semibold);
color: var(--color-text);
margin-top: var(--space-xl);
margin-bottom: var(--space-sm);
}
.faq-list dt:first-child {
margin-top: 0;
}
.faq-list dd {
margin: 0 0 0 var(--space-md);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
}
.schedule-section {
text-align: center;
background-color: var(--color-bg-subtle);
}
.schedule-text {
margin-bottom: var(--space-lg);
font-size: var(--font-size-large);
font-weight: var(--font-weight-normal);
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
max-width: var(--max-text-width);
margin-left: auto;
margin-right: auto;
}
/* Avoid anchor targets sitting under sticky nav */
[id] {
scroll-margin-top: 6rem;
}
</style>

View File

@@ -1,7 +1,8 @@
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
import type { PageMeta } from '$lib/seo'; import type { PageMeta } from '$lib/seo';
import { defaultJsonLdGraph } from '$lib/data/home/json-ld'; import { defaultJsonLdGraph } from '$lib/data/home/json-ld';
import { faqItems } from '$lib/data/stage-aligned-infrastructure/faq'; import { pageContent } from '$lib/data/services/stage-aligned-infrastructure/content';
import { faqItems } from '$lib/data/services/stage-aligned-infrastructure/faq';
const BASE = 'https://mifi.ventures'; const BASE = 'https://mifi.ventures';
const PAGE_URL = `${BASE}/services/stage-aligned-infrastructure/`; const PAGE_URL = `${BASE}/services/stage-aligned-infrastructure/`;
@@ -21,10 +22,11 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = { export const load: PageLoad = () => {
title: 'Stage-Aligned Infrastructure for Startups | Practical SaaS Infrastructure Strategy', const { meta } = pageContent;
description: const servicePageMeta: PageMeta = {
"Infrastructure decisions should match your company's stage. I help early-stage SaaS teams avoid unnecessary cloud complexity and SaaS sprawl while building infrastructure foundations that scale with the product.", title: meta.title,
description: meta.description,
jsonLd: [ jsonLd: [
...defaultJsonLdGraph, ...defaultJsonLdGraph,
{ {
@@ -32,8 +34,7 @@ const servicePageMeta: PageMeta = {
'@id': `${BASE}/services/stage-aligned-infrastructure/#service`, '@id': `${BASE}/services/stage-aligned-infrastructure/#service`,
name: 'mifi Ventures', name: 'mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
description: description: meta.jsonLdServiceDescription ?? meta.description,
'Stage-aligned infrastructure for early-stage SaaS: infrastructure audits, simplification, and strategy so complexity matches company stage. Capital efficiency, reduced sprawl, and foundations that evolve with the product.',
serviceType: [ serviceType: [
'SaaS Architecture Consulting', 'SaaS Architecture Consulting',
'Startup Infrastructure Strategy', 'Startup Infrastructure Strategy',
@@ -44,8 +45,6 @@ const servicePageMeta: PageMeta = {
}, },
buildFaqPageJsonLd(), buildFaqPageJsonLd(),
], ],
}; };
export const load: PageLoad = () => {
return { meta: servicePageMeta }; return { meta: servicePageMeta };
}; };

View File

@@ -2,9 +2,7 @@
import Navigation from '$lib/components/Navigation.svelte'; import Navigation from '$lib/components/Navigation.svelte';
import { termsOfService } from '$lib/data/terms-of-service'; import { termsOfService } from '$lib/data/terms-of-service';
const navItems = [ const navItems = [{ label: 'Home', href: '/', umamiEventLabel: 'home' }];
{ label: 'Home', href: '/', umamiEventLabel: 'home' },
];
</script> </script>
<Navigation items={navItems} page="terms-of-service" /> <Navigation items={navItems} page="terms-of-service" />
@@ -22,14 +20,22 @@
{/each} {/each}
{#each termsOfService.sections as section (section.id)} {#each termsOfService.sections as section (section.id)}
<section id={section.id} class="legal-section" aria-labelledby={`${section.id}-heading`}> <section
id={section.id}
class="legal-section"
aria-labelledby={`${section.id}-heading`}
>
<h2 id={`${section.id}-heading`}>{section.heading}</h2> <h2 id={`${section.id}-heading`}>{section.heading}</h2>
{#each section.body as para} {#each section.body as para}
<p> <p>
{#if section.id === 'contact' && para === 'legal@mifi.ventures'} {#if section.id === 'contact' && para === 'legal@mifi.ventures'}
<a href="mailto:legal@mifi.ventures">legal@mifi.ventures</a> <a href="mailto:legal@mifi.ventures"
>legal@mifi.ventures</a
>
{:else if section.id === 'contact' && para === 'https://mifi.ventures'} {:else if section.id === 'contact' && para === 'https://mifi.ventures'}
<a href="https://mifi.ventures" rel="noopener noreferrer">https://mifi.ventures</a> <a href="https://mifi.ventures" rel="noopener noreferrer"
>https://mifi.ventures</a
>
{:else} {:else}
{para} {para}
{/if} {/if}

View File

@@ -10,6 +10,46 @@ test.describe('visual regression', () => {
await expect(page).toHaveScreenshot('home.png', { fullPage: true }); await expect(page).toHaveScreenshot('home.png', { fullPage: true });
}); });
test('services page matches snapshot', async ({ page }) => {
await page.goto('/services');
await expect(page).toHaveTitle(/SaaS Architecture Services | mifi Ventures/);
await expect(page.locator('h1')).toBeVisible();
await expect(page.locator('#main')).toBeVisible();
await expect(page).toHaveScreenshot('services.png', { fullPage: true });
});
test('services/hands-on-saas-architecture-consultant page matches snapshot', async ({ page }) => {
await page.goto('/services/hands-on-saas-architecture-consultant');
await expect(page).toHaveTitle(/SaaS Product Architecture Consultant | mifi Ventures/);
await expect(page.locator('h1')).toBeVisible();
await expect(page.locator('#main')).toBeVisible();
await expect(page).toHaveScreenshot('services-hands-on-saas-architecture-consultant.png', { fullPage: true });
});
test('services/mvp-architecture-and-launch page matches snapshot', async ({ page }) => {
await page.goto('/services/mvp-architecture-and-launch');
await expect(page).toHaveTitle(/MVP Architecture & Launch Consultant | mifi Ventures/);
await expect(page.locator('h1')).toBeVisible();
await expect(page.locator('#main')).toBeVisible();
await expect(page).toHaveScreenshot('services-mvp-architecture-and-launch.png', { fullPage: true });
});
test('services/fractional-cto-for-early-stage-saas page matches snapshot', async ({ page }) => {
await page.goto('/services/fractional-cto-for-early-stage-saas');
await expect(page).toHaveTitle(/Fractional CTO for Early-Stage SaaS | mifi Ventures/);
await expect(page.locator('h1')).toBeVisible();
await expect(page.locator('#main')).toBeVisible();
await expect(page).toHaveScreenshot('services-fractional-cto-for-early-stage-saas.png', { fullPage: true });
});
test('services/stage-aligned-infrastructure page matches snapshot', async ({ page }) => {
await page.goto('/services/stage-aligned-infrastructure');
await expect(page).toHaveTitle(/Startup Infrastructure Strategy | mifi Ventures/);
await expect(page.locator('h1')).toBeVisible();
await expect(page.locator('#main')).toBeVisible();
await expect(page).toHaveScreenshot('services-stage-aligned-infrastructure.png', { fullPage: true });
});
test('privacy policy page matches snapshot', async ({ page }) => { test('privacy policy page matches snapshot', async ({ page }) => {
await page.goto('/privacy-policy'); await page.goto('/privacy-policy');
await expect(page).toHaveTitle(/Privacy Policy | mifi Ventures/); await expect(page).toHaveTitle(/Privacy Policy | mifi Ventures/);

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 KiB

After

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 KiB

After

Width:  |  Height:  |  Size: 549 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 784 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 KiB

After

Width:  |  Height:  |  Size: 351 KiB