Files
labhelper/AGENTS.md
Adrian A. Baumann d28c13d339
All checks were successful
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/labhelper) (push) Successful in 1m9s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/labhelper-data-loader) (push) Successful in 11s
Full deployment - bump versions and copy database
- Bump labhelper-data-loader to 0.010
- Bump labhelper to 0.032
- Copy cleaned database to data-loader/preload.sqlite3
2025-12-29 00:56:04 +01:00

12 KiB

AGENTS.md - AI Coding Agent Guidelines

This document provides guidelines for AI coding agents working in the labhelper repository.

Project Overview

  • Type: Django web application
  • Python: 3.13.7
  • Django: 5.2.9
  • Database: SQLite (development)
  • Virtual Environment: .venv/

Build/Run Commands

Development Server

python manage.py runserver              # Start dev server on port 8000
python manage.py runserver 0.0.0.0:8000 # Bind to all interfaces

Database Operations

python manage.py makemigrations         # Create migration files
python manage.py makemigrations boxes   # Create migrations for specific app
python manage.py migrate                # Apply all migrations
python manage.py showmigrations         # List migration status

Testing

# Run all tests
python manage.py test

# Run tests for a specific app
python manage.py test boxes

# Run a specific test class
python manage.py test boxes.tests.TestClassName

# Run a single test method
python manage.py test boxes.tests.TestClassName.test_method_name

# Run tests with verbosity
python manage.py test -v 2

# Run tests with coverage
coverage run manage.py test
coverage report
coverage html  # Generate HTML report

Django Shell

python manage.py shell                  # Interactive Django shell
python manage.py createsuperuser        # Create admin user
python manage.py collectstatic          # Collect static files

Production

gunicorn labhelper.wsgi:application     # Run with Gunicorn

Code Style Guidelines

Python Style

  • Follow PEP 8 conventions
  • Use 4-space indentation (no tabs)
  • Maximum line length: 79 characters (PEP 8 standard)
  • Use single quotes for strings: 'string'
  • Use double quotes for docstrings: """Docstring."""

Import Order

Organize imports in this order, with blank lines between groups:

# 1. Standard library imports
import os
import sys
from pathlib import Path

# 2. Django imports
from django.db import models
from django.contrib import admin
from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse

# 3. Third-party imports
import requests
from markdown import markdown

# 4. Local application imports
from .models import MyModel
from .forms import MyForm

Naming Conventions

Type Convention Example
Modules lowercase_with_underscores user_profile.py
Classes PascalCase UserProfile
Functions lowercase_with_underscores get_user_data()
Constants UPPERCASE_WITH_UNDERSCORES MAX_CONNECTIONS
Variables lowercase_with_underscores user_count
Django Models PascalCase (singular) Box, UserProfile
Django Apps lowercase (short) boxes, users

Django-Specific Conventions

Models:

from django.db import models

class Box(models.Model):
    """A storage box in the lab."""
    
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = 'boxes'
        ordering = ['-created_at']

    def __str__(self):
        return self.name

Views:

from django.shortcuts import render, get_object_or_404
from django.http import Http404

def box_detail(request, box_id):
    """Display details for a specific box."""
    box = get_object_or_404(Box, pk=box_id)
    return render(request, 'boxes/detail.html', {'box': box})

Error Handling

# Use specific exceptions
try:
    result = some_operation()
except SpecificError as exc:
    raise CustomError('Descriptive message') from exc

# Django: Use get_object_or_404 for model lookups
box = get_object_or_404(Box, pk=box_id)

# Log errors appropriately
import logging
logger = logging.getLogger(__name__)
logger.error('Error message: %s', error_detail)
from typing import Optional
from django.http import HttpRequest, HttpResponse

def get_box(request: HttpRequest, box_id: int) -> HttpResponse:
    """Retrieve a box by ID."""
    ...

Project Structure

labhelper/
├── manage.py               # Django CLI entry point
├── requirements.txt        # Python dependencies
├── labhelper/              # Project configuration
│   ├── settings.py         # Django settings
│   ├── urls.py             # Root URL routing
│   ├── wsgi.py             # WSGI application
│   └── asgi.py             # ASGI application
└── boxes/                  # Django app
    ├── admin.py            # Admin configuration
    ├── apps.py             # App configuration
    ├── models.py           # Data models
    ├── views.py            # View functions
    ├── tests.py            # Test cases
    ├── migrations/         # Database migrations
    └── templates/          # HTML templates

Available Django Extensions

The project includes these pre-installed packages:

  • django-mptt: Tree structures (categories, hierarchies)
  • django-mptt-admin: Admin interface for MPTT models
  • django-admin-sortable2: Drag-and-drop ordering in admin
  • django-nested-admin: Nested inline forms in admin
  • django-nested-inline: Additional nested inline support
  • django-revproxy: Reverse proxy functionality
  • sorl-thumbnail: Image thumbnailing
  • Font Awesome: Icon library (loaded via CDN)
  • jQuery: JavaScript library (loaded via CDN)

Frontend/CSS Guidelines

Base Template

The project uses a base template system at labhelper/templates/base.html. All page templates should extend this base:

{% extends "base.html" %}

{% block title %}Page Title - LabHelper{% endblock %}

{% block page_header %}
<!-- Optional page header with breadcrumbs -->
{% endblock %}

