AstroBaaS

Build on it

Architecture

Generated from architecture.md in the AstroBaaS repository. The repository is the source of truth; this page is a copy of it.

AstroBaaS is a self-hostable CMS and backend-as-a-service built on Astro. It runs as a server-rendered application (output: 'server' in astro.config.ts), reading content from the database on every request. There is no rebuild step to publish a post.

Status note (reflects the shipped code): AstroBaaS runs as a full Astro SSR app via the Node standalone adapter — public pages render per-request from LowDB, so the “build-time static generation” limitations discussed below do not apply. src/lib/sync-service.ts — the client-polling approach this document used to reference — was deleted: its change check compared changes.length against a response envelope, so it was undefined > 0 and had never fired since the day it was written, while shipping 3.2 KB to every reader. The rest of this document is retained as design background.

Current Architecture

1. Technology Stack

  • Frontend Framework: Astro.js (Static Site Generation + Islands Architecture)
  • Database: LowDB (JSON-based file database)
  • API Layer: Astro API Routes
  • UI Framework: Tailwind CSS + Vanilla JavaScript
  • Plugin System: Custom plugin architecture with filters and hooks

2. Data Flow Architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Admin Panel   │    │   API Routes    │    │   Database      │
│   (Backend)     │◄──►│   (Middleware)  │◄──►│   (LowDB)       │
└─────────────────┘    └─────────────────┘    └─────────────────┘


                       ┌─────────────────┐
                       │   Frontend      │
                       │   (Static)      │
                       └─────────────────┘

3. Current Data Entities

Posts

  • Storage: db.json → posts array
  • API Endpoints:
    • GET /api/posts/get - Fetch posts with filtering
    • GET /api/posts/[slug] - Fetch single post
    • POST /api/posts/create - Create new post
    • PUT /api/posts/update - Update existing post
    • DELETE /api/posts/delete - Delete post
  • Frontend Display: Static generation at build time

Themes

  • Storage: db.json → settings array (theme_settings, active_theme)
  • API Endpoints:
    • GET /api/themes/get - Fetch theme settings
    • POST /api/themes/update - Update theme configuration
  • Frontend Application: CSS custom properties injection

4. Current Limitations

  1. Static Generation Gap: Frontend content is generated at build time, not reflecting real-time database changes
  2. No Real-time Sync: Backend edits don’t automatically update frontend without rebuild
  3. Theme Application: Theme changes require manual frontend refresh
  4. Build Dependency: Content updates require full site rebuild for visibility

Architectural Options for Synchronization

Architecture Pattern: Static Site Generation with Dynamic Content Islands

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Admin Panel   │    │   API Routes    │    │   Database      │
│   (Backend)     │◄──►│   (Middleware)  │◄──►│   (LowDB)       │
└─────────────────┘    └─────────────────┘    └─────────────────┘


                       ┌─────────────────┐
                       │   Frontend      │
                       │   Static +      │
                       │   Dynamic       │
                       │   Islands       │
                       └─────────────────┘

Implementation Strategy:

  • Keep static generation for SEO and performance
  • Add dynamic content loading for real-time updates
  • Use Astro Islands for interactive components
  • Implement client-side content refresh mechanisms

Pros:

  • Best of both worlds (SEO + Real-time updates)
  • Maintains Astro’s performance benefits
  • Gradual migration path
  • Excellent caching strategies

Cons:

  • Increased complexity
  • Potential content flash during updates
  • Requires careful state management

Option 2: Server-Side Rendering (SSR)

Architecture Pattern: Full SSR with Dynamic Content

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Admin Panel   │    │   API Routes    │    │   Database      │
│   (Backend)     │◄──►│   (Middleware)  │◄──►│   (LowDB)       │
└─────────────────┘    └─────────────────┘    └─────────────────┘


                       ┌─────────────────┐
                       │   SSR Frontend  │
                       │   (Dynamic)     │
                       └─────────────────┘

Implementation Strategy:

  • Convert to Astro SSR mode
  • Fetch content on each request
  • Real-time content synchronization
  • Dynamic theme application

Pros:

  • True real-time synchronization
  • Simplified architecture
  • No build step required for content updates

Cons:

  • Loss of static generation benefits
  • Increased server load
  • Potential SEO implications
  • Higher hosting requirements

Option 3: Event-Driven Architecture with WebSockets

Architecture Pattern: Static + Real-time Event System

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Admin Panel   │    │   API Routes    │    │   Database      │
│   (Backend)     │◄──►│   (Middleware)  │◄──►│   (LowDB)       │
└─────────────────┘    └─────────────────┘    └─────────────────┘


                       ┌─────────────────┐    ┌─────────────────┐
                       │   WebSocket     │    │   Frontend      │
                       │   Server        │◄──►│   (Static +     │
                       │                 │    │   Real-time)    │
                       └─────────────────┘    └─────────────────┘

Implementation Strategy:

  • Maintain static generation
  • Add WebSocket server for real-time events
  • Push content updates to connected clients
  • Event-driven content refresh

Pros:

  • Real-time updates without page refresh
  • Maintains static benefits
  • Excellent user experience
  • Scalable event system

Cons:

  • Complex infrastructure
  • WebSocket management overhead
  • Requires persistent connections
  • Additional server resources

Option 4: API-First with Client-Side Hydration

