Files
query-orchestration/README.md
T
Jay Brown 730f3ba11a Merged in feature/preserve-folder-paths (pull request #179)
support folder paths

* support folder paths

* s3 storage docs
2025-09-05 18:25:31 +00:00

11 KiB

Query Orchestration

This repository contains the DoczyAI code.

Using the following project as a baseline: https://github.com/golang-standards/project-layout.

Installation and Usage

  • Install devbox: https://www.jetify.com/docs/devbox/installing_devbox

    • Ubuntu/MacOS: curl -fsSL https://get.jetify.com/devbox | bash
    • NixOS: devbox
  • Install docker: https://docs.docker.com/engine/install/

  • (IF NECESSARY) Ensure user in docker group and docker group is in sudo group

      sudo groupadd docker
      sudo usermod -aG docker $USER
    
  • Run touch .env to create .env file for custom environment variables

  • Run devbox shell to enter the environment

  • Run task fullsuite:ci to run all tests that ensure the current state

To find new packages: https://search.nixos.org/packages

For regular usage, please use task scripts in order run the most appropriate configuration.

Available Task Commands

Core Development Workflow

  • task fullsuite:ci - Complete CI workflow: generate, build, lint, test with coverage
  • task fullsuite - Full development suite (similar to CI but for local development)
  • task fullsuite:graph - Generate dependency graph visualization
  • task precommit - Pre-commit checks for CI/CD readiness

Code Generation

  • task generate - Generate all code (DB queries via SQLC, OpenAPI clients/servers, mocks, docs)
  • task go:generate - Generate Go-specific code
  • task openapi:generate - Generate OpenAPI clients and servers from specs
  • task db:generate - Generate database queries from SQL files
  • task docs:generate - Generate project documentation
  • task docs:ai:generate - Generate full system docs using AI ($$)
  • task test:mocks:generate - Generate test mocks

Build Commands

  • task build - Build the project
  • task docker:build - Build Docker images
  • task docker:build:debug - Build Docker images with debug support

Docker Compose Management

Build Commands

  • task compose:build - Build Docker images using local compose file
  • task compose:build:test - Build Docker images using test compose file
  • task compose:build:generate - Build Docker images using generate compose file

Start/Up Commands

  • task compose:up - Full local development startup with AWS resource initialization
  • task compose:up:test - Start test environment containers
  • task compose:up:generate - Start containers for code generation
  • task compose:up:aws - Start AWS-specific environment

Stop/Down Commands

  • task compose:down - Stop and remove local containers
  • task compose:down:test - Stop and remove test containers
  • task compose:down:aws - Stop and remove AWS containers

Cleanup Commands

  • task compose:clean - Stop containers and remove volumes (local)
  • task compose:clean:test - Stop containers and remove volumes (test)
  • task compose:clean:aws - Stop containers and remove volumes (AWS)

Other Compose Commands

  • task compose:refresh - Full restart: rebuild everything and start fresh
  • task compose:rebuild - Force complete rebuild of all containers (use when build cache causes issues)
  • task compose:lint - Validate syntax of all compose files

Testing Commands

  • task test:functional - Run functional tests with 80% coverage threshold
  • task test:functional:full - Run all tests and reset coverage tracking
  • task test:unit:short - Quick unit tests
  • task test:race - Race condition detection tests
  • task test:perf - Performance analysis with slowest test reporting
  • task test:mem - Memory usage profiling tests
  • task test:bench - Benchmark execution
  • task test:permitio - Run Permit.io integration tests (requires local PDP)
  • task test:graph - Generate test dependency graphs
  • task test:timeline - Show test execution timeline
  • task test:prune - Clean up test artifacts
  • task test:wait - Wait for test dependencies

Linting Commands

  • task lint - Run all linting (Go, YAML, JSON, Docker, OpenAPI)
  • task go:lint - Run Go-specific linting
  • task go:lint -- --fix - Fix automatically fixable Go linting issues
  • task docker:lint - Lint Docker files
  • task openapi:lint - Lint OpenAPI specifications
  • task yaml:lint - Lint YAML files
  • task json:lint - Lint JSON files
  • task db:lint - Lint database-related files

Database Commands

  • task db:mig:create - Create new database migration
  • task db:generate - Generate Go code from SQL queries

AWS Commands

  • task aws:login - Login to AWS services
  • task aws:textract:credentials - Set up AWS Textract credentials

Utility Commands

  • task deps:tidy - Tidy Go module dependencies

Environment Variables

When using environment variables, there is a hiearchy that will be respected. (First will override the next)

  1. Within the devbox.json file, a variable added to "env"
  2. Within the devbox.json file, a variable exported in "init_hook"
  3. A variable added to .env

Testing

For testing endtoends such as queries against a database, or interactions with an SQS queue, this repository employs the use of docker testcontainers.

https://testcontainers.com/

This enables tests to be fully self-contained, thus allowing allowing tests to be reliable and replicable.

Execution

The simplest way of ensuring the validity of the full project is by running task fullsuite when in the devbox shell.

This will:

  1. Generate the latest version of the specs.
  2. Run the linting commands.
  3. Run the unit tests.
  4. Run the endtoend tests.

Naming Conventions

Service - This term is used internally in order to refer to commands that get deployed as APIs. Runner - This term is used internally in order to refer to commands that get deployed as consumers of a queue.

Creating a new API

  1. Add a file named <api_name>.yml. The api name is important, as it will be used as a reference throughout the codebase. The api name must be in the format <functionality>API. E.g. queryAPI, ClientAPI
  2. Run task openapi:generate. This will generate the following: a. A location to implement the server-side functions in ./api/<api_name>/, as well as generated functions, models and swagger docs. b. A location with the client-side code in ./pkg/<api_name>/
  3. Implement the controllers in ./api/<api_name>/
  4. Create a command in ./cmd/<api_name>/main.go which creates a new instance from ./internal/api

Creating a new Runner

  1. Implement the controller in ./api/<runner_name>/ which implements the Controller interface in ./internal/queue. The runner name must be in the format <functionality>Runner. E.g. queryRunner, csvExportRunner
  2. Create a command in ./cmd/<runner_name>/main.go which creates a new instance from ./internal/queue

Debugging in Containers

This project supports debugging Go applications running inside Docker containers using Delve, the Go debugger.

Building Debug Images

The project includes two build tasks for different use cases:

  • task docker:build - Build the regular production image
  • task docker:build:debug - Build the debug image with Delve

The debug image is built using build/Dockerfile.debug, which:

  • Installs Delve debugger with static linking for Alpine compatibility
  • Builds Go binaries with debug symbols (-gcflags="all=-N -l")
  • Exposes port 2345 for debugger connections

Container Configuration for Debugging

To enable debugging for a service in deployments/compose.local.yaml, modify the service configuration:

query_api:
  image: queryorchestration:debug  # Use debug image instead of latest
  command: ["/dlv", "exec", "./queryAPI", "--listen=:2345", "--headless", "--api-version=2", "--accept-multiclient", "--continue"]
  ports:
    - "8080:8080"  # Application port
    - "2345:2345"  # Debugger port
  expose:
    - 8080
    - 2345

Key changes from production configuration:

  1. Image: Use queryorchestration:debug instead of queryorchestration:latest
  2. Command: Replace direct binary execution with Delve wrapper
  3. Ports: Expose port 2345 for debugger connections
  4. Delve flags:
    • --listen=:2345: Listen on port 2345 for debugger connections
    • --headless: Run without terminal interface
    • --accept-multiclient: Allow multiple debugger connections
    • --continue: Start the application immediately (don't wait for debugger)

Connecting a Debugger

GoLand/IntelliJ IDEA

  1. Go to Run → Edit Configurations...
  2. Click "+""Go Remote"
  3. Configure:
    • Name: Docker Debug
    • Host: localhost
    • Port: 2345
  4. Click Apply and OK
  5. Select the configuration and click Debug (Shift+F9)
  6. Set breakpoints in your code and make HTTP requests to trigger them

VS Code

  1. Add to .vscode/launch.json:
{
  "name": "Connect to Docker",
  "type": "go",
  "request": "attach",
  "mode": "remote",
  "remotePath": "/app",
  "port": 2345,
  "host": "localhost"
}
  1. Set breakpoints and start debugging

The debugger will connect to the running container and pause execution when breakpoints are hit, allowing you to inspect variables, step through code, and debug issues in the containerized environment.

S3 Storage Format

The system uses a structured naming convention for S3 objects that embeds metadata for parsing, recovery, and organization.

Object Key Structure

S3 object keys follow this format:

{client_id}/{location}/{date}/{part}/{filename}

Example

test_client_1757026403/import/20250904/0/2025-09-04T225324Z~test_client_1757026403~import~56df8aa9-873c-48ea-a0e4-bc4f6b8ad69e~019916ef-46ab-73f7-b97b-5709df5c3985

Components

Directory Path (Prefix)

  • Client ID: Unique identifier for the client (e.g., test_client_1757026403)
  • Location: Processing stage - import, text, or export
  • Date: Date in YYYYMMDD format (e.g., 20250904)
  • Part: Partition number for storage distribution (e.g., 0)

Filename

The filename uses tilde (~) as a delimiter and contains:

  • Timestamp: Full ISO timestamp (e.g., 2025-09-04T225324Z)
  • Client ID: Repeated for self-contained metadata
  • Location: Repeated for self-contained metadata
  • Entity ID: UUID for the specific document (e.g., 56df8aa9-873c-48ea-a0e4-bc4f6b8ad69e)
  • Batch ID: Optional UUID for batch uploads (e.g., 019916ef-46ab-73f7-b97b-5709df5c3985)
  • File Extension: Optional file type extension (e.g., .pdf)

Location Types

  • import: Initial document upload location
  • text: Text extraction results storage
  • export: Export results storage

Partitioning Strategy

The part number (0-n) is used to distribute files across multiple directories, preventing performance issues with too many objects in a single S3 prefix. Export location does not use partitioning.

Metadata Encoding

The filename contains all necessary metadata for document recovery and processing:

  • Self-contained recovery capability from filename alone
  • Support for both path-based and filename-based queries
  • Human-readable format for debugging and troubleshooting