A modern, secure desktop companion built on Electron and React/TypeScript for browsing and organizing booru-style imageboard content via its public API. Designed for performance and maintainability.
- Disclaimer & Risk Assessment
- Features
- Quick Start
- Documentation
- Architecture Overview
- Product Structure
- Core UX Principles
- Sync & Background
- Settings
- Current Status
- Active Roadmap
- Development Setup
- License & Legal
This project is unofficial and not affiliated with any external website or company.
- Content Risk: The application does not host, redistribute, or bundle any media. All content is loaded directly from the original website's API or CDN. Users are responsible for adhering to local laws regarding NSFW content and the target websiteβs API Terms of Service (ToS).
- API Risk (Polling): The Core Services are implemented with strict Exponential Backoff and Rate Limiting to minimize the risk of IP/key bans due to abusive polling behavior.
- Security Posture: The application is configured with mandatory Electron security hardening (Context Isolation, Preload Scripts) to prevent any potential Remote Code Execution (RCE) via the renderer process.
| Feature | Description |
|---|---|
| π API Authentication | Secure onboarding for Rule34.xxx API credentials (User ID and API Key). Credentials are encrypted at rest and only decrypted when the app needs them for API calls. |
| π€ Artist Tracking | Track artists by tag. Add, view, and delete tracked artists. Add Artist autocomplete suggests artist tags only; tag names are normalized (e.g. metadata like "(123)" is stripped). |
| π Background Synchronization | Fetches new posts from the booru API with rate limiting and exponential backoff on retries. Live sync progress appears in the UI. |
| πΎ Local Metadata Database | Local SQLite library for artists, post metadata (tags, ratings, URLs), and settings. Supports concurrent reads while sync runs. |
| πΌοΈ Artist Gallery | View cached posts for each tracked artist in a responsive grid. Shows previews, ratings, and metadata. Open the source site link; paginate; repair/resync an artist; mark posts as viewed. |
| π¨ Progressive Image Loading | Stills load a low-res preview first, then upgrade to sample when the card is visible. The viewer uses the full-resolution file. Video posts use sample/file for hover preview as applicable. |
| π Rule34 CDN host fallback | If a Rule34 media host fails, the viewer retries known alternate hosts so images and videos keep loading when possible. |
| π Post Metadata | Cached posts include file, preview, and sample URLs, tags, ratings, and publication timestamps for offline browsing and fast filtering. |
| π§ Artist Repair | Repair/resync to refresh low-quality previews or fix sync gaps by re-fetching from the start of that artist's feed. |
| πΎ Backup & Restore | Manual and automatic database backups under RuleDesk-Backups (sibling of RuleDesk-Data). Retention is configurable in Settings (keep last N manual and last N automatic backups separately). Restore replaces the live DB (with checks) and reloads the app. |
| π§Ή DB Maintenance (VACUUM) | Settings shows last VACUUM run, Run VACUUM now, and schedule (manual / weekly / monthly). Lightweight automatic maintenance still runs in the background. |
| π Search Functionality | Search artists locally, tags via booru autocomplete, and posts on Browse with infinite scroll. Artist / character / copyright tags are resolved for the viewer drawer. Multi-provider support (Rule34.xxx, Gelbooru). |
| β Favorites System | Mark posts as favorites and browse your collection. Toggle with F in the viewer or via UI. Favorites are stored locally only. |
| β¬οΈ Download Manager | Download full-resolution media to a folder you choose, with progress tracking and queue management. |
| π₯οΈ Full-Screen Viewer | Immersive viewer with keyboard shortcuts, download, favorites, and tag management. Auto-hide controls and navigation between posts. |
| π§ Navigation & Layout | Sidebar and global top bar across core pages. Updates shows an unread badge that clears when you open Updates. Optional IA polish remains a refinement task, not a missing core feature. |
| π Playlists & Collections | Curated collections independent of tracked artists. Create, rename, delete, export, and import. Add posts from cards or the viewer. Filter/sort galleries; drag-and-drop reorder for manual playlists; smart playlists resolve tags locally and remotely. |
| π Statistics | Statistics page with totals (artists/posts/favorites/unviewed), distribution charts, provider split, top artists/tags, and database file size. |
| π Auto-Updater | Checks for updates and notifies when a newer release is available. Choosing download opens the GitHub Releases page; you install manually (extract the Windows zip / replace the Linux AppImage). There is no automatic in-app install. |
| π Clean English UI | English-only user-facing copy (no i18n stack). |
| π Multi-Source Ready | Multi-booru support today: Rule34.xxx and Gelbooru. New sources can be added without rewriting the core library schema. |
Internal identifiers for maintainers (component names, IPC methods, constants, file paths) live in Architecture Documentation.
The application adheres to a strict Separation of Concerns (SoC) model:
This is the secure Node.js environment. It handles all I/O, persistence, and secrets.
- Desktop Runtime: Electron (desktop runtime for secure Main/Renderer process separation).
- Database: SQLite (via
better-sqlite3driver) with direct synchronous access in Main Process. WAL mode enabled for concurrent reads. - Data Layer: Drizzle ORM (TypeScript type-safety for queries, raw SQL timestamps in milliseconds).
- Security: Secure Storage using Electron's
safeStorageAPI for encrypting API credentials at rest. - API: Custom wrapper based on
axioswith retry and backoff logic. - CDN host fallback (Rule34 media): Renderer
ViewerMediaretries Rule34 media URLs across known alternate hosts when a host fails (viewer-media-urls.ts); Main does not rewrite URLs at fetch time. - Background Jobs: Node.js timers and asynchronous operations.
This is the sandboxed browser environment. It handles presentation.
- Frontend: React + TypeScript
- Locale: English-only β user-facing copy is inline string literals (or a local named constant when the same text is used in 3+ places). No i18n libraries.
- Styling: Tailwind CSS + shadcn/ui (modern UI, good baseline A11y).
- State Management: Zustand (minimalistic state layer, aligned with KISS/YAGNI).
- Data Fetching: TanStack Query (React Query) (caching, loading states, API boundary).
- IPC Architecture: Controller-based IPC handlers with
BaseControllerfor centralized error handling and validation. Type-safe dependency injection via DI Container. - IPC Bridge: Strictly typed TypeScript interface used by the Renderer to communicate with the Main Process (
src/preload/bridge.ts; see architecture). - Security: Context Isolation enforced globally; no direct Node.js access from the Renderer.
- Encryption: API credentials encrypted using Electron's
safeStorageAPI. Decryption only occurs in Main Process when needed for API calls. - Provider Pattern: Multi-booru support via
IBooruProviderinterface. Current implementations: Rule34.xxx, Gelbooru.
π For detailed architecture information, see Architecture Documentation.
The application is organized into the following main sections accessible via the Sidebar:
- Updates - View new posts from tracked artists
- Browse (All posts) - Search the live booru API with chip-based tags, infinite scroll, and advanced filters; Favorites / Browse Source Subscriptions filter modes search the local cache
- Favorites - Local favorites only. There is no booru account-favorites sync path
- Playlists (Collections) - Create and manage curated collections of posts
- Statistics - Extended local metrics and distribution charts (counts, pie charts, top artists/tags, provider artist split, DB size)
- Tracked (Artists/Tags management) - Manage tracked artists and tags
- Settings - Configure downloads, sync, appearance, account, backup/restore, and Danger-zone wipe
A unified Top Bar appears on all content pages providing:
- Search - Chip-based search with automatic updates while typing/selecting tags
- Search syntax help -
CircleHelppopover next to search input with supported Rule34 syntax examples - Filters - AI, media type, source (per
FiltersPanel) - Sort - Newest/oldest (
sortOrderon date-oriented lists) - View Toggle - Switch between grid and masonry layouts
- Sync Status - Real-time sync progress indicator with last sync timestamp β Global sync busy state is the Sidebar sync indicator. Sorting is handled by the dedicated date sort control in the top bar (outside Filters). Search stretches across the available left section and chip rows can expand to a second line when needed.
The full-screen viewer provides a polished media viewing experience:
- Full-screen Mode - Immersive viewing with auto-hide controls
- Navigation - Arrow keys (β/β) for previous/next post
- Hotkeys:
Esc- Close viewerβ/β- Navigate between postsF- Toggle favoriteV- Mark as viewedT- Toggle tags drawer- Mouse side buttons (
Back/Forward) - Captured by viewer and mapped to viewer exit flow (do not navigate background pages)
- Auto-hide Bars - Top and bottom bars automatically hide after inactivity
- Tags Drawer - Right-side sheet with tags grouped by type:
- Click tag to add to search (include)
- Right-click to add exclude (
-tag); state shown with green (include) / red (exclude) ring styling - Artist / Character / Copyright show a compact resolving indicator while tag-type lookup is in flight; βNo artist detectedβ / βNo character detectedβ / βNo copyright detectedβ only after the lookup finishes with no match (session-cached hits render immediately)
β
Implemented in
ViewerDialog/TagsDrawerviauseSearchStore(addIncludeTag/addExcludeTag).
Optimized image loading strategy for performance:
- Preview URL - Low-resolution blurred preview (instant display)
- Sample URL - Medium-resolution sample (loaded in gallery)
- File URL - Full-resolution original (loaded only in viewer)
This ensures fast initial page loads while maintaining high-quality viewing experience. Gallery cards upgrade still images from preview to sample when scrolled into view (PostCard viewport + image decode).
Post cards in gallery views include informative overlays:
- Viewed Badge - Indicator for already viewed posts
- Favorite Badge - Star icon for favorited posts
- Rating Badge - Visual indicator (Safe/Questionable/Explicit)
- Media Type Badge - Icon indicating image or video content β Rating label (S/Q/Explicit) appears in the card hover overlay; video type is indicated where applicable.
When enabled in Settings β Sync, the app starts a full Sync All after the main window is ready (if no sync is already running). Progress uses the same sync pipeline as manual sync.
Optional Sync new artist automatically (off by default) queues repairArtist for each newly added artist via the same exclusive sync mutex β it does not block the add-artist IPC response.
Each artist row stores syncStatus (idle / syncing / error) and lastError. A hard kill mid-sync cannot leave Syncing forever: the next DB init resets stuck syncing β idle. The Artists list badge updates live: AppLayout invalidates ["artists"] on sync:artist and repair start/end (DB remains source of truth).
Settings β Sync β Sync interval controls how often a background full sync runs (Disabled, 15 / 30 / 60 / 120 minutes). The main process enforces a minimum interval of 5 minutes (MIN_INTERVAL_MINUTES in SyncScheduler); values below that are treated as disabled. Rate limiting and backoff in SyncService / ProviderThrottle apply to scheduled runs as well as manual ones.
A lightweight maintenance scheduler runs PRAGMA wal_checkpoint(PASSIVE) and PRAGMA optimize after a short post-startup delay and on a daily timer. This is separate from user-initiated VACUUM/backup operations.
Settings are organized into tabs for faster scanning and lower cognitive load:
- Default download folder - Choose or reset destination folder
- Duplicate behavior -
skiporoverwritefor existing files - Folder structure -
flator{artist_id}subfolder mode - Proxy URL - Optional HTTP/HTTPS proxy for outbound requests/downloads
- Danger zone β Delete all data - Confirmed wipe of everything under
RuleDesk-Data(database,video-cache/, logs, Electron cache), then quit. Does not delete the separate media download folder or DB backups underRuleDesk-Backups. Prefer this over uninstall alone (uninstall leavesRuleDesk-Dataand backups).
- Sync on startup - Toggle automatic sync when app opens
- Sync new artist automatically - Queue sync for an artist right after it is added (off by default)
- Sync interval - Disabled, 15 / 30 / 60 / 120 minutes
- Sync now - Manual trigger in the sidebar with live
Last syncrelative time
- Theme -
System,Light,Dark
- Tag blacklist - Hide posts containing listed tags from Browse and local galleries. Maximum 100 tags
- Create backup - Manual timestamped backup (written to
RuleDesk-Backups) - Restore backup - Restore from backup file (dialog defaults to
RuleDesk-Backups) and reload app. A backup made by a newer app version fails with an error and rolls back β update the app first, then restore - Integrity check - Verify the database is not corrupted
- Orphaned data check - Read-only report of posts/playlist entries/search-index rows without parents (Settings β Database Maintenance); no automatic cleanup
- Auto-backup schedule -
Never/Daily/Weekly(checked on app startup and every hour while the app stays open; default Daily for new installs and for upgrades that still had Never with the opt-in prompt never seen). Daily = when 24 hours have passed since the last automatic backup; Weekly = when 7 days have passed - Automatic backup rotation - Keep the last N manual backups and the last N automatic backups independently (configurable in Settings, range 1β20). The two sets are not summed into one pool
- Optional storage cap - Advanced deployments may set an environment variable to cap total manual backup size in addition to keep-last-N (see Development Setup and architecture)
- Database maintenance (VACUUM) - Last run timestamp/status/error, manual run button, and schedule (
manual/weekly/monthly)
- Provider - Rule34 or Gelbooru; changing provider refreshes feed caches and saves the selection
- User ID - Required for providers that use it (shown when applicable)
- API key update - Password-style input with show/hide toggle
- Paste URL - Paste the full account page URL into either field; User ID and API Key are extracted automatically
- Key status badge - Configured / Not configured
- Settings success/error badges auto-hide after ~5 seconds to avoid stale status indicators.
The application is stable and production-ready (see package.json β version for the current release number) with the following features implemented:
- β Electron Version: 39.8.x with latest security patches
- β Build System: electron-vite for optimal build performance
- β
Database Architecture: Direct synchronous access via
better-sqlite3in Main Process with WAL mode for concurrent reads - β
User Data Path: Neutral
RuleDesk-Datadirectory for dev and packaged builds (same location on a given machine) - β
Testing Architecture: Vitest (unit, integration, property/fuzzing), Playwright (E2E); local
pre-pushhook runsvalidateβdocs:apifreshness βnpm testβnpm run test:isolatedβassert-vitest-min-total(Node 20) - β
Dual ABI Support: Automatic switching between Node.js and Electron ABI for
better-sqlite3during testing - β HMR Status: Renderer HMR is enabled, and Main/Preload sources are watched in development for faster backend iteration.
- β
Schema: Core tables
artists,posts,settings; additionaltag_metadata,search_results_cache,playlists,playlist_entries,tag_blacklist, and FTS5 external content for posts - β
Migrations: Fully functional migration system using
drizzle-kitwith idempotent migration handling - β
Media Type Support:
media_typecolumn inpoststable for efficient image/video filtering (image,video) - β
Indexes: Optimized indexes on
artistId,isViewed,publishedAt,isFavorited,lastChecked,createdAt,mediaType - β
Composite Indexes: Composite indexes on
(artist_id, rating, is_viewed)and(artist_id, media_type)for optimized multi-column filter queries - β
FTS5 Full-Text Search: FTS5 virtual table
posts_ftswithunicode61tokenizer for fast tag searching - β
Provider Support: Multi-booru support with
providerfield in artists table (rule34, gelbooru) - β
Artist Types: UI tracks artists by tag (schema still allows legacy
uploader/queryrows; see roadmap backlog)
- β
Secure Storage: API credentials encrypted using Electron's
safeStorageAPI viaSecureStorageonly (no parallel crypto helpers). Credentials encrypted at rest; decryption only in Main Process - β Database Backup/Restore: Manual backup and restore with integrity checks; configurable retention
- β
Wipe all data: Settings β General β Danger zone deletes
RuleDesk-Datacontents and quits - β
Input Validation: Zod validation per IPC handler via
BaseController(collapse for idempotent; spacing for mutate) - β Context Isolation: Enabled globally with sandbox mode for maximum security
- β CSP (Content Security Policy): Strict CSP in production, relaxed for development (HMR support)
- β
User Data Path: Packaged and dev builds use
%LOCALAPPDATA%/RuleDesk-Dataon Windows (not a folder next to the executable) - β
Age Gate: Age gate component implemented with legal confirmation (
confirmLegalmethod)
- β Tag Normalization: Inputs like "tag (123)" are automatically stripped to "tag" before saving/syncing
- β
Sync Service: Handles
ON CONFLICTcorrectly and populates the gallery with proper upsert logic - β Timestamp Handling: All timestamps use Drizzle timestamp mode with proper milliseconds precision
- β
Provider Pattern: Multi-booru support via
IBooruProviderinterface (Rule34, Gelbooru) - β
Rate Limiting: Shared
ProviderThrottle(~1200ms + 0β400ms jitter per request) across providers - β
Anti-Bot Measures: Shared
USER_AGENTfor API+CDN plus jittered request pacing viaProviderThrottle. - β
Sync integrity:
lastPostIdadvances only after complete pagination; unfinished runs setlastSyncIncomplete. Per-artistsyncStatus/lastErrorare written during sync; hard-kill recovery resets stucksyncingβidleon DB init. Video-cache writes are atomic (tmp+rename) with size-capped LRU last-accessed eviction β see Roadmap.
- β
Progressive image loading (stills):
PostCardupgrades preview β sample in viewport; original in viewer - β
Virtualization:
react-virtuosoimplemented for efficient large list rendering - β
Search Functionality: Local artist search, remote tag search via booru autocomplete API, and direct booru search (
searchBoorumethod) with tag resolution (resolveTags,resolveCharacterTags,resolveCopyrightTags) - β Sidebar Navigation: Persistent grouped sidebar structure (Discover / Library / System) with the current shipped IA.
- β
Global Top Bar: Search (chip-based include/exclude with OR-group tokens), syntax-help popover,
FiltersPanel(AI, media, source), dedicated date sort control, view toggle; Sidebar owns the sync indicator - β Advanced Filtering: Filter by AI-generated tags, media type (image/video), and source (all / favorites / Browse Source Subscriptions filter)
- β Sorting: Sort by date order (newest/oldest) across main feeds
- β View Modes: Grid (virtualized) and masonry (CSS columns) are both shipped and user-selectable. Trade-off remains intentional: masonry prioritizes visual layout over full virtualization on huge feeds.
- β Updates feed: Per-post viewed state, Mark all read for the feed, and a Creators tab with new-post counts and navigation to artist galleries
- β Full-Screen Viewer: Immersive viewer with keyboard shortcuts, download, favorites, and tag management
- β
Video Support:
.mp4,.webm,.mov,.avi,.mkv,.flv,.wmv,.m4vvideo formats supported with native<video>element - β Download Manager: Download full-resolution files with progress tracking and queue management
- β
Favorites System: Complete implementation with
isFavoriteddatabase field, toggle functionality, and keyboard shortcuts - β Backup Controls: UI component for creating and restoring database backups with integrity checks
- β Credential Verification: Verify API credentials before saving and during sync operations
- β
Age Gate Component: Fully implemented with legal confirmation (
AgeGate.tsxcomponent andconfirmLegalIPC method) - β Content Security Policy: Strict CSP with support for Rule34.xxx and Gelbooru.com media sources
- β Rule34 CDN host fallback: Viewer retries Rule34 media across alternate hosts when a host fails
- β
Safe Mode / NSFW blur: When Safe Mode is enabled, gallery cards and the full-screen viewer apply configurable blur to sensitive ratings (
PostCard,ViewerMedia,safeModeStore)
-
Get API Credentials:
- Visit https://rule34.xxx/index.php?page=account&s=options
- Copy your User ID and API Key from the API Access section
-
Age Gate and account:
- Launch the application
- Confirm legal age / ToS in the mandatory Age Gate
- If no API key is stored, enter User ID + API Key and click Save API Key (or paste the account page URL into either field). There is no Skip; the main shell loads only after credentials are configured
- Credentials can be updated later in Settings β Account
-
Add Artists:
- Click "Add Artist" button
- Search for an artist tag (character/copyright tags are filtered out)
- Confirm the tag and click "Add"
-
Sync Posts:
- Click "Sync All" to fetch posts from Rule34.xxx
- Wait for synchronization to complete (progress updates shown in real-time)
- Click on an artist to view their gallery
- Use "Repair" button in gallery to resync and update preview quality if needed
Comprehensive documentation is available in the docs/ directory:
- User Guide - Complete guide for end users (installation, usage, troubleshooting)
- Documentation Index - Complete navigation guide to all documentation
- Glossary - Key terms and concepts (booru, tags, sync, cache, etc.)
π‘ New to RuleDesk?
- Start here: Open the User Guide for the full end-user walkthrough.
- Need a map of docs? Use the Documentation Index.
- Quick Start - First launch and basic setup (this document)
- Features - Complete feature list (this document)
- Settings - Application configuration (this document)
- Sync & Background - Synchronization guide (this document)
- Roadmap - Development roadmap and planned features
- Features.md - Short internal priority list (P1 / P2)
- Product Strategy - Long-term positioning and research pillars
- Architecture Documentation - System architecture and boundaries
- API Reference - Generated IPC channel table (
npm run docs:api) - API Guide - IPC usage patterns, examples, security narrative
- Database Documentation - Schema, migrations, and operational notes
- Rule34 API Reference - Unofficial Rule34.xxx API documentation
- .cursorrules - Code standards and development principles
- .ai/LESSONS.txt - Canonical short lessons (
Problem -> Root Cause -> Invariant Rule)
π‘ Tip: If you're new to RuleDesk, start with the Documentation Index for structured navigation.
Current priority is roadmap parity and UX polish on top of already shipped core modules:
Goal: Allow users to refine the gallery view.
- β
Global top bar β
GlobalTopBar.tsx+FiltersPanel(AI, media, source) and separate date sort control - β
AI / media / source β Backed by
searchStoreand post queries - β
Source on Browse β Favorites / Browse Source Subscriptions filter require a tag query when using those modes (
SourceSwitcher); intentional (see roadmap). Local modes apply AI/media in SQL before pagination. Browse Source Subscriptions filter issinceTracking(join by artist + publish date), not tag-intersection. Distinct from tag-combination subscriptions (Closed β superseded by smart playlists (is_smart/query_json); no separate entity built (2026-09-12 backlog audit)). Remote Source: All AI hide/only on Rule34 is injected into the booru tag query; Gelbooru still uses the Browse worker for AI. Remote Videos / Images inject the live-verifiedvideo/-videotag on Rule34 and Gelbooru. - π‘ View modes β Grid (
VirtuosoGrid) vs masonry (CSS columns); different scaling behavior on huge lists - β FTS5 β Tag search where integrated in browse/search flows
Status: Day-to-day filtering works with current scope (AI/media/source + date sort).
Goal: Allow saving full-resolution files to the local file system.
- β "Download Original" button on post view (implemented in ViewerContent)
- β Download Handler: Downloads run in Main Process with progress tracking
- β
Progress Events: Real-time download progress via IPC events (
onDownloadProgress) - β
File Management: Open downloaded file in folder (
openFileInFolder) - β Batch download: "Download all" flows for galleries and lists (rate-limited; see Settings for folder behavior)
- β Settings: Default download folder and duplicate/structure options in Settings
Goal: Create curated collections of posts independent of Artists/Trackers.
Phase 1: MVP β COMPLETED
- β
Database Tables:
playliststable (id,name,is_smart,query_json,icon_name,created_at) andplaylist_entriestable (playlist_id,post_id,added_at) with proper indexes - β Playlist Management: Create, rename, delete playlists with full CRUD operations
- β Add to Playlist: Quick add menu on Post Cards and in viewer dialog
- β
Playlists Page: Dedicated page in Sidebar with playlist list (
PlaylistsPage) and gallery views (PlaylistGallery) - β Playlist Gallery: Grid and masonry view modes with filtering, sorting, and search
- β Smart Playlists: Support for dynamic playlists with tag-based queries (auto-fill based on tags)
- β Hybrid Smart Search: Smart collections resolve posts from local DB and remote API, merge, and deduplicate results
- β
Manual Reordering: Drag-and-drop post ordering for manual playlists (
positionsort mode) - β
Import/Export: JSON-based playlist transfer (
.ruledesk-playlist.json) via file dialogs - β FTS5 Integration: Fast tag searching within playlists using FTS5 full-text search
- β
IPC Controller: Full
PlaylistControllerimplementation with type-safe operations
Status: β Core playlist functionality fully implemented. Users can create playlists, add posts, view galleries, and manage collections independently of artist tracking.
- β
Database Architecture - β
COMPLETED: Direct synchronous access via
better-sqlite3with WAL mode for concurrent reads. All database operations run in Main Process. - β
Encrypt / Secure Storage for API Credentials - β
COMPLETED: Using Electron's
safeStorageAPI for encryption. API keys encrypted at rest, never exposed to Renderer process. - β Database Backup / Restore System - β COMPLETED: Manual backup and restore functionality implemented with integrity checks and timestamped backups.
- β
IPC Architecture - β
COMPLETED: Controller-based IPC handlers with
BaseControllerfor centralized error handling and validation. Type-safe dependency injection via DI Container. π For detailed roadmap information, see Roadmap Documentation. For backlog and planned work, see Backlog and Planned product work.
This project uses electron-vite as the build tool for both the Electron Main and Renderer processes, ensuring optimal build performance.
- Node.js: v20 LTS
- Git hooks: after clone, point Git at the repo hooks (once per clone):
git config core.hooksPath .githookspre-push runs exactly: npm run validate β npm run docs:api + git diff --exit-code docs/api.md β npm test β npm run test:isolated β node scripts/assert-vitest-min-total.mjs. A failing gate aborts the push. Node.js v20 LTS required.
- npm: v9 or higher
- Git: For version control
# Clone the repository
git clone https://github.com/KazeKaze93/ruledesk.git
cd ruledesk
# Install dependencies
npm install
# Start the application in development mode
# This runs the Vite dev server for the Renderer and starts the Electron Main process.
npm run devThe application stores configuration in SQLite database:
- API Credentials: Stored securely with encryption using Electron's
safeStorageAPI. API keys are encrypted at rest and only decrypted in Main Process when needed for API calls. - Database Location (development and packaged builds use the same neutral path):
- Windows:
%LOCALAPPDATA%\RuleDesk-Data\data.bin - Logs:
%LOCALAPPDATA%\RuleDesk-Data\logs\app.log - Backups:
%LOCALAPPDATA%\RuleDesk-Backups\ - macOS:
~/Library/Application Support/RuleDesk-Data/data.bin(backups:β¦/RuleDesk-Backups/) - Linux:
~/.config/RuleDesk-Data/data.bin(backups:β¦/RuleDesk-Backups/)
- Windows:
- Database Architecture: Direct synchronous access via
better-sqlite3with WAL mode for concurrent reads - Environment variables: None are required for normal use β configuration is handled through the UI. Optional advanced override:
BACKUP_RETENTION_MAX_TOTAL_MBcan cap total manual backup file size in addition to keep-last-N (newest backup is always kept even if a single file exceeds the cap). See architecture.
To package the application for distribution:
# Build for current platform
npm run build
# Package with electron-builder (after build)
npm run dist
# Or use electron-builder directly:
npx electron-builderThe built binaries will be available in the release/ directory. The exact output location may vary depending on your Electron builder configuration.
Official release artifacts (GitHub Releases on v* tags; see user guide β Installation):
| Platform | Artifact | CI |
|---|---|---|
| Windows | RuleDesk-<version>-win.zip β extract and run RuleDesk.exe |
β |
| Linux x64 | RuleDesk-<version>.AppImage β chmod +x and run |
β |
| macOS | β | β Not shipped (Apple signing/notarization not set up; build from source on a Mac if needed) |
Local packaging scripts: npm run dist:win, npm run dist:linux (after npm run build). npm run dist defaults to Windows zip on the current machine.
| Data path change | Unsafe to run below | Notes |
|---|---|---|
Electron default β .rdcache |
below v17.0.0 (e.g. v16.2.0 and older) | First release with .rdcache was v17.0.0. |
.rdcache β RuleDesk-Data |
below v18.1.0 | First release with RuleDesk-Data live path. |
If you already rolled back: stop, use backups under RuleDesk-Backups, or contact support before continuing. Maintainer detail: docs/database.md β Downgrade limitation.
Release hygiene: Production builds disable source maps (electron.vite.config.ts). electron-builder excludes .env*, databases, logs, tests, .cursorrules, .ai/, .cursor/, and *.map from app.asar. Run npm run check:release-artifacts on packaged builds before upload. User API keys are never bundled β they are entered at runtime and stored encrypted in the local user data directory (RuleDesk-Data), not in the installer.
# Typecheck + ESLint + renderer <img> loading/decoding policy
npm run validate
# Regenerate IPC channel reference (commit docs/api.md if it changes)
npm run docs:api
# Individual steps (if needed)
npm run typecheck
npm run lint
npm run check:img-attrs
# Production dependency audit (high severity and above)
npm audit --omit=dev --audit-level=high
# Full local gate before a PR (validate + all Vitest suites + Electron ABI restore)
npm run test:verifyVitest covers unit, integration, and property-based tests. Playwright covers E2E flows. Main: npm test. Isolated (happy-dom + video-proxy): npm run test:isolated. Combined floor: scripts/vitest-min-counts.mjs. tests/unit/TEST_COVERAGE.md is a file inventory (no case totals).
# Main suite: Node ABI β Vitest (excl. isolated) β always restore Electron ABI
npm test
# Isolated suite (forks + wall-clock in pre-push); also restores Electron ABI
npm run test:isolated
# Same main Vitest run via with-node-sqlite (restore on exit)
npm run test:run
# Watch / UI / coverage (Node ABI for the run, Electron ABI restored on exit)
npm run test:watch
npm run test:ui
npm run test:coverage
# Coverage HTML/JSON under coverage/ is gitignored β regenerate locally, do not commit
# Targeted suites
npm run test:integration
npm run test:integration:watch
# E2E (requires build + Playwright browsers)
npm run test:e2eTest layout:
| Directory | Purpose |
|---|---|
tests/unit/ |
Hooks, utilities, RTL component tests (jsdom), DI, credential decrypt |
tests/integration/ |
IPC controllers and services with in-memory SQLite |
tests/property/ |
Property-based / fuzzing tests (fast-check) |
tests/e2e/ |
Playwright user workflows |
Notable Vitest coverage:
| File | Area |
|---|---|
tests/unit/utils/decrypted-credentials.test.ts |
No ciphertext fallback on decrypt failure |
tests/unit/core/di-container.test.ts |
DI Map keyed by token.id |
tests/unit/hooks/useWorkerFilteredPosts.test.ts |
mapWorkerPostToPost field preservation |
tests/unit/shared/provider-search-ipc-payload.test.ts |
Electron IPC error wrapper β typed provider payload |
tests/unit/providers/rule34-provider-fetch-posts.test.ts |
Auth/429/network/parse vs genuine empty results |
tests/unit/services/tag-resolve-coordinator.test.ts |
Tag resolve dedup, rate-limit backoff, negative cache |
tests/integration/controllers/ArtistsController.limit.test.ts |
MAX_TRACKED_ARTISTS (5000) cap |
tests/integration/services/SyncService.queue.test.ts |
runExclusive serializes sync vs repair |
tests/integration/services/SyncService.test.ts |
Auth provider errors β SYNC.ERROR |
Dual ABI for better-sqlite3:
Vitest runs under Node.js; the packaged app uses Electron. Native module ABI must match the runtime:
- All Vitest npm scripts go through
scripts/with-node-sqlite.mjsβdb:rebuild:nodebefore the suite, then alwaysdb:rebuild(Electron) infinally/ on SIGINT npm run devprobes Electron loadability and auto-runsdb:rebuildif the ABI is still wrong
If integration tests fail with NODE_MODULE_VERSION mismatch mid-suite, stop other Node/Electron processes locking better_sqlite3.node and retry via npm test (not bare vitest).
Quality is local (.githooks/pre-push): validate β docs:api freshness β npm test β test:isolated β assert-vitest-min-total. See docs/development.md.
Release β GitHub Actions .github/workflows/release.yml on tag v* (or manual workflow_dispatch with an existing tag): Windows zip + Linux AppImage on native runners, then upload to the GitHub Release for that tag.
This project is licensed under Apache 2.0.
You may use, reproduce, modify, distribute, and sublicense the software under the terms of Apache 2.0. The license includes an express patent grant and requires preservation of copyright and license notices.
The full license text is available in the LICENSE file in this repository.
By using this software, you acknowledge and agree to the following:
18+ Only: This application is intended exclusively for adults (18+) in jurisdictions where viewing NSFW content is legal.
No Content Hosting: The application does not host, store, mirror, or redistribute any media content. All media is requested directly from the original websiteβs API/CDN at the userβs initiative.
Use at Your Own Risk: The authors and contributors of this project:
- Do not control the content provided by third-party services.
- Do not endorse, moderate, or curate any content accessed through this software.
- Are not responsible for how you use this software or which content you access with it.
Compliance with Laws & ToS: You are solely responsible for:
- Complying with the laws and regulations applicable in your country/region.
- Complying with the target website's Terms of Service, API rules, and any usage limitations (including rate limits and content policies).
No Warranty / Limitation of Liability: This software is provided βAS ISβ, without warranties or conditions of any kind, either express or implied. To the fullest extent permitted by applicable law, in no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
If you modify the database schema (src/main/db/schema.ts):
# Generate migration from schema changes
npm run db:generate
# Run migrations manually (migrations also run automatically on startup)
npm run db:migrate
# Open Drizzle Studio to inspect database
npm run db:studioNote: Migrations run automatically on application startup. The migration path is automatically detected based on whether the app is packaged or in development mode.
Performance Optimizations:
- FTS5 Full-Text Search: Fast tag searching using SQLite FTS5 virtual table with
unicode61tokenizer - Composite Indexes: Optimized indexes for common filter combinations (artist + rating + view status)
- External Content Tables: FTS5 uses external content to avoid data duplication and save storage space
- All builds: neutral user data directory (
RuleDesk-Data/βdata.bin,logs/app.log,backup-settings.json) plus siblingRuleDesk-Backups/for DB snapshots; see paths above
π For detailed database information, see Database Documentation.
This project adheres to strict development principles:
- Architecture: SOLID, DRY, KISS, YAGNI principles
- TypeScript: Strict typing, no
anyor unsafe casts - Error Handling: Proper error handling with descriptive messages via
BaseController - Security: Context Isolation enabled, sandbox mode, CSP headers, no direct Node.js access from Renderer
- Database: Type-safe queries via Drizzle ORM, no raw SQL (except migrations)
- UI: Tailwind CSS only, no inline styles, shadcn/ui components, accessibility considerations
- Logging:
electron-logfor all logging (noconsole.login production code); credential/path redaction via hooks (src/shared/utils/log-redaction.ts) on main and renderer transports - IPC: Controller-based architecture with dependency injection
π For detailed guidelines, see .cursorrules and .ai/LESSONS.txt.