Thank you for your interest in contributing. This guide covers everything you need to set up a development environment, understand the codebase, and build the application.
- Architecture Overview
- Processing Pipeline
- Tech Stack
- Project Structure
- Database Schema
- Developer Setup
- Building
- Release Process
┌──────────────────────────────────────────────┐
│ Tauri v2 Shell │
│ (Rust) │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ React Frontend (webview) │ │
│ │ │ │
│ │ Components ──▶ Services ──▶ SQLite DB │ │
│ │ │ │
│ │ React 19 + TypeScript │ │
│ │ React Query (server state) │ │
│ │ Zustand (client state) │ │
│ └──────────────┬───────────────────────────┘ │
│ │ │
│ │ Tauri Plugins │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ tauri-plugin-sql → SQLite DB │ │
│ │ tauri-plugin-http → External API │ │
│ │ tauri-plugin-dialog → File picker │ │
│ │ tauri-plugin-fs → File reads │ │
│ └─────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
│
│ External API (optional)
▼
┌──────────────┐
│ Agent.AI │
│ Webhook │
└──────────────┘
How it works: The React frontend calls TypeScript service functions directly (no HTTP layer). Services use the Tauri SQL plugin to read/write a local SQLite database. For LLM-powered Q&A extraction, the app calls the Agent.AI webhook via the Tauri HTTP plugin. Everything runs in-process — no sidecar, no server.
When processing a meeting transcript, the app runs a 4-stage pipeline:
| Stage | Description |
|---|---|
| 1. Parse Transcript | Parse SRT/VTT file into timestamped segments |
| 2. Q&A Extraction | LLM-based (Agent.AI) or rule-based question-answer pair extraction |
| 3. Keyword Extraction | TF-IDF keyword/keyphrase extraction (custom TypeScript implementation) |
| 4. Finalization | Save results to database, update meeting status |
Q&A Extraction logic (Stage 2):
- If Agent.AI is configured and monthly quota remains → send transcript to webhook
- If webhook fails or returns empty → fall back to rule-based extraction
- If no provider configured or quota exhausted → use rule-based extraction directly
- Usage counter increments only on successful LLM extraction
| Technology | Version | Purpose |
|---|---|---|
| Tauri | 2 | Desktop application framework (Rust) |
| React | 19 | UI framework |
| TypeScript | 5 | Type safety |
| TailwindCSS | 4 | Styling |
| React Router | 7 | Client-side routing |
| React Query | 5 | Data fetching + caching |
| Zustand | 5 | Client state management |
| Recharts | 2 | Dashboard charts |
| Lucide React | latest | Icons |
| Vite | 6 | Build tooling |
| SQLite | — | Local database (via tauri-plugin-sql) |
video-analytics/
├── README.md # Consumer-facing documentation
├── CONTRIBUTING.md # This file (developer guide)
├── package.json # Dependencies & scripts
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
├── index.html # SPA entry point
├── main.css # Global styles (Tailwind)
│
├── src/ # ── React Frontend ──
│ ├── main.tsx # React entry point
│ ├── App.tsx # Root component + routes
│ │
│ ├── services/ # TypeScript service layer
│ │ ├── db.ts # Database singleton + init + migrations
│ │ ├── db-schema.ts # CREATE TABLE SQL + ALTER TABLE migrations
│ │ ├── srtParser.ts # SRT/VTT subtitle file parsing
│ │ ├── qaExtractor.ts # Rule-based Q&A extraction (regex + patterns)
│ │ ├── keywordExtractor.ts # Custom TF-IDF keyword extraction
│ │ ├── llmService.ts # Agent.AI webhook client (submit + poll)
│ │ ├── settingsService.ts # Settings CRUD + usage tracking
│ │ ├── meetingService.ts # Meeting CRUD + analytics
│ │ ├── courseService.ts # Course CRUD + relationships
│ │ ├── attendanceParser.ts # Zoom CSV attendance parsing
│ │ ├── exportService.ts # Data export (text/CSV)
│ │ ├── pipeline.ts # Processing orchestrator + progress callbacks
│ │ └── speakerMerger.ts # Speaker data transformation
│ │
│ ├── components/
│ │ ├── layout/
│ │ │ ├── AppShell.tsx # Main layout wrapper
│ │ │ ├── Header.tsx # Top navigation bar
│ │ │ └── Sidebar.tsx # Left nav + privacy toggle
│ │ ├── dashboard/
│ │ │ └── DashboardView.tsx# Home dashboard with charts
│ │ ├── upload/
│ │ │ ├── UploadView.tsx # SRT/VTT upload form + usage counter
│ │ │ └── ProcessingProgress.tsx
│ │ ├── meetings/
│ │ │ ├── MeetingListView.tsx
│ │ │ └── MeetingDetailView.tsx # Transcript, Q&A, keywords tabs
│ │ ├── courses/
│ │ │ ├── CourseListView.tsx
│ │ │ └── CourseDetailView.tsx # Sessions, participants, attendance
│ │ ├── settings/
│ │ │ └── SettingsView.tsx # LLM provider config
│ │ ├── analytics/ # Analytics components
│ │ ├── keywords/ # Keyword display components
│ │ ├── transcript/ # Transcript display components
│ │ ├── common/ # Shared components
│ │ └── ui/
│ │ └── Spinner.tsx
│ ├── hooks/
│ │ └── useProcessing.ts # Processing state management
│ ├── store/
│ │ └── appStore.ts # Zustand global store
│ ├── types/ # TypeScript type definitions
│ └── lib/
│ └── formatters.ts # Date/time/text formatters
│
├── src-tauri/ # ── Tauri Desktop Shell ──
│ ├── Cargo.toml # Rust dependencies
│ ├── tauri.conf.json # Tauri app config (version, window, bundle)
│ ├── src/
│ │ ├── main.rs # App entry point
│ │ └── lib.rs # Plugin registration (SQL, HTTP, FS, dialog)
│ ├── capabilities/
│ │ └── default.json # Security permissions
│ └── icons/ # App icons (all platforms)
│
├── .github/
│ └── workflows/
│ └── build.yml # CI/CD: 4-platform build + GitHub Release
│
└── scripts/
├── build-standalone.ps1 # Local portable build (Windows)
└── kill-port.js # Dev utility: kill process on port
| Route | Component | Description |
|---|---|---|
/ |
DashboardView |
Home dashboard with summary charts |
/upload |
UploadView |
Upload SRT/VTT transcripts for processing |
/meetings |
MeetingListView |
Browse all processed meetings |
/meetings/:id |
MeetingDetailView |
Transcript, Q&A pairs, keywords tabs |
/courses |
CourseListView |
Browse courses |
/courses/:id |
CourseDetailView |
Sessions, participants, attendance matrix |
/settings |
SettingsView |
LLM provider config, usage tracking |
All data is stored in a local SQLite file managed by the Tauri SQL plugin.
| Table | Description |
|---|---|
app_settings |
Single-row config: LLM provider, webhook URL, prompt, privacy, usage tracking |
meetings |
Meeting metadata: title, date, file paths, processing status |
transcript_segments |
Individual transcript segments with timestamps and speaker labels |
qa_pairs |
Extracted question-answer pairs with speaker attribution |
keywords |
Extracted keywords/keyphrases per meeting |
courses |
Course metadata: name, description |
course_sessions |
Links meetings to courses as sessions |
attendance_records |
Parsed attendance data from Zoom CSV exports |
session_attendance |
Maps attendance records to course sessions |
- Node.js 18+ and npm
- Rust toolchain (install from https://rustup.rs)
- Visual Studio Build Tools (Windows) or Xcode CLI (macOS) or build-essential (Linux)
Linux also requires:
sudo apt install libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libgtk-3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev-
Clone the repo:
git clone https://github.com/HCarbajales/video-analytics.git cd video-analytics git checkout free-tier -
Install dependencies:
npm install
-
Run the full desktop app:
npm run tauri:dev
This starts the Vite dev server + the Tauri window with hot reload.
-
Or for frontend-only iteration (UI changes without recompiling Rust):
npm run dev
Build a portable zip locally using the PowerShell script:
npm run portableOr directly:
powershell -ExecutionPolicy Bypass -File scripts\build-standalone.ps1Output: release/VideoAnalytics-x.x.x-win-x64.zip
npm run tauri:buildFind the installer in src-tauri/target/release/bundle/.
Releases are automated via GitHub Actions. The workflow builds for 4 platforms and creates a draft GitHub Release with installers and portable zips.
-
Commit and push all changes to
free-tier -
Create a version tag:
git tag v0.7.0 git push origin v0.7.0
-
The
v*tag push triggers.github/workflows/build.yml -
GitHub Actions builds 4 platform targets in parallel:
Runner Target Outputs windows-latest x86_64-pc-windows-msvc NSIS installer + portable zip macos-latest aarch64-apple-darwin DMG + portable zip macos-13 x86_64-apple-darwin DMG + portable zip ubuntu-22.04 x86_64-unknown-linux-gnu DEB + AppImage + portable zip -
Once all builds complete, go to Releases on GitHub
-
Review the draft release and click Publish
Before tagging a new release, update the version in:
src-tauri/tauri.conf.json→"version"package.json→"version"
Keep these in sync with the git tag (e.g., all set to 0.7.0 for tag v0.7.0).
git tag -d v0.7.0 # delete local tag
git push origin :refs/tags/v0.7.0 # delete remote tag
# fix the issue, commit, push
git tag v0.7.0 # re-create tag
git push origin v0.7.0 # triggers workflow again