Skip to content

littlestmo/shelf-ai

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

290 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Shelf AI | Intelligent Library Management System

AI-Powered Library System with Real-Time Data Sync

User Dashboard Admin Dashboard
User Dashboard Admin Dashboard

Next.js React TypeScript SpacetimeDB Vercel AI SDK Clerk Turborepo Rust Zod pnpm CC BY-NC 4.0

Typecheck Prettier Check

Overview

Shelf AI is an AI-powered library management system built as a Turborepo monorepo. It features two Next.js 16 dashboards (admin and user), a Rust-based SpacetimeDB server module, and shared UI/logic packages. AI capabilities, semantic search, book generation, and magic shuffle, are powered by Google Gemini via the Vercel AI SDK.

Preview

User Dashboard Admin Dashboard
User Dashboard Admin Dashboard
AI Book Generator Admin AI Book Gen
Library Catalog Admin Books Catalog
Shelf View Admin Books View
AI Search Admin Users View
Book Details Admin Library Branches
Book Preview Admin Suspend User
i18n Support
Light Mode
User Profile
Upload Book

Monorepo Structure

shelf-ai/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ admin/          β†’ Admin dashboard (Next.js, port 3001)
β”‚   β”œβ”€β”€ user/           β†’ User dashboard (Next.js, port 3002)
β”‚   └── server/         β†’ SpacetimeDB module (Rust/WASM)
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ ui/             β†’ Shared React component library
β”‚   β”œβ”€β”€ shared/         β†’ Hooks, types, schemas, constants, i18n
β”‚   β”œβ”€β”€ eslint-config/  β†’ Shared ESLint configuration
β”‚   └── typescript-config/ β†’ Shared TSConfig presets
β”œβ”€β”€ docs/tutorials/     β†’ Setup and integration guides
β”œβ”€β”€ turbo.json          β†’ Turborepo pipeline config
└── pnpm-workspace.yaml β†’ Workspace definition

Architecture

Traditional library apps use REST APIs with PostgreSQL. Shelf AI replaces this with SpacetimeDB, a serverless database where backend logic runs as WASN modules. Clients subscribe to table changes over WebSockets and receive real-time delta updates, eliminating polling and HTTP round-trips entirely.

Data Synchronization Flow

sequenceDiagram
    participant C as Next.js Client
    participant WS as WebSocket Connection
    participant W as WASM Reducer
    participant T as In-Memory Tables

    rect rgb(15, 42, 30)
    Note over C: Action Dispatched
    C->>WS: Call Reducer (e.g. addBook)
    WS->>W: Execute WASM Logic
    W->>T: Mutate In-Memory State
    T-->>WS: Broadcast Delta to Subscribers
    WS-->>C: onUpdate Callback β†’ React Re-render
    Note over C: UI Updated Instantly
    end
Loading

AI Features Architecture

sequenceDiagram
    participant UC as Client (React)
    participant RH as Next.js Route Handler
    participant AI as Google Gemini 2.5 Flash
    participant SDB as SpacetimeDB

    UC->>RH: POST /api/ai/search { query, catalog }
    RH->>AI: generateObject(prompt + zod schema)
    AI-->>RH: Structured JSON (ranked results)
    RH-->>UC: Return matches with relevance scores

    opt Admin: Book Generation
        UC->>RH: POST /api/ai/generate { prompt }
        RH->>AI: generateObject(book metadata schema)
        AI-->>RH: Complete book object
        RH-->>UC: Return generated book
        UC->>SDB: Persist via useAddBook reducer
    end

    opt Magic Shuffle
        UC->>RH: POST /api/ai/shuffle { catalog }
        RH->>AI: generateObject(themed picks schema)
        AI-->>RH: Thematically linked books
        RH-->>UC: Return picks + theme name
    end
Loading

Authentication Flow

sequenceDiagram
    participant U as User
    participant C as Next.js App
    participant CK as Clerk
    participant SDB as SpacetimeDB

    U->>C: Visit /sign-in
    C->>CK: Render Clerk Sign-In Component
    U->>CK: Enter Credentials
    CK-->>C: Session Token + User Object
    C->>SDB: Connect WebSocket (with clerkId)
    SDB-->>C: Subscription Sync (user data, books, etc.)
    C-->>U: Render Dashboard
Loading

User Flows

Book Search and Issue

graph LR
    A([Home]) --> B([Search])
    B --> C([Book Details])
    C --> D{Available?}
    D -->|Yes| E([Issue Book])
    D -->|No| F([Reserve])
    E --> G([Confirm + Student ID])
    G --> H([Issued βœ“])

    style A fill:#10b981,color:#fff
    style H fill:#10b981,color:#fff
    style F fill:#f59e0b,color:#fff
Loading

AI-Powered Search

graph LR
    A([Home]) --> B([AI Search])
    B --> C([Write Prompt])
    C --> D([AI Ranked Suggestions])
    D --> E([Book Details])
    E --> F{Available?}
    F -->|Yes| G([Issue])
    F -->|No| H([Reserve])
    G --> I([Confirm])
    I --> J([Issued βœ“])

    style A fill:#10b981,color:#fff
    style J fill:#10b981,color:#fff
    style H fill:#f59e0b,color:#fff
Loading

Magic Shuffle Discovery

graph LR
    A([Home]) --> B([Search])
    B --> C([Magic Shuffle 🎲])
    C --> D([Themed Suggestions])
    D --> E([Book Details])
    E --> F{Available?}
    F -->|Yes| G([Issue])
    F -->|No| H([Reserve])
    G --> I([Confirm])
    I --> J([Issued βœ“])

    style A fill:#10b981,color:#fff
    style J fill:#10b981,color:#fff
    style C fill:#8b5cf6,color:#fff
    style H fill:#f59e0b,color:#fff
Loading

Book Return

graph LR
    A([Home]) --> B([My Books])
    B --> C([Select Book])
    C --> D([Return])
    D --> E([Rate Book ⭐])
    E --> F([Returned βœ“])

    style A fill:#10b981,color:#fff
    style F fill:#10b981,color:#fff
    style E fill:#f59e0b,color:#fff
Loading

Admin: AI Book Generation

graph LR
    A([Admin Dashboard]) --> B([AI Generate])
    B --> C([Enter Prompt])
    C --> D([AI Generates Metadata])
    D --> E([Review Book])
    E --> F([Save to Library])
    F --> G([Persisted in SpacetimeDB βœ“])

    style A fill:#6366f1,color:#fff
    style G fill:#10b981,color:#fff
    style D fill:#8b5cf6,color:#fff
Loading

Database Schema

erDiagram
    LibraryUser {
        string id PK
        string clerk_id UK
        string name
        string email
        UserRole role
        string phone
        string address
        string avatar
        string member_since
        MembershipType membership_type
        int borrow_limit
        string bio
        string register_number
        string department
        UserStatus status
        timestamp created_at
    }
    Book {
        string id PK
        string title
        string author
        string isbn
        BookCategory category
        string published_date
        string publisher
        int total_copies
        int available_copies
        BookStatus status
        string cover_url
        string description
        string location
        string branch_id FK
        BookFormat format
        int pages
        string language
        string edition
        float rating
        timestamp created_at
        timestamp updated_at
    }
    Branch {
        string id PK
        string name
        string address
        string city
        string phone
        string email
        string manager
        int total_books
        int total_members
        BranchStatus status
        string open_hours
    }
    BorrowRecord {
        string id PK
        string book_id FK
        string user_id FK
        string borrow_date
        string due_date
        string return_date
        BorrowStatus status
        string branch_id FK
        float fine
        int renew_count
    }
    Notification {
        string id PK
        string user_id FK
        NotificationType notification_type
        string title
        string message
        string date
        bool read
    }
    BookRating {
        string id PK
        string book_id FK
        string user_id FK
        float rating
        string created_at
    }
    AiGeneration {
        string id PK
        string user_id FK
        string prompt
        string result_book_id FK
        AiGenerationStatus status
        timestamp created_at
    }
    Branch ||--o{ Book : houses
    LibraryUser ||--o{ BorrowRecord : borrows
    Book ||--o{ BorrowRecord : tracked_in
    Branch ||--o{ BorrowRecord : processed_at
    LibraryUser ||--o{ Notification : receives
    LibraryUser ||--o{ BookRating : rates
    Book ||--o{ BookRating : rated_by
    LibraryUser ||--o{ AiGeneration : requests
    Book ||--o{ AiGeneration : generated_as
Loading

AI Capabilities

Feature Endpoint Description
Semantic Search POST /api/ai/search Natural language queries ranked by relevance
Book Generation POST /api/ai/generate Complete book metadata from a text prompt
Magic Shuffle POST /api/ai/shuffle Thematically linked book discovery

Scripts

Command Description
pnpm dev Start all dev servers via Turborepo
pnpm build TypeScript check + production build (all apps)
pnpm lint ESLint strict checks across monorepo
pnpm check-types TypeScript verification for all packages
pnpm format Prettier formatting

Getting Started

Prerequisites

  • Node.js 22+
  • pnpm 9+
  • Rust toolchain (for SpacetimeDB server module)
  • SpacetimeDB CLI (spacetime)

Quick Start

git clone https://github.com/littlestmo/shelf-ai.git
cd turbo
pnpm install

Environment Setup

Copy and configure .env.local in both apps/user/ and apps/admin/:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/home
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/home
NEXT_PUBLIC_SPACETIMEDB_URI=http://localhost:3000
NEXT_PUBLIC_SPACETIMEDB_MODULE=shelf-ai
GOOGLE_GENERATIVE_AI_API_KEY=your_key_here

Deploy SpacetimeDB Module

cd apps/server
spacetime start

# on a separate terminal:
spacetime publish -s local shelf-ai

Run Development Servers

pnpm dev

Admin: http://localhost:3001 Β· User: http://localhost:3002

Tutorials

Guide Description
Environment Setup Configure all environment variables
Clerk Auth Setup Get Clerk API keys step by step
Google AI Setup Get Gemini API key from Google AI Studio
SpacetimeDB Setup Install CLI, publish module, connect client
AI Integration How the Vercel AI SDK is used in the codebase
i18n Setup Internationalization with react-i18next
Railway Deployment Guide Deploy to Railway

License

CC BY-NC 4.0

This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.