# AGENTS.md - labhelper **Type**: Django 5.2 web app (lab inventory) **Python**: 3.13 | **DB**: SQLite (dev) | **Env**: `.venv/` ## Essential Commands ```bash # Activate venv first source .venv/bin/activate # Dev server python manage.py runserver # localhost:8000 python manage.py runserver 0.0.0.0:8000 # all interfaces # Database python manage.py makemigrations boxes # after model changes python manage.py migrate python manage.py showmigrations # Testing python manage.py test # all python manage.py test boxes # app only python manage.py test boxes.tests.BoxModelTests.test_method # specific # Custom commands python manage.py create_default_users # admin/admin123, staff/staff123, viewer/viewer123 python manage.py clean_orphaned_files --dry-run python manage.py clean_orphaned_images --dry-run python manage.py collectstatic # after CSS changes ``` ## Critical Rules 1. **NEVER commit/push without explicit permission** - wait for user to say "commit and push" 2. Use `get_object_or_404()` not bare `.get()` for model lookups 3. Run `makemigrations` then `migrate` after any model change 4. Default users: `admin/admin123` (superuser), `staff/staff123`, `viewer/viewer123` ## Data Model - **BoxType** → Box (1:N, PROTECT) - **Box** → Thing (1:N, PROTECT) — Box.pk is CharField(max=10) - **Facet** → Tag (1:N, CASCADE) — Facet.cardinality: single/multiple - **Thing** ↔ Tag (M2M) - **Thing** → ThingFile, ThingLink (1:N, CASCADE) ## Deployment (when instructed) **Full deploy**: bump both versions in `argocd/deployment.yaml` (+0.001), then: ```bash cp data/db.sqlite3 data-loader/preload.sqlite3 ``` **Partial deploy**: bump main container only, skip DB copy. ## Key Directories - `boxes/` — main app (models, views, forms, templates) - `labhelper/` — project settings, base template - `argocd/` — Kubernetes manifests for production - `data-loader/` — init container with preloaded DB ## Gotchas - Template base: `labhelper/templates/base.html` - App templates: `boxes/templates/boxes/` - Box ID is CharField (e.g., "A1-001"), not auto-increment - Views use `conditional_login_required` - bypasses login for IPs in `ALLOWED_CIDR_NETS` env var - Markdown via `{{ text|render_markdown }}` (sanitized with bleach) - Third-party: django-mptt, sorl-thumbnail, bleach, markdown