- Bump labhelper-data-loader to 0.010 - Bump labhelper to 0.032 - Copy cleaned database to data-loader/preload.sqlite3
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)
Type Hints (Recommended)
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
#f5f5f5with 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
-
Always extend base template
{% extends "base.html" %} -
Use block system for content injection
title: Page title tagpage_header: Page header with breadcrumbscontent: Main page contentextra_css: Additional stylesextra_js: Additional JavaScript
-
Load required template tags
{% load static %} {% load mptt_tags %} {% load thumbnail %} -
Use URL names for links
<a href="{% url 'box_detail' box.id %}"> -
Use icons with Font Awesome
<i class="fas fa-box"></i> -
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.TestCasefor database tests - Use
django.test.SimpleTestCasefor tests without database - Name test files
test_*.pyor*_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 variablesdata/db.sqlite3- Database filekeys/- Secret keys
Common Pitfalls
- NEVER commit or push without explicit permission: Always ask the user before running
git commitorgit 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. - Always activate venv:
source .venv/bin/activate - Run migrations after model changes:
makemigrationsthenmigrate - Add new apps to INSTALLED_APPS in
settings.py - Templates in labhelper/templates/: The base template and shared templates are in
labhelper/templates/. App-specific templates remain inapp_name/templates/. - Use get_object_or_404 instead of bare
.get()calls - 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:
-
Bump container versions: In
argocd/deployment.yaml, increment the version numbers by 0.001 for both containers:labhelper-data-loader(initContainer)labhelper(main container)
-
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:
- 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.