Current state
ui/layout/header.tsx imports and calls getPosts from io/notion/getPosts at render time, performing a live Notion API call inside a layout component. Layout components are not the appropriate place for I/O; they should receive already-fetched data as props from a page or data-fetching boundary. The same violation exists in ui/sections/blog-post-list.tsx, which also calls getPosts directly. The layout layer carrying its own I/O means the Notion call cannot be controlled, cached, or tested independently of the component.
Ideal state
Header accepts posts as a prop; it contains no imports from @/io
BlogPostList (or equivalent section component) accepts posts as a prop; it contains no imports from @/io
- Page-level components call
getPosts once and pass the result to both Header and the post-listing section
- Each component is renderable in tests with plain props and zero network access
Out of scope
Starting points
ui/layout/header.tsx — the getPosts import and call to remove; the props interface to add
ui/sections/blog-post-list.tsx — the same pattern in the section component
- Page files that render
Header and BlogPostList — the new home for the getPosts call
QA plan
- Open
ui/layout/header.tsx — expect no imports from @/io and a posts prop in the component signature
- Open
ui/sections/blog-post-list.tsx — expect no imports from @/io and a posts prop
- Run
npm run build — expect no build errors
- Open the home page and a blog post page in the browser — expect the header nav and post list to render correctly with all expected posts
Done when
Neither ui/layout/header.tsx nor ui/sections/blog-post-list.tsx imports from @/io; both receive post data as props.
Current state
ui/layout/header.tsximports and callsgetPostsfromio/notion/getPostsat render time, performing a live Notion API call inside a layout component. Layout components are not the appropriate place for I/O; they should receive already-fetched data as props from a page or data-fetching boundary. The same violation exists inui/sections/blog-post-list.tsx, which also callsgetPostsdirectly. The layout layer carrying its own I/O means the Notion call cannot be controlled, cached, or tested independently of the component.Ideal state
Headeracceptspostsas a prop; it contains no imports from@/ioBlogPostList(or equivalent section component) acceptspostsas a prop; it contains no imports from@/iogetPostsonce and pass the result to bothHeaderand the post-listing sectionOut of scope
getPostsitself or the Notion clientStarting points
ui/layout/header.tsx— thegetPostsimport and call to remove; the props interface to addui/sections/blog-post-list.tsx— the same pattern in the section componentHeaderandBlogPostList— the new home for thegetPostscallQA plan
ui/layout/header.tsx— expect no imports from@/ioand apostsprop in the component signatureui/sections/blog-post-list.tsx— expect no imports from@/ioand apostspropnpm run build— expect no build errorsDone when
Neither
ui/layout/header.tsxnorui/sections/blog-post-list.tsximports from@/io; both receive post data as props.