Skip to content
Open
10 changes: 10 additions & 0 deletions app/(main)/about/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { OG_SIZE, ogCard } from '../../../lib/og-image'

export const dynamic = 'force-static'
export const alt = 'Jordan Winters - Software Consultant, Minneapolis'
export const size = OG_SIZE
export const contentType = 'image/png'

export default function OpengraphImage() {
return ogCard('Jordan Winters', 'Software Consultant · Minneapolis')
}
73 changes: 73 additions & 0 deletions app/(main)/about/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { axeTest, render, screen } from 'lib/test-utils'
import { describe, expect, it } from 'vitest'
import AboutPage from './page'

describe('About Page', () => {
it('names Jordan Winters with the Minneapolis base and experience claim', () => {
render(<AboutPage />)

expect(
screen.getByRole('heading', { level: 1, name: /about jordan winters/i })
).toBeInTheDocument()
expect(screen.getByText(/live and work in minneapolis/i)).toBeInTheDocument()
expect(screen.getByText(/over a decade/i)).toBeInTheDocument()
})

it('links the public proof surfaces safely', () => {
render(<AboutPage />)

const linkedin = screen.getByRole('link', { name: /linkedin/i })
expect(linkedin).toHaveAttribute('href', 'https://www.linkedin.com/in/wintersjordan/')
const github = screen.getByRole('link', { name: /github/i })
expect(github).toHaveAttribute('href', 'https://github.com/dralgorhythm')
for (const link of [linkedin, github]) {
expect(link).toHaveAttribute('target', '_blank')
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
}
expect(screen.getByRole('link', { name: /coordinating ai coding agents/i })).toHaveAttribute(
'href',
'/blog/agent-coordination'
)
})

it('states beliefs and the solo working model', () => {
render(<AboutPage />)

expect(screen.getByRole('heading', { name: /what i believe/i })).toBeInTheDocument()
expect(screen.getByRole('heading', { name: /how i work/i })).toBeInTheDocument()
expect(screen.getByText(/solo by design/i)).toBeInTheDocument()
})

it('links all four services and the contact page from Work With Me', () => {
render(<AboutPage />)

expect(screen.getByRole('link', { name: /software consulting/i })).toHaveAttribute(
'href',
'/services/software-consulting'
)
expect(screen.getByRole('link', { name: /career coaching/i })).toHaveAttribute(
'href',
'/services/career-coaching'
)
expect(screen.getByRole('link', { name: /get in touch/i })).toHaveAttribute('href', '/contact')
})

it('has exactly one h1 and a coherent h2 set', () => {
render(<AboutPage />)

expect(screen.getAllByRole('heading', { level: 1 })).toHaveLength(1)
expect(screen.getAllByRole('heading', { level: 2 })).toHaveLength(5)
})

it('is accessible', async () => {
const { container } = render(<AboutPage />)
await axeTest(container)
})

it('has entity-page metadata', async () => {
const { metadata } = await import('./page')
expect(metadata.title).toBe('About Jordan Winters')
expect(metadata.description).toContain('Minneapolis-based software consultant')
expect(metadata.alternates?.canonical).toBe('/about')
})
})
129 changes: 129 additions & 0 deletions app/(main)/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import type { Metadata } from 'next'
import Link from 'next/link'
import type React from 'react'
import { serviceEntries } from '../../config/services'

export const metadata: Metadata = {
title: 'About Jordan Winters',
description:
'Jordan Winters is a Minneapolis-based software consultant with over a decade in engineering, infrastructure, and practice improvement. Serving the Twin Cities.',
alternates: { canonical: '/about' },
openGraph: {
title: 'Jordan Winters - Software Consultant, Minneapolis',
description:
'Over a decade in engineering, infrastructure, and practice improvement. Based in Minneapolis, serving the Twin Cities.',
type: 'profile',
},
}

