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

@@ -4,191 +4,191 @@
*/ */
export interface LegalSection { export interface LegalSection {
id: string; id: string;
heading: string; heading: string;
body: string[]; body: string[];
list?: string[]; list?: string[];
/** Numbered sub-sections (e.g. Messaging Policy 16) */ /** Numbered sub-sections (e.g. Messaging Policy 16) */
subsections?: { title: string; body: string[]; list?: string[] }[]; subsections?: { title: string; body: string[]; list?: string[] }[];
} }
export const privacyPolicy = { export const privacyPolicy = {
title: 'Privacy Policy', title: 'Privacy Policy',
lastUpdated: 'March 5, 2026', lastUpdated: 'March 5, 2026',
intro: [ intro: [
'mifi Ventures LLC respects your privacy and is committed to protecting personal information shared through this website and related communications.', 'mifi Ventures LLC respects your privacy and is committed to protecting personal information shared through this website and related communications.',
'This policy explains what information we collect, how it is used, and how it is protected.', 'This policy explains what information we collect, how it is used, and how it is protected.',
], ],
sections: [ sections: [
{ {
id: 'information-we-collect', id: 'information-we-collect',
heading: 'Information We Collect', heading: 'Information We Collect',
body: [ body: [
'We may collect limited personal information when you interact with the website or contact us.', 'We may collect limited personal information when you interact with the website or contact us.',
'This may include:', 'This may include:',
], ],
}, },
{ {
id: 'contact-information', id: 'contact-information',
heading: 'Contact Information', heading: 'Contact Information',
body: [], body: [],
list: ['Name', 'Email address', 'Phone number'], list: ['Name', 'Email address', 'Phone number'],
}, },
{ {
id: 'communication-data', id: 'communication-data',
heading: 'Communication Data', heading: 'Communication Data',
body: [ body: [
'Information you provide when contacting us through email, contact forms, or SMS.', 'Information you provide when contacting us through email, contact forms, or SMS.',
], ],
}, },
{ {
id: 'technical-information', id: 'technical-information',
heading: 'Technical Information', heading: 'Technical Information',
body: [ body: [
'Basic technical information collected through analytics or server logs, such as:', 'Basic technical information collected through analytics or server logs, such as:',
], ],
list: ['IP address', 'Browser type', 'Pages visited', 'Device type'], list: ['IP address', 'Browser type', 'Pages visited', 'Device type'],
}, },
{ {
id: 'technical-information-use', id: 'technical-information-use',
heading: 'Use of technical information', heading: 'Use of technical information',
body: [ body: [
'This information is used only to maintain the website, improve performance, and monitor security.', 'This information is used only to maintain the website, improve performance, and monitor security.',
], ],
}, },
{ {
id: 'how-we-use', id: 'how-we-use',
heading: 'How We Use Information', heading: 'How We Use Information',
body: ['Information collected may be used to:'], body: ['Information collected may be used to:'],
list: [ list: [
'Respond to inquiries', 'Respond to inquiries',
'Provide consulting or development services', 'Provide consulting or development services',
'Communicate with clients', 'Communicate with clients',
'Improve website functionality', 'Improve website functionality',
'Maintain security and prevent abuse', 'Maintain security and prevent abuse',
], ],
}, },
{ {
id: 'messaging-policy', id: 'messaging-policy',
heading: 'Messaging Policy (SMS)', heading: 'Messaging Policy (SMS)',
body: [ body: [
'mifi Ventures uses SMS messages only for direct, conversational communication with clients or prospective clients.', 'mifi Ventures uses SMS messages only for direct, conversational communication with clients or prospective clients.',
], ],
subsections: [ subsections: [
{ {
title: 'Purpose', title: 'Purpose',
body: ['SMS may be used for:'], body: ['SMS may be used for:'],
list: [ list: [
'Responding to inbound inquiries', 'Responding to inbound inquiries',
'Scheduling and appointment coordination', 'Scheduling and appointment coordination',
'Project and service-related communication', 'Project and service-related communication',
'Status updates and time-sensitive notifications requested by the client', 'Status updates and time-sensitive notifications requested by the client',
], ],
}, },
{ {
title: 'No Marketing / No Sale of Data', title: 'No Marketing / No Sale of Data',
body: [ body: [
'We do not send unsolicited marketing text messages. We do not sell, rent, or share phone numbers for marketing purposes.', 'We do not send unsolicited marketing text messages. We do not sell, rent, or share phone numbers for marketing purposes.',
], ],
}, },
{ {
title: 'Consent', title: 'Consent',
body: [ body: [
'You provide consent by initiating contact with us, requesting communication by text, and/or providing your phone number for communication related to your inquiry or services.', 'You provide consent by initiating contact with us, requesting communication by text, and/or providing your phone number for communication related to your inquiry or services.',
], ],
}, },
{ {
title: 'Opt-Out', title: 'Opt-Out',
body: [ body: [
'You may opt out at any time by replying STOP. After opting out, you will no longer receive SMS messages unless you re-initiate contact.', 'You may opt out at any time by replying STOP. After opting out, you will no longer receive SMS messages unless you re-initiate contact.',
], ],
}, },
{ {
title: 'Message Frequency and Rates', title: 'Message Frequency and Rates',
body: [ body: [
'Message frequency varies depending on the nature of the communication. Standard message and data rates may apply depending on your mobile carrier.', 'Message frequency varies depending on the nature of the communication. Standard message and data rates may apply depending on your mobile carrier.',
], ],
}, },
{ {
title: 'Support', title: 'Support',
body: ['For support, contact: contact@mifi.ventures'], body: ['For support, contact: contact@mifi.ventures'],
}, },
], ],
}, },
{ {
id: 'sms-phone-communications', id: 'sms-phone-communications',
heading: 'SMS and Phone Communications', heading: 'SMS and Phone Communications',
body: [ body: [
'If you provide a phone number when contacting us, we may respond via phone call or SMS.', 'If you provide a phone number when contacting us, we may respond via phone call or SMS.',
'SMS messages are used only for direct communication with clients or prospective clients, including scheduling, service communication, or responses to inquiries.', 'SMS messages are used only for direct communication with clients or prospective clients, including scheduling, service communication, or responses to inquiries.',
'We do not send unsolicited marketing messages.', 'We do not send unsolicited marketing messages.',
'You may opt out of SMS communication at any time by replying STOP.', 'You may opt out of SMS communication at any time by replying STOP.',
], ],
}, },
{ {
id: 'data-security', id: 'data-security',
heading: 'Data Security', heading: 'Data Security',
body: [ body: [
'mifi Ventures implements reasonable administrative and technical safeguards to protect personal information.', 'mifi Ventures implements reasonable administrative and technical safeguards to protect personal information.',
'Security measures may include:', 'Security measures may include:',
], ],
list: [ list: [
'Encrypted website connections (HTTPS)', 'Encrypted website connections (HTTPS)',
'Secure hosting infrastructure', 'Secure hosting infrastructure',
'Restricted access to internal systems', 'Restricted access to internal systems',
], ],
}, },
{ {
id: 'data-security-note', id: 'data-security-note',
heading: 'Security limitations', heading: 'Security limitations',
body: [ body: [
'While we take reasonable precautions, no online system can guarantee absolute security.', 'While we take reasonable precautions, no online system can guarantee absolute security.',
], ],
}, },
{ {
id: 'data-sharing', id: 'data-sharing',
heading: 'Data Sharing', heading: 'Data Sharing',
body: [ body: [
'mifi Ventures does not sell, rent, or trade personal information.', 'mifi Ventures does not sell, rent, or trade personal information.',
'Information may be shared only when necessary with trusted service providers that support the operation of the website or business services. These providers are required to protect the confidentiality of the data they process.', 'Information may be shared only when necessary with trusted service providers that support the operation of the website or business services. These providers are required to protect the confidentiality of the data they process.',
], ],
}, },
{ {
id: 'data-retention', id: 'data-retention',
heading: 'Data Retention', heading: 'Data Retention',
body: [ body: [
'Personal information is retained only for as long as necessary to fulfill communication, operational, or legal obligations.', 'Personal information is retained only for as long as necessary to fulfill communication, operational, or legal obligations.',
], ],
}, },
{ {
id: 'your-rights', id: 'your-rights',
heading: 'Your Rights', heading: 'Your Rights',
body: [ body: [
'Depending on your jurisdiction, you may have the right to: request access to personal data; request correction or deletion of data; withdraw consent for communications.', 'Depending on your jurisdiction, you may have the right to: request access to personal data; request correction or deletion of data; withdraw consent for communications.',
'Requests may be submitted using the contact information below.', 'Requests may be submitted using the contact information below.',
], ],
list: [ list: [
'Request access to personal data', 'Request access to personal data',
'Request correction or deletion of data', 'Request correction or deletion of data',
'Withdraw consent for communications', 'Withdraw consent for communications',
], ],
}, },
{ {
id: 'policy-updates', id: 'policy-updates',
heading: 'Policy Updates', heading: 'Policy Updates',
body: [ body: [
'This Privacy Policy may be updated periodically to reflect operational or legal changes. The updated date will appear at the top of the page.', 'This Privacy Policy may be updated periodically to reflect operational or legal changes. The updated date will appear at the top of the page.',
], ],
}, },
{ {
id: 'contact', id: 'contact',
heading: 'Contact', heading: 'Contact',
body: [ body: [
'Questions regarding this Privacy Policy may be directed to:', 'Questions regarding this Privacy Policy may be directed to:',
'mifi Ventures LLC', 'mifi Ventures LLC',
'legal@mifi.ventures', 'legal@mifi.ventures',
'https://mifi.ventures', 'https://mifi.ventures',
], ],
}, },
] as LegalSection[], ] as LegalSection[],
}; };

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

