JSPM

  • Created
  • Published
  • Downloads 269
  • Score
    100M100P100Q94478F
  • License MIT

Rytass Content Management System NestJS Base Module

Package Exports

  • @rytass/cms-base-nestjs-module
  • @rytass/cms-base-nestjs-module/index.cjs.js
  • @rytass/cms-base-nestjs-module/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@rytass/cms-base-nestjs-module) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Rytass Utils - CMS Base NestJS Module

Powerful content management system base module designed specifically for NestJS applications. Provides complete multi-language article management, version control, approval workflows, and category management functionality, making it the ideal choice for building enterprise-grade CMS systems.

Features

  • Multi-language article and category management
  • Article version control system
  • Hierarchical category structure (N:M relationships)
  • Article review and publishing workflows
  • Draft mode support
  • Full-text search functionality
  • Custom field support
  • DataLoader query performance optimization
  • TypeORM entities and repositories
  • Built-in error handling
  • Flexible permission control
  • GraphQL query support

Installation

npm install @rytass/cms-base-nestjs-module @nestjs/typeorm typeorm
# or
yarn add @rytass/cms-base-nestjs-module @nestjs/typeorm typeorm

Basic Usage

Module Configuration

// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CmsBaseModule } from '@rytass/cms-base-nestjs-module';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      // Database configuration
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'username',
      password: 'password',
      database: 'cms_database',
      entities: [/* other entities */],
      synchronize: true, // Development environment only
    }),
    CmsBaseModule.forRoot({
      multipleLanguageMode: true,
      draftMode: true,
      signatureLevels: [
        { id: 1, name: 'Editor', level: 1 },
        { id: 2, name: 'Senior Editor', level: 2 },
        { id: 3, name: 'Chief Editor', level: 3 }
      ],
      fullTextSearchMode: true,
      autoReleaseAfterApproved: false
    })
  ],
})
export class AppModule {}

Async Configuration

// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { CmsBaseModule } from '@rytass/cms-base-nestjs-module';

@Module({
  imports: [
    ConfigModule.forRoot(),
    CmsBaseModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        multipleLanguageMode: configService.get('CMS_MULTI_LANGUAGE') === 'true',
        draftMode: configService.get('CMS_DRAFT_MODE') === 'true',
        signatureLevels: JSON.parse(configService.get('CMS_SIGNATURE_LEVELS')),
        fullTextSearchMode: configService.get('CMS_FULL_TEXT_SEARCH') === 'true'
      })
    })
  ],
})
export class AppModule {}

Core Services

Article Management

// article.service.ts
import { Injectable } from '@nestjs/common';
import { ArticleBaseService } from '@rytass/cms-base-nestjs-module';

@Injectable()
export class ArticleService {
  constructor(
    private readonly articleBaseService: ArticleBaseService
  ) {}

  async createArticle(data: CreateArticleDto) {
    return await this.articleBaseService.create({
      title: data.title,
      content: data.content,
      categoryIds: data.categoryIds,
      language: data.language || 'zh-TW',
      authorId: data.authorId,
      customFields: data.customFields
    });
  }

  async publishArticle(articleId: string, userId: string) {
    return await this.articleBaseService.release(articleId, { userId });
  }

  async getArticleWithVersions(articleId: string) {
    return await this.articleBaseService.findById(articleId);
  }
}

Category Management

// category.service.ts
import { Injectable } from '@nestjs/common';
import { CategoryBaseService } from '@rytass/cms-base-nestjs-module';

@Injectable()
export class CategoryService {
  constructor(
    private readonly categoryBaseService: CategoryBaseService
  ) {}

  async createCategory(data: CreateCategoryDto) {
    return await this.categoryBaseService.create({
      names: data.names, // Multi-language names
      parentId: data.parentId,
      description: data.description,
      sortOrder: data.sortOrder
    });
  }

  async getCategoryTree() {
    return await this.categoryBaseService.findAll();
  }

  async getArticlesByCategory(categoryId: string, options = {}) {
    return await this.categoryBaseService.findArticles(
      categoryId, 
      {
        page: options.page || 1,
        limit: options.limit || 10,
        includeSubCategories: true
      }
    );
  }
}

Data Models

Article Entity

import { BaseArticleEntity } from '@rytass/cms-base-nestjs-module';
import { Entity, Column } from 'typeorm';

@Entity('articles')
export class Article extends BaseArticleEntity {
  @Column({ type: 'jsonb', nullable: true })
  customFields?: Record<string, any>;

  @Column({ nullable: true })
  featuredImage?: string;

  @Column({ type: 'text', array: true, default: [] })
  tags: string[];
}

