Skip to content

Blogs & Docs

RoutePurpose
/blogBlog list (user’s blogs)
/blog/newCreate new blog
/blog/[slug]View blog
/blog/[slug]/editEdit blog
/hubs/[hubId]/blogsHub-scoped blog management
RoutePurpose
/docsDocument grid (personal + hub docs)
/docs/[id]Document editor
/hubs/[hubId]/docsHub-scoped document management

FieldTypeRequiredValidation
titletextYes1-200 chars
slugauto/textYes1-100 chars, [a-z0-9-] only, unique per hub
contentEditorJSNoRich text blocks
statusselectYesdraft / published / archived
visibilityselectYespublic / private / unlisted
seoKeytextNoMax 100 chars (focus keyword)
seoTitletextNoMax 70 chars
seoDescriptiontextareaNoMax 160 chars
  1. Lowercase title
  2. Remove special characters (keep [a-z0-9\s-])
  3. Replace spaces with hyphens
  4. Collapse multiple hyphens
  5. Remove leading/trailing hyphens
  6. Limit to 100 characters

Uniqueness: Checked with 500ms debounce against Firestore (same hub, excluding current blog).

ToolDescription
HeaderHeading levels
ParagraphText blocks
ListOrdered/unordered
QuoteBlock quotes with captions
CodeCode blocks
WarningAlert/warning blocks
DelimiterHorizontal separators
TableData tables
MarkerText highlighting (CMD+SHIFT+M)
LinkURL linking
ChecklistCheckbox lists
ImageImage upload with Firebase Storage
SettingValue
Accepted formatsJPEG, PNG, GIF, WebP
Storage pathhubs/{hubId}/blogs/{blogSlug}/{fileId}.{ext}
Storage limitChecked against subscription plan
TrackingCreates StorageUserService entry

Content stored as JSON string in Firestore (avoids nested array limitations). Parsed back via parseBlogContent() on retrieval.

  • Read-only rendering with BlogPreview component
  • Article layout with author bar: avatar, name, created/updated dates, read time
  • Read time calculation: Math.ceil(totalWords / 200), minimum 1 minute
  • Table: Title, Slug, Status, Visibility, Created Date, Actions
  • Status badges: draft (yellow), published (green), archived (gray)
  • Actions: View, Edit, Delete (with confirmation)
  • GET endpoint proxying https://mindhyv.com/wp-json/wp/v2/posts
  • Optional lang query parameter
  • Returns WordPress posts for dashboard “What’s New” section

document, list, board, calendar

FieldTypeRequired
Title/NametextYes (non-empty)
DescriptiontextareaNo
TypeselectAuto (document)
FieldTypeRequired
NametextYes (non-empty)
  • Metadata: Firestore (documents/{docId} or hubs/{hubId}/documents/{docId})
  • Content: Firebase Realtime Database at documents/{docId}
  • Same EditorJS tools as blogs (minus image upload)
  1. Search personal documents/{docId} in Firestore
  2. Connect to RTDB at documents/{docId}
  3. If not found, search through all user’s hubs
  4. Try hubs/{hubId}/documents/{docId} in Firestore

Soft delete: Sets status: 'deleted'. Records remain in Firestore, filtered from queries.

  • Personal section: Docs from root documents collection
  • Hub sections: One per hub, docs from hubs/{hubId}/documents
  • Responsive grid: 2 cols (mobile) to 6 cols (xl)
  • Cards show: type icon (color-coded), title, created date, status badge
TypeColor
DocumentBlue
ListGreen
BoardPurple
CalendarOrange

BlockerModuleDescription
Slug takenBlogsMust be unique per hub
Storage limitBlogsImage upload blocked if exceeded
Empty titleBothCannot save without title
Status deletedDocsSoft-deleted docs hidden from queries