diff --git a/index.html b/index.html
index 526507d7..fbcb8a4c 100644
--- a/index.html
+++ b/index.html
@@ -75,7 +75,12 @@
"logo": "https://oullin.io/brand/logo-touch.png",
"image": "https://oullin.io/brand/logo-touch.png",
"description": "Oullin is a boutique software engineering and architecture consultancy for startups and scale-ups navigating the AI era. AI architecture, modernisation, and resilient systems for regulated and high-trust environments.",
- "sameAs": ["https://github.com/oullin"]
+ "sameAs": ["https://github.com/oullin"],
+ "founder": {
+ "@type": "Person",
+ "name": "Gustavo Ocanto",
+ "url": "https://gocanto.sh"
+ }
}
]
diff --git a/src/pages/AboutPage.vue b/src/pages/AboutPage.vue
index 3b7ed20f..cda5a660 100644
--- a/src/pages/AboutPage.vue
+++ b/src/pages/AboutPage.vue
@@ -16,7 +16,7 @@
{{ sidebar.founder.name }}
{{ sidebar.founder.copy }}
diff --git a/src/pages/WorkWithUsPage.vue b/src/pages/WorkWithUsPage.vue
index 93e24364..fedd6a53 100644
--- a/src/pages/WorkWithUsPage.vue
+++ b/src/pages/WorkWithUsPage.vue
@@ -51,8 +51,9 @@
{{ item }}
You leave with: {{ engagement.outcome }}
- {{ engagement.price }}
- {{ engagement.cta.label }}
+ {{
+ engagement.cta.label
+ }}
diff --git a/src/support/content-types.ts b/src/support/content-types.ts
index e8095757..8ce93a62 100644
--- a/src/support/content-types.ts
+++ b/src/support/content-types.ts
@@ -30,6 +30,10 @@ export interface SiteContent {
organization: {
description: string;
sameAs: string[];
+ founder: {
+ name: string;
+ url: string;
+ };
};
nav: {
links: RouteLink[];
@@ -204,7 +208,6 @@ export interface WorkWithUsPageContent {
includesLabel: string;
includes: string[];
outcome: string;
- price: string;
cta: RouteLink;
}>;
faq: {
diff --git a/src/support/seo.ts b/src/support/seo.ts
index b421664d..d3cd097e 100644
--- a/src/support/seo.ts
+++ b/src/support/seo.ts
@@ -26,6 +26,11 @@ export const ORGANIZATION_JSON_LD = {
image: siteUrlFor(SITE_LOGO),
description: siteContent.organization.description,
sameAs: siteContent.organization.sameAs,
+ founder: {
+ '@type': 'Person',
+ name: siteContent.organization.founder.name,
+ url: siteContent.organization.founder.url,
+ },
};
type TwitterCard = 'summary' | 'summary_large_image' | 'app' | 'player';
diff --git a/storage/fixtures/about-page.json b/storage/fixtures/about-page.json
index dcf32b80..f64aa203 100644
--- a/storage/fixtures/about-page.json
+++ b/storage/fixtures/about-page.json
@@ -12,8 +12,8 @@
"label": "// founder & lead architect",
"name": "Gustavo Ocanto",
"copy": "Engineering leader with 20+ years across software engineering, consulting, architecture, AI-first products and companies, and technical management. 10+ years in banking and fintech.",
- "linkLabel": "LinkedIn Profile →",
- "linkUrl": "https://www.linkedin.com/in/gocanto/"
+ "linkLabel": "Founder bio →",
+ "linkUrl": "https://gocanto.sh"
},
"proof": {
"label": "// proof",
diff --git a/storage/fixtures/site.json b/storage/fixtures/site.json
index a15012a5..a750ff38 100644
--- a/storage/fixtures/site.json
+++ b/storage/fixtures/site.json
@@ -23,7 +23,11 @@
},
"organization": {
"description": "Oullin is a boutique software engineering and architecture consultancy for startups and scale-ups navigating the AI era. AI architecture, modernisation, and resilient systems for regulated and high-trust environments.",
- "sameAs": ["https://github.com/oullin"]
+ "sameAs": ["https://github.com/oullin"],
+ "founder": {
+ "name": "Gustavo Ocanto",
+ "url": "https://gocanto.sh"
+ }
},
"nav": {
"links": [
diff --git a/storage/fixtures/work-with-us-page.json b/storage/fixtures/work-with-us-page.json
index 6b3d785a..c7039d29 100644
--- a/storage/fixtures/work-with-us-page.json
+++ b/storage/fixtures/work-with-us-page.json
@@ -39,8 +39,7 @@
"— Two 90-minute working sessions with the founding/engineering team"
],
"outcome": "A clear, honest answer to where AI fits in your stack — and an architectural plan that survives contact with production.",
- "price": "From $8,000 · Fixed fee",
- "cta": { "label": "START A CONVERSATION →", "to": "/contact" }
+ "cta": { "label": "More info", "to": "/contact" }
},
{
"label": "[ 02 ] Fractional AI Architect",
@@ -59,8 +58,7 @@
"— Quarterly roadmap refresh aligned to business goals"
],
"outcome": "Senior architectural oversight without a full-time hire. A team that gets better at building as the engagement runs.",
- "price": "From $8,000/mo · 3-month minimum",
- "cta": { "label": "START A CONVERSATION →", "to": "/contact" }
+ "cta": { "label": "More info", "to": "/contact" }
},
{
"label": "[ 03 ] Production Hardening",
@@ -79,8 +77,7 @@
"— 2-week async support window post-engagement"
],
"outcome": "AI features that hold under real conditions. Documentation your team owns. No dependency on us to keep it running.",
- "price": "From $15,000 · Scoped after a paid discovery session ($2,500)",
- "cta": { "label": "START A CONVERSATION →", "to": "/contact" }
+ "cta": { "label": "More info", "to": "/contact" }
},
{
"label": "[ 04 ] AI-Era Team Enablement",
@@ -97,8 +94,7 @@
"— A written playbook the team owns after we leave"
],
"outcome": "Engineers who can build with AI and review what it produces with real judgment. The capability stays in your team.",
- "price": "From $6,000 · 4-week programme",
- "cta": { "label": "START A CONVERSATION →", "to": "/contact" }
+ "cta": { "label": "More info", "to": "/contact" }
}
],
"faq": {
diff --git a/tests/pages/AboutPage.test.ts b/tests/pages/AboutPage.test.ts
index 380bc114..4fffe242 100644
--- a/tests/pages/AboutPage.test.ts
+++ b/tests/pages/AboutPage.test.ts
@@ -75,7 +75,9 @@ describe('AboutPage', () => {
expect(wrapper.text()).toContain(aboutPageContent.sidebar.founder.copy);
expect(wrapper.text()).toContain(aboutPageContent.sidebar.proof.items[1]);
expect(wrapper.find('[data-testid="recommendation-partial"]').text()).toContain('Recommendations partial');
- expect(wrapper.html()).toContain(aboutPageContent.sidebar.founder.linkUrl);
+ const founderLink = wrapper.find(`a[href="${aboutPageContent.sidebar.founder.linkUrl}"]`);
+ expect(founderLink.text()).toBe('Founder bio →');
+ expect(founderLink.attributes('rel')).toContain('me');
});
it('renders the about footer without the skills marquee band', async () => {
diff --git a/tests/pages/WorkWithUsPage.test.ts b/tests/pages/WorkWithUsPage.test.ts
index f8be2c3f..280e3e3e 100644
--- a/tests/pages/WorkWithUsPage.test.ts
+++ b/tests/pages/WorkWithUsPage.test.ts
@@ -22,4 +22,16 @@ describe('WorkWithUsPage', () => {
expect(wrapper.text()).toContain(workWithUsPageContent.faq.items[0].question);
expect(wrapper.text()).toContain(workWithUsPageContent.cta.button.label);
});
+
+ it('replaces engagement prices with contact links', () => {
+ const wrapper = mount(WorkWithUsPage, { global });
+ const moreInfoLinks = wrapper.findAll('a').filter((link) => link.text() === 'More info');
+
+ expect(moreInfoLinks).toHaveLength(workWithUsPageContent.engagements.length);
+ moreInfoLinks.forEach((link, index) => {
+ expect(link.attributes('to')).toBe('/contact');
+ expect(link.attributes('aria-label')).toBe(`${workWithUsPageContent.engagements[index]?.cta.label} about ${workWithUsPageContent.engagements[index]?.label}`);
+ });
+ expect(wrapper.text()).not.toMatch(/(?:[$€£]\s*\d[\d,.]*(?:[km])?|\b\d[\d,.]*(?:[km])?\s*(?:USD|EUR|GBP)\b)/i);
+ });
});
diff --git a/tests/support/seo-content.test.ts b/tests/support/seo-content.test.ts
index 3903e621..5fd9532f 100644
--- a/tests/support/seo-content.test.ts
+++ b/tests/support/seo-content.test.ts
@@ -9,6 +9,7 @@ import { siteContent } from '@/support/content.ts';
import { termsAndPoliciesPageContent } from '@/support/content/terms-and-policies-page.ts';
import { workWithUsPageContent } from '@/support/content/work-with-us-page.ts';
import { writingPageContent } from '@/support/content/writing-page.ts';
+import { ORGANIZATION_JSON_LD } from '@/support/seo.ts';
const indexHtml = readFileSync(resolve(process.cwd(), 'index.html'), 'utf8');
const staleGustavoTitle = 'Gustavo Ocanto - Engineering, Leadership, Fintech & eCommerce | Software Engineer, Architect, AI , AI Architect & Manager';
@@ -46,6 +47,21 @@ describe('SEO content fixtures', () => {
expect(writingPageContent.seo.description).toContain('engineering judgment');
expect(termsAndPoliciesPageContent.seo.description).toContain("Oullin's terms and policies");
});
+
+ it('connects the organization founder metadata to the canonical bio site', () => {
+ expect(ORGANIZATION_JSON_LD.founder).toEqual({
+ '@type': 'Person',
+ name: 'Gustavo Ocanto',
+ url: 'https://gocanto.sh',
+ });
+
+ const jsonLdMatch = indexHtml.match(/