Category Entity

import { BaseCategoryEntity } from '@rytass/cms-base-nestjs-module';
import { Entity, Column } from 'typeorm';

@Entity('categories')
export class Category extends BaseCategoryEntity {
  @Column({ nullable: true })
  icon?: string;

  @Column({ type: 'jsonb', nullable: true })
  metadata?: Record<string, any>;

  @Column({ default: true })
  isActive: boolean;
}

Multi-Language Support

// Create multi-language article
const article = await articleService.createArticle({
  title: {
    'zh-TW': '中文標題',
    'en-US': 'English Title',
    'ja-JP': '日本語タイトル'
  },
  content: {
    'zh-TW': '中文內容...',
    'en-US': 'English content...',
    'ja-JP': '日本語の内容...'
  },
  categoryIds: ['category-1', 'category-2'],
  language: 'zh-TW' // Primary language
});

// Query articles in specific language
const articles = await articleService.findArticles({
  language: 'en-US',
  status: 'published'
});

Version Control

// Create article version
const version = await articleService.createVersion(articleId, {
  title: 'Updated Title',
  content: 'Updated content',
  changeReason: 'Fixed typos',
  authorId: userId
});

// Get version history
const versions = await articleService.getVersionHistory(articleId);

// Revert to specific version
await articleService.revertToVersion(articleId, versionId);

// Compare version differences
const diff = await articleService.compareVersions(articleId, version1Id, version2Id);

Approval Workflow

// Submit article for approval
const signatureRequest = await articleService.submitForApproval(articleId, {
  submitterId: userId,
  comments: 'Please review this article'
});

// Approve article
await articleService.approveArticle(articleId, {
  approverId: managerId,
  level: 2, // Approval level
  comments: 'Content looks good, approved'
});

// Reject article
await articleService.rejectArticle(articleId, {
  reviewerId: managerId,
  reason: 'Content needs revision',
  suggestions: 'Please add more details'
});
// Full-text search
const searchResults = await articleService.searchArticles({
  query: 'search keywords',
  language: 'zh-TW',
  categories: ['tech', 'news'],
  dateRange: {
    from: new Date('2024-01-01'),
    to: new Date('2024-12-31')
  },
  page: 1,
  limit: 20
});

// Search suggestions (auto-complete)
const suggestions = await articleService.getSuggestions('keywords');

DataLoader Integration

// Use DataLoader to optimize N+1 query problems
import { ArticleDataloader, CategoryDataloader } from '@rytass/cms-base-nestjs-module';

@Injectable()
export class ArticleResolver {
  constructor(
    private readonly articleDataloader: ArticleDataloader,
    private readonly categoryDataloader: CategoryDataloader
  ) {}

  @ResolveField()
  async categories(@Parent() article: Article) {
    return this.categoryDataloader.loadMany(article.categoryIds);
  }

  @ResolveField()
  async relatedArticles(@Parent() article: Article) {
    return this.articleDataloader.loadRelated(article.id);
  }
}

Configuration Options

CmsBaseModuleOptions

Option Type Default Description
multipleLanguageMode boolean false Enable multi-language support
draftMode boolean true Enable draft mode
signatureLevels SignatureLevel[] [] Approval level settings
fullTextSearchMode boolean false Enable full-text search
autoReleaseAfterApproved boolean false Auto-publish after approval
circularCategoryMode boolean false Allow circular category references
multipleCategoryParentMode boolean false Allow multiple parent categories

Error Handling

import { 
  ArticleNotFoundError,
  CategoryNotFoundError,
  InsufficientPermissionError
} from '@rytass/cms-base-nestjs-module';

try {
  await articleService.publishArticle(articleId, userId);
} catch (error) {
  if (error instanceof ArticleNotFoundError) {
    throw new NotFoundException('Article not found');
  } else if (error instanceof InsufficientPermissionError) {
    throw new ForbiddenException('Insufficient permissions');
  }
  throw error;
}

Best Practices

Performance

  • Use DataLoader to avoid N+1 query problems
  • Set up appropriate database indexes
  • Use pagination for large data queries
  • Enable query caching mechanisms

Security

  • Implement proper permission controls
  • Validate user inputs
  • Use parameterized queries to prevent SQL injection
  • Log sensitive operation activities

Scalability

  • Separate read and write operations
  • Use Redis caching for hot content
  • Implement content delivery networks (CDN)
  • Consider database sharding strategies

Migration

# Generate migration files
npm run typeorm:migration:generate -- -n CreateCmsBaseTables

# Run migrations
npm run typeorm:migration:run

# Revert migrations
npm run typeorm:migration:revert

License

MIT