Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Sep 26, 2025

Summary

  • extend the SEO client and sections to cover social links, recommendations, experience, and education content
  • generate standalone SEO templates for the about, projects, and resume pages using the shared builder helpers
  • expose fixture helpers for additional data sets and expand test coverage for the new renderers

Testing

  • go test ./...

https://chatgpt.com/codex/tasks/task_e_68d654e275688333b138e642b49386ac

Summary by CodeRabbit

  • New Features

    • Generates additional SEO pages in one run: About, Projects, Resume, Posts (including individual post pages).
    • Renders new sections: Social, Recommendations, Experience, Education, and full Post content.
  • Improvements

    • Enhanced project listings with linked titles and structured details.
    • Consistent per-page metadata (titles, canonical URLs) and safer content sanitization, preserving allowed line breaks for rendered output.

@coderabbitai
Copy link

coderabbitai bot commented Sep 26, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a generic fetch helper and new Client getters (social, recommendations, experience, education); extends Generator to orchestrate About/Projects/Resume/Posts pages with per-page build helpers; implements rendering for posts and new sections; updates fixtures, defaults, manifest, portal utilities, and tests.

Changes

Cohort / File(s) Summary
SEO client updates
metal/cli/seo/client.go
Introduces generic get[T] helper; refactors GetTalks, GetProfile, GetProjects to use it; adds GetSocial, GetRecommendations, GetExperience, GetEducation.
Client tests
metal/cli/seo/client_test.go
Extends TestClientLoadsFixtures to call/assert new client methods: Social, Recommendations, Experience, Education.
Generator orchestration & builders
metal/cli/seo/generator.go
Replaces GenerateIndex() with Generate(); adds GenerateAbout, GenerateProjects, GenerateResume, GeneratePosts; adds buildForPage, BuildForPost, canonical/title helpers, sanitizers, and per-page data adjustments; updates export/path logic and logging.
Generator tests
metal/cli/seo/generator_test.go
Renamed to TestGeneratorGenerateAllPages; seeds richer fixtures (user, post, tag, category); calls Generate() and validates generated about, projects, resume, index and per-post SEO pages including escaping.
Sections rendering
metal/cli/seo/sections.go
Adds renderers: Post, Social, Recommendations, Experience, Education; adds FormatPostContent, FormatDetails; nil guards for Profile/Skills/Talks; enhances Projects rendering and sanitization.
Sections tests
metal/cli/seo/sections_test.go
Adds test data and assertions for Social, Recommendations, Experience, Education, and Post rendering; adds TestSectionsGuardNilInputs.
Router fixture accessors
metal/router/fixture.go
Adds GetSocialFile, GetEducationFile, GetExperienceFile, GetRecommendationsFile to expose fixture file paths.
Defaults & manifest
metal/cli/seo/defaults.go, metal/cli/seo/manifest.go
Adds WebPostsName and WebPostsUrl; inserts a "Posts" shortcut into generated manifest.
Test helpers / seeding
metal/cli/seo/testhelpers_test.go
Adds seedTag, seedUser, seedPost; changes seedCategory to return created database.Category; uses repository to seed posts.
Portal utilities
pkg/portal/support.go
Adds AllowLineBreaks, FilterNonEmpty, SanitiseURL and imports html/template for sanitization/formatting used by sections.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant CLI as CLI (caller)
  participant Gen as Generator
  participant Client as SEO Client
  participant Sections as Renderer
  participant Export as Exporter

  CLI->>Gen: Generate()
  note right of Gen: Orchestrates multiple page builds

  rect rgb(236,245,255)
    Gen->>Gen: GenerateAbout()
    Gen->>Client: GetProfile(), GetSocial(), GetRecommendations()
    Client-->>Gen: Profile, Social, Recs
    Gen->>Sections: Render About (profile, social, recs)
    Sections-->>Gen: HTML body
    Gen->>Export: Export(about.seo.html)
    Export-->>Gen: OK
  end

  rect rgb(240,255,240)
    Gen->>Gen: GenerateProjects()
    Gen->>Client: GetProjects()
    Client-->>Gen: Projects
    Gen->>Sections: Render Projects
    Sections-->>Gen: HTML body
    Gen->>Export: Export(projects.seo.html)
    Export-->>Gen: OK
  end

  rect rgb(255,248,236)
    Gen->>Gen: GenerateResume()
    Gen->>Client: GetExperience(), GetEducation(), GetRecommendations()
    Client-->>Gen: Exp, Edu, Recs
    Gen->>Sections: Render Resume
    Sections-->>Gen: HTML body
    Gen->>Export: Export(resume.seo.html)
    Export-->>Gen: OK
  end

  rect rgb(245,245,255)
    Gen->>Gen: GeneratePosts()
    Gen->>Client: GetPosts()
    Client-->>Gen: Posts
    loop per post
      Gen->>Gen: BuildForPost(post)
      Gen->>Sections: Render Post
      Sections-->>Gen: HTML body
      Gen->>Export: Export(posts/<slug>.seo.html)
      Export-->>Gen: OK
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

