FILE_STRUCTURE

Project Structure

A summary of how HTML templates, CSS, and JavaScript interact in this project.


Overview

This is a Flask application with a single-page frontend. The server renders one HTML page via Jinja2 templates, loads all CSS globally, and boots a single ES module entry point. All subsequent UI interaction is handled in JavaScript without page reloads.


File Map

templates/                          Jinja2 HTML templates
├── index.html                      Root page — loads CSS, loads main.js
├── sidebar.html                    Sidebar partial
├── workspace.html                  Workspace partial
├── start_page.html                 Empty-state page partial
├── components/
│   ├── server_panel.html           Server connection UI
│   └── shortcut_legend.html        Keyboard shortcut reference
├── workspace_panels/
│   ├── waveform_panel.html         Audio player and waveform
│   ├── speakers_panel.html         Speaker list and management
│   └── transcript_panel.html       Transcript editor
└── documentation/
    └── guide/                      User guide pages (standalone)

static/css/
├── variables.css                   Global CSS custom properties (colors, dark + light theme)
├── main.css                        Base/global styles
├── sidebar.css                     Sidebar layout (includes folder breadcrumb styles)
├── start_page.css                  Empty-state page styles
├── components/
│   ├── confirm_dialog.css
│   ├── export_panel.css
│   ├── hue_picker.css
│   ├── info_widget.css
│   ├── segment_context_menu.css
│   ├── server_panel.css
│   ├── shortcut_legend.css
│   ├── split_popup.css
│   └── transcribe_dialog.css
├── workspace/
│   ├── workspace.css
│   ├── waveform_panel.css
│   ├── speakers_panel.css
│   └── transcript_panel.css
└── documentation/
    └── guide.css

static/js/
├── main.js                         Entry point — App class, sidebar, project list, folder navigation
├── project.js                      Project, ProjectData, Transcript, Speaker classes
├── workspace.js                    Workspace — coordinates the three panels
├── server.js                       Server class — connection state, auth, and all server operations
├── start_page.js                   StartPage class
├── workspace_panels/
│   ├── waveform_panel.js           WaveformPanel — audio playback, waveform, regions
│   ├── speakers_panel.js           SpeakersPanel — speaker list and editing
│   └── transcript_panel.js         TranscriptPanel — transcript display and editing
├── components/
│   ├── server_panel.js             ServerPanel — login/logout UI logic
│   ├── segment_context_menu.js     SegmentContextMenu — right-click menu on segments
│   ├── project_context_menu.js     ProjectContextMenu — right-click menu on projects
│   ├── split_popup.js              SplitPopup — word-level segment splitting
│   ├── confirm_dialog.js           ConfirmDialog — modal confirmation
│   ├── export_panel.js             ExportPanel — export format selection and download
│   ├── hue_picker.js               HuePicker — speaker color selection
│   ├── info_widget.js              InfoWidget — toast/notification display
│   └── transcribe_dialog.js        TranscribeDialog — transcription options and progress
└── utilities/
    ├── tools.js                    General utility functions
    ├── audio.js                    Audio loading helpers
    ├── constants.js                Shared constants (GAP_THRESHOLD, SPEAKER_COLORS, etc.)
    ├── export.js                   Export formatting helpers (PDF, DOCX, TXT, CSV, MD)
    ├── theme.js                    Theme switching (dark/light/auto) helpers
    ├── transcription_pricing.js    Cloud transcription cost estimation
    └── server_access.js            Low-level fetch functions (raw API calls, no state)

application/                        Flask server
├── __init__.py                     App factory
├── projects.py                     Project CRUD logic
├── auth.py                         Authentication
├── files.py                        Filesystem helpers
├── folders.py                      Folder hierarchy management
├── config.py                       Server configuration
├── stats.py                        Usage statistics tracking
├── tools.py                        Server-side utility functions (multipart upload)
└── transcription/
    ├── transcribe.py               Local transcription (CPU, faster-whisper + pyannote)
    └── modal_transcribe.py         Cloud transcription (Modal AI, serverless GPU)

app.py                              Flask application and route definitions
serve.py                            Production WSGI launcher (Gunicorn/Waitress)
run.sh / run.bat                    Convenience startup scripts
Caddyfile                           Caddy reverse-proxy configuration

How Templates, CSS, and JS Interact

1. Template Composition

index.html is the single root template rendered by Flask. It composes the page using Jinja2 {% include %} tags:

index.html
├── {% include "sidebar.html" %}
│   ├── {% include "components/server_panel.html" %}
│   └── {% include "components/shortcut_legend.html" %}
└── {% include "workspace.html" %}
    ├── {% include "start_page.html" %}
    ├── {% include "workspace_panels/waveform_panel.html" %}
    ├── {% include "workspace_panels/speakers_panel.html" %}
    └── {% include "workspace_panels/transcript_panel.html" %}