export default function AboutPage(): React.JSX.Element {
return (
<section>
<h1 className='mb-4 text-2xl font-semibold tracking-tighter'>About Jordan Winters</h1>

<div className='mb-12'>
<h2 className='mb-3 text-xl font-medium tracking-tight'>Hi, I&apos;m Jordan</h2>
<p className='mb-4 text-neutral-700 dark:text-neutral-300'>
I live and work in Minneapolis, and I&apos;ve spent over a decade building software and
building the teams that build software. The short version: I led operations through an
organizational doubling at an ad-tech startup, spent five and a half years as a Staff
DevOps Engineer at NerdWallet (including steering a cloud cost journey that took over
$1.5M out of yearly spend), founded an Observability practice as an Engineering Manager at
a Fortune 500 financial services company, and took an AI-native startup from empty
repository to public beta in six months as its founding engineer. Bidwell Consulting is
where I now do that work directly for companies across the Twin Cities metro, and remotely
everywhere else.
</p>
<p className='mb-4 text-neutral-700 dark:text-neutral-300'>
You can verify most of this the same way I would:{' '}
<a
href='https://www.linkedin.com/in/wintersjordan/'
target='_blank'
rel='noopener noreferrer'
className='underline'
>
LinkedIn
</a>{' '}
for the career,{' '}
<a
href='https://github.com/dralgorhythm'
target='_blank'
rel='noopener noreferrer'
className='underline'
>
GitHub
</a>{' '}
for the code, and my essay on{' '}
<Link href='/blog/agent-coordination' className='underline'>
coordinating AI coding agents
</Link>{' '}
for how I think.
</p>
</div>

<div className='mb-12'>
<h2 className='mb-3 text-xl font-medium tracking-tight'>What I Believe</h2>
<ul className='mb-4 ml-6 list-disc space-y-2 text-neutral-700 dark:text-neutral-300'>
<li>
Customer-focused solutions are easier to deliver when following the Product Operating
Model - teams do their best work when they can run real experiments and watch the
results land with customers.
</li>
<li>
Agile practice helps teams rapidly deliver value and execute more experiments - and
speed and stability reinforce each other along the way.
</li>
<li>
Writing and owning our code, in the tradition of DevOps, helps teams build better
software - you build it, you own it, and it stays healthy after launch.
</li>
</ul>
</div>

<div className='mb-12'>
<h2 className='mb-3 text-xl font-medium tracking-tight'>How I Work</h2>
<p className='mb-4 text-neutral-700 dark:text-neutral-300'>
Solo by design - the person you meet on the discovery call designs the system, writes the
code, and answers the hard questions himself. No juniors to hand you off to.
</p>
</div>

<div className='mb-12'>
<h2 className='mb-3 text-xl font-medium tracking-tight'>Beyond Work</h2>
<p className='mb-4 text-neutral-700 dark:text-neutral-300'>
When I&apos;m not shipping software I&apos;m usually making music - you can hear what that
sounds like on{' '}
<a
href='https://soundcloud.com/dralgorhythm'
target='_blank'
rel='noopener noreferrer'
className='underline'
>
SoundCloud
</a>
. Minneapolis is home, and the coffee-meeting offer is real.
</p>
</div>

<div>
<h2 className='mb-3 text-xl font-medium tracking-tight'>Work With Me</h2>
<ul className='mb-4 ml-6 list-disc space-y-2'>
{serviceEntries.map(service => (
<li key={service.href}>
<Link href={service.href} className='underline'>
{service.title}
</Link>
</li>
))}
</ul>
<p className='text-neutral-700 dark:text-neutral-300'>
Or just{' '}
<Link href='/contact' className='underline'>
get in touch
</Link>{' '}
- the discovery call is free.
</p>
</div>
</section>
)
}
23 changes: 15 additions & 8 deletions app/(main)/blog/agent-coordination/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { siteConfig } from 'lib/site-config'
import { blogPostingSchema } from 'lib/structured-data'
import type { Metadata } from 'next'
import Link from 'next/link'
import Breadcrumb from '../../../components/breadcrumb'
import JsonLd from '../../../components/structured-data'
import { formatPostDate, agentCoordinationPost as post } from '../posts'

export const metadata: Metadata = {
title: post.title,
title: post.seoTitle,
description: post.description,
alternates: { canonical: `/blog/${post.slug}` },
openGraph: {
Expand All @@ -33,19 +34,18 @@ export default function AgentCoordinationPost() {
<h1 className='title font-semibold text-2xl tracking-tighter'>{post.title}</h1>
<div className='flex justify-between items-center mt-2 mb-8 text-sm'>
<p className='text-sm text-neutral-600 dark:text-neutral-400'>
{formatPostDate(post.publishedAt)}
<Link href='/about' className='underline'>
Jordan Winters
</Link>{' '}
· {formatPostDate(post.publishedAt)}
</p>
</div>
<article className='prose'>
<p>
In my day-job, I'm a leader of{' '}
<a
href='https://www.linkedin.com/in/wintersjordan/'
target='_blank'
rel='noopener noreferrer'
>
<Link href='/services/engineering-practice-improvement'>
Engineering Practice Improvement
</a>
</Link>
. I help teams build better software - faster. We can talk more about my feelings on all
of that soon
<a href='#fn1' id='ref1'>
Expand Down Expand Up @@ -408,6 +408,13 @@ export default function AgentCoordinationPost() {
</ol>
</div>
</article>
<p className='mt-12 pt-6 border-t border-neutral-200 dark:border-neutral-800 text-sm text-neutral-600 dark:text-neutral-400'>
I help teams put this into practice - see{' '}
<Link href='/services/ai-consulting' className='underline'>
AI &amp; agent engineering consulting
</Link>
.
</p>
</section>
)
}
10 changes: 9 additions & 1 deletion app/(main)/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { formatPostDate, posts } from './posts'

export const metadata: Metadata = {
title: 'Blog',
description: 'Updates and insights from the Bidwell Consulting team.',
description:
'Notes on software engineering, AI coding agents, and engineering practice from Jordan Winters, a software consultant in Minneapolis.',
alternates: { canonical: '/blog' },
}

Expand All @@ -29,6 +30,13 @@ export default function BlogPage() {
</Link>
))}
</div>
<p className='mt-8 text-sm text-neutral-600 dark:text-neutral-400'>
Subscribe via{' '}
<a href='/rss.xml' className='underline'>
RSS
</a>
.
</p>
</section>
)
}
8 changes: 6 additions & 2 deletions app/(main)/blog/posts.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/**
* Blog post registry the single source of truth for post metadata.
* Blog post registry - the single source of truth for post metadata.
* Pure data with no imports: app/sitemap.ts consumes this and must stay
* executable by tsx (health-check generation) outside the Next bundler.
*/
export interface Post {
slug: string
title: string
/** Search-targeted <title> when it should differ from the on-page h1. */
seoTitle: string
description: string
/** ISO date (YYYY-MM-DD) the post was first published. Never derived from build time. */
publishedAt: string
Expand All @@ -14,7 +16,9 @@ export interface Post {
export const agentCoordinationPost: Post = {
slug: 'agent-coordination',
title: 'Agent Coordination Structure',
description: 'A framework for managing AI agents within the Bidwell ecosystem.',
seoTitle: 'Coordinating AI Coding Agents',
description:
'A practical structure for coordinating AI coding agents - critical directives, artifact handoffs, and personas.',
publishedAt: '2025-11-27',
}

Expand Down
Loading
Loading