How RecordVault Works — Full Breakdown
Technology Stack
The app is built on Flask, a lightweight Python web framework. It runs as a local server on your machine (or any server you deploy it to). There are two main pieces: the backend (app.py) which handles all the logic, and the frontend(index.html + login.html) which is what users see in the browser.

1. Starting the App
You run python app.py in your terminal. Flask starts a web server on port 5000. Anyone on your network (or just you locally) can open http://localhost:5000 in their browser to access it. Nothing is cloud-hosted — it runs entirely on the machine where you launch it.

2. Login Wall
The very first thing every visitor hits is the login page. Flask checks whether the user has an active session (a secure browser cookie). If they don't, they cannot reach any other page — every route is protected by the login_requireddecorator.
When the user submits a username and password, Flask checks it against the USERS dictionary in app.py. If it matches, a session is created and they're redirected to the dashboard. If it doesn't match, they get an error and stay on the login page. The session persists until they click Sign Out or close the browser, at which point the cookie is cleared.

3. The Dashboard
Once logged in, the user sees the main dashboard. The page is entirely static at first — no data has been sent yet. The Submit button is intentionally disabled until the user completes the required steps.

4. File Upload & Sheet Detection (the Peek)
When the user drops or selects an .xlsx file, the browser immediately sends it to the /peek endpoint on the server — before they've pressed Start. This is a lightweight scan that does the following:
	•	Saves the file temporarily to the uploads/ folder
	•	Opens it with openpyxl in read-only mode (faster, no full data load)
	•	Reads only the sheet names
	•	Deletes the file immediately
	•	Returns the list of sheet names as JSON
The whole peek takes under a second for most files. The frontend receives the sheet names and renders them as clickable chips on the page. The file itself is gone from the server at this point — it hasn't been processed yet.

5. Sheet Selection
The user now sees every sheet in their workbook displayed as a chip. They can select 1, 2, or 3 sheets. The chips are colour-coded — orange for the first selection, blue for the second, green for the third — with a number badge showing the order. If they try to select a 4th sheet, the UI blocks it and shows a note.
The Submit button label updates live as they make selections, e.g. "Start Download — 2 sheets simultaneously →".

6. Submitting the Job
When the user clicks Start, the browser does the following in one request:
	•	Sends the Excel file again (this time for real processing)
	•	Sends the optional filename prefix they typed
	•	Sends the list of selected sheet names as a JSON array
The server receives this at the /upload endpoint. It saves the file to uploads/, creates a job — a dictionary stored in memory with a unique ID — and immediately returns that job ID to the browser. The actual downloading hasn't started yet, but the job is registered and the browser now knows what ID to poll.
A background thread is then launched to do the real work. The server response to the browser is instant — the user sees the progress panel appear right away.

7. Background Processing (the Core Engine)
The background thread runs process_multi_sheet_job. Here's exactly what happens:
Step A — Load the workbook. The saved Excel file is opened with openpyxl.
Step B — Extract URLs. For each selected sheet, the code reads every row from row 2 downward in Column K (column 11). For each cell it checks two things: whether the cell has a hyperlink object attached (Telesure sometimes embeds URLs as hyperlinks rather than visible text), and whether the cell's plain text value starts with http. Any URL found is added to that sheet's list.
Step C — Spawn parallel threads. A ThreadPoolExecutor is created with up to 3 worker threads — one per selected sheet. All sheets begin downloading at the same time. They do not wait for each other.
Step D — Download each MP3. Within each sheet's thread, the code loops through that sheet's URLs one by one. For each URL it makes an HTTP GET request, streams the response in 8KB chunks into an in-memory buffer, and stores it. If a download fails (timeout, bad URL, server error), the failure is logged and the loop continues — one bad file does not stop the rest.
Step E — Track progress. As each file finishes (success or failure), the job dictionary in memory is updated: the per-sheet progress counter increments, the file's name and status are appended to the sheet's file list, and the overall progress counter increments. This is what the browser reads when it polls.
Step F — Build the ZIP. Once all threads have finished, all the downloaded audio buffers are written into a single ZIP file. Each sheet gets its own subfolder named after it — so Sheet1/recording_001.mp3, Sheet2/recording_001.mp3, and so on. The ZIP is saved to uploads/ under the job's ID.
Step G — Clean up. The original Excel file is deleted. The ZIP remains until the user downloads it.

8. Live Progress Polling
While the background thread runs, the browser is polling /status/<job_id> every 700 milliseconds. The server simply reads the current state of the job dictionary and returns it as JSON — no computation happens here. The browser uses this data to:
	•	Update the overall progress bar and file count
	•	Update each sheet's individual progress lane, bar, and file count
	•	Append new log lines (✓ filename or ✗ filename — reason) to each sheet's scrolling log as they arrive
	•	Update the status badges (Queued → Running → Done)
When the job status returns "done", polling stops and the Download ZIP button appears along with a summary showing total files downloaded, failures, and the folder names inside the ZIP.

9. Downloading the ZIP
The user clicks Download ZIP. The browser hits /download/<job_id>. Flask reads the saved .zip file from disk and streams it to the browser as a file attachment. The browser handles it as a normal file download — the user saves it wherever they like.
The ZIP contains one subfolder per sheet, each named after the sheet, each containing that sheet's MP3 files numbered sequentially (or named from the URL if no prefix was given).

10. Security Model
Every route except /login is protected by login_required. If a session cookie is absent or invalid, the user is redirected to login regardless of what URL they try to access. Uploaded files are given randomised UUID-prefixed names so they can't be guessed or collided. The peek scan deletes the file immediately after reading sheet names. The main file is deleted as soon as processing finishes. There are no permanent user uploads on the server at any point after a job completes.
The app is designed to run on a private network. For exposure beyond localhost, you should put it behind a reverse proxy (nginx or Caddy) with HTTPS and a valid SSL certificate.

What the ZIP looks like when you open it

recordings.zip
 ├── January 2026/
 │    ├── telesure_001.mp3
 │    ├── telesure_002.mp3
 │    └── telesure_003.mp3
 ├── February 2026/
 │    ├── telesure_001.mp3
 │    └── telesure_002.mp3
 └── March 2026/
      ├── telesure_001.mp3
      ├── telesure_002.mp3
      └── telesure_003.mp3
The folder names come directly from the sheet names in your Excel file, so whatever you've named your sheets is exactly what the folders will be called.