codex, testing

Poem

I thump my paw on fresh-cut logs,
New pages bloom like springtime blogs.
Social threads and recs align,
Resume, projects — posts in line.
I nibble tests and tweak a line. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely summarizes the primary change of generating SEO pages for the About, Projects, and Resume sections, which aligns with the pull request’s main objectives without introducing unnecessary detail.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cea87f and 2a484e4.

📒 Files selected for processing (3)
  • metal/cli/seo/generator.go (11 hunks)
  • metal/cli/seo/sections.go (6 hunks)
  • pkg/portal/support.go (2 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gocanto gocanto marked this pull request as draft September 26, 2025 09:07
@gemini-code-assist
Copy link

Summary of Changes

Hello @gocanto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's SEO capabilities by integrating more content types into the SEO generation process. It introduces the ability to create specific SEO-optimized pages for 'About', 'Projects', and 'Resume' sections, ensuring that rich, structured data from social links, recommendations, and professional history is properly exposed to search engines. This change aims to improve the overall discoverability and ranking of these key web pages.

Highlights

  • Expanded SEO Client: The SEO client has been extended to include new methods for fetching social links, recommendations, experience, and education content, enabling broader data integration for SEO generation.
  • New SEO Templates: Dedicated SEO templates are now generated for the About, Projects, and Resume pages, improving their search engine visibility and structured data representation.
  • Enhanced Data Handling and Testing: Fixture helpers have been exposed for additional datasets, and comprehensive test coverage has been added for the new client methods and template renderers, ensuring data integrity and correct HTML output.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request extends the SEO generation to cover the About, Projects, and Resume pages. The changes are well-structured, introducing new client methods, section renderers, and generator functions, along with corresponding tests. My feedback focuses on improving maintainability by reducing code duplication and adhering to idiomatic Go practices. I've identified several areas where helper functions could be used to create more concise and DRY code.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
metal/cli/seo/client_test.go (1)

97-131: Subtest structure would improve readability and isolation.

Consider using t.Run for each payload (social, recommendations, experience, education) so failures don't mask subsequent checks and output is scoped.

metal/cli/seo/generator_test.go (1)

109-182: Solid end-to-end assertions for newly generated pages.

As a follow-up, consider asserting page-specific <title> and canonical link tags to exercise titleFor/canonicalFor and Build validation more directly.

metal/router/fixture.go (1)

42-44: Avoid mutating the receiver when resolving fixtures.

resolveFor assigns clone := f (pointer copy), then mutates fields, which mutates the original Fixture. This can cause subtle bugs if the same Fixture is reused. Copy the struct value instead.

Outside the changed lines, update resolveFor as:

func (f *Fixture) resolveFor(slug string) *Fixture {
	clone := *f // copy by value, not by pointer
	clone.fullPath = clone.getFileFor(slug)
	clone.file = slug
	return &clone
}

Also applies to: 66-68, 74-76, 82-84

metal/cli/seo/sections.go (1)

3-4: Minor HTML semantics and micro-optimizations.

  • Consider removing the surrounding

    around

      blocks;
        should not be nested in

        . Repeat across sections for consistency.

      • allowLineBreaks creates a new Replacer on each call; a package-level var would avoid allocations. Example:
        var brReplacer = strings.NewReplacer("<br/>", "
        ", "<br />", "
        ", "<br>", "
        ")
        and return brReplacer.Replace(text).

      Also applies to: 143-188, 190-240, 242-286, 305-314

metal/cli/seo/client.go (1)

67-121: Client extensions follow existing pattern cleanly.

Consistent error wrapping and fetch usage. If duplication grows, consider a small generic helper to DRY the fetch+wrap pattern.

metal/cli/seo/generator.go (1)

362-374: Normalize path input in canonicalFor for extra safety.

Guard against paths lacking a leading slash to avoid accidental concatenation issues if constants change.

Apply this diff:

 func (g *Generator) canonicalFor(path string) string {
 	base := strings.TrimSuffix(g.Page.SiteURL, "/")
 
 	if path == "" || path == "/" {
 		return base
 	}
 
+	if !strings.HasPrefix(path, "/") {
+		path = "/" + path
+	}
+
 	if strings.HasSuffix(base, path) {
 		return base
 	}
 
 	return base + path
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c07d16 and 62fcb1b.

📒 Files selected for processing (7)
  • metal/cli/seo/client.go (1 hunks)
  • metal/cli/seo/client_test.go (1 hunks)
  • metal/cli/seo/generator.go (7 hunks)
  • metal/cli/seo/generator_test.go (3 hunks)
  • metal/cli/seo/sections.go (3 hunks)
  • metal/cli/seo/sections_test.go (2 hunks)
  • metal/router/fixture.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
metal/cli/seo/sections_test.go (4)
handler/payload/social.go (2)
  • SocialResponse (3-6)
  • SocialData (8-14)
handler/payload/recommendations.go (3)
  • RecommendationsResponse (3-6)
  • RecommendationsData (8-15)
  • RecommendationsPersonData (17-22)
handler/payload/experience.go (2)
  • ExperienceResponse (3-6)
  • ExperienceData (8-20)
handler/payload/education.go (2)
  • EducationResponse (3-6)
  • EducationData (8-17)
metal/cli/seo/sections.go (4)
handler/payload/social.go (1)
  • SocialResponse (3-6)
handler/payload/recommendations.go (1)
  • RecommendationsResponse (3-6)
handler/payload/experience.go (1)
  • ExperienceResponse (3-6)
handler/payload/education.go (1)
  • EducationResponse (3-6)
metal/cli/seo/client.go (10)
handler/payload/social.go (1)
  • SocialResponse (3-6)
metal/router/static.go (1)
  • StaticRouteResource (10-12)
handler/social.go (1)
  • MakeSocialHandler (16-20)
metal/router/fixture.go (1)
  • Fixture (15-20)
handler/payload/recommendations.go (1)
  • RecommendationsResponse (3-6)
handler/recommendations.go (1)
  • MakeRecommendationsHandler (16-20)
handler/payload/experience.go (1)
  • ExperienceResponse (3-6)
handler/experience.go (1)
  • MakeExperienceHandler (16-20)
handler/payload/education.go (1)
  • EducationResponse (3-6)
handler/education.go (1)
  • MakeEducationHandler (16-20)
metal/cli/seo/generator.go (9)
handler/payload/profile.go (1)
  • ProfileResponse (3-6)
handler/payload/social.go (1)
  • SocialResponse (3-6)
handler/payload/recommendations.go (1)
  • RecommendationsResponse (3-6)
metal/cli/seo/client.go (1)
  • Client (13-16)
metal/cli/seo/sections.go (1)
  • NewSections (13-15)
metal/cli/seo/defaults.go (8)
  • WebAboutName (16-16)
  • WebAboutUrl (17-17)
  • WebProjectsName (22-22)
  • WebProjectsUrl (23-23)
  • WebResumeName (19-19)
  • WebResumeUrl (20-20)
  • WebHomeName (14-14)
  • WebHomeUrl (13-13)
handler/payload/experience.go (1)
  • ExperienceResponse (3-6)
handler/payload/education.go (1)
  • EducationResponse (3-6)
metal/cli/seo/data.go (2)
  • TemplateData (20-38)
  • Page (5-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test (1.25.1)
  • GitHub Check: test (1.25.1)
🔇 Additional comments (2)
metal/cli/seo/sections_test.go (1)

33-41: Good coverage of escaping and allowed tags across new sections.

The new fixtures and assertions validate both escaping and the deliberate allowance of
in recommendations. Aggregation check for headings is consistent with the new renderers.

Also applies to: 42-53, 54-67, 69-78, 107-111, 112-116, 117-121, 122-126, 133-136

metal/cli/seo/generator.go (1)

85-96: New page generation flow looks correct and cohesive.

Good separation per page and reuse of buildForPage/canonicalFor/titleFor. Error messages are contextualized per page.

Also applies to: 143-182, 184-206, 207-246, 279-341

@gocanto gocanto marked this pull request as ready for review October 1, 2025 03:18
@gocanto gocanto removed the codex label Oct 1, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62fcb1b and 0cea87f.

📒 Files selected for processing (9)
  • metal/cli/seo/client.go (1 hunks)
  • metal/cli/seo/defaults.go (1 hunks)
  • metal/cli/seo/generator.go (10 hunks)
  • metal/cli/seo/generator_test.go (4 hunks)
  • metal/cli/seo/manifest.go (1 hunks)
  • metal/cli/seo/sections.go (6 hunks)
  • metal/cli/seo/sections_test.go (3 hunks)
  • metal/cli/seo/testhelpers_test.go (4 hunks)
  • pkg/portal/support.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • metal/cli/seo/sections_test.go
🧰 Additional context used
🧬 Code graph analysis (6)
metal/cli/seo/manifest.go (1)
metal/cli/seo/defaults.go (2)
  • WebPostsUrl (20-20)
  • WebPostsName (19-19)
metal/cli/seo/generator.go (5)
metal/cli/seo/defaults.go (11)
  • WebHomeName (14-14)
  • WebHomeUrl (13-13)
  • WebAboutName (16-16)
  • WebAboutUrl (17-17)
  • WebProjectsName (25-25)
  • WebProjectsUrl (26-26)
  • WebResumeName (22-22)
  • WebResumeUrl (23-23)
  • Description (35-35)
  • AboutPhotoUrl (9-9)
  • WebPostsUrl (20-20)
pkg/cli/message.go (4)
  • Successln (17-19)
  • Error (5-7)
  • Grayln (57-59)
  • Cyanln (49-51)
handler/payload/posts.go (2)
  • GetPostsResponse (54-79)
  • PostResponse (21-36)
metal/cli/seo/data.go (2)
  • Page (5-18)
  • TemplateData (20-38)
metal/cli/seo/manifest.go (2)
  • Manifest (10-24)
  • NewManifest (41-99)
metal/cli/seo/sections.go (6)
pkg/portal/support.go (3)
  • SanitizeURL (39-49)
  • FilterNonEmpty (27-37)
  • AllowLineBreaks (17-25)
handler/payload/posts.go (1)
  • PostResponse (21-36)
handler/payload/social.go (1)
  • SocialResponse (3-6)
handler/payload/recommendations.go (1)
  • RecommendationsResponse (3-6)
handler/payload/experience.go (1)
  • ExperienceResponse (3-6)
handler/payload/education.go (1)
  • EducationResponse (3-6)
metal/cli/seo/testhelpers_test.go (6)
database/connection.go (1)
  • Connection (12-17)
database/model.go (3)
  • Category (106-118)
  • Tag (127-139)
  • User (57-81)
database/repository/posts.go (1)
  • Posts (13-17)
database/repository/categories.go (1)
  • Categories (13-15)
database/repository/tags.go (1)
  • Tags (13-15)
database/attrs.go (3)
  • PostsAttrs (62-72)
  • CategoriesAttrs (19-24)
  • TagAttrs (26-30)
metal/cli/seo/generator_test.go (2)
metal/cli/seo/defaults.go (2)
  • WebHomeName (14-14)
  • WebHomeUrl (13-13)
database/model.go (5)
  • User (57-81)
  • Category (106-118)
  • PostCategory (120-125)
  • Tag (127-139)
  • PostTag (141-146)
metal/cli/seo/client.go (8)
metal/router/static.go (1)
  • StaticRouteResource (10-12)
handler/talks.go (1)
  • MakeTalksHandler (16-20)
handler/profile.go (1)
  • MakeProfileHandler (16-20)
handler/projects.go (1)
  • MakeProjectsHandler (16-20)
handler/social.go (1)
  • MakeSocialHandler (16-20)
handler/recommendations.go (1)
  • MakeRecommendationsHandler (16-20)
handler/experience.go (1)
  • MakeExperienceHandler (16-20)
handler/education.go (1)
  • MakeEducationHandler (16-20)
🪛 GitHub Actions: Tests
metal/cli/seo/generator_test.go

[error] 201-201: TestGeneratorGenerateAllPages failed: expected escaped post title in seo output. The test expected a specific HTML-escaped title string but it was not matched.

🔇 Additional comments (11)
metal/cli/seo/testhelpers_test.go (4)

126-140: LGTM!

The updated signature returning database.Category improves usability by allowing callers to access the created entity directly.


142-156: LGTM!

The function follows the established pattern for seed helpers and correctly creates and returns a tag entity.


158-190: LGTM!

The helper correctly constructs a test user with appropriate defaults. The display name logic gracefully handles empty name components.


192-227: LGTM!

The helper correctly uses the repository pattern to create a post with proper associations. All required fields are populated appropriately for testing.

metal/cli/seo/defaults.go (1)

19-20: LGTM!

The new Posts page constants follow the established naming pattern and are appropriately positioned with other web page definitions.

metal/cli/seo/manifest.go (1)

77-82: LGTM!

The new Posts shortcut is correctly structured and positioned consistently with the other manifest shortcuts.

pkg/portal/support.go (2)

27-37: LGTM!

The function correctly filters and trims non-empty values from the input slice.


17-25: No action needed: inputs to AllowLineBreaks are always pre-escaped.

Every call site (excerpt, item.Text, item.Description, and paragraph content) applies template.HTMLEscapeString (and only then replaces newline markers) before passing to AllowLineBreaks, ensuring no unescaped HTML can be injected.

metal/cli/seo/client.go (3)

25-33: Generic helper successfully addresses code duplication.

The extracted get[T] function effectively eliminates the boilerplate that was previously duplicated across multiple methods, directly addressing the earlier review feedback.


35-51: LGTM!

The refactoring successfully simplifies these methods while maintaining identical behavior. The code is now more maintainable and consistent.


53-75: LGTM!

The new getter methods follow the established pattern and correctly utilize the generic helper, maintaining consistency across the client interface.

@gocanto gocanto merged commit 730cab5 into main Oct 1, 2025
0 of 2 checks passed
@gocanto gocanto deleted the codex/implement-seo-generation-for-about,-projects,-resume branch October 1, 2025 03:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants