wu-community-publishing
Implement or review WU-COMMUNITY-001 Urdu Writers one slice at a time. Covers authenticated submission snapshots, editor publishing prompts, Product OS human moderation, immutable approved public SSR
Files1
View on GitHubSKILL.md.claude/skills/wu-community-publishing/SKILL.md
GitHubWriteUrdu Community Publishing — implementation skill
Use this skill for any implementation/review task under WU-COMMUNITY-001.
The product is Urdu Writers: signed-in writers explicitly submit writing snapshots, Product OS moderators approve/reject them, and only approved immutable snapshots become durable public WriteUrdu pages.
1. Mandatory read order
Always read current main and these parent contracts first:
specs/WU-COMMUNITY-001-moderated-urdu-writing-publishing.mdspecs/WU-AUTH-001-social-authentication-foundation.mdspecs/WU-DRAFT-001-cross-device-cloud-drafts.mdspecs/WU-GROWTH-002-account-save-share-entry-points.mdspecs/WU-SHARE-001-public-share-pages-viral-publishing-loop.mdspecs/WU-PLAT-002-v2-product-journey-workspace-handoffs.md- current
functions/lib/auth.mjs - current
/api/documents*implementation - current Product OS
/api/internal/*security/host patterns - current
functions/s/[id].js+ share report patterns - current migrations, route registry, sitemap, SEO, AdSense, telemetry and service-worker owners.
Then read the exact slice file being implemented:
COMMUNITY-A → specs/WU-COMMUNITY-001A-submission-data-api.md
COMMUNITY-B → specs/WU-COMMUNITY-001B-editor-prompt-submission-ux.md
COMMUNITY-C → specs/WU-COMMUNITY-001C-os-moderation-publishing.md
COMMUNITY-D → specs/WU-COMMUNITY-001D-public-reader-seo-reporting.md
COMMUNITY-E → specs/WU-COMMUNITY-001E-my-publications-revisions-withdrawal.md
COMMUNITY-F → specs/WU-COMMUNITY-001F-taxonomy-guidelines-launch-closure.md
Do not implement from this skill alone. The slice spec owns detailed acceptance criteria.
2. Core invariant
Private writing is never the public object.
The only valid path to public content is:
editor / My Documents
→ explicit authenticated snapshot
→ community_writing_submissions
→ Product OS human approval
→ community_writing_publications
→ /urdu-writers/:slug
Never point a public page/API at writing_documents.
Never let a private edit mutate an approved publication.
Never let writer/public APIs set approval state.
3. Existing platform decisions to preserve
Database
Use:
env.METRICS_DB
Do not create COMMUNITY_DB, WRITE_URDU_DB, ACCOUNT_DB or another D1 database.
Before migration work:
- inspect current migration sequence;
- reconcile next migration number;
- capture current table inventory;
- add community tables additively;
- prove telemetry/share/Auth.js/
writing_documentstables remain unchanged.
Never edit an already-applied migration.
Identity
Authorization subject is always:
session.user.id
obtained through the project auth wrapper.
Never authorize by email.
Provider name/email/image are not public author identity.
Local-first writing
Normal writing remains anonymous/local-first.
Publishing may require sign-in only after explicit publish intent.
Auth/publish failure must never disable:
transliteration
Basic Writer
Rich Editor
Urdu Keyboard
Voice input
local autosave/history
My Documents
copy/export/share-link flows
4. Slice boundaries
COMMUNITY-A — submission data + API
Build only the private submission foundation:
community_writing_submissions
community_writing_publications schema
community_writing_reports schema
controlled taxonomy
server content validation/sanitization
owner-only submission CRUD/pending update
quota/rate/duplicate guards
No public reader route. No approval endpoint.
COMMUNITY-B — editor prompt + submission UX
Build shared publishing discovery across:
Basic Writer
Rich Editor
Urdu Keyboard
Voice transcript
Automatic prompt heuristic:
>= 600 non-whitespace characters
OR
>= 90 whitespace-delimited words
Also ship manual Publish to Urdu Writers so short poetry can submit.
Signed-out publish intent uses existing safe short-lived same-origin auth continuity. Never put writing in URL/OAuth state.
COMMUNITY-C — Product OS moderation
Build the only approval boundary.
Expected internal operations:
queue/detail
approve exact revision
reject exact revision
approved-revision replacement
emergency unpublish
Moderation writes must fail closed behind current Product OS + Cloudflare Access boundary.
Do not enable public corpus before this slice’s security/state tests are green.
COMMUNITY-D — public reader + SEO/reporting
Only read:
community_writing_publications WHERE status='published'
Build:
/urdu-writers
/urdu-writers/:slug
/urdu-writers/category/:category
/sitemap-community.xml
public read API
report API
Pending/rejected/private content must be impossible to retrieve anonymously.
COMMUNITY-E — My Publications lifecycle
Build authenticated private writer status/control:
/my-publications
pending update
revision submission
rejection state
withdrawal
source-document return
Current public version remains live while a revision is pending/rejected.
Writer withdrawal removes public visibility but never deletes private source writing.
COMMUNITY-F — launch closure
Close:
taxonomy/indexing quality
Community Guidelines
Privacy/Terms reconciliation
navigation/route/sitemap registries
AdSense boundaries
telemetry schema
Product OS operational metrics
moderation capacity/pause controls
feature-flag rollout/rollback
production launch proof
No comments/likes/follows/profiles/social feed/AI auto-approval in this epic.
5. Community state model
Submission
Expected states:
pending
approved
rejected
withdrawn
Writer can replace only an owned pending submission with optimistic revision safety.
Publication
Expected states:
published
unpublished
Public routes always require published.
Revision rule
After first approval:
current publication stays live
→ writer submits a new pending revision
→ moderator reviews exact revision
→ approval atomically replaces public snapshot
A rejected revision never changes current public version.
Withdrawal
Owner withdrawal:
publication → unpublished
hub/category/API/sitemap remove it
public detail → 410 + noindex
private source document untouched
Republishing always requires moderation again.
6. Public author identity
Submission asks for:
public author name / pen name
Rules:
- account name may be prefilled only as convenience;
- writer explicitly confirms/edits it;
- never prefill/show provider email as public name;
- provider image is not part of v1;
- public name is snapshotted into submission/publication;
- later account profile changes do not silently alter public writing.
No public author profile pages in v1.
7. Controlled taxonomy
Initial primary categories:
poetry
essay
prose
thought
story
Initial curated tags:
ghazal
nazm
shayari
essay
prose
critical-thinking
personal-reflection
society
culture
education
story
other
Enforce:
exactly 1 category
1–5 unique curated tags
No free-form public tags.
Moderator may correct category/tags before approval.
Moderator may not silently rewrite title/body/public name.
8. Content safety
Server owns validation.
Initial common guards from the feature family:
title <= 180 chars
public author name <= 80 chars
manual body >= 80 chars
body bounded well below platform maximums
max 5 pending submissions/user
bounded rolling submission rate
Rich HTML
If rich community publishing is retained:
- use a proven server-side allowlist sanitizer compatible with Cloudflare runtime;
- derive plain text after sanitization;
- strip unsafe tags/attributes/URLs.
If a proven sanitizer is unavailable, publish plain text in v1.
Never hand-roll regex HTML sanitization.
9. Moderation security
Product OS approval/rejection/unpublish mutations must require the current verified OS/Cloudflare Access boundary.
At minimum:
correct PRODUCT_OS_HOST
Cloudflare Access protected hostname
verified authenticated Access identity/current project pattern
optional configured moderator allowlist
Never authorize from:
query flag
localStorage
client role string
hidden form field
unverified arbitrary email header
Never persist Access tokens/assertion bodies.
Approval/rejection requires the moderator’s expected submission_revision.
Stale review => conflict and reload.
10. Approval atomicity
First approval must atomically:
- verify exact pending revision;
- generate publication ID + stable server slug;
- copy approved snapshot to publication table;
- mark submission approved/reviewed;
- link publication/submission.
Use a current supported D1 atomic transaction/batch pattern after verifying platform semantics at implementation time.
Duplicate exact approval must be idempotent.
Revision approval atomically replaces approved publication fields while keeping stable canonical slug and original published_at.
11. Public SSR/SEO rules
Public detail must be server-rendered/crawler-readable and include:
approved title
approved public author name
category/tags
published date
full approved safe writing
lang=ur / dir=rtl
canonical
OG/Twitter metadata
truthful Article/CreativeWork JSON-LD
report action
Write your own Urdu CTA
Never expose:
user ID
email
provider/account data
source document ID
submission ID
moderation identity/rejection data
Community sitemap contains published canonical URLs only.
Category pages remain conservative/noindex until corpus quality threshold + manual SEO review are met.
/s/:id remains the separate noindex direct-share surface.
12. Public reporting
Controlled reasons:
spam
abuse
privacy
copyright
other
Report records are community-owned and do not store reporter identity in v1.
Reports raise moderator visibility but do not auto-unpublish by count.
Do not write community reports into share-artifact tables.
13. Guidelines/legal product boundary
Before broad launch:
/community-guidelinesexists;- Privacy distinguishes local/private/submitted/public writing;
- publishing consent/Terms match actual license/withdrawal behavior;
- report/takedown path works;
- account deletion interaction is documented.
Core rights principle:
Writer keeps copyright they own; WriteUrdu receives the permission needed to display/distribute the approved version under the publishing terms.
Do not claim ownership of writer copyright.
14. Ads
Do not place ads on:
submission flow
/my-publications
Product OS moderation
Do not insert ads inside writer body.
Any public-reading monetization uses existing safe post-content/reading boundaries and current WU-GROWTH-001 operating contract.
Do not use this feature as an excuse to increase site-wide Auto ads.
15. Telemetry privacy
Allowed event family is defined in Slice F.
Telemetry can contain only bounded product-state metadata such as:
workspace/route type
entry point
category
size bucket
state bucket
outcome/error category
Never include:
title
body/excerpt
public author name
email
user ID
document ID
submission ID
publication ID/slug
content signature
moderator identity
Focused tests must enforce forbidden fields.
16. Feature flags and rollback
Use at least:
COMMUNITY_SUBMISSIONS_ENABLED
COMMUNITY_PUBLIC_ENABLED
Rollback never drops shared D1 tables.
Disabling submissions must not break writing/My Documents/current public reading.
Disabling public corpus must fail public community routes closed/noindex while retaining private/moderation data.
17. Implementation workflow for an agent
For each requested slice:
- read parent + exact slice spec;
- inspect current
mainowners/dependencies; - reconcile any spec drift explicitly;
- record baseline tests before code changes;
- implement the smallest shared owner set that satisfies the slice;
- add focused contract/unit/browser tests from that slice;
- run existing auth/documents/share/editor/SEO regressions affected by touched files;
- run full repository gate;
- verify no writing/private identity appears in logs/telemetry/public HTML;
- update parent/child status and
specs/README.md/specs/BACKLOG.mdonly if implementation state actually changed; - provide production/preview verification notes and unresolved gates.
Do not combine multiple slices in one implementation PR unless explicitly requested and the earlier slice acceptance gates are already green.
18. Suggested test families
Names can follow repository conventions, but coverage must include:
community-submission-api-contract
community-publishing-editor-contract
community-moderation-security-contract
community-public-reader-contract
community-publications-lifecycle-contract
community-launch-governance-contract
Also retain/re-run relevant existing contracts for:
auth foundation
My Documents basic/editors
Voice typing/input
share loop
product telemetry
SEO authority/sitemap
AdSense route governance
service worker/application shell
19. Slice exit gates
A exit
- owner-only pending submission API green;
- migration safe;
- controlled taxonomy/content guard green;
- no public publishing capability.
B exit
- automatic prompt + manual short-poetry path green on all eligible editors;
- auth continuity preserves writing;
- successful submit says
In review, not published.
C exit
- OS/Access security green;
- exact-revision approval/rejection green;
- atomic/idempotent publication creation green;
- stale review cannot publish.
D exit
- published-only SSR corpus green;
- pending/rejected/private leakage impossible;
- report + sitemap + withdrawal/unpublish public behavior green.
E exit
- My Publications state model green;
- pending revisions preserve current public version;
- owner withdrawal green;
- no direct republish bypass.
F exit
- guidelines/privacy/terms + taxonomy/indexing + ads + telemetry + OS metrics + rollout/rollback production checklist closed.
20. Global stop conditions
Stop and fix immediately if any implementation does any of the following:
- introduces another D1 database;
- makes sign-in required for normal writing;
- points public pages at
writing_documents/submission rows; - lets writer/public API approve content;
- lets private edits mutate approved publication;
- exposes provider email/name automatically as public identity;
- makes arbitrary user tags into public crawlable URLs;
- authorizes moderator writes from public origin/client flag;
- approves a stale unseen revision;
- accepts rich HTML without a proven server sanitizer;
- logs/telemeters writing or private identifiers;
- allows pending/rejected content into public API/HTML/sitemap;
- lets CDN caching keep withdrawn writing publicly readable;
- deletes private My Documents content when publication is withdrawn;
- inserts ads inside writer content/private/moderation surfaces;
- claims WriteUrdu owns writer copyright;
- enables AI automatic approval to compensate for moderation volume;
- builds comments/likes/follows/profiles/social feed inside this epic.