working companion prototype
This commit is contained in:
@@ -4,6 +4,44 @@ This document provides a technical deep-dive into GridPilot's Clean Architecture
|
||||
|
||||
---
|
||||
|
||||
## iRacing Automation Strategy
|
||||
|
||||
**IMPORTANT**: Understanding the distinction between iRacing's interfaces is critical for our automation approach.
|
||||
|
||||
### Two iRacing Interfaces
|
||||
|
||||
1. **iRacing Website (members.iracing.com)**: Standard HTML/DOM web application accessible at `https://members-ng.iracing.com/`. This is where hosted session management lives. Being a standard web application, it can be automated with browser automation tools like **Playwright** or **Puppeteer**. This is 100% legal and our preferred approach.
|
||||
|
||||
2. **iRacing Desktop App (Electron)**: The iRacing desktop application is a sandboxed Electron app. Its DOM is inaccessible, and any modification violates iRacing's Terms of Service. This is why tools like iRefined were shut down.
|
||||
|
||||
### Automation Rules
|
||||
|
||||
**Allowed Approaches:**
|
||||
- ✅ Browser automation of the iRacing website using Playwright/Puppeteer
|
||||
- ✅ Standard DOM manipulation and interaction via browser automation APIs
|
||||
|
||||
**Forbidden Approaches:**
|
||||
- ❌ DOM automation inside the iRacing Electron desktop app
|
||||
- ❌ Script injection into the desktop client
|
||||
- ❌ Any client modification (similar to what got iRefined shut down)
|
||||
|
||||
### Technology Stack
|
||||
|
||||
- **Primary**: Playwright for browser automation of members.iracing.com
|
||||
- **Alternative**: Puppeteer (if Playwright isn't suitable for specific use cases)
|
||||
|
||||
### Development vs Production Mode
|
||||
|
||||
- **Development Mode**: Launches a Playwright-controlled browser to automate the real iRacing website
|
||||
- **Production Mode**: Same as development - browser automation targeting members.iracing.com
|
||||
- **Test Mode**: Uses mocked browser automation (no real browser interaction)
|
||||
|
||||
### HTML Fixtures (resources/iracing-hosted-sessions/)
|
||||
|
||||
The HTML files in `resources/iracing-hosted-sessions/` are **static snapshots for reference and testing**. They help developers understand the iRacing UI structure and serve as fixtures for E2E tests. Production automation always targets the REAL iRacing website at members-ng.iracing.com.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
### Clean Architecture Principles
|
||||
@@ -151,7 +189,7 @@ GridPilot's monorepo structure enforces layer boundaries through directory organ
|
||||
└── /companion # Electron desktop app
|
||||
├── /main # Electron main process
|
||||
├── /renderer # Electron renderer (React)
|
||||
└── /automation # Nut.js browser automation scripts
|
||||
└── /automation # Playwright browser automation scripts
|
||||
```
|
||||
|
||||
### Import Rules (Enforced via ESLint)
|
||||
@@ -639,7 +677,7 @@ function useCreateLeague() {
|
||||
**Main Process (Node.js)**
|
||||
- Handles IPC from renderer process
|
||||
- Invokes use cases (directly calls application layer, not via HTTP)
|
||||
- Manages Nut.js automation workflows
|
||||
- Manages Playwright browser automation workflows
|
||||
|
||||
```typescript
|
||||
// Electron IPC handler
|
||||
@@ -648,7 +686,7 @@ ipcMain.handle('create-iracing-session', async (event, sessionData) => {
|
||||
const result = await useCase.execute(sessionData);
|
||||
|
||||
if (result.requiresAutomation) {
|
||||
// Trigger Nut.js automation
|
||||
// Trigger Playwright browser automation
|
||||
await automationService.createSessionInBrowser(result.sessionDetails);
|
||||
}
|
||||
|
||||
@@ -660,22 +698,38 @@ ipcMain.handle('create-iracing-session', async (event, sessionData) => {
|
||||
- UI for session creation, result monitoring
|
||||
- IPC communication with main process
|
||||
|
||||
**Nut.js Automation** ([`AutomationService`](../src/apps/companion/automation/AutomationService.ts))
|
||||
**Playwright Browser Automation** ([`PlaywrightAutomationAdapter`](../packages/infrastructure/adapters/automation/PlaywrightAutomationAdapter.ts))
|
||||
|
||||
GridPilot uses Playwright for all automation tasks. This is the only automation approach—there is no OS-level automation or fallback.
|
||||
|
||||
```typescript
|
||||
export class AutomationService {
|
||||
import { chromium, Browser, Page } from 'playwright';
|
||||
|
||||
export class PlaywrightAutomationAdapter {
|
||||
private browser: Browser | null = null;
|
||||
private page: Page | null = null;
|
||||
|
||||
async createSessionInBrowser(details: SessionDetails): Promise<void> {
|
||||
// 1. Launch browser via Nut.js
|
||||
await mouse.click(/* iRacing icon position */);
|
||||
// 1. Launch browser via Playwright
|
||||
this.browser = await chromium.launch({ headless: false });
|
||||
this.page = await this.browser.newPage();
|
||||
|
||||
// 2. Navigate to session creation page
|
||||
await keyboard.type('https://members.iracing.com/membersite/CreateSession');
|
||||
// 2. Navigate to iRacing session creation page
|
||||
await this.page.goto('https://members-ng.iracing.com/web/racing/hosted/create');
|
||||
|
||||
// 3. Fill form fields
|
||||
await this.fillField('session-name', details.name);
|
||||
await this.fillField('track', details.track);
|
||||
// 3. Fill form fields using DOM selectors
|
||||
await this.page.fill('[data-testid="session-name"]', details.name);
|
||||
await this.page.selectOption('[data-testid="track-select"]', details.track);
|
||||
|
||||
// 4. Submit form
|
||||
await this.clickButton('create-session');
|
||||
await this.page.click('[data-testid="create-session-button"]');
|
||||
|
||||
// 5. Wait for confirmation
|
||||
await this.page.waitForSelector('[data-testid="session-created-confirmation"]');
|
||||
}
|
||||
|
||||
async cleanup(): Promise<void> {
|
||||
await this.browser?.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1045,4 +1099,4 @@ test('User creates league via Web Client', async ({ page }) => {
|
||||
|
||||
*This architecture documentation will evolve as GridPilot matures. All changes must maintain Clean Architecture principles and the dependency rule.*
|
||||
|
||||
*Last Updated: 2025-11-21*
|
||||
*Last Updated: 2025-11-23*
|
||||
Reference in New Issue
Block a user