Merge pull request 'Humanize README and admin guides' (#102) from docs/humanize-prose-rebase into master
CI / skip-ci-check (push) Successful in 31s
CI / python-lint (push) Successful in 34s
CI / docker-ci (push) Successful in 34s
CI / secret-scan (push) Successful in 45s
CI / viewer-unit (push) Successful in 2m6s
CI / admin-unit (push) Successful in 2m42s
CI / e2e (push) Successful in 3m46s

This commit was merged in pull request #102.
This commit is contained in:
2026-08-05 14:49:23 -05:00
11 changed files with 342 additions and 3172 deletions
+26 -508
View File
@@ -1,522 +1,40 @@
# Contributing to PunimTag
# Contributing
Thank you for your interest in contributing to PunimTag! This document provides guidelines and instructions for contributing to the project.
## Setup
---
- Python 3.12+, Node 18+, PostgreSQL, Redis
- Follow the root [README](README.md) (`./install.sh`, `.env` from `.env.example`)
- Activate the venv before backend work: `source venv/bin/activate`
## 📋 Table of Contents
## Workflow
1. [Code of Conduct](#code-of-conduct)
2. [Getting Started](#getting-started)
3. [Development Workflow](#development-workflow)
4. [Coding Standards](#coding-standards)
5. [Testing](#testing)
6. [Documentation](#documentation)
7. [Pull Request Process](#pull-request-process)
8. [Project Structure](#project-structure)
1. Branch from `main` / `master` for the change.
2. Keep commits focused; reference issues when you have them.
3. Run `npm run ci:local` before opening a PR.
4. Update docs when behavior or setup steps change.
---
## Coding notes
## 🤝 Code of Conduct
- Backend: FastAPI + SQLAlchemy under `backend/`; prefer typed Pydantic models for API I/O.
- Admin: React + Vite + TypeScript in `admin-frontend/`.
- Viewer: Next.js + Prisma in `viewer-frontend/`; regenerate Prisma clients after schema edits.
- Do not commit secrets, real `.env` files, or production photo paths with PII.
### Our Pledge
We are committed to providing a welcoming and inclusive environment for all contributors.
### Expected Behavior
- Be respectful and considerate
- Welcome newcomers and help them learn
- Accept constructive criticism gracefully
- Focus on what's best for the project
- Show empathy towards other contributors
### Unacceptable Behavior
- Harassment or discriminatory language
- Trolling or insulting comments
- Public or private harassment
- Publishing others' private information
- Other unprofessional conduct
---
## 🚀 Getting Started
### Prerequisites
- Python 3.12+
- Git
- Basic understanding of Python and Tkinter
- Familiarity with face recognition concepts (helpful)
### Setting Up Development Environment
1. **Fork and Clone**
```bash
git fork <repository-url>
git clone <your-fork-url>
cd punimtag
```
2. **Create Virtual Environment**
```bash
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
```
3. **Install Dependencies**
```bash
pip install -r requirements.txt
pip install -r requirements-dev.txt # If available
```
4. **Verify Installation**
```bash
python src/gui/dashboard_gui.py
```
---
## 🔄 Development Workflow
### Branch Strategy
```
main/master - Stable releases
develop - Integration branch
feature/* - New features
bugfix/* - Bug fixes
hotfix/* - Urgent fixes
release/* - Release preparation
```
### Creating a Feature Branch
## Tests
```bash
git checkout develop
git pull origin develop
git checkout -b feature/your-feature-name
npm run test:backend
npm run lint:python
npm run lint:all
npm run test:e2e # needs services; see e2e/README.md
```
### Making Changes
## Pull requests
1. Make your changes in the appropriate directory:
- Business logic: `src/core/`
- GUI components: `src/gui/`
- Utilities: `src/utils/`
- Tests: `tests/`
- Describe what changed and how you verified it.
- CI lint/test gates are hard; do not mute them with `|| true`.
- Screenshots help for UI changes.
2. Follow coding standards (see below)
3. Add/update tests
4. Update documentation
5. Test your changes thoroughly
### Committing Changes
Use clear, descriptive commit messages:
```bash
git add .
git commit -m "feat: add face clustering algorithm"
```
**Commit Message Format:**
```
<type>: <subject>
<body>
<footer>
```
**Types:**
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `style`: Code style changes (formatting)
- `refactor`: Code refactoring
- `test`: Adding or updating tests
- `chore`: Maintenance tasks
**Examples:**
```
feat: add DeepFace integration
- Replace face_recognition with DeepFace
- Implement ArcFace model
- Add cosine similarity matching
- Update database schema
Closes #123
```
---
## 📏 Coding Standards
### Python Style Guide
Follow **PEP 8** with these specifics:
#### Formatting
- **Indentation**: 4 spaces (no tabs)
- **Line Length**: 100 characters max (120 for comments)
- **Imports**: Grouped and sorted
```python
# Standard library
import os
import sys
# Third-party
import numpy as np
from PIL import Image
# Local
from src.core.database import DatabaseManager
```
#### Naming Conventions
- **Classes**: `PascalCase` (e.g., `FaceProcessor`)
- **Functions/Methods**: `snake_case` (e.g., `process_faces`)
- **Constants**: `UPPER_SNAKE_CASE` (e.g., `DEFAULT_TOLERANCE`)
- **Private**: Prefix with `_` (e.g., `_internal_method`)
#### Documentation
All public classes and functions must have docstrings:
```python
def process_faces(self, limit: int = 50) -> int:
"""Process unprocessed photos for faces.
Args:
limit: Maximum number of photos to process
Returns:
Number of photos successfully processed
Raises:
DatabaseError: If database connection fails
"""
pass
```
#### Type Hints
Use type hints for all function signatures:
```python
from typing import List, Dict, Optional
def get_similar_faces(
self,
face_id: int,
tolerance: float = 0.6
) -> List[Dict[str, Any]]:
pass
```
### Code Organization
#### File Structure
```python
#!/usr/bin/env python3
"""
Module description
"""
# Imports
import os
from typing import List
# Constants
DEFAULT_VALUE = 42
# Classes
class MyClass:
"""Class description"""
pass
# Functions
def my_function():
"""Function description"""
pass
# Main execution
if __name__ == "__main__":
main()
```
#### Error Handling
Always use specific exception types:
```python
try:
result = risky_operation()
except FileNotFoundError as e:
logger.error(f"File not found: {e}")
raise
except ValueError as e:
logger.warning(f"Invalid value: {e}")
return default_value
```
---
## 🧪 Testing
### Writing Tests
Create tests in `tests/` directory:
```python
import pytest
from src.core.face_processing import FaceProcessor
def test_face_detection():
"""Test face detection on sample image"""
processor = FaceProcessor(db_manager, verbose=0)
result = processor.process_faces(limit=1)
assert result > 0
def test_similarity_calculation():
"""Test face similarity metric"""
processor = FaceProcessor(db_manager, verbose=0)
similarity = processor._calculate_cosine_similarity(enc1, enc2)
assert 0.0 <= similarity <= 1.0
```
### Running Tests
```bash
# All tests
python -m pytest tests/
# Specific test file
python tests/test_face_recognition.py
# With coverage
pytest --cov=src tests/
# Verbose output
pytest -v tests/
```
### Test Guidelines
1. **Test Coverage**: Aim for >80% code coverage
2. **Test Names**: Descriptive names starting with `test_`
3. **Assertions**: Use clear assertion messages
4. **Fixtures**: Use pytest fixtures for setup/teardown
5. **Isolation**: Tests should not depend on each other
---
## 📚 Documentation
### What to Document
1. **Code Changes**: Update docstrings
2. **API Changes**: Update API documentation
3. **New Features**: Add to README and docs
4. **Breaking Changes**: Clearly mark in changelog
5. **Architecture**: Update ARCHITECTURE.md if needed
### Documentation Style
- Use Markdown for all documentation
- Include code examples
- Add diagrams where helpful
- Keep language clear and concise
- Update table of contents
### Files to Update
- `README.md`: User-facing documentation
- `docs/ARCHITECTURE.md`: Technical architecture
- `.notes/task_list.md`: Task tracking
- Inline comments: Complex logic explanation
---
## 🔀 Pull Request Process
### Before Submitting
- [ ] Code follows style guidelines
- [ ] All tests pass
- [ ] New tests added for new features
- [ ] Documentation updated
- [ ] No linting errors
- [ ] Commit messages are clear
- [ ] Branch is up to date with develop
### Submitting PR
1. **Push your branch**
```bash
git push origin feature/your-feature-name
```
2. **Create Pull Request**
- Go to GitHub/GitLab
- Click "New Pull Request"
- Select your feature branch
- Fill out PR template
3. **PR Title Format**
```
[Type] Short description
Examples:
[Feature] Add DeepFace integration
[Bug Fix] Fix face detection on rotated images
[Docs] Update architecture documentation
```
4. **PR Description Template**
```markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Related Issues
Closes #123
## Testing
Describe testing performed
## Screenshots (if applicable)
Add screenshots
## Checklist
- [ ] Code follows style guidelines
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] All tests pass
```
### Review Process
1. **Automated Checks**: Must pass all CI/CD checks
2. **Code Review**: At least one approval required
3. **Discussion**: Address all review comments
4. **Updates**: Make requested changes
5. **Approval**: Merge after approval
### After Merge
1. Delete feature branch
2. Pull latest develop
3. Update local repository
---
## 🏗️ Project Structure
### Key Directories
```
src/
├── core/ # Business logic - most changes here
├── gui/ # GUI components - UI changes here
└── utils/ # Utilities - helper functions
tests/ # All tests go here
docs/ # User documentation
.notes/ # Developer notes
```
### Module Dependencies
```
gui → core → database
gui → utils
core → utils
```
**Rules:**
- Core modules should not import GUI modules
- Utils should not import core or GUI
- Avoid circular dependencies
---
## 💡 Tips for Contributors
### Finding Issues to Work On
- Look for `good first issue` label
- Check `.notes/task_list.md`
- Ask in discussions
### Getting Help
- Read documentation first
- Check existing issues
- Ask in discussions
- Contact maintainers
### Best Practices
1. **Start Small**: Begin with small changes
2. **One Feature**: One PR = one feature
3. **Test Early**: Write tests as you code
4. **Ask Questions**: Better to ask than assume
5. **Be Patient**: Reviews take time
---
## 🎯 Areas Needing Contribution
### High Priority
- DeepFace integration
- Test coverage improvement
- Performance optimization
- Documentation updates
### Medium Priority
- GUI improvements
- Additional search filters
- Export functionality
- Backup/restore features
### Low Priority
- Code refactoring
- Style improvements
- Additional themes
- Internationalization
---
## 📞 Contact
- **Issues**: GitHub Issues
- **Discussions**: GitHub Discussions
- **Email**: [Add email]
---
## 🙏 Recognition
Contributors will be:
- Listed in AUTHORS file
- Mentioned in release notes
- Thanked in documentation
---
## 📄 License
By contributing, you agree that your contributions will be licensed under the same license as the project.
---
**Thank you for contributing to PunimTag! 🎉**
Every contribution, no matter how small, makes a difference!
## Project layout
See the root README. Deeper design notes: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
+70 -857
View File
@@ -1,898 +1,111 @@
# PunimTag Web
# PunimTag
**Modern Photo Management and Facial Recognition System**
Local photo library with face recognition (DeepFace / ArcFace). One monorepo
holds the FastAPI backend, React admin UI, and Next.js viewer. Data stays on
your machines; there is no cloud dependency for core photo or face storage.
A fast, simple, and modern web application for organizing and tagging photos using state-of-the-art DeepFace AI with ArcFace recognition model.
Status: active.
**Monorepo Structure:** This project contains both the admin interface (React) and viewer interface (Next.js) in a unified repository for easier maintenance and setup.
## Requirements
---
- Python 3.12+
- Node.js 18+ (20+ recommended for the viewer)
- PostgreSQL (two databases: app + auth)
- Redis (RQ background jobs)
- Python tkinter (native folder picker in admin Scan)
## Features
- **Web-Based**: Modern React frontend with FastAPI backend
- **DeepFace AI**: State-of-the-art face detection with RetinaFace and ArcFace models
- **Superior Accuracy**: 512-dimensional embeddings (4x more detailed than face_recognition)
- **Multiple Detectors**: Choose from RetinaFace, MTCNN, OpenCV, or SSD detectors
- **Flexible Models**: Select ArcFace, Facenet, Facenet512, or VGG-Face recognition models
- **Person Identification**: Identify and tag people across your photo collection
- **Smart Auto-Matching**: Intelligent face matching with quality scoring and cosine similarity
- **Confidence Calibration**: Empirical-based confidence scores for realistic match probabilities
- **Advanced Search**: Search by people, dates, tags, and folders
- **Tag Management**: Organize photos with hierarchical tags
- **Batch Processing**: Process thousands of photos efficiently
- **Unique Faces Filter**: Hide duplicate faces to focus on unique individuals
- **Real-time Updates**: Live progress tracking and job status updates
- **Network Path Support**: Browse and scan folders on network shares (UNC paths on Windows, mounted shares on Linux)
- **Native Folder Picker**: Browse button uses native OS folder picker with full absolute path support
- **Privacy-First**: All data stored locally, no cloud dependencies
---
## Quick Start
### Prerequisites
- **Python 3.12 or higher** (with pip)
- **Node.js 18+ and npm**
- **PostgreSQL** (required for both development and production)
- **Redis** (for background job processing)
- **Python tkinter** (for native folder picker in Scan tab)
**Note:** The automated installation script (`./install.sh`) will install PostgreSQL, Redis, and Python tkinter automatically on Ubuntu/Debian systems.
### Installation
#### Option 1: Automated Installation (Recommended for Linux/Ubuntu/Debian)
The automated installation script will install all system dependencies, Python packages, frontend dependencies, and set up databases:
## Quick start
```bash
# Clone the repository
git clone <repository-url>
cd punimtag
# Run the installation script
./install.sh
./install.sh # Ubuntu/Debian: deps, venv, DBs; elsewhere install Postgres/Redis yourself
cp .env.example .env # set DATABASE_URL, DATABASE_URL_AUTH, SECRET_KEY, ADMIN_*
```
The script will:
- Check prerequisites (Python 3.12+, Node.js 18+)
- Install system dependencies (PostgreSQL, Redis, Python tkinter) on Ubuntu/Debian
- Set up PostgreSQL databases (main + auth)
- Create Python virtual environment
- Install all Python dependencies
- Install all frontend dependencies (admin-frontend and viewer-frontend)
- Create `.env` configuration files
- Create necessary data directories
**Note:** After installation, you'll need to generate Prisma clients for the viewer-frontend:
```bash
cd viewer-frontend
npx prisma generate
```
**Note:** On macOS or other systems, the script will skip system dependency installation. You'll need to install PostgreSQL, Redis, and Python tkinter manually.
**Installing tkinter manually:**
- **Ubuntu/Debian:** `sudo apt install python3-tk`
- **RHEL/CentOS:** `sudo yum install python3-tkinter`
- **macOS:** Usually included with Python, but if missing: `brew install python-tk` (if using Homebrew Python)
- **Windows:** Usually included with Python installation
#### Option 2: Manual Installation
After install on the viewer:
```bash
# Clone the repository
git clone <repository-url>
cd punimtag
# Create and activate virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install Python dependencies
pip install -r requirements.txt
# Install frontend dependencies
cd admin-frontend
npm install
cd ../viewer-frontend
npm install
# Generate Prisma clients for viewer-frontend (after setting up .env)
npx prisma generate
cd ..
cd viewer-frontend && npx prisma generate && cd ..
```
### Database Setup
**Database Configuration:**
The application uses **two separate PostgreSQL databases**:
1. **Main database** (`punimtag`) - Stores photos, faces, people, tags, and backend user accounts
- **Required: PostgreSQL**
2. **Auth database** (`punimtag_auth`) - Stores frontend website user accounts and moderation data
- **Required: PostgreSQL**
Both database connections are configured via the `.env` file.
#### Development Database
For development, you can use the shared development PostgreSQL server:
**Dev PostgreSQL Server:**
- **Host**: `<db-host>`
- **Port**: 5432
- **User**: `<db-user>`
- **Password**: [Contact administrator for password]
**Development Server:**
- **Host**: `<backend-host>`
- **User**: appuser
- **Password**: [Contact administrator for password]
Configure your `.env` file for development:
```bash
# Main database (dev)
DATABASE_URL=postgresql+psycopg2://<db-user>:[PASSWORD]@<db-host>:5432/punimtag
# Auth database (dev)
DATABASE_URL_AUTH=postgresql+psycopg2://<db-user>:[PASSWORD]@<db-host>:5432/punimtag_auth
```
**Install PostgreSQL (if not installed):**
```bash
# On Ubuntu/Debian:
sudo apt update && sudo apt install -y postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresql
# Or use the automated setup script:
./scripts/setup_postgresql.sh
```
**Create Main Database and User:**
```bash
sudo -u postgres psql -c "CREATE USER punimtag WITH PASSWORD '<choose-a-password>';"
sudo -u postgres psql -c "CREATE DATABASE punimtag OWNER punimtag;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE punimtag TO punimtag;"
```
**Create Auth Database (for frontend website user accounts):**
```bash
sudo -u postgres psql -c "CREATE DATABASE punimtag_auth OWNER punimtag;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE punimtag_auth TO punimtag;"
```
**Note:** The auth database (`punimtag_auth`) stores user accounts for the frontend website, separate from the main application database. Both databases are required for full functionality.
**Grant DELETE Permissions on Auth Database Tables:**
If you encounter permission errors when trying to delete records from the auth database (e.g., when using "Clear database" in the admin panel), grant DELETE permissions:
Run three processes:
```bash
# Grant DELETE permission on all auth database tables
sudo -u postgres psql -d punimtag_auth << 'EOF'
GRANT DELETE ON TABLE pending_photos TO punimtag;
GRANT DELETE ON TABLE users TO punimtag;
GRANT DELETE ON TABLE pending_identifications TO punimtag;
GRANT DELETE ON TABLE inappropriate_photo_reports TO punimtag;
EOF
# Or grant on a single table:
sudo -u postgres psql -d punimtag_auth -c "GRANT DELETE ON TABLE pending_photos TO punimtag;"
./run_api_with_worker.sh # API http://127.0.0.1:8000 + RQ worker
cd admin-frontend && npm run dev # http://localhost:3000
cd viewer-frontend && npm run dev # http://localhost:3001
```
Alternatively, use the automated script (requires sudo password):
```bash
./scripts/grant_auth_db_delete_permission.sh
```
API docs: http://127.0.0.1:8000/docs
**Configuration:**
The `.env` file in the project root contains database connection strings:
Or use root npm scripts: `npm run dev:admin`, `npm run dev:viewer`, `npm run ci:local`.
**Local Development:**
```bash
# Main application database (PostgreSQL - required)
DATABASE_URL=postgresql+psycopg2://punimtag:<choose-a-password>@localhost:5432/punimtag
## Config
# Auth database (PostgreSQL - required for frontend website users)
DATABASE_URL_AUTH=postgresql+psycopg2://punimtag:<choose-a-password>@localhost:5432/punimtag_auth
```
Root `.env` (see `.env.example`):
**Development Server:**
```bash
# Main database (dev PostgreSQL server)
DATABASE_URL=postgresql+psycopg2://<db-user>:[PASSWORD]@<db-host>:5432/punimtag
| Variable | Purpose |
|----------|---------|
| `DATABASE_URL` | Main app DB (photos, faces, people, tags) |
| `DATABASE_URL_AUTH` | Viewer auth / moderation DB |
| `SECRET_KEY` | JWT signing |
| `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Bootstrap admin |
| `REDIS_URL` | RQ jobs |
| `PHOTO_STORAGE_DIR` | Uploaded media (default `data/uploads`) |
# Auth database (dev PostgreSQL server)
DATABASE_URL_AUTH=postgresql+psycopg2://<db-user>:[PASSWORD]@<db-host>:5432/punimtag_auth
```
Viewer and admin each have their own `.env.example` under those folders.
Secrets for deployed instances belong in Infisical (`/apps/punimtag`), not in git.
**Automatic Initialization:**
The database and all tables are automatically created on first startup. No manual migration is needed!
## What it does
The web application will:
- Connect to the database using the `.env` configuration
- Create all required tables with the correct schema on startup
- Match the desktop version schema exactly for compatibility
- Detect and match faces (RetinaFace + ArcFace by default; other detectors/models configurable)
- Identify people across a library; auto-match with quality scoring
- Search by person, date, tag, folder
- Admin UI for scan/process/identify; viewer UI for browsing
- Hierarchical tags, batch jobs via Redis/RQ
- Network path browsing (UNC on Windows, mounted shares on Linux)
**Database Schema:**
The web version uses the **exact same schema** as the desktop version for full compatibility:
- `photos` - Photo metadata (path, filename, date_taken, processed, media_type)
- `people` - Person records (first_name, last_name, middle_name, maiden_name, date_of_birth)
- `faces` - Face detections (encoding, location, quality_score, face_confidence, exif_orientation, excluded)
- `person_encodings` - Person face encodings for matching
- `tags` - Tag definitions
- `phototaglinkage` - Photo-tag relationships (with linkage_type)
- `users` - Backend user accounts (with password hashing, roles, permissions)
- `photo_person_linkage` - Direct photo-person associations (for videos)
- `role_permissions` - Role-based permission matrix
**Auth Database Schema:**
The separate auth database (`punimtag_auth`) stores frontend website user accounts:
- `users` - Frontend website user accounts (email, password_hash, is_active)
- `pending_photos` - Photos pending moderation
- `pending_identifications` - Face identifications pending approval
- `inappropriate_photo_reports` - Reported photos for review
### Running the Application
**Prerequisites:**
- **PostgreSQL** must be installed and running (see Database Setup section above)
- **Redis** must be installed and running (for background jobs)
**Install Redis (if not installed):**
```bash
# On Ubuntu/Debian:
sudo apt update && sudo apt install -y redis-server
sudo systemctl start redis-server
sudo systemctl enable redis-server # Auto-start on boot
# On macOS with Homebrew:
brew install redis
brew services start redis
# Verify Redis is running:
redis-cli ping # Should respond with "PONG"
```
**Start Redis (if installed but not running):**
```bash
# On Linux:
sudo systemctl start redis-server
# Or run directly:
redis-server
```
#### Option 1: Using Helper Scripts (Recommended)
**Terminal 1 - Backend API + Worker:**
```bash
cd punimtag
./run_api_with_worker.sh
```
This script will:
- Check if Redis is running (start it if needed)
- Ensure database schema is up to date
- Start the RQ worker in the background
- Start the FastAPI server
- Handle cleanup on Ctrl+C
You should see:
```
✅ Database schema ready
🚀 Starting RQ worker...
🚀 Starting FastAPI server...
✅ Server running on http://127.0.0.1:8000
✅ Worker running (PID: ...)
✅ API running (PID: ...)
```
**Alternative: Start backend only (without worker):**
```bash
cd punimtag
./start_backend.sh
```
**Stop the backend:**
```bash
cd punimtag
./stop_backend.sh
```
**Terminal 2 - Admin Frontend:**
```bash
cd punimtag/admin-frontend
npm run dev
```
You should see:
```
VITE v5.4.21 ready in 811 ms
➜ Local: http://localhost:3000/
```
**Terminal 3 - Viewer Frontend (Optional):**
```bash
cd punimtag/viewer-frontend
# Generate Prisma clients (only needed once or after schema changes)
npx prisma generate
npm run dev
```
You should see:
```
▲ Next.js 16.1.1 (Turbopack)
- Local: http://localhost:3001/
```
#### Option 2: Manual Start
**Terminal 1 - Backend API:**
```bash
cd punimtag
source venv/bin/activate
export PYTHONPATH="$(pwd)"
python3 -m uvicorn backend.app:app --host 127.0.0.1 --port 8000 --reload
```
**Note:** If you encounter warnings about "Electron/Chromium" when running `uvicorn`, use `python3 -m uvicorn` instead, or use the helper scripts above.
**Terminal 2 - Admin Frontend:**
```bash
cd punimtag/admin-frontend
npm run dev
```
**Terminal 3 - Viewer Frontend (Optional):**
```bash
cd punimtag/viewer-frontend
npx prisma generate # Only needed once or after schema changes
npm run dev
```
#### Access the Applications
1. **Admin Interface**: Open your browser to **http://localhost:3000**
- Log in with the credentials configured in your `.env` (`ADMIN_USERNAME` / `ADMIN_PASSWORD`)
2. **Viewer Interface** (Optional): Open your browser to **http://localhost:3001**
- Public photo viewing interface
- Separate authentication system
3. **API Documentation**: Available at **http://127.0.0.1:8000/docs**
#### Troubleshooting
**Port 8000 already in use:**
```bash
# Use the stop script
cd punimtag
./stop_backend.sh
# Or manually find and kill the process
lsof -i :8000
kill <PID>
# Or use pkill
pkill -f "uvicorn.*backend.app"
```
**Port 3000 already in use:**
```bash
# Find and kill the process using port 3000
lsof -i :3000
kill <PID>
# Or change the port in admin-frontend/vite.config.ts
```
**Redis not running:**
```bash
# Start Redis
sudo systemctl start redis-server
# Or
redis-server
# Verify Redis is running
redis-cli ping # Should respond with "PONG"
```
**Worker module not found error:**
If you see `ModuleNotFoundError: No module named 'backend'`:
- Make sure you're using the helper scripts (`./run_api_with_worker.sh` or `./start_backend.sh`)
- These scripts set PYTHONPATH correctly
- If running manually, ensure `export PYTHONPATH="$(pwd)"` is set
**Python/Cursor interception warnings:**
If you see warnings about "Electron/Chromium" when running `uvicorn`:
- Use `python3 -m uvicorn` instead of just `uvicorn`
- Or use the helper scripts which handle this automatically
**Database issues:**
```bash
# The database is automatically created on first startup
# If you need to reset it, delete the database file:
rm data/punimtag.db
# The schema will be recreated on next startup
```
**Browse button returns 503 error or doesn't show folder picker:**
This indicates that Python tkinter is not available. Install it:
```bash
# Ubuntu/Debian:
sudo apt install python3-tk
# RHEL/CentOS:
sudo yum install python3-tkinter
# Verify installation:
python3 -c "import tkinter; print('tkinter available')"
```
**Note:** If running on a remote server without a display, you may need to set the DISPLAY environment variable or use X11 forwarding:
```bash
export DISPLAY=:0
# Or for X11 forwarding:
export DISPLAY=localhost:10.0
```
**Viewer frontend shows 0 photos:**
- Make sure the database has photos (import them via admin frontend)
- Verify `DATABASE_URL` in `viewer-frontend/.env` points to the correct database
- Ensure Prisma client is generated: `cd viewer-frontend && npx prisma generate`
- Check that photos are marked as `processed: true` in the database
#### Important Notes
- The database and tables are **automatically created on first startup** - no manual setup needed!
- The RQ worker starts automatically in a background subprocess when the API server starts
- Make sure Redis is running first, or the worker won't start
- Worker names are unique to avoid conflicts when restarting
- Photo uploads are stored in `data/uploads` (configurable via `PHOTO_STORAGE_DIR` env var)
- **DeepFace models download automatically on first use** (can take 5-10 minutes, ~100MB)
- First run is slower due to model downloads (subsequent runs are faster)
---
## Documentation
- **[Architecture](docs/ARCHITECTURE.md)**: System design and technical details
*
## Project Structure
## Layout
```
punimtag/
├── backend/ # FastAPI backend
│ ├── api/ # API routers
│ ├── db/ # Database models and session
│ ├── schemas/ # Pydantic models
│ ├── services/ # Business logic services
│ ├── constants/ # Constants and configuration
│ ├── utils/ # Utility functions
│ ├── app.py # FastAPI application
│ └── worker.py # RQ worker for background jobs
├── admin-frontend/ # React admin interface
│ ├── src/
│ │ ├── api/ # API client
│ │ ├── components/ # React components
│ │ ├── context/ # React contexts (Auth)
│ │ ├── hooks/ # Custom hooks
│ │ └── pages/ # Page components
│ └── package.json
├── viewer-frontend/ # Next.js viewer interface
│ ├── app/ # Next.js app router
│ ├── components/ # React components
│ ├── lib/ # Utilities and database
│ ├── prisma/ # Prisma schemas
│ └── package.json
├── src/ # Legacy desktop code
│ └── core/ # Legacy desktop business logic
├── tests/ # Test suite
├── docs/ # Documentation
├── data/ # Application data (database, images)
├── scripts/ # Utility scripts
├── deploy/ # Docker deployment configs
└── package.json # Root package.json for monorepo
├── backend/ # FastAPI + SQLAlchemy
├── admin-frontend/ # React + Vite (port 3000)
├── viewer-frontend/ # Next.js (port 3001)
├── e2e/ # Playwright (@levkin/playkit)
├── scripts/ # Install / DB helpers
├── docs/ # Guides and reference
└── install.sh
```
---
## Docs
## Current Status
| Doc | Purpose |
|-----|---------|
| [docs/README.md](docs/README.md) | Doc index |
| [docs/QUICK_START.md](docs/QUICK_START.md) | Day-to-day run commands |
| [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) | Deploy overview |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | System design |
| [docs/USER_GUIDE.md](docs/USER_GUIDE.md) | Product walkthrough |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Dev workflow |
| [e2e/README.md](e2e/README.md) | End-to-end tests |
### Foundations
Homelab deploy runbooks (hosts, Caddy, monitoring) live in the private
`ansible` repo, not here.
**Backend:**
- FastAPI application with CORS middleware
- Health, version, and metrics endpoints
- JWT authentication (login, refresh, user info)
- Job management endpoints (RQ/Redis integration)
- SQLAlchemy models for all entities
- Alembic migrations configured and applied
- Database initialized (PostgreSQL required)
- RQ worker auto-start (starts automatically with API server)
- Pending linkage moderation API for user tag suggestions
## Security notes
**Frontend:**
- React + Vite + TypeScript setup
- Tailwind CSS configured
- Authentication flow with login page
- Protected routes with auth context
- Navigation layout (left sidebar + top bar)
- All page routes (Dashboard, Scan, Process, Search, Identify, Auto-Match, Tags, Settings)
- User Tagged Photos moderation tab for approving/denying pending tag linkages
Set strong `ADMIN_*` and `SECRET_KEY` before any shared deploy. Older commits
may still show LAN examples; treat matching real passwords as compromised and
rotate. Prefer placeholders in public docs.
**Database:**
- All tables created automatically on startup: `photos`, `faces`, `people`, `person_encodings`, `tags`, `phototaglinkage`
- Schema matches desktop version exactly for full compatibility
- Indices configured for performance
- PostgreSQL database (required for both development and production)
- Separate auth database (PostgreSQL) for frontend user accounts
## Known limits
### Image Ingestion & Processing
**Backend:**
- Photo import service with checksum computation
- EXIF date extraction and image metadata
- Folder scanning with recursive option
- File upload support
- Background job processing with RQ
- Real-time job progress via SSE (Server-Sent Events)
- Duplicate detection (by path and checksum)
- Photo storage configuration (`PHOTO_STORAGE_DIR`)
- **DeepFace pipeline integration**
- **Face detection (RetinaFace, MTCNN, OpenCV, SSD)**
- **Face embeddings computation (ArcFace, Facenet, Facenet512, VGG-Face)**
- **Face processing service with configurable detectors/models**
- **EXIF orientation handling**
- **Face quality scoring and validation**
- **Batch processing with progress tracking**
- **Job cancellation support**
**Frontend:**
- Scan tab UI with folder selection
- **Native folder picker (Browse button)** - Uses tkinter for native OS folder selection
- **Network path support** - Handles UNC paths (Windows: `\\server\share\folder`) and mounted network shares (Linux: `/mnt/nfs-share/photos`)
- **Full absolute path handling** - Automatically normalizes and validates paths
- Drag-and-drop file upload
- Recursive scan toggle
- Real-time job progress with progress bar
- Job status monitoring (SSE integration)
- Results display (added/existing counts)
- Error handling and user feedback
- **Process tab UI with configuration controls**
- **Detector/model selection dropdowns**
- **Batch size configuration**
- **Start/Stop processing controls**
- **Processing progress display with photo count**
- **Results summary (faces detected, faces stored)**
- **Job cancellation support**
**Worker:**
- RQ worker auto-starts with API server
- Unique worker names to avoid conflicts
- Graceful shutdown handling
- **String-based function paths for reliable serialization**
### Identify Workflow & Auto-Match
**Backend:**
- Identify face endpoints with person creation
- Auto-match engine with similarity thresholds
- Unidentified faces management and filtering
- Person creation and linking
- Batch identification support
- Similar faces search with cosine similarity
- Confidence calibration system (empirical-based)
- Face unmatch/removal functionality
- Batch similarity calculations
**Frontend:**
- Identify page UI with face navigation
- Person creation and editing
- Similar faces panel with confidence display
- Auto-Match page with person-centric view
- Checkbox selection for batch identification
- Confidence percentages with color coding
- Unique faces filter (hide duplicates)
- Date filtering for faces
- Real-time face matching and display
### PSearch & Tags
**Backend:**
- Search endpoints with filters (people, dates, tags, folders)
- Tag management endpoints (create, update, delete)
- Photo-tag linkage system
- Advanced filtering and querying
- Photo grid endpoints with pagination
**Frontend:**
- Search page with advanced filters
- Tag management UI
- Photo grid with virtualized rendering
- Filter by people, dates, tags, and folders
- Search results display
---
## Configuration
### Database
**PostgreSQL (Required):**
Both databases use PostgreSQL. Configure via the `.env` file:
```bash
# Main application database (PostgreSQL - required)
DATABASE_URL=postgresql+psycopg2://punimtag:<choose-a-password>@localhost:5432/punimtag
# Auth database (PostgreSQL - required for frontend website users)
DATABASE_URL_AUTH=postgresql+psycopg2://punimtag:<choose-a-password>@localhost:5432/punimtag_auth
```
### Environment Variables
Configuration is managed via the `.env` file in the project root. A `.env.example` template is provided.
**Required Configuration:**
```bash
# Main Database (PostgreSQL - required)
DATABASE_URL=postgresql+psycopg2://punimtag:<choose-a-password>@localhost:5432/punimtag
# Auth Database (PostgreSQL - required for frontend website user accounts)
DATABASE_URL_AUTH=postgresql+psycopg2://punimtag:<choose-a-password>@localhost:5432/punimtag_auth
# JWT Secrets (change in production!)
SECRET_KEY=dev-secret-key-change-in-production
# Single-user credentials (set your own values!)
ADMIN_USERNAME=admin
ADMIN_PASSWORD=<choose-a-password>
# Photo storage directory (default: data/uploads)
PHOTO_STORAGE_DIR=data/uploads
```
**Admin Frontend Configuration:**
Create a `.env` file in the `admin-frontend/` directory:
```bash
# Backend API URL (must be accessible from browsers)
VITE_API_URL=http://127.0.0.1:8000
```
**Viewer Frontend Configuration:**
Create a `.env` file in the `viewer-frontend/` directory:
```bash
# Main database connection (PostgreSQL - required)
DATABASE_URL=postgresql://punimtag:<choose-a-password>@localhost:5432/punimtag
# Auth database connection (PostgreSQL - required)
DATABASE_URL_AUTH=postgresql://punimtag:<choose-a-password>@localhost:5432/punimtag_auth
# Write-capable database connection (optional, falls back to DATABASE_URL if not set)
DATABASE_URL_WRITE=postgresql://punimtag:<choose-a-password>@localhost:5432/punimtag
# NextAuth configuration
NEXTAUTH_URL=http://localhost:3001
NEXTAUTH_SECRET=dev-secret-key-change-in-production
```
**Generate Prisma Clients:**
After setting up the `.env` file, generate the Prisma clients:
```bash
cd viewer-frontend
npx prisma generate
```
**Important:** The viewer frontend uses **PostgreSQL** for the main database (matching the backend). The Prisma schema is configured for PostgreSQL.
**Note:** The viewer frontend uses the same database as the backend by default. For production deployments, you may want to create separate read-only and write users for better security.
**Note:** The `.env` file is automatically loaded by the application using `python-dotenv`. Environment variables can also be set directly in your shell if preferred.
---
---
### Phase 5: Polish & Release (In Progress)
- Performance optimization
- Accessibility improvements
- Production deployment
- Documentation updates
---
## Architecture
**Backend:**
- **Framework**: FastAPI (Python 3.12+)
- **Database**: PostgreSQL (required)
- **ORM**: SQLAlchemy 2.0
- **Configuration**: Environment variables via `.env` file (python-dotenv)
- **Jobs**: Redis + RQ
- **Auth**: JWT (python-jose)
**Frontend:**
- **Framework**: React 18 + TypeScript
- **Build Tool**: Vite
- **Styling**: Tailwind CSS
- **State**: React Query + Context API
- **Routing**: React Router
**Deployment:**
- Docker Compose for local development
- Containerized services for production
---
## Dependencies
**Backend:**
- `fastapi==0.115.0`
- `uvicorn[standard]==0.30.6`
- `pydantic==2.9.1`
- `SQLAlchemy==2.0.36`
- `alembic==1.13.2`
- `python-jose[cryptography]==3.3.0`
- `redis==5.0.8`
- `rq==1.16.2`
- `psycopg2-binary==2.9.9` (PostgreSQL driver)
- `python-multipart==0.0.9` (file uploads)
- `python-dotenv==1.0.0` (environment variables)
- `bcrypt==4.1.2` (password hashing)
- `deepface>=0.0.79`
- `tensorflow>=2.13.0`
- `opencv-python>=4.8.0`
- `retina-face>=0.0.13`
- `numpy>=1.21.0`
- `pillow>=8.0.0`
**Frontend:**
- `react==18.2.0`
- `react-router-dom==6.20.0`
- `@tanstack/react-query==5.8.4`
- `axios==1.6.2`
- `tailwindcss==3.3.5`
---
## Security
- JWT-based authentication with refresh tokens
- Password hashing with bcrypt
- CORS configured for development (restrict in production)
- SQL injection prevention via SQLAlchemy ORM
- Input validation via Pydantic schemas
- Separate auth database for frontend website user accounts
**Note**: Set strong values for `ADMIN_USERNAME`, `ADMIN_PASSWORD`, and `SECRET_KEY` before deploying.
**History:** Older commits may still contain LAN IPs or example passwords in docs. Treat those as compromised for any real credentials that matched; rotate DB/admin passwords if they were ever used outside localhost. Prefer placeholders (`<db-host>`, `<choose-a-password>`) in all public docs.
---
## Known Limitations
- Multi-user support with role-based permissions (single-user mode deprecated)
- PostgreSQL for both development and production
- GPU acceleration not yet implemented (CPU-only for now)
- Large databases (>50K photos) may require optimization
- DeepFace model downloads on first use (can take 5-10 minutes, ~100MB)
- Face processing is CPU-intensive (~2-3x slower than face_recognition, but more accurate)
- First run is slower due to model downloads (subsequent runs are faster)
---
- Face pipeline is CPU-only for now; first DeepFace model download is large and slow
- Libraries over ~50k photos may need tuning
- Multi-user RBAC is the supported mode (single-user path deprecated)
## License
[Add your license here]
---
## Authors
PunimTag Development Team
---
## Acknowledgments
- **DeepFace** library by Sefik Ilkin Serengil - Modern face recognition framework
- **ArcFace** - Additive Angular Margin Loss for Deep Face Recognition
- **RetinaFace** - State-of-the-art face detection
- TensorFlow, React, FastAPI, and all open-source contributors
---
## Deployment
### Development Server Deployment
The project includes scripts for deploying to the development server.
**Development Server:**
- **Host**: `<backend-host>`
- **User**: appuser
- **Password**: [Contact administrator for password]
**Development Database:**
- **Host**: `<db-host>`
- **Port**: 5432
- **User**: `<db-user>`
- **Password**: [Contact administrator for password]
#### Build and Deploy to Dev
```bash
# Build all frontends and prepare for deployment
npm run deploy:dev
# Or build individually
npm run build:admin
npm run build:viewer
```
The deployment script will:
1. Build admin-frontend for production
2. Build viewer-frontend for production
3. Prepare deployment package
4. Copy files to deployment directory (ready for manual transfer)
#### Manual Deployment Steps
1. **Build the applications:**
```bash
npm run deploy:dev
```
2. **Transfer files to server:**
```bash
# Transfer backend and built frontends
scp -r backend admin-frontend/dist viewer-frontend/.next appuser@<backend-host>:/path/to/deployment
```
3. **Set up environment on server:**
- Create `.env` file with dev database credentials
- Install Python dependencies: `pip install -r requirements.txt`
- Set up systemd services or PM2 for process management
4. **Start services:**
- Backend API (FastAPI)
- RQ Worker
- Frontend servers (nginx or similar)
See `docs/DEPLOYMENT.md` for detailed deployment instructions.
### Production Deployment
For production deployment:
1. Update environment variables with production credentials
2. Configure PostgreSQL connection strings
3. Set up Redis for background jobs
4. Configure reverse proxy (nginx)
5. Set up SSL certificates
6. Configure firewall rules
7. Set up monitoring and logging
See `docs/DEPLOYMENT.md` for complete production deployment guide.
---
## Support
For questions or issues:
1. Check documentation in `docs/`
2. Review `docs/DEPLOYMENT.md` for deployment questions
3. Check `docs/ARCHITECTURE.md` for technical details
---
**Made for photo enthusiasts**
MIT. See [LICENSE](LICENSE).
+25 -40
View File
@@ -1,56 +1,41 @@
# PunimTag Frontend
# Admin frontend
React + Vite + TypeScript frontend for PunimTag.
React + Vite + TypeScript UI for PunimTag admin (scan, process, identify,
tags, settings).
## Setup
From repo root, install once (`./install.sh` or `npm install` in this folder).
API must be reachable at http://127.0.0.1:8000 (see root README).
```bash
cd frontend
cd admin-frontend
npm install
cp .env.example .env # if present
npm run dev # http://localhost:3000
```
## Development
Log in with `ADMIN_USERNAME` / `ADMIN_PASSWORD` from the root `.env`.
Start the dev server:
## Scripts
```bash
npm run dev
```
| Command | Purpose |
|---------|---------|
| `npm run dev` | Dev server |
| `npm run build` | Production build |
| `npm run lint` | Lint |
The frontend will run on http://localhost:3000
Make sure the backend API is running on http://127.0.0.1:8000
## Default Login
- Username / password: set `ADMIN_USERNAME` / `ADMIN_PASSWORD` in `.env` (never commit real values)
## Features (Phase 1)
- ✅ Login page with JWT authentication
- ✅ Protected routes with auth check
- ✅ Navigation layout (left sidebar + top bar)
- ✅ Dashboard page (placeholder)
- ✅ Search page (placeholder)
- ✅ Identify page (placeholder)
- ✅ Auto-Match page (placeholder)
- ✅ Tags page (placeholder)
- ✅ Settings page (placeholder)
## Project Structure
## Layout
```
frontend/
admin-frontend/
├── src/
│ ├── api/ # API client and endpoints
│ ├── components/ # React components
│ ├── hooks/ # Custom React hooks
│ ├── pages/ # Page components
│ ├── App.tsx # Main app component
── main.tsx # Entry point
│ └── index.css # Tailwind CSS
├── index.html
│ ├── api/
│ ├── components/
│ ├── hooks/
│ ├── pages/
│ ├── App.tsx
── main.tsx
├── package.json
── vite.config.ts
└── tailwind.config.js
── vite.config.ts
```
+3 -3
View File
@@ -6,7 +6,7 @@ Snapshot after Chabad Blue chrome parity (navy sidebar, theme toggle, shared tok
- Same brand tokens as viewer (`#0038A8`, gold `#C4A35A`, Rubik/Heebo).
- Light/dark toggle (persisted `punimtag-admin-theme`) + FOUC-safe boot script.
- Navy rail makes admin *read* as JRCC immediately (buttons alone were too weak).
- Navy rail makes admin read as JRCC immediately (buttons alone were too weak).
- Skip link, `:focus-visible`, `prefers-reduced-motion`, clearer page titles (no emoji soup).
- Merge people, Auto-Match progress, Identify keyboard nav already shipped.
@@ -21,7 +21,7 @@ Snapshot after Chabad Blue chrome parity (navy sidebar, theme toggle, shared tok
| P2 | iOS hamburger only — no desktop collapse | Optional collapsed icon rail for large monitors |
| P3 | Viewer filter comboboxes lack accessible names (axe `button-name`) | Label each Select trigger; then restore full-page axe on gallery home |
| Done | Admin Home was a SaaS marketing splash (orange/blue hero, emoji placeholders) | Quiet ops home: welcome + workflow links + recent processed strip |
| P3 | Emoji leftovers in Help / some toasts | Plain language + lucide/SVG icons over time |
| P3 | Emoji leftovers in Help / some toasts (remove over time) | Plain language + lucide/SVG icons over time |
## Accessibility status
@@ -33,7 +33,7 @@ Snapshot after Chabad Blue chrome parity (navy sidebar, theme toggle, shared tok
| Systematic axe CI | Smoke (`e2e/tests/a11y.smoke.spec.ts`) | Smoke (viewer home) |
| Form labels / live regions | Partial (login, toasts, some dialogs) | Stronger on gallery controls |
## Whats next (product)
## Next (product)
1. **People hub IA** (Identify / Auto-Match / Modify tabs) — biggest daily UX win.
2. **Phase 5 junk reject** (blur/pose) + soak Immich gates with real `match_decisions`.
+9 -10
View File
@@ -1,12 +1,11 @@
# PunimTag Deployment Guide
# Deployment
**Last Updated:** January 6, 2026
Deploy PunimTag to development or production. Homelab host and Caddy details
live in the private ansible repo.
This guide covers deployment of PunimTag to development and production environments.
Last reviewed: January 6, 2026.
---
## Table of Contents
## Table of contents
1. [Prerequisites](#prerequisites)
2. [Development Server Deployment](#development-server-deployment)
@@ -44,7 +43,7 @@ This guide covers deployment of PunimTag to development and production environme
---
## Development Server Deployment
## Development server deployment
### Step 1: Build Applications
@@ -277,7 +276,7 @@ sudo systemctl status punimtag-worker
---
## Production Deployment
## Production deployment
### Additional Production Considerations
@@ -361,7 +360,7 @@ server {
---
## Environment Configuration
## Environment configuration
### Required Environment Variables
@@ -402,7 +401,7 @@ NEXTAUTH_SECRET=your-nextauth-secret
---
## Service Management
## Service management
### Systemd Commands
+13 -13
View File
@@ -4,20 +4,20 @@ This guide provides detailed, step-by-step instructions for deploying PunimTag t
---
## 📋 Prerequisites Checklist
## Prerequisites Checklist
Before starting, ensure you have:
- **cPanel access** with Terminal/SSH capabilities
- **PostgreSQL database** (NOT MySQL - PunimTag requires PostgreSQL)
- **Python 3.11.2+ or 3.12+** (3.11.2+ matches dev environment; check via CPanel Terminal)
- **Node.js 18+** (check via CPanel Terminal or contact hosting provider)
- **Redis** (for background jobs - may need hosting provider to enable)
- **Domain name** configured in cPanel
- **File Manager** access in cPanel
- **Database management** access in cPanel
- **cPanel access** with Terminal/SSH capabilities
- **PostgreSQL database** (NOT MySQL - PunimTag requires PostgreSQL)
- **Python 3.11.2+ or 3.12+** (3.11.2+ matches dev environment; check via CPanel Terminal)
- **Node.js 18+** (check via CPanel Terminal or contact hosting provider)
- **Redis** (for background jobs - may need hosting provider to enable)
- **Domain name** configured in cPanel
- **File Manager** access in cPanel
- **Database management** access in cPanel
**⚠️ CRITICAL:** If PostgreSQL is not available, contact your hosting provider immediately. PunimTag **cannot** work with MySQL.
** CRITICAL:** If PostgreSQL is not available, contact your hosting provider immediately. PunimTag **cannot** work with MySQL.
---
@@ -98,7 +98,7 @@ redis-cli ping
**If any are missing:**
> **📘 Need to install prerequisites?** See [`INSTALL_PREREQUISITES_CPANEL.md`](./INSTALL_PREREQUISITES_CPANEL.md) for detailed instructions on installing Python 3.11.2+ (or 3.12+), Node.js, npm, PostgreSQL client, and Redis client **without sudo access**.
> ** Need to install prerequisites?** See [`INSTALL_PREREQUISITES_CPANEL.md`](./INSTALL_PREREQUISITES_CPANEL.md) for detailed instructions on installing Python 3.11.2+ (or 3.12+), Node.js, npm, PostgreSQL client, and Redis client **without sudo access**.
- Check cPanel → **Software** → **Python Selector** (if available)
- Check cPanel → **Software** → **Node.js Selector** (if available)
@@ -831,7 +831,7 @@ Most cPanel hosts disable `mod_proxy` in user `.htaccess` files for security. Co
### Option C: Configure Apache .htaccess (May Not Work)
**⚠️ Warning:** Most cPanel hosts disable `mod_proxy` in user `.htaccess` files. This option will likely fail, but you can try:
** Warning:** Most cPanel hosts disable `mod_proxy` in user `.htaccess` files. This option will likely fail, but you can try:
Create/edit `.htaccess` in your main domain's `public_html`:
@@ -1262,7 +1262,7 @@ If you encounter issues:
---
**Congratulations!** You've successfully deployed PunimTag to cPanel! 🎉
**Congratulations!** You've successfully deployed PunimTag to cPanel!
---
+9 -9
View File
@@ -1,6 +1,6 @@
# Installing Prerequisites in cPanel
> **⚠️ IMPORTANT:** This guide has two paths:
> ** IMPORTANT:** This guide has two paths:
> - **If you have sudo access:** Follow the [Quick Install with Sudo](#quick-install-with-sudo-access) section below
> - **If you don't have sudo access:** Follow the [Manual Installation Without Sudo](#manual-installation-without-sudo-access) section
@@ -183,7 +183,7 @@ redis-cli ping
pm2 --version
```
** You're done!** All prerequisites are installed. Continue with the deployment guide.
** You're done!** All prerequisites are installed. Continue with the deployment guide.
---
@@ -197,9 +197,9 @@ This guide shows how to install Python 3.11.2+ (or 3.12+), Node.js, npm, Postgre
**Important:** Your dev environment uses **Python 3.11.2**, which is perfectly fine!
- **Python 3.11.2+** - Works great (matches your dev environment)
- **Python 3.12+** - Recommended for latest features, but not required
- **Python 3.6.8** - Too old, needs upgrade
- **Python 3.11.2+** - Works great (matches your dev environment)
- **Python 3.12+** - Recommended for latest features, but not required
- **Python 3.6.8** - Too old, needs upgrade
**Recommendation:** Install **Python 3.11.9** (latest 3.11.x) to match your dev environment, or **Python 3.12.7** if you want the latest version.
@@ -284,7 +284,7 @@ openssl version
### 1.2 Install pyenv
**⚠️ IMPORTANT:** If you got "Permission denied" on gcc, pyenv won't be able to compile Python. Skip to the "Alternative: Pre-built Python Binary" section below, or contact your hosting provider first.
** IMPORTANT:** If you got "Permission denied" on gcc, pyenv won't be able to compile Python. Skip to the "Alternative: Pre-built Python Binary" section below, or contact your hosting provider first.
```bash
# Navigate to home directory
@@ -384,7 +384,7 @@ Some cPanel installations have a Python version selector:
### Option 3: Download Pre-compiled Python Binary (Advanced)
**⚠️ Note:** This still requires compilation, so it won't work if gcc has permission issues.
** Note:** This still requires compilation, so it won't work if gcc has permission issues.
If you have gcc access but pyenv failed, you can compile from source:
@@ -450,7 +450,7 @@ source ~/.bashrc
python3 --version
```
**⚠️ This won't work if gcc has permission denied!** Contact your hosting provider instead.
** This won't work if gcc has permission denied!** Contact your hosting provider instead.
**Note:** This requires build tools. If compilation fails, contact hosting provider or use pyenv method above.
@@ -1045,5 +1045,5 @@ If installation fails:
---
**Once all prerequisites are installed, you're ready to deploy PunimTag!** 🚀
**Once all prerequisites are installed, you're ready to deploy PunimTag!**
+51 -120
View File
@@ -1,129 +1,60 @@
# PunimTag - Quick Start Guide
# Quick start
## 🚀 Running the Application
Day-to-day commands for the web stack (API + admin + viewer). Full install
is in the root [README](../README.md).
### Start Dashboard
```bash
source venv/bin/activate
python run_dashboard.py
```
## Run
### Run CLI Tool
```bash
source venv/bin/activate
python -m src.photo_tagger --help
```
---
## 📁 Project Structure
```
punimtag/
├── src/
│ ├── core/ # Business logic
│ ├── gui/ # GUI components
│ └── utils/ # Utilities
├── tests/ # Test suite
├── docs/ # Documentation
├── .notes/ # Project planning
└── run_dashboard.py # Main launcher
```
---
## 📚 Key Documentation
- **README.md** - Main documentation
- **CONTRIBUTING.md** - How to contribute
- **docs/ARCHITECTURE.md** - System design
- **RESTRUCTURE_SUMMARY.md** - Restructure details
- **IMPORT_FIX_SUMMARY.md** - Import fixes
---
## 🔧 Common Tasks
### Add Photos
1. Open dashboard: `python run_dashboard.py`
2. Click "Scan Photos" in menu
3. Select folder with photos
### Process Faces
1. Open dashboard
2. Click "Process Photos" button
3. Wait for face detection to complete
### Identify People
1. Open "Identify" tab
2. View unidentified faces
3. Enter person name or select existing
4. Click "Identify"
### Search Photos
1. Open "Search" tab
2. Enter search criteria (name, date, tags)
3. View results
---
## 🐛 Troubleshooting
### ModuleNotFoundError
**Solution**: Use `run_dashboard.py` launcher, not direct file execution
### Import Errors
**Solution**: Make sure you're in the venv:
```bash
source venv/bin/activate
```
### PIL/ImageTk Error
**Solution**: Install Pillow in venv:
```bash
pip install Pillow
```
---
## 💡 Tips
- Always activate venv before running
- Use `run_dashboard.py` for GUI
- Use `python -m src.photo_tagger` for CLI
- Check `.notes/` for planning docs
- Read `docs/ARCHITECTURE.md` for system design
---
## 📞 Need Help?
1. Check documentation in `docs/`
2. Read `.notes/` for planning info
3. See `CONTRIBUTING.md` for guidelines
---
**Quick Command Reference:**
Three terminals from the repo root (venv activated for the API):
```bash
# Activate environment
source venv/bin/activate
# Run dashboard
python run_dashboard.py
# Run CLI
python -m src.photo_tagger
# Run tests
python -m pytest tests/
# Deactivate environment
deactivate
./run_api_with_worker.sh
# API: http://127.0.0.1:8000 docs: /docs
```
---
```bash
cd admin-frontend && npm run dev
# http://localhost:3000
```
**Last Updated**: October 15, 2025
```bash
cd viewer-frontend && npx prisma generate # once / after schema change
npm run dev
# http://localhost:3001
```
Stop the API/worker with `./stop_backend.sh` or Ctrl+C in that terminal.
## Common tasks
| Task | Where |
|------|--------|
| Scan a photo folder | Admin → Scan |
| Detect faces | Admin → Process |
| Name faces | Admin → Identify |
| Auto-match | Admin → Auto-Match |
| Browse library | Viewer at :3001 |
| API explore | http://127.0.0.1:8000/docs |
## Troubleshooting
| Symptom | Fix |
|---------|-----|
| `ModuleNotFoundError: backend` | Use `./run_api_with_worker.sh` or set `PYTHONPATH` to the repo root |
| Port 8000 in use | `./stop_backend.sh` or `pkill -f "uvicorn.*backend.app"` |
| Redis down | `redis-cli ping`; start with `redis-server` or `brew services start redis` |
| Browse returns 503 | Install tkinter (`python3-tk` on Debian) |
| Viewer shows 0 photos | Confirm `viewer-frontend` `DATABASE_URL`, run `npx prisma generate`, photos marked processed |
## Tests and lint
```bash
npm run ci:local # lint frontends + ruff + pytest + builds
npm run test:e2e # Playwright (see e2e/README.md)
```
## Legacy desktop / CLI
Older dashboard and CLI entrypoints (`run_dashboard.py`, `src.photo_tagger`)
may still exist for local experiments. Prefer the web stack above for
current development.
+39 -1033
View File
File diff suppressed because it is too large Load Diff
+64 -92
View File
@@ -1,34 +1,21 @@
# PunimTag Web - User Guide
# Admin user guide
**Complete guide to using the PunimTag web application**
How to use the PunimTag admin UI (http://localhost:3000) day to day.
Viewer browsing is separate (port 3001).
---
## Table of contents
## Table of Contents
1. [Getting Started](#getting-started)
2. [Navigation Overview](#navigation-overview)
3. [Page-by-Page Guide](#page-by-page-guide)
- [Login Page](#login-page)
- [Dashboard](#dashboard)
- [Scan Page](#scan-page)
- [Process Page](#process-page)
- [Identify Page](#identify-page)
- [Auto-Match Page](#auto-match-page)
- [Search Page](#search-page)
- [Modify Page](#modify-page)
- [Tags Page](#tags-page)
- [Faces Maintenance Page](#faces-maintenance-page)
- [Settings Page](#settings-page)
4. [Workflow Examples](#workflow-examples)
5. [Tips & Best Practices](#tips--best-practices)
1. [Getting started](#getting-started)
2. [Navigation](#navigation)
3. [Pages](#pages)
4. [Workflow examples](#workflow-examples)
5. [Tips](#tips)
6. [Troubleshooting](#troubleshooting)
---
## Getting Started
## Getting started
### First Time Setup
### First-time setup
1. **Start the Application**
- Ensure Redis is running
@@ -39,7 +26,7 @@
2. **Login**
- Default credentials:
- Use credentials from `.env` (`ADMIN_USERNAME` / `ADMIN_PASSWORD`)
- ⚠️ **Important**: Change these credentials in production!
- Change these credentials before any shared deploy.
3. **Initial Workflow**
- **Scan** → Import your photos
@@ -49,78 +36,74 @@
- **Search** → Find photos by people, dates, or tags
- **Tags** → Tag photos and manage tags
---
## Navigation Overview
## Navigation
The application uses a **left sidebar navigation** with the following pages:
- 🏠 **Dashboard** - Overview and statistics
- 📁 **Scan** - Import photos from folders or upload files
- ⚙️ **Process** - Detect and process faces in photos
- 👤 **Identify** - Manually identify people in faces
- 🤖 **Auto-Match** - Automatically match similar faces to previously identified faces
- 🔍 **Search** - Search and filter photos
- ✏️ **Modify** - Edit person information
- 🏷️ **Tags** - Tag photos and manage photo tags
- 🔧 **Faces Maintenance** - Manage face data
- ⚙️ **Settings** - Application settings
- **Dashboard** - Overview and statistics
- **Scan** - Import photos from folders or upload files
- **Process** - Detect and process faces in photos
- **Identify** - Manually identify people in faces
- **Auto-Match** - Automatically match similar faces to previously identified faces
- **Search** - Search and filter photos
- **Modify** - Edit person information
- **Tags** - Tag photos and manage photo tags
- **Faces Maintenance** - Manage face data
- **Settings** - Application settings
---
## Page-by-Page Guide
## Pages
### Login Page
**Purpose**: Authenticate and access the application
Purpose: Authenticate and access the application
**Features**:
Features:
- Username and password login
- JWT-based authentication
- Automatic redirect to dashboard after login
**How to Use**:
How to use:
1. Enter your username (`ADMIN_USERNAME` from `.env`)
2. Enter your password (`ADMIN_PASSWORD` from `.env`)
3. Click "Login" button
4. You'll be redirected to the Dashboard
**Notes**:
Notes:
- Session persists until logout
- Default credentials are for development only
- Change credentials in production for security
---
### Dashboard
**Purpose**: Overview of your photo collection and statistics
Purpose: Overview of your photo collection and statistics
**Features**:
Features:
- Collection statistics
- Quick access to main features
- Recent activity summary
**How to Use**:
How to use:
- View statistics about your photo collection
- Navigate to other pages using the sidebar
- Monitor overall system status
**Current Status**: Basic implementation - more features coming in future updates
Status: Basic implementation - more stats may be added later
---
### Scan Page
**Purpose**: Import photos into your collection from folders or upload files
Purpose: Import photos into your collection from folders or upload files
**Features**:
Features:
- **Folder Selection**: Browse and select folders containing photos
- **Recursive Scanning**: Option to scan subfolders recursively
- **Duplicate Detection**: Automatically detects and skips duplicate photos
- **Real-time Progress**: Live progress tracking during import
**How to Use**:
How to use:
**Folder Scan**
1. Click "Browse Folder" button
@@ -140,13 +123,12 @@ The application uses a **left sidebar navigation** with the following pages:
**Tips**:
- Large folders may take time - be patient!
---
### Process Page
**Purpose**: Detect faces in imported photos and generate face encodings
Purpose: Detect faces in imported photos and generate face encodings
**Features**:
Features:
- **face detection method used - `retinaface` - Best accuracy, medium speed
- **Face recognition model used - `ArcFace` - Best accuracy, medium speed
@@ -154,7 +136,7 @@ The application uses a **left sidebar navigation** with the following pages:
- **Real-time Progress**: Live progress tracking
- **Job Cancellation**: Stop processing if needed
**How to Use**:
How to use:
1. Optionally set **Batch Size** (leave empty for default)
2. Click "Start Processing" button
3. Monitor progress:
@@ -173,13 +155,12 @@ The application uses a **left sidebar navigation** with the following pages:
**Tips**:
- You can cancel and resume later
---
### Identify Page
**Purpose**: Manually identify people in detected faces
Purpose: Manually identify people in detected faces
**Features**:
Features:
- **Face Navigation**: Browse through unidentified faces
- **Person Creation**: Create new person records
- **Similar Faces Panel**: View similar faces for comparison
@@ -188,7 +169,7 @@ The application uses a **left sidebar navigation** with the following pages:
- **Unique Faces Filter**: Hide duplicate faces of same person
- **Face Information**: View face metadata (confidence, quality, detector/model)
**How to Use**:
How to use:
**Basic Identification**:
1. Navigate to Identify page
@@ -222,11 +203,11 @@ The application uses a **left sidebar navigation** with the following pages:
- Similar faces panel remains unfiltered
**Confidence Colors**:
- 🟢 **80%+** = Very High (Almost Certain)
- 🟡 **70%+** = High (Likely Match)
- 🟠 **60%+** = Medium (Possible Match)
- 🔴 **50%+** = Low (Questionable)
- **<50%** = Very Low (Unlikely)
- **80%+** = Very High (Almost Certain)
- **70%+** = High (Likely Match)
- **60%+** = Medium (Possible Match)
- **50%+** = Low (Questionable)
- **<50%** = Very Low (Unlikely)
**Tips**:
- Use similar faces to identify groups of photos
@@ -234,20 +215,19 @@ The application uses a **left sidebar navigation** with the following pages:
- Unique faces filter reduces clutter
- Confidence scores help prioritize identification
---
### Auto-Match Page
**Purpose**: Automatically match unidentified faces to identified people
Purpose: Automatically match unidentified faces to identified people
**Features**:
Features:
- **Person-Centric View**: Shows identified person on left, matches on right
- **Checkbox Selection**: Select which faces to identify
- **Confidence Display**: Color-coded match confidence
- **Batch Identification**: Identify multiple faces at once
- **Navigation**: Move between different people
**How to Use**:
How to use:
**Manual Match Workflow**:
1. Navigate to Auto-Match page
@@ -295,13 +275,12 @@ profile faces are excluded for better accuracy
- You can correct mistakes by going back and unchecking
- High confidence matches (>70%) are usually accurate
---
### Search Page
**Purpose**: Search and filter photos by various criteria
Purpose: Search and filter photos by various criteria
**Features**:
Features:
- **People Filter**: Filter by identified people
- **Date Filter**: Filter by date taken or date added
- **Tag Filter**: Filter by photo tags
@@ -309,7 +288,7 @@ profile faces are excluded for better accuracy
- **Photo Grid**: Virtualized grid of matching photos
- **Pagination**: Navigate through search results
**How to Use**:
How to use:
**Basic Search**:
1. Navigate to Search page
@@ -339,19 +318,18 @@ profile faces are excluded for better accuracy
- Tag filtering helps find themed photos
- People filter is most useful after identification
---
### Modify Page
**Purpose**: Edit person information and manage person records
Purpose: Edit person information and manage person records
**Features**:
Features:
- **Person Selection**: Choose person to edit
- **Information Editing**: Update names and date of birth
- **Face Management**: View and manage person's faces
- **Person Deletion**: Remove person records (with confirmation)
**How to Use**:
How to use:
**Editing Person Information**:
1. Navigate to Modify page
@@ -374,20 +352,19 @@ profile faces are excluded for better accuracy
- Update names if you learn more information
- Be careful with deletion - it's permanent
---
### Tags Page
**Purpose**: Manage photo tags and tag-photo relationships
Purpose: Manage photo tags and tag-photo relationships
**Features**:
Features:
- **Tag List**: View all existing tags
- **Tag Creation**: Create new tags
- **Tag Editing**: Edit tag names
- **Tag Deletion**: Remove tags
- **Photo-Tag Linkage**: Assign tags to photos
**How to Use**:
How to use:
**Creating Tags**:
1. Navigate to Tags page
@@ -400,7 +377,7 @@ profile faces are excluded for better accuracy
- View all tags in a list
- Edit tag names by clicking edit button
- Delete tags by selecting it's check box and clicking "Delete selected tags" button
- ⚠️ **Warning**: Deleting a tag removes it from all photos
- **Warning**: Deleting a tag removes it from all photos
**Assigning Tags to Photos**:
- Select photos from Tags page(or from Search page)
@@ -414,19 +391,18 @@ profile faces are excluded for better accuracy
- Create tags for events, locations, themes
- Tags help organize and find photos later
Note: Tags are case insensitive!*********
---
### Faces Maintenance Page
**Purpose**: Remove unwanted faces - mainly due to low quality face detections
Purpose: Remove unwanted faces - mainly due to low quality face detections
**Features**:
Features:
- **Face List**: View all faces in database
- **Face Filtering**: Filter quality
- **Face Deletion**: Remove unwanted faces
- **Bulk Operations**: Perform actions on multiple faces
**How to Use**:
How to use:
**Viewing Faces**:
1. Navigate to Faces Maintenance page
@@ -438,7 +414,7 @@ Note: Tags are case insensitive!*********
- Select faces to delete
- Click "Delete Selected" button
- Confirm deletion
- ⚠️ **Warning**: Deletion is permanent
- **Warning**: Deletion is permanent
**Bulk Operations**:
- Select multiple faces
@@ -449,12 +425,10 @@ Note: Tags are case insensitive!*********
- Remove low-quality face detections
- Regular maintenance keeps database clean
---
### Settings Page
**Purpose**: Configure application settings and preferences
---
Purpose: Configure application settings and preferences
@@ -489,13 +463,11 @@ Note: Tags are case insensitive!*********
- Find specific photos
- Assign tags for organization
---
**Last Updated**: October 2025
**Version**: 1.0
**Application**: PunimTag Web
---
*For technical details and development information, see the main README.md*
+33 -487
View File
@@ -1,504 +1,50 @@
# PunimTag Photo Viewer
# Viewer frontend
A modern, fast, and beautiful photo viewing website that connects to your PunimTag PostgreSQL database.
Next.js photo viewer for the PunimTag library. Talks to PostgreSQL (read
path for photos; separate auth DB for site users and moderation).
## 🚀 Quick Start
Default dev URL: http://localhost:3001 (admin is :3000).
### Prerequisites
## Prerequisites
See the [Prerequisites Guide](docs/PREREQUISITES.md) for a complete list of required and optional software.
- Node.js 20+ preferred (18 may work)
- PunimTag PostgreSQL schema populated
- Optional: FFmpeg (video thumbs), libvips (watermarks), Resend (email verify)
**Required:**
- Node.js 20+ (currently using 18.19.1 - may need upgrade)
- PostgreSQL database with PunimTag schema
- Read-only database user (see setup below)
See [docs/PREREQUISITES.md](docs/PREREQUISITES.md).
**Optional:**
- **FFmpeg** (for video thumbnail generation) - See [FFmpeg Setup Guide](docs/FFMPEG_SETUP.md)
- **libvips** (for image watermarking) - See [Prerequisites Guide](docs/PREREQUISITES.md)
- **Resend API Key** (for email verification)
- **Network-accessible storage** (for photo uploads)
## Setup
### Installation
**Quick Setup (Recommended):**
```bash
# Run the comprehensive setup script
cd viewer-frontend
npm run setup
# or: npm install && npm run prisma:generate:all
cp .env.example .env # if you do not already have .env
```
This will:
- Install all npm dependencies
- Set up Sharp library (for image processing)
- Generate Prisma clients
- Set up database tables (if DATABASE_URL_AUTH is configured)
- Create admin user (if needed)
- Verify the setup
Typical `.env` keys (placeholders only):
**Manual Setup:**
1. **Install dependencies:**
```bash
npm run install:deps
# Or manually:
npm install
npm run prisma:generate:all
```
The install script will:
- Check Node.js version
- Install npm dependencies
- Set up Sharp library (for image processing)
- Generate Prisma clients
- Check for optional system dependencies (libvips, FFmpeg)
2. **Set up environment variables:**
Create a `.env` file in the root directory:
```bash
DATABASE_URL="postgresql://viewer_readonly:password@localhost:5432/punimtag"
DATABASE_URL_WRITE="postgresql://viewer_write:password@localhost:5432/punimtag"
DATABASE_URL_AUTH="postgresql://viewer_write:password@localhost:5432/punimtag_auth"
NEXTAUTH_SECRET="your-secret-key-here"
NEXTAUTH_URL="http://localhost:3001"
NEXT_PUBLIC_SITE_NAME="PunimTag Photo Viewer"
NEXT_PUBLIC_SITE_DESCRIPTION="Family Photo Gallery"
# Email verification (Resend)
RESEND_API_KEY="re_your_resend_api_key_here"
RESEND_FROM_EMAIL="noreply@yourdomain.com"
# Optional: Override base URL for email links (defaults to NEXTAUTH_URL)
# NEXT_PUBLIC_APP_URL="http://localhost:3001"
# Upload directory for pending photos (REQUIRED - must be network-accessible)
# RECOMMENDED: Use the same server as your database (see docs/NETWORK_SHARE_SETUP.md)
# Examples:
# Database server via SSHFS: /mnt/db-server-uploads/pending-photos
# Separate network share: /mnt/shared/pending-photos
# Windows: \\server\share\pending-photos (mapped to drive)
UPLOAD_DIR="/mnt/db-server-uploads/pending-photos"
# Or use PENDING_PHOTOS_DIR as an alias
# PENDING_PHOTOS_DIR="/mnt/network-share/pending-photos"
```
**Note:** Generate a secure `NEXTAUTH_SECRET` using:
```bash
openssl rand -base64 32
```
3. **Grant read-only permissions on main database tables:**
The read-only user needs SELECT permissions on all main tables. If you see "permission denied" errors, run:
**✅ WORKING METHOD (tested and confirmed):**
```bash
PGPASSWORD=<choose-a-password> psql -h localhost -U punimtag -d punimtag -f grant_readonly_permissions.sql
```
**Alternative methods:**
```bash
# Using postgres user:
PGPASSWORD=postgres_password psql -h localhost -U postgres -d punimtag -f grant_readonly_permissions.sql
# Using sudo:
sudo -u postgres psql -d punimtag -f grant_readonly_permissions.sql
```
**Check permissions:**
```bash
npm run check:permissions
```
This will verify all required permissions and provide instructions if any are missing.
**For Face Identification (Write Access):**
You have two options to enable write access for face identification:
**Option 1: Grant write permissions to existing user** (simpler)
```bash
# Run as PostgreSQL superuser:
psql -U postgres -d punimtag -f grant_write_permissions.sql
```
Then use the same `DATABASE_URL` for both read and write operations.
**Option 2: Create a separate write user** (more secure)
```bash
# Run as PostgreSQL superuser:
psql -U postgres -d punimtag -f create_write_user.sql
```
Then add to your `.env` file:
```bash
DATABASE_URL_WRITE="postgresql://viewer_write:password@localhost:5432/punimtag"
```
4. **Create database tables for authentication:**
```bash
# Run as PostgreSQL superuser:
psql -U postgres -d punimtag_auth -f create_auth_tables.sql
```
**Add pending_photos table for photo uploads:**
```bash
# Run as PostgreSQL superuser:
psql -U postgres -d punimtag_auth -f migrations/add-pending-photos-table.sql
```
**Add email verification columns:**
```bash
# Run as PostgreSQL superuser:
psql -U postgres -d punimtag_auth -f migrations/add-email-verification-columns.sql
```
Then grant permissions to your write user:
```sql
-- If using viewer_write user:
GRANT SELECT, INSERT, UPDATE ON TABLE users TO viewer_write;
GRANT SELECT, INSERT, UPDATE ON TABLE pending_identifications TO viewer_write;
GRANT SELECT, INSERT, UPDATE ON TABLE pending_photos TO viewer_write;
GRANT USAGE, SELECT ON SEQUENCE users_id_seq TO viewer_write;
GRANT USAGE, SELECT ON SEQUENCE pending_identifications_id_seq TO viewer_write;
GRANT USAGE, SELECT ON SEQUENCE pending_photos_id_seq TO viewer_write;
-- Or if using viewer_readonly with write permissions:
GRANT SELECT, INSERT, UPDATE ON TABLE users TO viewer_readonly;
GRANT SELECT, INSERT, UPDATE ON TABLE pending_identifications TO viewer_readonly;
GRANT SELECT, INSERT, UPDATE ON TABLE pending_photos TO viewer_readonly;
GRANT USAGE, SELECT ON SEQUENCE users_id_seq TO viewer_readonly;
GRANT USAGE, SELECT ON SEQUENCE pending_identifications_id_seq TO viewer_readonly;
GRANT USAGE, SELECT ON SEQUENCE pending_photos_id_seq TO viewer_readonly;
```
5. **Generate Prisma client:**
```bash
npx prisma generate
```
6. **Run development server:**
```bash
npm run dev
```
7. **Open your browser:**
Navigate to http://localhost:3000
## 📁 Project Structure
```
punimtag-viewer/
├── app/ # Next.js 14 App Router
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page (photo grid with search)
│ ├── HomePageContent.tsx # Client component for home page
│ ├── search/ # Search page
│ │ ├── page.tsx # Search page
│ │ └── SearchContent.tsx # Search content component
│ └── api/ # API routes
│ ├── search/ # Search API endpoint
│ └── photos/ # Photo API endpoints
├── components/ # React components
│ ├── PhotoGrid.tsx # Photo grid with tooltips
│ ├── search/ # Search components
│ │ ├── CollapsibleSearch.tsx # Collapsible search bar
│ │ ├── FilterPanel.tsx # Filter panel
│ │ ├── PeopleFilter.tsx # People filter
│ │ ├── DateRangeFilter.tsx # Date range filter
│ │ ├── TagFilter.tsx # Tag filter
│ │ └── SearchBar.tsx # Search bar component
│ └── ui/ # shadcn/ui components
├── lib/ # Utilities
│ ├── db.ts # Prisma client
│ └── queries.ts # Database query helpers
├── prisma/
│ └── schema.prisma # Database schema
└── public/ # Static assets
```bash
DATABASE_URL="postgresql://viewer_readonly:password@localhost:5432/punimtag"
DATABASE_URL_WRITE="postgresql://viewer_write:password@localhost:5432/punimtag"
DATABASE_URL_AUTH="postgresql://viewer_write:password@localhost:5432/punimtag_auth"
NEXTAUTH_SECRET="$(openssl rand -base64 32)"
NEXTAUTH_URL="http://localhost:3001"
UPLOAD_DIR="/path/to/pending-photos"
```
## 🔐 Database Setup
Grant DB roles with the SQL helpers in this folder. Check with
`npm run check:permissions`.
### Create Read-Only User
On your PostgreSQL server, run:
```sql
-- Create read-only user
CREATE USER viewer_readonly WITH PASSWORD 'your_secure_password';
-- Grant permissions
GRANT CONNECT ON DATABASE punimtag TO viewer_readonly;
GRANT USAGE ON SCHEMA public TO viewer_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO viewer_readonly;
-- Grant on future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO viewer_readonly;
-- Verify no write permissions
REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM viewer_readonly;
```bash
npm run dev
```
## 🎨 Features
- ✅ Photo grid with responsive layout
- ✅ Image optimization with Next.js Image
- ✅ Read-only database access
- ✅ Type-safe queries with Prisma
- ✅ Modern, clean design
- ✅ **Collapsible search bar** on main page with filters
- ✅ **Search functionality** - Search by people, dates, and tags
- ✅ **Photo tooltips** - Hover over photos to see people names
- ✅ **Search page** - Dedicated search page at `/search`
- ✅ **Filter panel** - People, date range, and tag filters
## ✉️ Email Verification
The application includes email verification for new user registrations. Users must verify their email address before they can sign in.
### Setup
1. **Get a Resend API Key:**
- Sign up at [resend.com](https://resend.com)
- Create an API key in your dashboard
- Add it to your `.env` file:
```bash
RESEND_API_KEY="re_your_api_key_here"
RESEND_FROM_EMAIL="noreply@yourdomain.com"
```
2. **Run the Database Migration:**
```bash
psql -U postgres -d punimtag_auth -f migrations/add-email-verification-columns.sql
```
3. **Configure Email Domain (Optional):**
- For production, verify your domain in Resend
- Update `RESEND_FROM_EMAIL` to use your verified domain
- For development, you can use Resend's test domain (`onboarding@resend.dev`)
### How It Works
1. **Registration:** When a user signs up, they receive a confirmation email with a verification link
2. **Verification:** Users click the link to verify their email address
3. **Login:** Users must verify their email before they can sign in
4. **Resend:** Users can request a new confirmation email if needed
### Features
- ✅ Secure token-based verification (24-hour expiration)
- ✅ Email verification required before login
- ✅ Resend confirmation email functionality
- ✅ User-friendly error messages
- ✅ Backward compatible (existing users are auto-verified)
## 📤 Photo Uploads
Users can upload photos for admin review. Uploaded photos are stored on a **network-accessible location** (required) and tracked in the database.
### Storage Location
Uploaded photos are stored in a directory structure organized by user ID:
```
{UPLOAD_DIR}/
└── {userId}/
└── {timestamp}-{filename}
```
**Configuration (REQUIRED):**
- **Must** set `UPLOAD_DIR` or `PENDING_PHOTOS_DIR` environment variable
- **Must** point to a network-accessible location (database server recommended)
- The directory will be created automatically if it doesn't exist
**Recommended: Use Database Server**
The simplest setup is to use the same server where your PostgreSQL database is located:
1. **Create directory on database server:**
```bash
ssh user@db-server.example.com
sudo mkdir -p /var/punimtag/uploads/pending-photos
```
2. **Mount database server on web server (via SSHFS):**
```bash
sudo apt-get install sshfs
sudo mkdir -p /mnt/db-server-uploads
sudo sshfs user@db-server.example.com:/var/punimtag/uploads /mnt/db-server-uploads
```
3. **Set in .env:**
```bash
UPLOAD_DIR="/mnt/db-server-uploads/pending-photos"
```
**See full setup guide:** [`docs/NETWORK_SHARE_SETUP.md`](docs/NETWORK_SHARE_SETUP.md)
**Important:**
- Ensure the web server process has read/write permissions
- The approval system must have read access to the same location
- Test network connectivity and permissions before deploying
### Database Tracking
Upload metadata is stored in the `pending_photos` table in the `punimtag_auth` database:
- File location and metadata
- User who uploaded
- Status: `pending`, `approved`, `rejected`
- Review information (when reviewed, by whom, rejection reason)
### Access for Approval System
The approval system can:
1. **Read files from disk** using the `file_path` from the database
2. **Query the database** for pending photos:
```sql
SELECT * FROM pending_photos WHERE status = 'pending' ORDER BY submitted_at;
```
3. **Update status** after review:
```sql
UPDATE pending_photos
SET status = 'approved', reviewed_at = NOW(), reviewed_by = {admin_user_id}
WHERE id = {photo_id};
```
## 🚧 Coming Soon
- [ ] Photo detail page with lightbox
- [ ] Infinite scroll
- [ ] Favorites system
- [ ] People and tags browsers
- [ ] Authentication (optional)
## 📚 Documentation
For complete documentation, see:
- [Quick Start Guide](../../punimtag/docs/PHOTO_VIEWER_QUICKSTART.md)
- [Complete Plan](../../punimtag/docs/PHOTO_VIEWER_PLAN.md)
- [Architecture](../../punimtag/docs/PHOTO_VIEWER_ARCHITECTURE.md)
## 🛠️ Development
### Available Scripts
- `npm run dev` - Start development server
- `npm run build` - Build for production
- `npm run start` - Start production server
- `npm run lint` - Run ESLint
- `npm run check:permissions` - Check database permissions and provide fix instructions
- `npm test` - Run the unit test suite once (Vitest + React Testing Library)
- `npm run test:watch` - Run the unit test suite in watch mode
- `npm run test:coverage` - Run the unit test suite with coverage
### Unit Testing
Unit tests live alongside the code they cover, in `__tests__/` folders (e.g.
`lib/__tests__/`, `hooks/__tests__/`, `components/__tests__/`). They use
[Vitest](https://vitest.dev/) with a `jsdom` environment and
[React Testing Library](https://testing-library.com/react) for components/hooks.
- `vitest.config.ts` — test runner config (jsdom environment, `@/` path alias)
- `vitest.setup.ts` — global test setup: `@testing-library/jest-dom` matchers,
plus jsdom polyfills that Radix UI components and layout-aware hooks need
(`matchMedia`, `ResizeObserver`, pointer capture, `offsetParent`)
This covers frontend *unit* tests only — end-to-end browser tests live in
`../e2e` (Playwright + `@levkin/playkit`), and backend API tests live in
`../tests` (pytest).
### Prisma Commands
- `npx prisma generate` - Generate Prisma client
- `npx prisma studio` - Open Prisma Studio (database browser)
- `npx prisma db pull` - Pull schema from database
## 🔍 Troubleshooting
### Permission Denied Errors
If you see "permission denied for table photos" errors:
1. **Check permissions:**
```bash
npm run check:permissions
```
2. **Grant permissions (WORKING METHOD - tested and confirmed):**
```bash
PGPASSWORD=<choose-a-password> psql -h localhost -U punimtag -d punimtag -f grant_readonly_permissions.sql
```
**Alternative methods:**
```bash
# Using postgres user:
PGPASSWORD=postgres_password psql -h localhost -U postgres -d punimtag -f grant_readonly_permissions.sql
# Using sudo:
sudo -u postgres psql -d punimtag -f grant_readonly_permissions.sql
```
3. **Or check health endpoint:**
```bash
curl http://localhost:3001/api/health
```
### Database Connection Issues
- Verify `DATABASE_URL` is set correctly in `.env`
- Check that the database user exists and has the correct password
- Ensure PostgreSQL is running and accessible
## ⚠️ Known Issues
- Node.js version: Currently using Node 18.19.1, but Next.js 16 requires >=20.9.0
- **Solution:** Upgrade Node.js or use Node Version Manager (nvm)
## 📝 Notes
### Image Serving (Hybrid Approach)
The application automatically detects and handles two types of photo storage:
1. **HTTP/HTTPS URLs** (SharePoint, CDN, etc.)
- If `photo.path` starts with `http://` or `https://`, images are served directly
- Next.js Image optimization is applied automatically
- Configure allowed domains in `next.config.ts` → `remotePatterns`
2. **File System Paths** (Local storage)
- If `photo.path` is a file system path, images are served via API proxy
- Make sure photo file paths are accessible from the Next.js server
- No additional configuration needed
**Benefits:**
- ✅ Works with both SharePoint URLs and local file system
- ✅ Automatic detection - no configuration needed per photo
- ✅ Optimal performance for both storage types
- ✅ No N+1 database queries (path passed via query parameter)
### Search Features
The application includes a powerful search system:
1. **Collapsible Search Bar** (Main Page)
- Minimized by default to save space
- Click to expand and reveal full filter panel
- Shows active filter count badge
- Filters photos in real-time
2. **Search Filters**
- **People Filter**: Multi-select searchable dropdown
- **Date Range Filter**: Presets (Today, This Week, This Month, This Year) or custom range
- **Tag Filter**: Multi-select searchable tag filter
- All filters work together with AND logic
3. **Photo Tooltips**
- Hover over any photo to see people names
- Shows "People: Name1, Name2" if people are identified
- Falls back to filename if no people identified
4. **Search Page** (`/search`)
- Dedicated search page with full filter panel
- URL query parameter sync for shareable search links
- Pagination support
## 🤝 Contributing
This is a private project. For questions or issues, refer to the main PunimTag documentation.
---
**Built with:** Next.js 14, React, TypeScript, Prisma, Tailwind CSS
## More docs
| Doc | Purpose |
|-----|---------|
| [SETUP.md](SETUP.md) | Full setup |
| [SETUP_AUTH.md](SETUP_AUTH.md) | Auth |
| [docs/FFMPEG_SETUP.md](docs/FFMPEG_SETUP.md) | Video thumbs |
| [GRANT_PERMISSIONS.md](GRANT_PERMISSIONS.md) | Postgres grants |