SaaSyBase
SaaSyBase

Content Management

SaaSyBase includes a full blog CMS, editable site pages, and a unified image/file storage system — all managed through the admin dashboard.

Blog & CMS

A full-featured blog is built into the app with public-facing pages, admin CRUD operations, rich text editing, and SEO support.

Routes

TypeRoutePurpose
Public/blogBlog listing page
Public/blog/[slug]Individual blog post
Public/blog/category/[category]Posts filtered by category
Admin/admin/blogList, create, edit, and delete posts

Rich text editing

Blog posts use the TipTap editor, which supports images, links, colors, text alignment, YouTube embeds, horizontal rules, and more. Content is stored as HTML and sanitized via lib/htmlSanitizer.ts to prevent XSS attacks.

Official docs: TipTap docs.

Categories

Blog posts use a many-to-many category system. A post can belong to multiple categories, and categories can contain multiple posts. Categories are managed in the admin blog interface.

SEO fields

Every blog post and site page includes dedicated SEO fields:

  • metaTitle, metaDescription, canonicalUrl, noIndex
  • Open Graph: ogTitle, ogDescription, ogImage

Note

Blog posts are stored using the SitePage model (shared with editable site pages) and differentiated by the collection field (page vs blog).

Tip

Choose the built-in CMS when you want marketing pages and blog content managed inside the same admin surface as the rest of the product. Keep content in code only when your marketing surface is tiny and rarely changes.

Site Pages

Editable public pages like Terms, Privacy, and Refund Policy are managed in the admin dashboard. Core pages are seeded automatically if they don't exist.

Routes

TypeRoutePurpose
Admin/admin/pagesList, create, and edit site pages
Public/termsTerms of service
Public/privacyPrivacy policy
Public/refund-policyRefund policy
Public/[slug]Dynamic catch-all for custom pages

Template variables

Pages support template variables that are interpolated at render time from admin settings. For example, {{siteName}} is replaced with your configured site name.

Note

Choose editable site pages when non-developers need to update policies, landing copy, or support content without a redeploy.

Image & File Uploads

SaaSyBase includes a unified file storage system for managing images, logos, and other public assets. These are managed via the built-in image picker inside the blog editor and site configuration pages.

Storage Providers

The active storage provider is determined by the FILE_STORAGE environment variable.

  • Local Filesystem (fs): The default behavior. Files are saved directly to public/_uploads/ and served automatically by Next.js. Ideal for local development or single-server deployments.
  • S3-Compatible (s3): Recommended for production on serverless platforms like Vercel. Works with AWS S3, Cloudflare R2, MinIO, or DigitalOcean Spaces.

Note

On serverless hosting, the local filesystem is not durable. Use FILE_STORAGE="s3" before you enable admin-managed uploads in production if you expect files to survive redeploys or instance replacement.

S3 Configuration

To enable S3 uploads, configure the following environment variables in your .env file:

  • FILE_STORAGE="s3"
  • FILE_S3_BUCKET: Your bucket name
  • AWS_REGION: Your bucket region
  • AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY
  • FILE_S3_ENDPOINT: (Optional) For non-AWS providers like R2 or Spaces
  • FILE_CDN_DOMAIN: (Optional) A custom CDN URL to serve the assets through

Leave FILE_CDN_DOMAIN unset if you are happy serving files directly from the bucket origin. Set it when you want a custom asset domain or an extra CDN layer in front of S3-compatible storage.

Security & Scopes

The backend API (/api/admin/file/upload) is strictly protected by the admin role guard and rate-limited. It accepts a scope parameter to organize uploads internally:

  • file: General assets (blog images, hero banners).
  • logo: Branding assets (site logos, favicons).

Note

SVG uploads are explicitly supported but sanitized server-side through lib/htmlSanitizer.ts before storage to prevent active content from riding along with the upload.