# 3D Face Annotation

This repository contains a small monorepo for a face-annotation workflow:

- a Node.js and Express backend with PostgreSQL storage
- a React and Vite frontend for browsing models, editing annotations, and managing atlas assets
- a Docker Compose stack for running the full app locally

The current default ports are:

- frontend dev server: `http://localhost:5173`
- backend API: `http://localhost:3002`
- Docker frontend: `http://localhost:8081`
- PostgreSQL: `localhost:5432`

## Repository layout

```text
.
|- backend/
|  |- data/atlases/                # bundled atlas JSON files and Czech translation sidecars
|  |- public/images/               # bundled reference images
|  |- public/user_added_images/    # user-contributed atlas images
|  |- repositories/                # database access layer
|  |- services/                    # business logic
|  |- tests/                       # Jest test suites (backend integration and unit tests)
|  |- uploads/                     # uploaded OBJ/MTL/texture files
|  |- server.js                    # Express entry point
|  |- seeder.js                    # destructive seed script
|  `- scripts/                     # atlas maintenance and import scripts
|- frontend/
|  |- src/components/layout/       # dashboard, editor, atlas management views
|  |- src/components/model/        # model viewport helpers
|  |- src/context/                 # language and dialog state
|  |- src/hooks/                   # editor and annotation hooks
|  |- src/api/generated/           # generated API client
|  |- src/utils/api.js             # backend base URL resolution
|  |- tests/                       # Vitest test suites (frontend unit and integration tests)
|  `- openapi.yaml                 # API description used for client generation
`- docker-compose.yml
```

## What the app does today

The current UI is centered around three working areas:

- Dashboard: browse annotations and models, filter by atlas and checked state, export CSV, and import CSV-based updates
- Editor: upload or reuse OBJ, MTL, and texture files, then create or continue annotations for a selected atlas
- Atlases: browse atlas schema, add user images and drawings to trait options, export local atlas updates to ZIP, and import ZIP updates back in

The app supports Czech and English labels in the UI and in atlas content.

## Testing

Run all tests:

```bash
cd backend 
npm test
```

Run Jest in watch mode:

```bash
cd backend
npm run test:watch
```

The test command seeds the test database before running Jest. The `npm test` command also runs frontend tests using Vitest.

## Run with Docker Compose

From the repository root:

```bash
docker compose up --build -d
```

This starts:

- `postgres`
- `backend`
- `frontend`

Open the app at `http://localhost:8081`.

Useful checks:

- backend health: `http://localhost:3002/health`
- backend root: `http://localhost:3002/`

Stop the stack:

```bash
docker compose down
```

Remove the database volume too:

```bash
docker compose down -v
```

### Seed a fresh database

The main stack does not run the destructive seed automatically. To initialize a fresh database with bundled data:

```bash
docker compose --profile setup run --rm backend-seed
```

### Docker notes

- the frontend container serves static files with Nginx on port `8081`
- Nginx proxies `/api`, `/annotations`, `/models`, `/public`, and `/export` to the backend container
- uploaded model files live in the `backend_uploads` volume
- user-contributed atlas images live in the `backend_user_images` volume
- PostgreSQL data lives in the `postgres_data` volume

## Development Workflow

### Local Development

1. Start the database:
   ```bash
   docker compose up postgres -d
   ```

2. Seed the database:
   ```bash
   docker compose --profile setup run --rm backend-seed
   ```

3. Start backend and frontend:
   ```bash
   cd backend && npm start &
   cd frontend && npm run dev &
   ```

4. Run tests as needed:
   ```bash
   cd backend && npm test
   ```

### Testing Strategy

The test suite covers:
- **Frontend**: React hooks, CSV utilities, annotation orchestration
- **Backend**: API endpoints, file uploads, database transactions, critical workflows
- **Integration**: End-to-end scenarios like duplicate detection and rollback


## Run locally without Docker

### Backend

```bash
cd backend
npm install
npm start
```

The backend defaults to `http://localhost:3002`.

For local configuration, copy `backend/.env.example` to `backend/.env` and adjust the database connection if needed.

To run the backend on a different port locally, set `PORT` before starting:

- PowerShell:
  ```powershell
  cd backend
  $env:PORT = 8081
  npm start
  ```
- CMD:
  ```cmd
  cd backend
  set PORT=8081&& npm start
  ```
- or add `PORT=8081` to `backend/.env`

The frontend dev server reads the backend URL from `frontend/.env` using `VITE_API_BASE_URL`.
For example, if the backend runs on `8081`, use:

```dotenv
VITE_API_BASE_URL=http://localhost:8081
```

### Frontend

In a second terminal:

```bash
cd frontend
npm install
npm run dev
```

The frontend dev server starts on `http://localhost:5173`.

If `VITE_API_BASE_URL` is not set, the frontend falls back to `http://localhost:3002`.

## Atlas source files

Bundled atlases use a split format in `backend/data/atlases/`:

- an English source file such as `somatoscopy.json`
- a Czech translation sidecar such as `somatoscopy.translations.cs.json`

The backend merges both files during seed and import operations.

To import a single atlas into an existing database without reseeding everything:

```bash
cd backend
npm run import:atlas -- somatoscopy.json
```

To normalize or split atlas source files:

```bash
cd backend
npm run normalize:atlases
npm run split:atlases
```

## API shape

The backend does not use a single route prefix for everything. The current route groups are:

- `/api/form-schema`, `/api/atlases`, `/api/models`, `/api/updates/*`
- `/annotations/*` for annotation CRUD
- `/api/annotations/:annotationId/check` for checked-state updates
- `/export/full` for a full JSON export
- `/models/*` and `/public/*` for static file serving

## Notes

- the backend listens on port `3002` by default, not `3001`
- the backend package currently exposes `npm start` and `npm test`, but not a dedicated `npm run dev` script
- the frontend package currently uses Vite and reads the backend base URL from `src/utils/api.js`