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
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:
+26
-508
@@ -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).
|
||||
|
||||
@@ -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
@@ -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
|
||||
```
|
||||
|
||||
@@ -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 |
|
||||
|
||||
## What’s 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
@@ -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
|
||||
|
||||
|
||||
@@ -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!
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+64
-92
@@ -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
@@ -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 |
|
||||
|
||||
Reference in New Issue
Block a user