A location-based gamification platform where users unlock landmarks by taking AI-verified selfies at specific locations.
PicASpot is a mobile application that gamifies exploration by challenging users to visit real-world landmarks and verify their presence through AI-powered photo matching. Using computer vision and geospatial technologies, the app creates an engaging experience for discovering and collecting locations.
- π― Location-Based Unlocks: Visit landmarks and unlock achievements
- π€ AI Photo Verification: GeoMatchAI validates user photos against Mapillary street view data
- πΊοΈ Geospatial Queries: Find nearby landmarks and areas using PostGIS
- π€ User Profiles: Track achievements, manage profile pictures, and view unlock history
- π Hierarchical Areas: Organize landmarks into cities, regions, and countries
- π± Mobile-First: React Native (Expo) app with seamless API integration
βββββββββββββββ βββββββββββββββββ βββββββββββββββ
β Frontend ββββββΆ β Nginx ββββββΆ β Backend β
β React Nativeβ β Reverse Proxy β β FastAPI β
βββββββββββββββ βββββββββββββββββ ββββββββ¬βββββββ
β
ββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββ
β β β β
βΌ βΌ βΌ βΌ
βββββββββββββββββ βββββββββββββββ ββββββββββββ ββββββββββββ
β Apache Kafka β β PostgreSQL β β Redis β β MinIO β
β (3 brokers) β β + PostGIS β β Cache β β Storage β
βββββββββ¬ββββββββ βββββββββββββββ ββββββββββββ ββββββββββββ
β
βββββββββββββ΄ββββββββββββ
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββ
βImage Serviceβ βEmail Serviceβ
β GeoMatchAI β β SMTP β
βββββββββββββββ βββββββββββββββ
- Backend Service: FastAPI REST API handling authentication, landmarks, areas, and unlocks
- Image Service: AI-powered photo verification using GeoMatchAI and Mapillary API
- Email Service: Asynchronous email sending for verification and password resets
- PostgreSQL + PostGIS: Geospatial database with Geography types for location queries
- Apache Kafka: 3-broker message streaming cluster for inter-service communication
- Redis: Distributed caching, rate limiting, and session management
- MinIO: S3-compatible object storage for images
- Nginx: Reverse proxy and API gateway
- FastAPI - Modern async Python web framework
- SQLAlchemy 2.0 - Async ORM with declarative models
- Alembic - Database migrations
- PostGIS - Geospatial extensions for PostgreSQL
- Pydantic V2 - Data validation and serialization
- aiokafka - Async Kafka client
- GeoMatchAI - Computer vision for location verification
- MinIO Python SDK - Object storage client
- React Native - Cross-platform mobile framework
- Expo - Development and build tooling
- NativeWind - Tailwind CSS for React Native
- React Native Reusables - UI component library
- Docker & Docker Compose - Container orchestration
- Nginx - Reverse proxy and load balancing
- Apache Kafka - Distributed message streaming
- Redis - In-memory data store
- PostgreSQL 16 - Primary database
- MinIO - Object storage
- Docker and Docker Compose
- Node.js 18+ and npm
- Mapillary API key (Get one here)
- Clone the repository
git clone https://github.com/yehorkarabanov/PicASpot.git
cd PicASpot- Configure environment variables
Create a .env file in the root directory:
MAPILLARY_API_KEY=your_mapillary_api_key_here
POSTGRES_PASSWORD=your_secure_password
JWT_SECRET_KEY=your_jwt_secret_key- Start the backend services
docker-compose up -dThis will start all backend services:
- Backend API (port 8000)
- PostgreSQL + PostGIS (port 5432)
- Redis (port 6379)
- Kafka cluster (ports 9092-9094)
- MinIO (port 9000)
- Nginx reverse proxy (port 80)
- Image verification service
- Email service
- Install frontend dependencies
cd src/frontend
npm install- Detect backend server IP (Windows)
npm run predevNote: This script automatically detects your server IP and configures the API URL. For other operating systems, manually update the API endpoint in the frontend configuration.
- Start the frontend development server
npm run dev- Run the app
- iOS: Press
ito launch in iOS simulator (Mac only) - Android: Press
ato launch in Android emulator - Web: Press
wto run in browser - Physical Device: Scan the QR code with Expo Go app
Once the backend is running, interactive API documentation is available:
- Swagger UI: http://localhost/api/docs
- ReDoc: http://localhost/api/redoc
- OpenAPI Schema: http://localhost/api/openapi.json
POST /api/v1/auth/register- Register new userPOST /api/v1/auth/login- Login and get JWT tokenPOST /api/v1/auth/verify-email- Verify email addressPOST /api/v1/auth/reset-password- Reset password
GET /api/v1/user/me- Get current user profilePATCH /api/v1/user/me- Update user profilePOST /api/v1/user/me/profile-picture- Upload profile picture
POST /api/v1/area- Create new areaGET /api/v1/area/{area_id}- Get area detailsGET /api/v1/area/nearby- Find nearby areas
POST /api/v1/landmark- Create new landmarkGET /api/v1/landmark/{landmark_id}- Get landmark detailsGET /api/v1/landmark/nearby- Find nearby landmarksPOST /api/v1/landmark/{landmark_id}/unlock- Attempt to unlock
GET /api/v1/unlock/me- Get user's unlocksGET /api/v1/unlock/feed- Get global unlock feed
# Database
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=picaspot
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
# JWT
JWT_SECRET_KEY=your_jwt_secret
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# MinIO
MINIO_ENDPOINT=minio1:9000
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
MINIO_BUCKET_NAME=picaspot-storage
# Kafka
KAFKA_BOOTSTRAP_SERVERS=kafka-0:9092,kafka-1:9092,kafka-2:9092# GeoMatchAI
GEOMATCH_SIMILARITY_THRESHOLD=0.65
GEOMATCH_DEVICE=cuda # cuda, cpu, or auto
GEOMATCH_MODEL_TYPE=timm
GEOMATCH_MODEL_VARIANT=tf_efficientnet_b4.ns_jft_in1k
# Mapillary
MAPILLARY_API_KEY=your_mapillary_key- UUID-based primary key
- Username and email (unique, indexed)
- Hashed password with bcrypt
- Email verification status
- Superuser flag
- Profile picture URL
- Timestamps (created_at, updated_at)
- Hierarchical geographic regions (self-referencing parent)
- Name, description, image, and badge URLs
- Creator reference and verification flag
- PostGIS Geography type for boundaries
- Relationships: child areas, landmarks
- Points of interest with coordinates (PostGIS Geography)
- Area reference, difficulty rating, points value
- Image and hint image URLs
- Photo location with radius for verification
- Relationships: unlocks, attempts
- User achievement records
- Landmark and user references
- Unlock timestamp and photo URL
- Similarity score from AI verification
- Feed visibility flag
- Temporary verification requests (5-minute TTL)
- User, landmark, and photo references
- Status: PENDING, APPROVED, REJECTED
- Linked to final unlock on approval
- User submits photo at landmark location via mobile app
- Backend validates location proximity and creates Attempt record
- Backend publishes message to Kafka topic
image-verify-requests - Image Service consumes message and downloads photo from MinIO
- GeoMatchAI verifies photo against Mapillary street view data
- Fetches reference images from Mapillary API
- Uses EfficientNet B4 model for feature extraction
- Computes similarity score (threshold: 0.65)
- Image Service publishes result to
image-verify-resultstopic - Backend consumes result and creates Unlock or rejects Attempt
- User receives notification of success/failure
PicASpot/
βββ src/
β βββ backend/ # FastAPI backend service
β β βββ app/
β β β βββ area/ # Area domain
β β β βββ auth/ # Authentication
β β β βββ core/ # Core utilities
β β β βββ database/ # Database config & migrations
β β β βββ kafka/ # Kafka producers/consumers
β β β βββ landmark/ # Landmark domain
β β β βββ middleware/ # Custom middleware
β β β βββ storage/ # MinIO integration
β β β βββ unlock/ # Unlock domain
β β β βββ user/ # User domain
β β β βββ main.py # FastAPI app entry
β β β βββ settings.py # Configuration
β β βββ tests/ # Test suite
β βββ image-service/ # AI verification service
β β βββ app/
β β β βββ kafka/ # Kafka integration
β β β βββ storage/ # MinIO client
β β β βββ verification/ # GeoMatchAI integration
β β β βββ main.py
β β βββ Dockerfile
β βββ image-service-dev/ # Mock verification (dev mode)
β βββ email-service/ # Email sending service
β βββ frontend/ # React Native mobile app
β β βββ app/ # Expo Router screens
β β βββ components/ # Reusable components
β β βββ lib/ # Utilities and API client
β β βββ assets/ # Images and fonts
β βββ backup/ # Database backup scripts
β βββ nginx/ # Nginx configuration
βββ docker-compose.yaml # Service orchestration
βββ .env.example # Environment template
βββ README.md
# Run all tests
docker-compose exec backend pytest
# Run with coverage
docker-compose exec backend pytest --cov=app --cov-report=html
# Run specific test file
docker-compose exec backend pytest tests/unit/test_auth.py- Unit tests for business logic
- Integration tests for API endpoints
- Database fixtures with in-memory SQLite
- Mock external services (Kafka, MinIO, Redis)
- JWT Authentication: Secure token-based authentication with refresh tokens
- Password Hashing: Bcrypt with configurable rounds
- Rate Limiting: Redis-backed rate limiting on authentication endpoints
- Input Validation: Pydantic models with custom validators
- SQL Injection Prevention: SQLAlchemy parameterized queries
- CORS Configuration: Configurable allowed origins
- File Upload Validation: File type, size, and content validation
- UUID-based Filenames: Prevents path traversal attacks
- Pre-signed URLs: Temporary access to MinIO objects
- Sensitive Data Filtering: Automatic redaction in logs
The backend provides a comprehensive health check endpoint:
GET /healthResponse:
{
"status": "healthy",
"checks": {
"redis": true,
"database": true,
"minio": true,
"kafka": true
}
}- Structured JSON Logging: In production mode
- Human-Readable Logs: In development mode
- Service-Specific Logs: Separate log files per service
- Async Queue Logging: Non-blocking I/O operations
- Sensitive Data Redaction: Automatic filtering of passwords, tokens, API keys
- Request duration tracking
- Status code distribution
- Database connection pool stats
- Kafka consumer lag monitoring
Interactive backup manager for PostgreSQL:
# Access backup shell
docker exec -it backup /backup/backup.sh
# Create backup (non-interactive)
docker-compose exec backup /backup/backup.sh backup
# List backups
docker-compose exec backup /backup/backup.sh list
# Restore backup
docker-compose exec backup /backup/backup.sh restore <filename>Backups are stored in ./backups directory with timestamped filenames.
# Build all services
docker-compose -f docker-compose.prod.yaml build
# Start services
docker-compose -f docker-compose.prod.yaml up -d
# View logs
docker-compose logs -f backendContributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Backend: Follow PEP 8, use
rufffor linting - Frontend: Follow Airbnb style guide, use ESLint
- Commits: Use conventional commits (feat:, fix:, docs:, etc.)
This project is licensed under the MIT License - see the LICENSE file for details.
- Denys Shevchenko - Project Lead, Architecture, Docker Orchestration, MinIO, GeoMatchAI, Nginx Configuration
- Yehor Karabanov - Backend Development, Database Design, API Implementation
- Krzysztof Kozak - Frontend Development, Mobile UI/UX, React Native Implementation
- GeoMatchAI - Computer vision for location verification
- Mapillary API - Street-level imagery data
- FastAPI - Modern Python web framework
- Expo - React Native development platform
- PostGIS - Spatial database extension
Made with β€οΈ by the PicASpot Team








