Skip to content

Conversation

@barbaraperic
Copy link
Collaborator

@barbaraperic barbaraperic commented Dec 9, 2025

📝 Description

This PR introduces a new architecture for the Digest feature, separating Issues and Articles into distinct content types with a relationship model.

  1. Digest Issues (Collection-level)
  • Represent a published edition of the digest
  • Contains metadata: issue number, title, description, guest-editor, publication-dates
  • Acts as a parent container for related articles
  1. Digest Articles (Item-level)
  • Individual content pieces within an issue
  • Links to parent issue via issue-number field
  • Contains metadata: title, authors, content, article-number

📌 To-Do Before Merging

  • Fix tests

Key Changes

  • Added a new collection for "Digest Issues" in the admin configuration for FF-site.

  • Updated paths and utilities to support the retrieval of articles associated with specific issues.

  • Refactored existing schemas and data handling.

  • Improved metadata generation and article retrieval logic.

  • Type: Refactor

- Added a new collection for "Digest Issues" in the admin configuration, allowing for better management of digest content.
- Updated paths and utilities to support the retrieval of articles associated with specific issues, improving content organization.
- Introduced multiple new articles for the inaugural digest issue, enriching the content with diverse topics related to the Filecoin ecosystem.
- Refactored existing schemas and data handling to ensure consistency and clarity across the digest feature.
- Improved metadata generation and article retrieval logic to enhance user experience and maintainability.
@notion-workspace
Copy link

@vercel
Copy link

vercel bot commented Dec 9, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
ffdweb-site Ready Ready Preview, Comment Dec 18, 2025 9:58am
filecoin-foundation-site Ready Ready Preview, Comment Dec 18, 2025 9:58am
filecoin-foundation-uxit Ready Ready Preview, Comment Dec 18, 2025 9:58am
filecoin-site Ready Ready Preview, Comment Dec 18, 2025 9:58am

Copy link
Collaborator

@CharlyMartin CharlyMartin left a comment

Choose a reason for hiding this comment

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

Phew, big PR! I understand it's the same set up on both apps, but it would have been easier (for the reviewer) to split these PR. But I also understand that you want to get this done after so many reworks 🙃

Have a look at the suggestions below and let me know what you think!

Comment on lines 1 to 13
import type { DigestIssueParams } from '@filecoin-foundation/utils/types/paramsTypes'

export async function parseDigestIssueParams(
params: Promise<DigestIssueParams>,
) {
const resolvedParams = await params
const issueNumber = parseIssueNumberFromSlug(resolvedParams.issue)
return { issueNumber }
}

export async function parseDigestArticleParams(
params: Promise<DigestArticleParams>,
) {
const resolvedParams = await params
const issueNumber = parseIssueNumberFromSlug(resolvedParams.issue)
return {
issueNumber,
articleSlug: resolvedParams.slug,
}
}

function parseIssueNumberFromSlug(issue: string) {
return issue.replace('issue-', '')
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here's how I would rework this file:

Suggested change
const ISSUE_NUMBER_PREFIX = 'issue-'
export function parseIssueSlug(issue: string) {
if (!issue.startsWith(ISSUE_NUMBER_PREFIX)) {
throw new Error(`Invalid issue slug: ${issue}`)
}
return issue.replace(ISSUE_NUMBER_PREFIX, '')
}
export function buildIssueSlug(issueNumber: string | number) {
return `${ISSUE_NUMBER_PREFIX}${issueNumber}`
}

Then in apps/ffdweb-site/src/app/digest/[issue]/page.tsx

const { issue } = await props.params
const issueNumber = parseIssueSlug(issue)

// ...

return allIssues.map(({ issueNumber }) => ({
    issue: buildIssueSlug(issueNumber),
}))

Copy link
Collaborator

Choose a reason for hiding this comment

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

buildIssueSlug could also be used here:

    issueUrl: ({ issueNumber }: IssueUrlProps) =>
      `/digest/issue-${issueNumber}`,
    articleUrl: ({ issueNumber, articleSlug }: ArticleUrlProps) =>
      `/digest/issue-${issueNumber}/${articleSlug}`,

Comment on lines 39 to 40
notFound()
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

When would digestIssue be a falsy value? Meaning, when would this run?

(According to TS, never, since digestIssue is always an object)

issue.issueNumber,
)
return issueArticles.map((article) => ({
issue: `issue-${article.issueNumber}`,
Copy link
Collaborator

Choose a reason for hiding this comment

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

The util function to build the slug can be used here too. Everywhere issue- is used as a standalone string basically.

Comment on lines 22 to 30
const allIssues = await getAllDigestIssuesData()
const allArticles = await getDigestArticlesData()

const issueNumbersThatHaveArticles = new Set(
allArticles.map((article) => article.issueNumber),
)
const digestIssues = allIssues.filter((issue) =>
issueNumbersThatHaveArticles.has(issue.issueNumber),
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I would extract this in a helpfer function with a clear name to highlight intent.

I didn't test it, but something like this:

async function getDigestIssuesWithArticles() {
  const allArticles = await getDigestArticlesData()

  const allIssueNumbers = Array.from(
    new Set(allArticles.map((article) => article.issueNumber)),
  )

  const allIssues = await Promise.all(
    allIssueNumbers.map((issueNumber) => getDigestIssueData(issueNumber)),
  )

  return allIssues
}

bio: z.string().optional(),
}),
),
'issue-number': IssueNumberField,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand why we transform a number into a string here? What's the benefit? I might be missing some context.

}),
),
'issue-number': IssueNumberField,
'article-number': z.number(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should add some validation here. Right now, two article within the same issue can have the same article number.

Also, this number cannot be negative.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Finally, it shouldn't be possible to go from 1 to 3.

CleanShot 2025-12-11 at 10 49 56@2x

… path generation. Introduced getDigestIssuesThatHaveArticles function to streamline fetching issues with articles. Updated related components and tests for consistency.
@barbaraperic
Copy link
Collaborator Author

These are all great suggestions, thank you @CharlyMartin ❤️

@vercel vercel bot temporarily deployed to Preview – filecoin-foundation-site December 12, 2025 17:11 Inactive
@vercel vercel bot temporarily deployed to Preview – ffdweb-site December 12, 2025 17:11 Inactive
@vercel vercel bot temporarily deployed to Preview – filecoin-foundation-uxit December 12, 2025 17:11 Inactive
@github-actions github-actions bot added size/L and removed size/L labels Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants