Replace static form-based vote buttons with a new VoteManager class that submits votes via fetch, returns JSON with net/up/down/current value, and updates vote count spans using data-vote-count attributes across all templates. Add JSONResponse endpoint in votes router for AJAX requests, switch VoteManager import from Http to Toast for error feedback, and refactor link_attachments to handle comma-separated UIDs.
Add a new `get_gist_languages()` function in database.py that queries distinct language codes from the gists table and caches results for 60 seconds. Create a database index on the `language` column of the gists table for efficient queries. Update the gists router to pass the set of active language codes to the template. Modify the gists.html sidebar to only display language filter links for codes that actually have gists in the database, hiding empty language categories and conditionally showing the plaintext link.
- Add .dockerignore, Dockerfile, and docker compose targets to Makefile for containerized deployment
- Implement gists router with CRUD operations, database schema, and polymorphic comment/vote reuse
- Create attachment upload system with thumbnail generation, MIME detection, and storage path management
- Add attachments_prune CLI command to clean orphaned attachment records and files
- Introduce rate limiting middleware with 60 requests per minute window
- Add custom 404 and 500 error handlers with SEO-optimized template responses
- Extend database initialization with gists and attachments indexes plus upload site settings defaults
- Update load_comments to include attachment mapping for comment resources
- Register gists and uploads routers in main application and update AGENTS.md documentation