Skip to content

Contributing to Smyles Station

Thank you for your interest in contributing to Smyles Station! This guide will help you get started with development and understand the project's structure and conventions.

Table of Contents

Getting Started

Prerequisites

  • Node.js >= 23.0.0
  • npm (comes with Node.js)
  • Git
  • A code editor (VS Code recommended)

Initial Setup

  1. Fork and clone the repository:

    git clone https://github.com/buff-sudo/smyles-station.git
    cd smyles-station
    

  2. Install dependencies:

    npm install
    

  3. Start the development server:

    npm start
    

The application will start in development mode with hot-reload enabled.

Development Workflow

Running the Application

# Start in development mode (hot-reload enabled)
npm start

# Build all packages
npm run build

# Run type checking
npm run typecheck

# Run end-to-end tests
npm test

# Compile executable for distribution
npm run compile

Development Mode Features

  • Hot-reload for renderer changes (React components, CSS)
  • Automatic restart on main process changes
  • React DevTools available in development
  • Source maps enabled for debugging

Project Architecture

Smyles Station follows Electron's security-first architecture with strict process isolation.

Monorepo Structure

The project is organized as a monorepo with the following packages:

packages/
   main/              # Electron main process (Node.js)
      src/
         index.ts   # Application entry point
         modules/   # Feature modules
   preload/           # Preload scripts (secure bridge)
      src/
          index.ts   # Exposed APIs
   renderer/          # React UI (browser context)
      src/
          App.tsx    # Main React component
          components/
   integrate-renderer/ # Build tooling
   electron-versions/ # Helper utilities

Process Communication

graph TB
    R["Renderer<br/>(packages/renderer)<br/><br/>React UI - Browser context<br/>no Node.js"]
    P["Preload<br/>(packages/preload)<br/><br/>Secure bridge<br/>Limited Electron APIs"]
    M["Main<br/>(packages/main)<br/><br/>Node.js runtime<br/>Full system access"]

    R -->|Import/Call| P
    P -->|IPC| M

Code Organization

Main Process Modules

All main process features are implemented as modules in packages/main/src/modules/:

  • AdminModule.ts - Password-protected admin panel
  • SessionModule.ts - Time-limited session management
  • UsageStatsModule.ts - Usage tracking and statistics
  • ShutdownScheduleModule.ts - Automatic shutdowns
  • WindowManager.ts - Window creation and management
  • BlockNotAllowedOrigins.ts - URL whitelist enforcement
  • ExternalUrls.ts - External URL handling
  • AbstractSecurityModule.ts - Base class for security features

Module Pattern

Each module follows a consistent pattern:

export class MyModule {
  constructor(private readonly browserWindow: BrowserWindow) {
    this.init();
  }

  private init() {
    // Setup IPC handlers, event listeners, etc.
  }

  // Public methods exposed via IPC
  // Private helper methods
}

Adding New Features

1. Main Process Features

To add a new feature to the main process:

  1. Create a new module in packages/main/src/modules/:

    // packages/main/src/modules/MyFeatureModule.ts
    import {BrowserWindow, ipcMain} from 'electron';
    
    export class MyFeatureModule {
      constructor(private readonly browserWindow: BrowserWindow) {
        this.setupIpcHandlers();
      }
    
      private setupIpcHandlers() {
        ipcMain.handle('my-feature:action', async () => {
          // Implementation
          return result;
        });
      }
    }
    

  2. Register the module in packages/main/src/index.ts:

    import {MyFeatureModule} from './modules/MyFeatureModule';
    
    // In the app initialization
    new MyFeatureModule(browserWindow);
    

2. Exposing APIs to Renderer

To make functionality available to the React UI:

  1. Add the function to packages/preload/src/index.ts:

    export async function myFeatureAction(): Promise<Result> {
      return ipcRenderer.invoke('my-feature:action');
    }
    

  2. Update TypeScript types in packages/renderer/src/electron.d.ts:

    interface Window {
      myFeatureAction: () => Promise<Result>;
    }
    

  3. Use in React components:

    import {myFeatureAction} from '@app/preload';
    
    const result = await myFeatureAction();
    

3. UI Components

Create new React components in packages/renderer/src/components/:

// packages/renderer/src/components/MyComponent.tsx
import React from 'react';
import './MyComponent.css';

export const MyComponent: React.FC = () => {
  return (
    <div className="my-component">
      {/* Component content */}
    </div>
  );
};

Testing

End-to-End Tests

E2E tests are located in the tests/ directory and use Playwright:

// tests/my-feature.spec.ts
import {test, expect} from '@playwright/test';
import {ElectronApplication} from 'playwright';

test('my feature works', async ({page}) => {
  // Test implementation
});

Run tests with:

npm test

Manual Testing Checklist

Before submitting a PR, manually verify:

  • [ ] Application starts without errors
  • [ ] Feature works in both development and compiled modes
  • [ ] No console errors in DevTools
  • [ ] TypeScript compilation passes (npm run typecheck)
  • [ ] UI is responsive and accessible
  • [ ] Security features (URL blocking, session limits) still work

Code Style

TypeScript

  • Use TypeScript for all new code
  • Enable strict mode
  • Prefer interfaces over types for object shapes
  • Use async/await over promises
  • Avoid any - use proper types or unknown

Naming Conventions

  • Files: PascalCase for modules (e.g., SessionModule.ts)
  • Components: PascalCase (e.g., AdminDashboard.tsx)
  • Functions: camelCase (e.g., startSession)
  • Constants: UPPER_SNAKE_CASE (e.g., MAX_SESSION_TIME)
  • CSS classes: kebab-case (e.g., session-timer)

File Organization

// 1. Imports (external first, then internal)
import {BrowserWindow} from 'electron';
import {myHelper} from './helpers';

// 2. Types/Interfaces
interface MyConfig {
  // ...
}

// 3. Constants
const DEFAULT_TIMEOUT = 5000;

// 4. Class/Function definitions
export class MyModule {
  // ...
}

Security Guidelines

Smyles Station is designed for use with children, so security is critical.

Security Principles

  1. Never expose Node.js APIs to renderer - Always use the preload bridge
  2. Validate all inputs - Especially from IPC and user input
  3. Sanitize URLs - Prevent navigation to unauthorized sites
  4. Use context isolation - Already enabled, don't disable it
  5. Enable sandbox - Keep renderer processes sandboxed
  6. Minimize privileges - Only request permissions you need

Security Checklist

Before adding new features:

  • [ ] Does this expose any system APIs to the renderer?
  • [ ] Are all IPC handlers validated and sanitized?
  • [ ] Could this be used to bypass URL restrictions?
  • [ ] Does this handle user input safely?
  • [ ] Could this be exploited by malicious web content?

Common Security Pitfalls

DON'T:

// Exposing shell access to renderer
ipcMain.handle('run-command', (_, cmd) => {
  exec(cmd); // Dangerous!
});

DO:

// Specific, validated operations
ipcMain.handle('shutdown-system', async () => {
  // Verify admin authentication first
  if (!isAdminAuthenticated()) return;

  // Execute specific, safe operation
  await shutdownSystem();
});

Pull Request Process

Before Submitting

  1. Create a feature branch:

    git checkout -b feature/my-new-feature
    

  2. Make your changes:

  3. Write clean, documented code
  4. Follow the code style guidelines
  5. Add tests if applicable

  6. Test thoroughly:

    npm run typecheck
    npm run build
    npm test
    

  7. Commit with clear messages:

    git commit -m "Add scheduled shutdown feature"
    

Submitting the PR

  1. Push to your fork:

    git push origin feature/my-new-feature
    

  2. Open a Pull Request with:

  3. Clear title describing the change
  4. Description of what changed and why
  5. Screenshots/videos for UI changes
  6. Reference any related issues

  7. Respond to review feedback

PR Review Criteria

Your PR will be reviewed for:

  • Code quality and style
  • Security implications
  • Test coverage
  • Documentation updates
  • Breaking changes (if any)

Questions or Issues?

  • Bug reports: Open an issue with steps to reproduce
  • Feature requests: Open an issue describing the use case
  • Questions: Open a discussion or contact smyles-station-safety@proton.me
  • Security issues: Email smyles-station-safety@proton.me (do not open public issues)

License

By contributing, you agree that your contributions will be licensed under the same license as the project.

Thank you for contributing to Smyles Station!