Architecture Pattern: Static Shell + Dynamic Content Loading

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Admin Panel   │    │   API Routes    │    │   Database      │
│   (Backend)     │◄──►│   (Middleware)  │◄──►│   (LowDB)       │
└─────────────────┘    └─────────────────┘    └─────────────────┘


                       ┌─────────────────┐
                       │   Frontend      │
                       │   Static Shell  │
                       │   + API Calls   │
                       └─────────────────┘

Implementation Strategy:

  • Generate static page shells
  • Load content dynamically via API calls
  • Client-side rendering for content areas
  • Progressive enhancement approach

Pros:

  • Fast initial page loads
  • Real-time content updates
  • API-first design
  • Flexible content management

Cons:

  • SEO challenges for dynamic content
  • JavaScript dependency
  • Potential loading states
  • Complex state management

Phase 1: Hybrid Static + Dynamic (Option 1)

Immediate Implementation:

  1. Content Synchronization System

    • Create content refresh mechanisms
    • Implement client-side API polling
    • Add cache invalidation strategies
    • Build content update notifications
  2. Theme Synchronization

    • Real-time CSS custom property updates
    • Dynamic stylesheet injection
    • Theme change event system
    • Frontend theme state management
  3. API Enhancement

    • Add content change timestamps
    • Implement incremental update endpoints
    • Create theme change notifications
    • Build content validation layers

Phase 2: Advanced Features

  1. Real-time Updates

    • WebSocket integration for instant updates
    • Live preview capabilities
    • Multi-user editing support
    • Conflict resolution mechanisms
  2. Performance Optimization

    • Intelligent caching strategies
    • Content delivery optimization
    • Progressive loading mechanisms
    • Background sync capabilities
  3. Developer Experience

    • Hot module replacement for themes
    • Live reload for content changes
    • Development mode enhancements
    • Debugging tools and logging

Implementation Details

Content Synchronization Architecture

// Content Sync Service
class ContentSyncService {
  private lastSync: number = 0;
  private syncInterval: number = 5000; // 5 seconds
  
  async checkForUpdates(): Promise<ContentUpdate[]> {
    const response = await fetch(`/api/content/changes?since=${this.lastSync}`);
    const updates = await response.json();
    this.lastSync = Date.now();
    return updates.changes;
  }
  
  async applyUpdates(updates: ContentUpdate[]): Promise<void> {
    for (const update of updates) {
      switch (update.type) {
        case 'post_update':
          await this.updatePostContent(update);
          break;
        case 'theme_update':
          await this.updateTheme(update);
          break;
      }
    }
  }
}

Theme Synchronization Architecture

// Theme Sync Service
class ThemeSyncService {
  async applyThemeUpdate(themeSettings: ThemeSettings): Promise<void> {
    // Update CSS custom properties
    const root = document.documentElement;
    Object.entries(themeSettings.colors).forEach(([key, value]) => {
      root.style.setProperty(`--${key}-color`, value);
    });
    
    // Load Google Fonts if needed
    if (themeSettings.typography.headingFont !== this.currentFont) {
      await this.loadGoogleFont(themeSettings.typography.headingFont);
    }
    
    // Apply layout changes
    this.applyLayoutSettings(themeSettings.layout);
  }
}

Database Schema Evolution

Current Schema

{
  "posts": [...],
  "categories": [...],
  "users": [...],
  "themes": [...],
  "settings": [...]
}

Enhanced Schema for Synchronization

{
  "posts": [...],
  "categories": [...],
  "users": [...],
  "themes": [...],
  "settings": [...],
  "content_changes": [
    {
      "id": "change_id",
      "entity_type": "post|theme|category",
      "entity_id": "entity_id",
      "change_type": "create|update|delete",
      "timestamp": "2024-01-01T00:00:00Z",
      "data": {...}
    }
  ],
  "sync_metadata": {
    "last_content_update": "2024-01-01T00:00:00Z",
    "last_theme_update": "2024-01-01T00:00:00Z",
    "version": "1.0.0"
  }
}

Security Considerations

  1. API Security

    • Authentication for admin operations
    • Rate limiting for public APIs
    • Input validation and sanitization
    • CSRF protection
  2. Content Security

    • XSS prevention in dynamic content
    • Content sanitization
    • Safe HTML rendering
    • User permission validation
  3. Theme Security

    • CSS injection prevention
    • Safe custom property handling
    • Theme validation
    • Malicious code detection

Performance Considerations

  1. Caching Strategy

    • Browser caching for static assets
    • API response caching
    • Content-based cache invalidation
    • CDN integration
  2. Loading Optimization

    • Lazy loading for non-critical content
    • Progressive enhancement
    • Critical CSS inlining
    • Resource prioritization
  3. Bundle Optimization

    • Code splitting for sync features
    • Tree shaking for unused code
    • Compression and minification
    • Asset optimization

Monitoring and Analytics

  1. Performance Monitoring

    • Page load times
    • API response times
    • Content sync latency
    • Error tracking
  2. Usage Analytics

    • Content update frequency
    • Theme change patterns
    • User engagement metrics
    • Admin panel usage
  3. Health Checks

    • Database connectivity
    • API endpoint availability
    • Sync service status
    • Theme application success

Conclusion

The recommended hybrid approach (Option 1) provides the best balance of performance, SEO benefits, and real-time synchronization capabilities. This architecture maintains Astro’s static generation advantages while adding dynamic content synchronization features.

The implementation should be phased, starting with basic content and theme synchronization, then evolving to more advanced real-time features as needed. This approach ensures a stable, performant, and maintainable CMS that can grow with user requirements.