# Store Dwell Alert Offline Bundle Design ## Goal Add a portable offline delivery bundle for `store_dwell_alert_108` so the project can be copied to another machine matching `192.168.5.108` and installed without internet access. ## Constraints - Target machines are assumed to match `.108` closely: - Ubuntu 24.04 - Python 3.12 - NVIDIA GPU in the RTX 3080 class - Compatible CUDA driver already present - The bundle must not depend on live package downloads. - Production configuration must not be embedded in the bundle. - Operators should edit `scripts/run.sh` after install to fill in the RTSP URL and other local values. - Existing runtime behavior must stay unchanged. ## Recommended Approach Build a native offline bundle similar to `people_flow_project.gz`, but scoped to this lighter project. The bundle should contain source code, locked Python requirements, wheels, model weights, install/run scripts, and a portable service template. The generated archive should be self-contained for installation on the target machine. This is preferred over bundling the current `.venv` because Python virtual environments are less portable across machines, paths, and local shared-library differences. It is also preferred over an online installer because the user requires offline installation. ## Bundle Layout The generated archive should unpack into a single directory such as `store_dwell_alert_bundle/` with the following contents: - `app/` - `config/config.example.yaml` - `data/staff_gallery/` - `data/runtime/` - `deploy/store-dwell-alert.service.tpl` - `logs/` - `requirements.txt` - `requirements.lock.txt` - `scripts/install.sh` - `scripts/run.sh` - `scripts/install_service.sh` - `wheelhouse/` - `weights/yolo11n.pt` - `README.md` The bundle should intentionally omit host-specific files such as `config/108.local.yaml`, local runtime logs, and any active virtual environment. ## Dependency Strategy Dependencies should be split into two groups: 1. Runtime Python packages needed on the target machine. 2. Runtime assets needed to execute immediately after install. The offline installer must use: ```bash pip install --no-index --find-links wheelhouse -r requirements.lock.txt ``` `requirements.lock.txt` should pin exact versions suitable for the `.108` class of host. It should include the versions already proven on the running deployment where practical, especially for `torch`, `torchvision`, `ultralytics`, `opencv-python-headless`, `numpy`, `PyYAML`, and `requests`. The `wheelhouse/` directory should contain all required wheels for the locked requirements set. `weights/` should contain `yolo11n.pt` so the target host does not need to download model weights at first run. ## Install Flow `scripts/install.sh` should: 1. Verify the project root and required bundled files exist. 2. Verify `python3.12` and `ffmpeg` are available on the target machine. 3. Create `.venv` under the unpacked bundle directory. 4. Install Python packages from `wheelhouse/` using `requirements.lock.txt`. 5. Ensure runtime directories exist. 6. Print the next-step instruction to edit and run `scripts/run.sh`. The installer should fail fast with clear messages if any required file is missing. ## Run Flow `scripts/run.sh` should be the operator-facing entry point. It should: - Expose editable shell variables near the top of the file, including: - `RTSP_URL` - `CONFIG_TEMPLATE` - `CONFIG_PATH` - `LOG_DIR` - Generate or refresh a local config file from the template if needed. - Validate that `RTSP_URL` has been changed from its placeholder. - Launch `.venv/bin/python -m app.main --config "$CONFIG_PATH"`. The script should avoid storing production configuration in git-tracked files. ## Service Installation `deploy/store-dwell-alert.service.tpl` should be a portable template rather than a host-pinned unit. `scripts/install_service.sh` should render the template using the unpack path and config path, then install the final service file with `systemctl`. This keeps the bundle portable even when unpacked into different directories on different machines. ## Packaging Workflow Add a development-side script `scripts/package_bundle.sh` that: 1. Creates a clean staging directory under `dist/`. 2. Copies the required source tree and assets into the staging directory. 3. Generates `requirements.lock.txt`. 4. Builds or refreshes `wheelhouse/`. 5. Ensures `weights/yolo11n.pt` is present. 6. Writes bundle-facing scripts and service template into the staging directory. 7. Produces a tarball such as `dist/store_dwell_alert_bundle_2026-04-16.tar.gz`. The script should be idempotent and safe to rerun. ## Validation The bundle feature is complete when all of the following are true: - A tarball can be generated locally from the project. - The tarball unpacks into the expected layout. - `scripts/install.sh` installs without using the network. - `scripts/run.sh` starts the app after the operator sets `RTSP_URL`. - `python -m app.main --once` works on a compatible target host using the bundle environment. - Events are written to `logs/events.jsonl`. - The optional service install flow can render and install a working unit file.