@@ -4,96 +4,96 @@
*/ */
export interface LegalSection { export interface LegalSection {
id: string; id: string;
heading: string; heading: string;
body: string[]; body: string[];
list?: string[]; list?: string[];
} }
export const termsOfService = { export const termsOfService = {
title: 'Terms of Service', title: 'Terms of Service',
lastUpdated: 'March 5, 2026', lastUpdated: 'March 5, 2026',
intro: [ intro: [
'These Terms of Service govern the use of the website operated by mifi Ventures LLC ("mifi Ventures", "we", "our", or "us").', 'These Terms of Service govern the use of the website operated by mifi Ventures LLC ("mifi Ventures", "we", "our", or "us").',
'By accessing or using this website, you agree to these terms. If you do not agree, you should not use this website.', 'By accessing or using this website, you agree to these terms. If you do not agree, you should not use this website.',
], ],
sections: [ sections: [
{ {
id: 'services', id: 'services',
heading: 'Services', heading: 'Services',
body: [ body: [
'mifi Ventures provides consulting, software development, technical architecture, and related professional services. The information presented on this website is for informational purposes and may be updated or modified at any time.', 'mifi Ventures provides consulting, software development, technical architecture, and related professional services. The information presented on this website is for informational purposes and may be updated or modified at any time.',
'Use of the website does not create a client relationship unless explicitly established through a written agreement.', 'Use of the website does not create a client relationship unless explicitly established through a written agreement.',
], ],
}, },
{ {
id: 'client-communications', id: 'client-communications',
heading: 'Client Communications', heading: 'Client Communications',
body: [ body: [
'If you contact mifi Ventures through this website, email, phone, or other communication channels, you consent to receiving responses related to your inquiry.', 'If you contact mifi Ventures through this website, email, phone, or other communication channels, you consent to receiving responses related to your inquiry.',
'These communications may include:', 'These communications may include:',
], ],
list: ['Email', 'Phone calls', 'SMS or text messages'], list: ['Email', 'Phone calls', 'SMS or text messages'],
}, },
{ {
id: 'client-communications-sms', id: 'client-communications-sms',
heading: 'SMS and text messages', heading: 'SMS and text messages',
body: [ body: [
'SMS messages are used solely for direct communication with clients or prospective clients. These may include scheduling messages, project communications, or responses to inquiries.', 'SMS messages are used solely for direct communication with clients or prospective clients. These may include scheduling messages, project communications, or responses to inquiries.',
'mifi Ventures does not send unsolicited marketing text messages and does not sell or share phone numbers for marketing purposes.', 'mifi Ventures does not send unsolicited marketing text messages and does not sell or share phone numbers for marketing purposes.',
'Message frequency varies depending on the nature of the communication. Standard messaging and data rates may apply depending on your mobile carrier.', 'Message frequency varies depending on the nature of the communication. Standard messaging and data rates may apply depending on your mobile carrier.',
'You may opt out of SMS communications at any time by replying STOP.', 'You may opt out of SMS communications at any time by replying STOP.',
], ],
}, },
{ {
id: 'acceptable-use', id: 'acceptable-use',
heading: 'Acceptable Use', heading: 'Acceptable Use',
body: ['Users of this website agree not to:'], body: ['Users of this website agree not to:'],
list: [ list: [
'Use the website for unlawful purposes', 'Use the website for unlawful purposes',
'Attempt to gain unauthorized access to systems or data', 'Attempt to gain unauthorized access to systems or data',
'Interfere with the operation or security of the website', 'Interfere with the operation or security of the website',
'Use automated tools to scrape or harvest data from the site', 'Use automated tools to scrape or harvest data from the site',
], ],
}, },
{ {
id: 'intellectual-property', id: 'intellectual-property',
heading: 'Intellectual Property', heading: 'Intellectual Property',
body: [ body: [
'All content on this website, including text, graphics, branding, and software, is the property of mifi Ventures LLC unless otherwise stated.', 'All content on this website, including text, graphics, branding, and software, is the property of mifi Ventures LLC unless otherwise stated.',
'Content may not be reproduced, distributed, or reused without written permission.', 'Content may not be reproduced, distributed, or reused without written permission.',
], ],
}, },
{ {
id: 'third-party-services', id: 'third-party-services',
heading: 'Third-Party Services', heading: 'Third-Party Services',
body: [ body: [
'This website may reference or integrate with third-party platforms or services. mifi Ventures is not responsible for the privacy practices or content of external services.', 'This website may reference or integrate with third-party platforms or services. mifi Ventures is not responsible for the privacy practices or content of external services.',
], ],
}, },
{ {
id: 'limitation-of-liability', id: 'limitation-of-liability',
heading: 'Limitation of Liability', heading: 'Limitation of Liability',
body: [ body: [
'To the fullest extent permitted by law, mifi Ventures LLC shall not be liable for indirect, incidental, or consequential damages arising from use of this website or related services.', 'To the fullest extent permitted by law, mifi Ventures LLC shall not be liable for indirect, incidental, or consequential damages arising from use of this website or related services.',
], ],
}, },
{ {
id: 'changes', id: 'changes',
heading: 'Changes to These Terms', heading: 'Changes to These Terms',
body: [ body: [
'These Terms of Service may be updated periodically. Continued use of the website after updates indicates acceptance of the revised terms.', 'These Terms of Service may be updated periodically. Continued use of the website after updates indicates acceptance of the revised terms.',
], ],
}, },
{ {
id: 'contact', id: 'contact',
heading: 'Contact', heading: 'Contact',
body: [ body: [
'Questions regarding these Terms of Service may be directed to:', 'Questions regarding these Terms of Service may be directed to:',
'mifi Ventures LLC', 'mifi Ventures LLC',
'legal@mifi.ventures', 'legal@mifi.ventures',
'https://mifi.ventures', 'https://mifi.ventures',
], ],
}, },
] satisfies LegalSection[], ] satisfies LegalSection[],
} as const; } as const;

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

