How I Redesigned 4 Years of Blog Posts (196 of them!) Overnight with AI
Why a Renewal Was Necessary
When I applied to AdSense for aicoreutility.com, I received a clear rejection reason: "Insufficient content quality." I had migrated 196 posts from Tistory, where I had written for 4 years, onto the site. Over half of these posts were short (under 1500 characters) and old (from 2020-2023).
I had two options:
- Shut down Tistory — Lose original search results, break backlinks, a gamble.
- Full Renewal — Rewrite all 196 posts one by one. Impossible by hand.
I'm a solo developer. I don't have time to rewrite 196 posts while taking care of my family. So, I built an automated renewal pipeline using Gemini Flash-Lite.
Step 1: Ruthless Culling
Not every post is worth saving. Valueless posts are a negative for SEO. I archived 31 posts based on two criteria.
-- Posts that are very short and have almost no views
UPDATE blog_posts SET status='archived'
WHERE length(content_original) < 1500 AND view_count <= 3;
-- Posts of moderate length + low value + old
UPDATE blog_posts SET status='archived'
WHERE length(content_original) < 2500
AND view_count <= 2
AND ai_score < 7
AND original_published_at < '2024-01-01';
199 posts → 168 posts. I lost 31 posts, but the average quality increased.
Step 2: A 5-Stage Renewal Chain
A simple "rewrite this post" prompt leads to hallucinations. I broke it down into 5 stages.
- extract_facts — Extract only verifiable facts from the original.
- seo_research — Generate title and keyword candidates.
- write_body — Write the body based on the facts.
- validate — Verify if facts are missing or added.
- seo_meta — Generate title, description, and excerpt.
The model used was gemini-2.5-flash-lite. Cost per post is about ₩2.
Trap 1: Year Hallucination
When I reviewed the first batch of results, the post body contained phrases like "5 things in 2024." It's currently 2026. Gemini was using old years from its training data.
I added the current KST time at the beginning of every stage's prompt.
def _now_context() -> str:
now = datetime.now(KST)
return (
f"[Current Time — Must Adhere]\n"
f"Today is {now.strftime('%Y년 %m월 %d일')} (KST).\n"
f"When referring to years/time periods, please use {now.year} as the basis. "
f"Do not arbitrarily use old years from training data (like 2023, 2024, etc.).\n"
)
Solved.
Trap 2: Idempotence
I ran 130 posts at once, but it stopped halfway due to Gemini API rate limits. It halted at post 49. Would running it again start from scratch?
I added an HTML marker at the end of each post.
<!-- renewed-2026 -->
The script skips posts with this marker. Even if it stops, running it again only processes the remaining ones. In the end, I ran it twice more to complete 143 posts.
Trap 3: Korean Slugs
Some original post slugs were in Korean, like /blog/리액트-훅-정리. While they work in browser address bars, they cause issues with SEO and social media sharing.
I normalized all slugs to ASCII and used a sha1 hash as a fallback.
Step 3: Timestamping
I forcefully added two sections to the renewed posts.
- 🕒 This Post's Timestamp — Specifies the original writing year ("Originally written in 2022, reviewed as of May 2026").
- 📌 A Comment from 2026 — An additional paragraph from the current perspective.
This is to prevent readers from wondering "Is this an old post?" and to help AdSense recognize it as "fresh content."
Final Results
| Metric | Value |
|---|---|
| Renewal Cost | Approx. ₩300 (Gemini Flash-Lite, 143 posts) |
| Total Time Spent | Approx. 35 minutes (script execution time) |
| Published Posts | 146 (143 renewed + 3 native) |
| Archived Posts | 53 |
| Consistency | 100% (all posts timestamped for 2026) |
Learnings
- Full automation is possible, but injecting time context into prompts is essential.
- Without idempotence, even a single interruption causes significant loss.
- Don't save valueless posts. Average quality determines SEO.
- For solo developers, an LLM pipeline is a time-creating tool. It took only 35 minutes and cost ₩300.
📌 Next Steps
I've reapplied to AdSense and am waiting for the results. If approved, I plan to place ad units in only one location that doesn't disrupt readability. I won't enable auto ads.