Templates define static HTML structure and element IDs only. No data is injected into templates at render time (aside from static asset URLs via url_for). All dynamic content is written by JavaScript after the page loads.

2. CSS Loading

All stylesheets are declared as <link> tags in index.html, referenced via Flask's url_for('static', filename=...). There is no CSS bundler or preprocessor.

Load order matters:

  1. variables.css — defines CSS custom properties consumed by everything else
  2. main.css — base/reset styles
  3. Layout stylesheets (sidebar.css, start_page.css)
  4. Component stylesheets (components/*.css)
  5. Workspace panel stylesheets (workspace/*.css)

CSS files are scoped by directory: global styles live at the top level, component styles under components/, panel styles under workspace/.

3. JavaScript as ES Modules

index.html loads a single script:

<script src="{{ url_for('static', filename='js/main.js') }}" type="module"></script>

main.js imports all other JS files using native ES module import syntax. There is no bundler (Webpack, Vite, etc.) — the browser resolves modules directly from the filesystem via Flask's static file serving.

4. JS ↔ Template Binding

JavaScript classes bind to the pre-rendered DOM by querying element IDs defined in the templates:

// Example from main.js / Workspace
this.sidebar     = document.querySelector("#sidebar");
this.sidebarList = document.querySelector("#sidebarList");

The templates establish the DOM contract (IDs, element types). The JS classes assume those IDs exist and will fail silently or throw if a template changes an ID without updating the corresponding JS.

5. Dynamic HTML Generation

Not all HTML comes from templates. Some elements are created entirely in JavaScript:

  • Sidebar project items — built by App.#buildProjectItem() in main.js
  • Context menusProjectContextMenu, SegmentContextMenu create their own DOM trees
  • Confirm dialogsConfirmDialog appends a modal to document.body
  • Status badgesWorkspace.updateProjectServerStatus() writes badge elements into #projectServerStatus

These dynamic elements inherit styles from the globally-loaded CSS via shared class names (e.g., .ctx-item, .sidebar-item, .project-cloud-badge).

6. Cross-Panel Communication

The three workspace panels (WaveformPanel, TranscriptPanel, SpeakersPanel) do not reference each other directly. Workspace owns all three and wires them together at construction time via callbacks:

TranscriptPanel  --onSegmentHover-->  Workspace  --calls-->  WaveformPanel.setHoveredRegion()
WaveformPanel    --onRegionSelect-->  Workspace  --calls-->  TranscriptPanel.setSelectedSegment()
SpeakersPanel    --onSpeakerHover-->  Workspace  --calls-->  WaveformPanel.drawRegions()

This keeps panels decoupled: each panel exposes a callback API; Workspace provides the implementations.

7. State Management

State is split across two layers:

LayerLocationContents
Server/connectionServer (server.js)Server connection, auth token, connection status
Per-projectProject instancesTranscript, speakers, waveform data, dirty flags

Project tracks dirty state per data category (transcriptDirty, speakersDirty, waveformDirty). When a category is marked dirty, the project fires registered callbacks that trigger UI re-renders in Workspace. This is the primary mechanism for keeping the three panels in sync after an edit.

8. Server Communication

Server communication is handled by two layers:

  • Server class (server.js) — stateful class owned by App. Manages connection URL, auth token, and connection lifecycle. Exposes all server operations as methods. Fires callbacks (onStatusChanged, onConnect, onDisconnect) when connection state changes.
  • server_access.js (utilities) — stateless module of raw fetch() wrappers. Called by Server with the current base URL and token. All functions are async and throw on non-2xx responses.

The Flask server (application/) handles:

  • / — serves the main application page
  • /docs, /docs/developer/ — developer documentation
  • /auth/login, /auth/logout — authentication
  • /api/projects — list all projects (flat, with folder_path); create project
  • /api/projects/<id> — get, update, delete a project
  • /api/projects/<id>/duplicate — duplicate a project
  • /api/projects/<id>/audio — audio streaming (Range header support)
  • /api/projects/<id>/audio-ready — check if background MP3 conversion is complete
  • /api/projects/<id>/transcript — CSV transcript download / delete
  • /api/projects/<id>/speakers — speaker metadata
  • /api/projects/<id>/samples/<spkId> — voice sample files
  • /api/projects/<id>/waveform — waveform data
  • /api/projects/<id>/transcribe — SSE stream of transcription progress
  • /api/projects/<id>/folder — move project to a different folder
  • /api/folders — list folders and projects at a given path
  • /api/folders/<path> — create, rename, or delete a folder
  • /api/folders/<path>/count — count nested projects/folders
  • /api/stats — usage statistics (logins, request counts)