- Add format and platform fields to packages table - Add checksum_md5 and metadata JSONB to artifacts with CHECK constraints - Add updated_at and composite index to tags table - Add tag_name, user_agent, duration_ms, deduplicated, checksum_verified to uploads - Add change_type field to tag_history table - Add composite indexes and GIN index to audit_logs - Add partial index for public projects - Add triggers for ref_count accuracy and updated_at timestamps - Create migration script (002) for existing databases
6.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
⚠️ BEFORE STARTING ANY NEW ISSUE
ALWAYS run /start-issue before beginning work on a new task. This ensures you have the latest code and prevents merge conflicts.
If you cannot use the slash command, manually run:
git checkout main && git pull
Project Overview
Orchard is a content-addressable artifact storage system. Artifacts are stored and referenced by their SHA256 hash, enabling automatic deduplication. The system uses a Project → Package → Artifact hierarchy with Tags as human-readable aliases.
Tech Stack
- Backend: Python 3.12 + FastAPI + SQLAlchemy
- Frontend: React 18 + TypeScript + Vite
- Database: PostgreSQL 16
- Object Storage: MinIO (S3-compatible)
- Cache: Redis (configured but not yet used)
Common Commands
Local Development (Docker Compose)
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f orchard-server
# Stop services
docker-compose down
Backend Development
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8080
Frontend Development
cd frontend
npm install
npm run dev # Dev server with API proxy to localhost:8080
npm run build # Production build
Building Docker Image
docker build -t orchard .
# With custom NPM registry
docker build --build-arg NPM_REGISTRY=https://registry.example.com -t orchard .
Architecture
Content-Addressable Storage
Artifacts use SHA256 hash as their primary identifier. The storage flow:
- Upload receives file → compute SHA256 → check if hash exists
- If new: store in S3 at
fruits/{hash[:2]}/{hash[2:4]}/{hash} - If duplicate: increment
ref_count, skip S3 upload - Artifact ID = SHA256 hash (64-char hex string)
Key Backend Files
backend/app/routes.py- All API endpointsbackend/app/storage.py- S3 storage layer with deduplication logicbackend/app/models.py- SQLAlchemy ORM modelsbackend/app/schemas.py- Pydantic request/response schemasbackend/app/config.py- Environment-based settings (ORCHARD_* prefix)
API URL Patterns
/api/v1/search- Global search across projects, packages, and artifacts/api/v1/projects- Project CRUD (supportsvisibility,search,sort,orderparams)/api/v1/project/{project}/packages- Package CRUD (supportsformat,platform,search,sort,orderparams)/api/v1/project/{project}/{package}/upload- Upload artifact (multipart form)/api/v1/project/{project}/{package}/+/{ref}- Download artifact/api/v1/project/{project}/{package}/tags- Tag management (search includes artifact filename)
Download ref parameter supports: tag name, tag:name, artifact:sha256hash
Database Schema
Core tables in migrations/001_initial.sql:
projects- Top-level containerspackages- Collections within projectsartifacts- Content-addressable storage (SHA256 as PK, includes ref_count)tags- Aliases pointing to artifactsuploads- Upload event log (tracks all uploads including duplicates)
Frontend Structure
frontend/src/api.ts- API client functionsfrontend/src/types.ts- TypeScript interfaces matching backend schemasfrontend/src/pages/- Route components (Home, ProjectPage, PackagePage)
Frontend dev server proxies /api, /health, /project to backend at localhost:8080.
Environment Variables
All config uses ORCHARD_ prefix. Key variables:
ORCHARD_DATABASE_HOST/PORT/USER/PASSWORD/DBNAMEORCHARD_S3_ENDPOINT/BUCKET/ACCESS_KEY_ID/SECRET_ACCESS_KEYORCHARD_S3_USE_PATH_STYLE=truefor MinIO
Local Services
| Service | Port | Purpose |
|---|---|---|
| orchard-server | 8080 | API + Web UI |
| postgres | 5432 | Metadata |
| minio | 9000 | Object storage |
| minio console | 9001 | MinIO web UI (minioadmin/minioadmin) |
| redis | 6379 | Cache (future) |
Git Workflow
The code flows through multiple remotes:
Local (this laptop) → Bitstorm → Work laptop → BSF (GitLab) → Work laptop → Bitstorm
- Local laptop: Claude makes changes, pushes feature branch to Bitstorm
- Bitstorm: Remote git repo (origin)
- Work laptop: Fetch from Bitstorm, checkout feature branch
- BSF (GitLab at work): Push branch, merge to main (squash merge recommended)
- Work laptop: Pull merged main from BSF
- Bitstorm: Push updated main back to keep repos in sync
Squash merging is recommended when merging feature branches to main on BSF to keep history clean.
Workflow Guidelines
- Run
/start-issuebefore starting any new issue (or manually:git checkout main && git pull) - Do NOT include AI attribution in commit messages (no "Generated with Claude Code", no "Co-Authored-By: Claude", etc.)
- Always update documentation with each completed work
- Always output complete acceptance criteria in a markdown code block so it can be copied, marking completed items as checked
- Use
- [ ]for unchecked items - Use
- [x]for checked items - Example format:
## Acceptance Criteria - [x] Completed item - [ ] Incomplete item
- Use
- NEVER merge branches to main without explicit user approval - If testing requires changes from another branch to be merged first, inform the user and wait for approval before merging. Do not merge branches autonomously.
- Testing dependencies - If you cannot fully test functionality because it depends on unmerged changes from another branch, clearly inform the user what is blocking testing and what needs to be merged first.
- Always run linting before committing:
- Frontend:
cd frontend && npm run lint(if available) ornpm run buildto catch TypeScript errors - Backend:
cd backend && python -m py_compile app/*.pyto check for syntax errors
- Frontend:
- Update CHANGELOG.md - At the end of each issue, add entries under the
[Unreleased]section with appropriateAdded,Changed,Fixed, orRemovedsubsections. Ask the user for the GitLab issue number to include in the entry (e.g.,(#16)).