@@ -1,165 +1,171 @@
<script lang="ts"> <script lang="ts">
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" />
<main id="main" class="legal-page"> <main id="main" class="legal-page">
<div class="container container--narrow"> <div class="container container--narrow">
<header id="header" class="legal-header"> <header id="header" class="legal-header">
<h1>{privacyPolicy.title}</h1> <h1>{privacyPolicy.title}</h1>
<p class="legal-last-updated">Last updated: {privacyPolicy.lastUpdated}</p> <p class="legal-last-updated">Last updated: {privacyPolicy.lastUpdated}</p>
</header> </header>
<div class="legal-content"> <div class="legal-content">
{#each privacyPolicy.intro as para} {#each privacyPolicy.intro as para}
<p>{para}</p> <p>{para}</p>
{/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
<h2 id={`${section.id}-heading`}>{section.heading}</h2> id={section.id}
{#each section.body as para} class="legal-section"
<p> aria-labelledby={`${section.id}-heading`}
{#if section.id === 'contact' && para === 'legal@mifi.ventures'} >
<a href="mailto:legal@mifi.ventures">legal@mifi.ventures</a> <h2 id={`${section.id}-heading`}>{section.heading}</h2>
{:else if section.id === 'contact' && para === 'https://mifi.ventures'} {#each section.body as para}
<a href="https://mifi.ventures" rel="noopener noreferrer">https://mifi.ventures</a> <p>
{:else} {#if section.id === 'contact' && para === 'legal@mifi.ventures'}
{para} <a href="mailto:legal@mifi.ventures"
{/if} >legal@mifi.ventures</a
</p> >
{/each} {:else if section.id === 'contact' && para === 'https://mifi.ventures'}
{#if section.list} <a href="https://mifi.ventures" rel="noopener noreferrer"
<ul> >https://mifi.ventures</a
{#each section.list as item} >
<li>{item}</li> {:else}
{/each} {para}
</ul> {/if}
{/if} </p>
{#if section.subsections} {/each}
{#each section.subsections as sub (sub.title)} {#if section.list}
<div class="legal-subsection"> <ul>
<h3>{sub.title}</h3> {#each section.list as item}
{#each sub.body as para} <li>{item}</li>
<p>{para}</p> {/each}
{/each} </ul>
{#if sub.list} {/if}
<ul> {#if section.subsections}
{#each sub.list as item} {#each section.subsections as sub (sub.title)}
<li>{item}</li> <div class="legal-subsection">
{/each} <h3>{sub.title}</h3>
</ul> {#each sub.body as para}
{/if} <p>{para}</p>
</div> {/each}
{/each} {#if sub.list}
{/if} <ul>
</section> {#each sub.list as item}
{/each} <li>{item}</li>
</div> {/each}
</ul>
{/if}
</div>
{/each}
{/if}
</section>
{/each}
</div>
<nav class="legal-cross-links" aria-label="Related legal pages"> <nav class="legal-cross-links" aria-label="Related legal pages">
<a href="/terms-of-service">Terms of Service</a> <a href="/terms-of-service">Terms of Service</a>
</nav> </nav>
</div> </div>
</main> </main>
<style> <style>
.legal-page { .legal-page {
padding: var(--space-xxl) 0; padding: var(--space-xxl) 0;
background-color: var(--color-bg); background-color: var(--color-bg);
} }
.container--narrow { .container--narrow {
max-width: var(--max-narrow-width); max-width: var(--max-narrow-width);
margin: 0 auto; margin: 0 auto;
padding: 0 var(--space-md); padding: 0 var(--space-md);
} }
.legal-header { .legal-header {
margin-bottom: var(--space-xl); margin-bottom: var(--space-xl);
} }
.legal-header h1 { .legal-header h1 {
font-family: var(--font-family-heading); font-family: var(--font-family-heading);
font-size: var(--font-size-xxl); font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading); line-height: var(--line-height-heading);
color: var(--color-text); color: var(--color-text);
margin: 0 0 var(--space-sm) 0; margin: 0 0 var(--space-sm) 0;
} }
.legal-last-updated { .legal-last-updated {
font-size: var(--font-size-medium); font-size: var(--font-size-medium);
color: var(--color-text-tertiary); color: var(--color-text-tertiary);
margin: 0; margin: 0;
} }
.legal-content { .legal-content {
font-size: var(--font-size-base); font-size: var(--font-size-base);
line-height: var(--line-height-base); line-height: var(--line-height-base);
color: var(--color-text); color: var(--color-text);
} }
.legal-content p { .legal-content p {
margin: 0 0 var(--space-md) 0; margin: 0 0 var(--space-md) 0;
} }
.legal-section { .legal-section {
margin-bottom: var(--space-xl); margin-bottom: var(--space-xl);
} }
.legal-section h2 { .legal-section h2 {
font-family: var(--font-family-heading); font-family: var(--font-family-heading);
font-size: var(--font-size-xl); font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold);
line-height: var(--line-height-tight); line-height: var(--line-height-tight);
color: var(--color-text); color: var(--color-text);
margin: 0 0 var(--space-md) 0; margin: 0 0 var(--space-md) 0;
} }
.legal-subsection { .legal-subsection {
margin-top: var(--space-lg); margin-top: var(--space-lg);
} }
.legal-subsection h3 { .legal-subsection h3 {
font-family: var(--font-family-heading); font-family: var(--font-family-heading);
font-size: var(--font-size-large); font-size: var(--font-size-large);
font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold);
line-height: var(--line-height-tight); line-height: var(--line-height-tight);
color: var(--color-text); color: var(--color-text);
margin: 0 0 var(--space-sm) 0; margin: 0 0 var(--space-sm) 0;
} }
.legal-section ul, .legal-section ul,
.legal-subsection ul { .legal-subsection ul {
margin: 0 0 var(--space-md) 0; margin: 0 0 var(--space-md) 0;
padding-left: var(--space-lg); padding-left: var(--space-lg);
} }
.legal-section li, .legal-section li,
.legal-subsection li { .legal-subsection li {
margin-bottom: var(--space-xs); margin-bottom: var(--space-xs);
} }
.legal-cross-links { .legal-cross-links {
margin-top: var(--space-xxl); margin-top: var(--space-xxl);
padding-top: var(--space-xl); padding-top: var(--space-xl);
border-top: 1px solid var(--color-border); border-top: 1px solid var(--color-border);
} }
.legal-cross-links a { .legal-cross-links a {
color: var(--color-primary); color: var(--color-primary);
text-decoration: underline; text-decoration: underline;
text-underline-offset: 0.2em; text-underline-offset: 0.2em;
} }
.legal-cross-links a:hover { .legal-cross-links a:hover {
color: var(--color-primary-hover); color: var(--color-primary-hover);
} }
</style> </style>

View File

@@ -6,23 +6,23 @@ const PATH = '/privacy-policy';
const PAGE_URL = `${BASE}${PATH}`; const PAGE_URL = `${BASE}${PATH}`;
const privacyPageMeta: PageMeta = { const privacyPageMeta: PageMeta = {
title: 'Privacy Policy | mifi Ventures', title: 'Privacy Policy | mifi Ventures',
description: description:
'Privacy Policy for mifi Ventures LLC. Describes information we collect, how we use it, messaging policy (SMS), data security, and your rights. Last updated March 5, 2026.', 'Privacy Policy for mifi Ventures LLC. Describes information we collect, how we use it, messaging policy (SMS), data security, and your rights. Last updated March 5, 2026.',
canonical: PAGE_URL, canonical: PAGE_URL,
jsonLd: [ jsonLd: [
{ {
'@type': 'WebPage', '@type': 'WebPage',
'@id': `${PAGE_URL}#webpage`, '@id': `${PAGE_URL}#webpage`,
name: 'Privacy Policy | mifi Ventures', name: 'Privacy Policy | mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
dateModified: '2026-03-05', dateModified: '2026-03-05',
publisher: { '@id': `${BASE}/#organization` }, publisher: { '@id': `${BASE}/#organization` },
inLanguage: 'en-US', inLanguage: 'en-US',
}, },
], ],
}; };
export const load: PageLoad = () => { export const load: PageLoad = () => {
return { meta: privacyPageMeta }; return { meta: privacyPageMeta };
}; };

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 {/each}
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> </div>
</section> </section>
<section id="services-grid" class="section services-grid-section" aria-labelledby="services-heading"> <ServicesCardGrid services={pageContent.services} />
<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}
</ul>
</div>
</section>
<section id="how-engagements-work" class="section" aria-labelledby="engagements-heading"> <EngagementsDl
<div class="container container--narrow"> items={pageContent.engagements}
<h2 id="engagements-heading">How engagements work</h2> intro={pageContent.engagementsIntro}
<p>Most engagements fall into one of three patterns:</p> outro={pageContent.engagementsOutro}
<dl class="engagements-list"> />
<dt>Architecture engagements</dt>
<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,35 +1,34 @@
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 = {
title: 'SaaS Architecture Consulting 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.',
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
description:
'SaaS architecture consulting for early-stage teams: hands-on product architecture, MVP launch support, fractional CTO, and stage-aligned infrastructure strategy.',
serviceType: [
'SaaS Architecture Consulting',
'MVP Development Consulting',
'Fractional CTO Services',
'Startup Infrastructure Strategy',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
],
};
export const load: PageLoad = () => { export const load: PageLoad = () => {
const { meta } = pageContent;
const servicePageMeta: PageMeta = {
title: meta.title,
description: meta.description,
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
description: meta.jsonLdServiceDescription ?? meta.description,
serviceType: [
'SaaS Architecture Consulting',
'MVP Development Consulting',
'Fractional CTO Services',
'Startup Infrastructure Strategy',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
],
};
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,31 +22,29 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = {
title: 'Fractional CTO for Early-Stage SaaS | Hands-On Technical Leadership',
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.',
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/fractional-cto-for-early-stage-saas/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
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: [
'Fractional CTO',
'Technical Leadership',
'SaaS Engineering Consulting',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
export const load: PageLoad = () => { export const load: PageLoad = () => {
const { meta } = pageContent;
const servicePageMeta: PageMeta = {
title: meta.title,
description: meta.description,
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/fractional-cto-for-early-stage-saas/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
description: meta.jsonLdServiceDescription ?? meta.description,
serviceType: [
'Fractional CTO',
'Technical Leadership',
'SaaS Engineering Consulting',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
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" {/each}
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"> <WhoGrid {...pageContent.who} />
<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"> <FAQ faqList={faqItems} />
<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"> <ScheduleSection {...pageContent.scheduleCta} />
<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}
</dl>
</div>
</section>
<ScheduleSection
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
/>
</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,31 +22,29 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = {
title: 'Hands-On SaaS Architecture Consultant | Frontend Systems That Scale',
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.',
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/hands-on-saas-architecture-consultant/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
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: [
'Product Architecture',
'SaaS Engineering Consulting',
'Frontend Systems Architecture',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
export const load: PageLoad = () => { export const load: PageLoad = () => {
const { meta } = pageContent;
const servicePageMeta: PageMeta = {
title: meta.title,
description: meta.description,
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/hands-on-saas-architecture-consultant/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
description: meta.jsonLdServiceDescription ?? meta.description,
serviceType: [
'Product Architecture',
'SaaS Engineering Consulting',
'Frontend Systems Architecture',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
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"> {/each}
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"> <WhoGrid {...pageContent.who} />
<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"> <FAQ faqList={faqItems} />
<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"> <ScheduleSection {...pageContent.scheduleCta} />
<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}
</dl>
</div>
</section>
<ScheduleSection
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
/>
</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,31 +22,29 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = {
title: 'MVP Architecture Consultant | Ship Fast Without Structural Debt',
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.',
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/mvp-architecture-and-launch/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
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: [
'MVP Architecture',
'SaaS Engineering Consulting',
'Product Architecture',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
export const load: PageLoad = () => { export const load: PageLoad = () => {
const { meta } = pageContent;
const servicePageMeta: PageMeta = {
title: meta.title,
description: meta.description,
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/mvp-architecture-and-launch/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
description: meta.jsonLdServiceDescription ?? meta.description,
serviceType: [
'MVP Architecture',
'SaaS Engineering Consulting',
'Product Architecture',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
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"> {/each}
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"> <WhoGrid {...pageContent.who} />
<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"> <FAQ faqList={faqItems} />
<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"> <ScheduleSection {...pageContent.scheduleCta} />
<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}
</dl>
</div>
</section>
<ScheduleSection
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}-sechedule_section`}
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,31 +22,29 @@ function buildFaqPageJsonLd(): Record<string, unknown> {
}; };
} }
const servicePageMeta: PageMeta = {
title: 'Stage-Aligned Infrastructure for Startups | Practical SaaS Infrastructure Strategy',
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.",
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/stage-aligned-infrastructure/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
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: [
'SaaS Architecture Consulting',
'Startup Infrastructure Strategy',
'Technical Leadership Consulting',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
export const load: PageLoad = () => { export const load: PageLoad = () => {
const { meta } = pageContent;
const servicePageMeta: PageMeta = {
title: meta.title,
description: meta.description,
jsonLd: [
...defaultJsonLdGraph,
{
'@type': 'ProfessionalService',
'@id': `${BASE}/services/stage-aligned-infrastructure/#service`,
name: 'mifi Ventures',
url: PAGE_URL,
description: meta.jsonLdServiceDescription ?? meta.description,
serviceType: [
'SaaS Architecture Consulting',
'Startup Infrastructure Strategy',
'Technical Leadership Consulting',
],
provider: { '@id': `${BASE}/#organization` },
areaServed: { '@type': 'Country', name: 'United States' },
},
buildFaqPageJsonLd(),
],
};
return { meta: servicePageMeta }; return { meta: servicePageMeta };
}; };

View File

@@ -1,133 +1,139 @@
<script lang="ts"> <script lang="ts">
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" />
<main id="main" class="legal-page"> <main id="main" class="legal-page">
<div class="container container--narrow"> <div class="container container--narrow">
<header id="header" class="legal-header"> <header id="header" class="legal-header">
<h1>{termsOfService.title}</h1> <h1>{termsOfService.title}</h1>
<p class="legal-last-updated">Last updated: {termsOfService.lastUpdated}</p> <p class="legal-last-updated">Last updated: {termsOfService.lastUpdated}</p>
</header> </header>
<div class="legal-content"> <div class="legal-content">
{#each termsOfService.intro as para} {#each termsOfService.intro as para}
<p>{para}</p> <p>{para}</p>
{/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
<h2 id={`${section.id}-heading`}>{section.heading}</h2> id={section.id}
{#each section.body as para} class="legal-section"
<p> aria-labelledby={`${section.id}-heading`}
{#if section.id === 'contact' && para === 'legal@mifi.ventures'} >
<a href="mailto:legal@mifi.ventures">legal@mifi.ventures</a> <h2 id={`${section.id}-heading`}>{section.heading}</h2>
{:else if section.id === 'contact' && para === 'https://mifi.ventures'} {#each section.body as para}
<a href="https://mifi.ventures" rel="noopener noreferrer">https://mifi.ventures</a> <p>
{:else} {#if section.id === 'contact' && para === 'legal@mifi.ventures'}
{para} <a href="mailto:legal@mifi.ventures"
{/if} >legal@mifi.ventures</a
</p> >
{/each} {:else if section.id === 'contact' && para === 'https://mifi.ventures'}
{#if section.list} <a href="https://mifi.ventures" rel="noopener noreferrer"
<ul> >https://mifi.ventures</a
{#each section.list as item} >
<li>{item}</li> {:else}
{/each} {para}
</ul> {/if}
{/if} </p>
</section> {/each}
{/each} {#if section.list}
</div> <ul>
{#each section.list as item}
<li>{item}</li>
{/each}
</ul>
{/if}
</section>
{/each}
</div>
<nav class="legal-cross-links" aria-label="Related legal pages"> <nav class="legal-cross-links" aria-label="Related legal pages">
<a href="/privacy-policy">Privacy Policy</a> <a href="/privacy-policy">Privacy Policy</a>
</nav> </nav>
</div> </div>
</main> </main>
<style> <style>
.legal-page { .legal-page {
padding: var(--space-xxl) 0; padding: var(--space-xxl) 0;
background-color: var(--color-bg); background-color: var(--color-bg);
} }
.container--narrow { .container--narrow {
max-width: var(--max-narrow-width); max-width: var(--max-narrow-width);
margin: 0 auto; margin: 0 auto;
padding: 0 var(--space-md); padding: 0 var(--space-md);
} }
.legal-header { .legal-header {
margin-bottom: var(--space-xl); margin-bottom: var(--space-xl);
} }
.legal-header h1 { .legal-header h1 {
font-family: var(--font-family-heading); font-family: var(--font-family-heading);
font-size: var(--font-size-xxl); font-size: var(--font-size-xxl);
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading); line-height: var(--line-height-heading);
color: var(--color-text); color: var(--color-text);
margin: 0 0 var(--space-sm) 0; margin: 0 0 var(--space-sm) 0;
} }
.legal-last-updated { .legal-last-updated {
font-size: var(--font-size-medium); font-size: var(--font-size-medium);
color: var(--color-text-tertiary); color: var(--color-text-tertiary);
margin: 0; margin: 0;
} }
.legal-content { .legal-content {
font-size: var(--font-size-base); font-size: var(--font-size-base);
line-height: var(--line-height-base); line-height: var(--line-height-base);
color: var(--color-text); color: var(--color-text);
} }
.legal-content p { .legal-content p {
margin: 0 0 var(--space-md) 0; margin: 0 0 var(--space-md) 0;
} }
.legal-section { .legal-section {
margin-bottom: var(--space-xl); margin-bottom: var(--space-xl);
} }
.legal-section h2 { .legal-section h2 {
font-family: var(--font-family-heading); font-family: var(--font-family-heading);
font-size: var(--font-size-xl); font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold);
line-height: var(--line-height-tight); line-height: var(--line-height-tight);
color: var(--color-text); color: var(--color-text);
margin: 0 0 var(--space-md) 0; margin: 0 0 var(--space-md) 0;
} }
.legal-section ul { .legal-section ul {
margin: 0 0 var(--space-md) 0; margin: 0 0 var(--space-md) 0;
padding-left: var(--space-lg); padding-left: var(--space-lg);
} }
.legal-section li { .legal-section li {
margin-bottom: var(--space-xs); margin-bottom: var(--space-xs);
} }
.legal-cross-links { .legal-cross-links {
margin-top: var(--space-xxl); margin-top: var(--space-xxl);
padding-top: var(--space-xl); padding-top: var(--space-xl);
border-top: 1px solid var(--color-border); border-top: 1px solid var(--color-border);
} }
.legal-cross-links a { .legal-cross-links a {
color: var(--color-primary); color: var(--color-primary);
text-decoration: underline; text-decoration: underline;
text-underline-offset: 0.2em; text-underline-offset: 0.2em;
} }
.legal-cross-links a:hover { .legal-cross-links a:hover {
color: var(--color-primary-hover); color: var(--color-primary-hover);
} }
</style> </style>

View File

@@ -6,23 +6,23 @@ const PATH = '/terms-of-service';
const PAGE_URL = `${BASE}${PATH}`; const PAGE_URL = `${BASE}${PATH}`;
const termsPageMeta: PageMeta = { const termsPageMeta: PageMeta = {
title: 'Terms of Service | mifi Ventures', title: 'Terms of Service | mifi Ventures',
description: description:
'Terms of Service for mifi Ventures LLC. Covers use of the website, services, client communications including SMS, acceptable use, and contact information.', 'Terms of Service for mifi Ventures LLC. Covers use of the website, services, client communications including SMS, acceptable use, and contact information.',
canonical: PAGE_URL, canonical: PAGE_URL,
jsonLd: [ jsonLd: [
{ {
'@type': 'WebPage', '@type': 'WebPage',
'@id': `${PAGE_URL}#webpage`, '@id': `${PAGE_URL}#webpage`,
name: 'Terms of Service | mifi Ventures', name: 'Terms of Service | mifi Ventures',
url: PAGE_URL, url: PAGE_URL,
dateModified: '2026-03-05', dateModified: '2026-03-05',
publisher: { '@id': `${BASE}/#organization` }, publisher: { '@id': `${BASE}/#organization` },
inLanguage: 'en-US', inLanguage: 'en-US',
}, },
], ],
}; };
export const load: PageLoad = () => { export const load: PageLoad = () => {
return { meta: termsPageMeta }; return { meta: termsPageMeta };
}; };

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