{% block content %}
<!-- Main page content -->
{% endblock %}

{% block extra_css %}{% endblock %}
{% block extra_js %}{% endblock %}

Design System

Color Scheme:

  • Primary gradient: #667eea (purple) to #764ba2 (purple-blue)
  • Success: Green gradient
  • Error: Red gradient
  • Background: Light gray #f5f5f5 with gradient overlays
  • Cards: White with subtle shadows

Components:

  • Navigation: Glassmorphism effect with blur backdrop
  • Buttons: Gradient backgrounds with hover lift effect
  • Cards: White with rounded corners and box shadows
  • Tables: Gradient headers with hover row effects
  • Alerts: Gradient backgrounds with icons
  • Form Inputs: Focused states with color transitions

Typography:

  • System fonts: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif
  • Headings: Bold, colored
  • Body: Regular, dark gray

Icons:

  • Font Awesome 6.5.1 (CDN)
  • Use semantic icons for actions
  • Color: Match context or inherit from parent

Responsive Design:

  • Mobile-first approach
  • Grid layouts with repeat(auto-fill, minmax(250px, 1fr))
  • Flexbox for component layouts
  • Breakpoints handled by grid and flex-wrap

CSS Guidelines

Naming:

  • Use descriptive class names
  • BEM pattern encouraged for complex components
  • Inline styles allowed for template-specific styling

Styles:

  • Use base template styles when possible
  • Template-specific styles in {% block extra_css %}
  • JavaScript in {% block extra_js %}
  • Smooth transitions (0.2s - 0.3s)
  • Hover effects with transform and box-shadow

jQuery Usage:

  • Loaded in base template
  • Use for interactive elements (toggles, hovers)
  • Event delegation for dynamically added elements
  • Focus/blur events for form inputs

Available Pages/Views

View Name URL Pattern Description
index / Home page with boxes grid and thing types tree
box_detail /box/<str:box_id>/ List items in a specific box
thing_detail /thing/<int:thing_id>/ Thing details with move-to-box form
thing_type_detail /thing-type/<int:type_id>/ Thing type hierarchy and items
add_things /box/<str:box_id>/add/ Form to add/edit items in a box
search /search/ Search page with AJAX autocomplete
search_api /search/api/ AJAX endpoint for search results

Template Best Practices

  1. Always extend base template

    {% extends "base.html" %}
    
  2. Use block system for content injection

    • title: Page title tag
    • page_header: Page header with breadcrumbs
    • content: Main page content
    • extra_css: Additional styles
    • extra_js: Additional JavaScript
  3. Load required template tags

    {% load static %}
    {% load mptt_tags %}
    {% load thumbnail %}
    
  4. Use URL names for links

    <a href="{% url 'box_detail' box.id %}">
    
  5. Use icons with Font Awesome

    <i class="fas fa-box"></i>
    
  6. Add breadcrumbs for navigation

    <p class="breadcrumb">
        <a href="/"><i class="fas fa-home"></i> Home</a> / 
        <a href="/box/{{ box.id }}/"><i class="fas fa-box"></i> Box {{ box.id }}</a>
    </p>
    

Testing Guidelines

  • Use django.test.TestCase for database tests
  • Use django.test.SimpleTestCase for tests without database
  • Name test files test_*.py or *_tests.py
  • Name test methods test_*
  • Use descriptive test method names
from django.test import TestCase
from .models import Box

class BoxModelTests(TestCase):
    """Tests for the Box model."""

    def setUp(self):
        """Set up test fixtures."""
        self.box = Box.objects.create(name='Test Box')

    def test_box_str_returns_name(self):
        """Box __str__ should return the box name."""
        self.assertEqual(str(self.box), 'Test Box')

Files to Never Commit

Per .gitignore:

  • __pycache__/, *.pyc - Python bytecode
  • .venv/ - Virtual environment
  • .env - Environment variables
  • data/db.sqlite3 - Database file
  • keys/ - Secret keys

Common Pitfalls

  1. NEVER commit or push without explicit permission: Always ask the user before running git commit or git push. The user will explicitly say "commit and push" when they want you to do this. Do NOT automatically commit/push after making changes unless instructed to do so.
  2. Always activate venv: source .venv/bin/activate
  3. Run migrations after model changes: makemigrations then migrate
  4. Add new apps to INSTALLED_APPS in settings.py
  5. Templates in labhelper/templates/: The base template and shared templates are in labhelper/templates/. App-specific templates remain in app_name/templates/.
  6. Use get_object_or_404 instead of bare .get() calls
  7. Never commit SECRET_KEY - use environment variables in production

Deployment Commands

Prepare a Full Deployment

When instructed to "Prepare a full deployment", perform the following steps:

  1. Bump container versions: In argocd/deployment.yaml, increment the version numbers by 0.001 for both containers:

    • labhelper-data-loader (initContainer)
    • labhelper (main container)
  2. Copy database: Copy the current development database to the data-loader preload location:

    cp data/db.sqlite3 data-loader/preload.sqlite3
    

Prepare a Partial Deployment

When instructed to "Prepare a partial deployment", perform the following step:

  1. Bump main container version only: In argocd/deployment.yaml, increment the version number by 0.001 for the main container only:
    • labhelper (main container)

Do NOT bump the data-loader version or copy the database.