brand
무료Apply this site's visual identity — colours, type, logo files and fixed brand strings. Use for any page, component, social asset or document that should look like the site.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Publishing content or deploying site-os — what caches exist, what refreshes them, and how to prove a change is actually live. Use when publishing a post or product, launching a page, deploying, or when someone says a change "isn't showing".
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
실행 점수 미검증
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
1. Next ISR cache on the origin disk cleared by revalidateFor()
2. Cloudflare edge ~300 cities cleared by a PURGE, not by revalidate
3. Browser per visitor cleared by a new content hash
They do not know about each other. revalidatePath refreshes the origin and
nothing else. That is the single most common misunderstanding here.
A new post, product, job or copy edit is data, not code. The route
/products/[slug] is a wildcard compiled once at deploy; it already serves
every product that will ever exist.
admin saves → row in Postgres
→ revalidateFor({kind, slug}) origin marked stale + Cloudflare purged
→ next request regenerates that ONE page
Never run pnpm build to publish content. A rebuild is only needed when the
template changes — moving a button, adding a field, changing a layout.
Three registries, each keyed by type. Adding one is an entry, never a migration:
lib/content-revalidation.ts which paths a change invalidates
lib/structured-data.ts the schema.org JSON-LD for it
lib/fulfilment.ts how a purchase is delivered
All three are exhaustive Records, so a new kind is a compile error until
its entry exists. That is deliberate — it is what stops the next content type
shipping with no structured data, which is exactly how blog posts ended up
with none.
60s /products/[slug], /templates price and offer dates
300s /blog, /blog/[slug], /careers published content
3600s /, /about, /services, /contact marketing copy
86400s /privacy /terms /refund-policy legal text
The layout is a CEILING, not a default: Next takes the LOWEST revalidate across matched segments, so a page can never be cached longer than its layout allows. Setting the layout low silently caps every page beneath it.
These are worst cases. revalidateFor() pushes changes immediately; the window
only catches a write path that forgot to call it.
A dynamic route without generateStaticParams emits no-store, however
short its revalidate. Next cannot know the slugs, so it gives up and renders
per request. This left all ten blog posts uncrawled by Google. Any
[slug] route that should be cached needs it.
Route segment config is INERT in a 'use client' file. export const dynamic = 'force-dynamic' there looks right and does nothing. Use a segment
layout.tsx instead.
Cloudflare does NOT cache HTML by default (it is extension-based: js/css/images).
Without a rule every page shows cf-cache-status: DYNAMIC whatever s-maxage says.
Since 2026-09-30 the zone has one rule, "Cache public HTML (respect origin)":
match host is www.example.com or example.com
and path does NOT start with /api/ /admin /account /go/ /login /auth
/complete-profile /data-deletion/request /_next/image
action Eligible for cache
Edge TTL: use cache-control if present, bypass if not (origin stays in control)
Cache key: Ignore query string (Free plan cannot exclude only utm_*)
Consequences: a route is cached at the edge only if the origin sends s-maxage
(so no-store/private/Set-Cookie responses are never cached); a NEW public
route is cached automatically, a new private route must be added to the exclusion
list. Query strings are ignored, so a public page must never vary its HTML on
?param — use a path segment instead (this is why drafts live at /preview).
Attribution does not depend on utm_*: /go/<slug> sets the vb_attr cookie.
A deploy replaces the container, so the previous build's JavaScript chunks are gone. Cached HTML still references them by hash, and a visitor served that HTML gets a 404 on the chunk and a page with no JavaScript.
src/instrumentation.ts purges Cloudflare on boot to close this. It requires
CLOUDFLARE_CACHE_PURGE_TOKEN and CLOUDFLARE_ZONE_ID in the environment
(not app_secrets — instrumentation is compiled for the edge runtime too and
cannot import the crypto-dependent secrets module). Without them it logs a
warning and the stale-chunk window is live.
Read the build output and the live headers. Both have lied in ways that reasoning would not have caught.
pnpm build # ○ static ● static per slug ƒ per request
# the last two columns are revalidate and expire
curl -sI https://www.example.com/blog/<slug> \
| grep -iE 'cache-control|cf-cache-status'
# want: s-maxage=N, stale-while-revalidate · cf-cache-status: HIT
# no-store or DYNAMIC means it is NOT cached
Confirm the server you measured is the one you built. A stale process
holding the port produced a completely wrong reading once — check the log for
EADDRINUSE before believing any measurement.
1. edit the row directly in Postgres → page should NOT change (proves it is cached)
2. go through the app's write path → page changes at once (proves revalidation)
If step 1 changes the page, nothing is cached. If step 2 does not, the write
path is not calling revalidateFor().
In this order:
cf-cache-status — HIT means the edge is serving an old copy. Purge:
the purge server action purgeCloudflareCache() (no UI button yet) or wait out the window.revalidateFor()? A row edited straight in the
database does not, by design./products/<slug>/preview (never read searchParams on a cached page: it throws DYNAMIC_SERVER_USAGE and 500s).sitemap lastmod real row timestamps, refreshed by revalidateFor
IndexNow Bing + Yandex, automatic on publish
Google NO push API for ordinary pages. Sitemap + the manual
Request Indexing button are the only levers.
Do not build a "tell Google" automation. It does not exist, and the Indexing
API is restricted to JobPosting and BroadcastEvent — using it for ordinary
pages risks the property.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Apply this site's visual identity — colours, type, logo files and fixed brand strings. Use for any page, component, social asset or document that should look like the site.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use FIRST when someone asks for a new feature or a change to an existing one — before any schema, code or test. Works out what is actually being asked for, whether to build it or integrate a third party (Trustpilot, Stripe, Calendly and the like), where the data lives, who may do what, and what happens when the vendor is down. Produces a decision, then hands to feature-schema.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a new feature needs a table, column or capability — evolving the schema so the new thing joins the permission, audit and RLS contract instead of sitting outside it. Covers the DDL/DML split, the resource/capability wiring, and the self-verifying migration.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use after building a feature — explore it in a real browser to find what nobody predicted, then turn each finding into a deterministic test that guards it forever. Covers the agentic pass, what to generate vs hand-write, and how to skip honestly when a capability is missing.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Handling secrets, keys and credentials for site-os — reading vigyan-secrets.md safely, moving keys into app_secrets, rotating, and responding to an exposure. Use whenever a task touches a key, token, password, .env file, app_secrets, encryption, or the secrets document.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Audit a page or the whole yoursite site (or a new site) for indexing readiness — cache headers, sitemap, robots, canonical, JSON-LD, internal links — and check the publish pipeline (Cloudflare purge/warm, IndexNow, GSC, Bing). Use before/after publishing content or launching a site.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.