Skip to content

Contributing

Prerequisites

  • Node.js 24+
  • npm 10+
  • Git

Setup

bash
git clone https://github.com/tvcsantos/retrosync.git
cd retrosync
npm install
npm run dev

This starts the Electron app in development mode with hot module replacement for the renderer.

Project Structure

text
retrosync/
├── src/
│   ├── main/                   # Electron main process
│   │   ├── index.ts            # App entry, window creation, IPC handlers
│   │   ├── config.ts           # JSON config management
│   │   ├── igdb.ts             # IGDB API integration
│   │   ├── platforms.ts        # Device profiles & platform definitions
│   │   ├── library.ts          # Library management (add/remove games)
│   │   ├── imageCache.ts       # IGDB cover image caching
│   │   ├── fs-utils.ts         # Shared async filesystem helpers
│   │   ├── db/                 # Database setup & schema
│   │   │   ├── index.ts        # SQLite initialization (WAL mode)
│   │   │   └── schema.ts       # Drizzle table definitions
│   │   ├── addons/             # Addon system
│   │   │   ├── index.ts        # Barrel exports
│   │   │   ├── types.ts        # Addon interface contracts
│   │   │   ├── context.ts      # Context passed to addon factories
│   │   │   ├── loader.ts       # Dynamic addon loading from disk
│   │   │   ├── registry.ts     # Addon lifecycle & parallel queries
│   │   │   ├── ipc.ts          # Addon IPC handlers
│   │   │   └── local-folder/   # Built-in local folder addon
│   │   ├── imports/            # Import queue manager
│   │   │   ├── manager.ts      # Queue, concurrency, staging, transfer lifecycle
│   │   │   ├── types.ts        # Import types & interfaces
│   │   │   └── index.ts        # Import IPC handlers
│   │   └── bios/               # BIOS management
│   │       └── index.ts        # BIOS source aggregation & installation
│   ├── renderer/               # React frontend
│   │   └── src/
│   │       ├── App.tsx         # Root component, routing, layout
│   │       ├── main.tsx        # React mount
│   │       ├── pages/          # Top-level views
│   │       ├── components/     # Reusable UI components
│   │       ├── store/          # Zustand state management
│   │       ├── types/          # Renderer type definitions
│   │       └── assets/         # CSS, images
│   └── preload/                # Electron preload (IPC bridge)
│       ├── index.ts            # contextBridge API
│       └── index.d.ts          # Type declarations for window.api
├── addons/                     # External addon packages (gitignored, runtime only)
├── resources/
│   └── migrations/             # Main database migrations
├── build/                      # Build assets (icons, entitlements)
├── docs/                       # Documentation
├── electron.vite.config.ts     # Vite + Electron build config
├── electron-builder.yml        # Packaging config
├── drizzle.config.ts           # Main Drizzle migration config
├── eslint.config.mjs           # ESLint config
├── tsconfig.json               # Root TypeScript config
├── tsconfig.node.json          # Main + preload TypeScript config
└── tsconfig.web.json           # Renderer TypeScript config

Scripts

ScriptDescription
npm run devStart in development mode with HMR (Hot Module Replacement)
npm run buildTypecheck + build for production
npm run startPreview the production build
npm run lintRun ESLint
npm run formatRun Prettier on all files
npm run typecheckRun both TypeScript checks
npm run typecheck:nodeTypecheck main + preload
npm run typecheck:webTypecheck renderer
npm run db:generateGenerate main database migrations
npm run build:macBuild macOS DMG
npm run build:winBuild Windows installer
npm run build:linuxBuild Linux packages
npm run build:unpackBuild + unpack (no installer)
npm run docs:devStart VitePress dev server
npm run docs:buildBuild the documentation site
npm run docs:previewPreview the built documentation site

Code Style

General

  • TypeScript throughout - no any types (enforced by ESLint)
  • Prettier for formatting - run npm run format before committing
  • Unused variables/parameters prefixed with _ (e.g., _platformIds)
  • Prefer const over let; avoid var
  • Default exports for React components (one component per file)

React

  • Functional components only
  • Zustand for state - no useContext for global state
  • Headless UI for accessible interactive primitives
  • Tailwind utility classes - no CSS modules or styled-components

Electron

  • All filesystem/network I/O in the main process
  • Renderer communicates exclusively through window.api.*
  • IPC handlers return { ok: true, data? } or { ok: false, error } shapes
  • Use electron-log scoped loggers, not console.log

Naming

  • Files: kebab-case for directories, PascalCase.tsx for components, camelCase.ts for modules
  • Types/Interfaces: PascalCase
  • Functions/variables: camelCase
  • Constants: UPPER_SNAKE_CASE for module-level constants
  • Database tables: snake_case

Verification

Before submitting changes, run:

bash
npm run lint          # Zero errors, zero warnings
npm run typecheck     # Both node and web configs pass

For addon changes, run the addon's own typecheck in its repository:

bash
cd path/to/<addon-name>
npm run typecheck

Database Changes

If you modify the database schema:

  1. Edit the schema file (src/main/db/schema.ts)

  2. Generate a migration:

    bash
    npm run db:generate
  3. Review the generated SQL in resources/migrations/

  4. Test the migration by running the app fresh

External addons manage their own migrations independently in their own repositories.

Adding a New Page

  1. Create src/renderer/src/pages/MyPage.tsx
  2. Add the page ID to the Page type in src/renderer/src/types/
  3. Add a route case in App.tsx
  4. Add a sidebar entry in Sidebar.tsx

Adding a New IPC Channel

  1. Add the handler in the appropriate main-process module
  2. Register it in src/main/index.ts (or the relevant ipc.ts)
  3. Add the bridge call in src/preload/index.ts
  4. Add the type declaration in src/preload/index.d.ts
  5. Call it from the renderer via window.api.*

Released under the MIT License.