This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Stash-box is an open-source video indexing and metadata API server for adult content, developed by Stash App. It serves as a community-driven database of metadata, similar to MusicBrainz for music. The application uses Go for the backend API with GraphQL, and React/TypeScript for the frontend.
make build- Build the Go binary with embedded frontendmake test- Run unit testsmake it- Run integration testsmake lint- Run golangci-lint on Go codemake fmt- Format Go code with gofmtmake generate- Regenerate GraphQL files, sqlc queries, and UI typesmake generate-backend- Generate Go GraphQL files onlymake generate-ui- Generate frontend GraphQL types onlymake generate-sqlc- Generate sqlc query code onlymake generate-goverter- Generate goverter type conversion codemake generate-dataloaders- Generate dataloader files
make pre-ui- Install frontend dependencies via pnpmmake ui- Build the frontend for productionmake ui-start- Start frontend development servermake ui-fmt- Format frontend code with prettiermake ui-validate- Run linting, format checking, and TypeScript validation
make stash-box- Full build: dependencies, generation, UI, linting, and binary
The application uses PostgreSQL extensions, created automatically by migrations (superuser required):
CREATE EXTENSION IF NOT EXISTS bktree;— pHash distance search (optional, only if installed on system)CREATE EXTENSION IF NOT EXISTS pg_search;— ParadeDB full-text search (optional, only if installed on system)- Database schema migrations run automatically on startup
- Migrations: Located in
internal/database/migrations/postgres/and executed sequentially by filename - Default connection string:
postgres@localhost/stash-box?sslmode=disable - Query Code Generation: Uses sqlc (configured in
sqlc.yaml) to generate type-safe Go code from SQL queries
internal/api/- GraphQL resolvers, HTTP handlers, and server setupinternal/auth/- Authentication and authorization logicinternal/models/- Data models, database entity definitions, and generated GraphQL typesinternal/database/- Database connection, migrations, and PostgreSQL-specific codeinternal/queries/- Type-safe database query code generated by sqlc from SQL filesinternal/service/- Business logic layer organized by entity (draft, edit, image, performer, scene, site, studio, tag, user, etc.)internal/email/- Email handling and templatesinternal/image/- Image processing, storage (local/S3), caching, and resizinginternal/storage/- Storage abstraction layer for local/S3 backendsinternal/config/- Configuration management and parsinginternal/converter/- Generated type conversion code via goverterinternal/dataloader/- Generated DataLoader implementations for efficient GraphQL N+1 query resolutioninternal/cron/- Scheduled task management
frontend/src/pages/- Page components organized by entity type (performers, scenes, studios, tags, users)frontend/src/components/- Reusable UI components and form elementsfrontend/src/graphql/- GraphQL queries, mutations, fragments, and generated TypeScript typesfrontend/src/hooks/- Custom React hooks for authentication, pagination, and state managementfrontend/src/utils/- Utility functions for data transformation, routing, and validation
- Entities: Performers, Scenes, Studios, Tags, Sites - the main data types in the system
- Edits: All changes go through an edit/voting system before being applied to entities
- Drafts: Temporary submissions that can be converted to edits
- Roles: User permission system (READ, VOTE, EDIT, MODIFY, ADMIN) controlling access to operations
- Images: Stored locally or on S3, with automatic resizing and caching capabilities
- Fingerprints: Used for scene matching and duplicate detection via three algorithms:
- MD5: Hash of entire video file for exact matching
- OSHASH: OpenSubtitles Hash implementation - hash of leading and trailing 64kb of video file
- PHASH: Perceptual hash based on a 5x5 grid of frames at regular intervals for content-based matching
- Schema files in
graphql/schema/define the API structure - Code generation via gqlgen creates Go resolvers and TypeScript types
- Uses dataloader pattern to prevent N+1 queries when fetching related data
- Authorization Directives:
@hasRole(role: ROLE)implemented ininternal/api/directives.gofor field-level access control
- YAML configuration file (
stash-box-config.yml) controls server behavior - Support for PostgreSQL connection settings, image storage, email, and security options
- Environment variables can override configuration values
- Integration tests preferred: All tests should be integration tests utilizing the GraphQL API as much as possible
- Unit tests:
make test- Fast tests that don't require database (use sparingly) - Integration tests:
make it- Full tests against PostgreSQL test database - Integration tests use PostgreSQL with default connection string
postgres@localhost/stash-box-test?sslmode=disable - Can override test database via
POSTGRES_DBenvironment variable - Warning: Integration tests drop all tables, never run against production database
- Test files follow pattern
internal/api/*_integration_test.gowith GraphQL client helper ingraphql_client_test.go - Test Data Setup: Tests use the service layer to create test data (see
internal/api/integration_test.gofor user setup example)
cd frontend && pnpm run validate- Runs ESLint, stylelint, prettier check, and TypeScript compilation- No unit tests currently implemented in frontend
- Setup: Ensure PostgreSQL is running with required extensions
- Dependencies: Run
make pre-uito install frontend packages - Development: Use
make ui-startfor frontend development server - API Development: Modify GraphQL schema, run
make generateto update code - Database Changes: Add migration files to
internal/database/migrations/postgres/(executed sequentially by filename) - Query Changes: Modify SQL files in
internal/queries/sql/, runmake generate-sqlcto regenerate Go code - Testing: Run
make lint test itbefore committing changes - Build: Use
make stash-boxfor complete production build
- The application requires libvips for image processing on Linux systems
- Default admin user (
root) is created on first run with random password printed to stdout - Frontend development can use API key in
.env.development.localto bypass login - Integration tests require PostgreSQL (default:
postgres@localhost/stash-box-test?sslmode=disable) - pHash distance matching requires the
bktreeextension (built from thepg-spgist_hammingrepo), installed via the production Dockerfile