A self-hosted photo and video management application.
- Photo and video upload with automatic thumbnail generation
- EXIF data extraction and display
- GPS location support with map display
- Albums for organizing media
- Share links with optional password protection
- Multi-user support with admin panel
- Dark/light theme
- Responsive design
- Backend: Node.js, Fastify, Drizzle ORM, PostgreSQL
- Frontend: React, Vite, TailwindCSS, TanStack Query, Zustand
- Media Processing: Sharp, FFmpeg, exifr
- Infrastructure: Docker, GitHub Actions
-
Clone the repository:
git clone https://github.com/clucraft/Photon.git cd Photon -
Install dependencies:
pnpm install
-
Start the development environment:
docker-compose up
-
Access the application:
- Frontend: http://localhost:5173
- API: http://localhost:3000
-
Register the first user (will become admin automatically)
-
Copy the environment example:
cp .env.example .env
-
Edit
.envwith your production values (especially JWT_SECRET and POSTGRES_PASSWORD) -
Start the production environment:
docker-compose -f docker-compose.prod.yml up -d
Photon/
├── .github/workflows/ # CI/CD pipelines
├── apps/
│ ├── api/ # Fastify backend
│ │ ├── src/
│ │ │ ├── db/ # Drizzle schema
│ │ │ ├── modules/ # Route modules
│ │ │ ├── services/ # Business logic
│ │ │ └── middleware/
│ │ └── Dockerfile
│ └── web/ # React frontend
│ ├── src/
│ │ ├── components/
│ │ ├── pages/
│ │ ├── stores/
│ │ └── api/
│ └── Dockerfile
├── docker-compose.yml # Development
├── docker-compose.prod.yml # Production
└── storage/ # Media files
POST /api/v1/auth/register- Register new userPOST /api/v1/auth/login- LoginPOST /api/v1/auth/refresh- Refresh access tokenPOST /api/v1/auth/logout- LogoutGET /api/v1/auth/me- Get current user
GET /api/v1/media- List media (paginated)GET /api/v1/media/:id- Get single mediaGET /api/v1/media/timeline- Get media timelinePOST /api/v1/media/upload- Upload mediaPUT /api/v1/media/:id/favorite- Toggle favoriteDELETE /api/v1/media/:id- Move to trashPOST /api/v1/media/:id/restore- Restore from trashDELETE /api/v1/media/:id/permanent- Permanently delete
GET /api/v1/albums- List albumsPOST /api/v1/albums- Create albumGET /api/v1/albums/:id- Get albumPUT /api/v1/albums/:id- Update albumDELETE /api/v1/albums/:id- Delete albumGET /api/v1/albums/:id/media- Get album mediaPOST /api/v1/albums/:id/media- Add media to album
GET /api/v1/shares- List user's sharesPOST /api/v1/shares- Create shareDELETE /api/v1/shares/:id- Delete shareGET /api/v1/shares/s/:token- Access shared content
GET /api/v1/admin/stats- Get system statsGET /api/v1/admin/users- List usersPOST /api/v1/admin/users- Create userPUT /api/v1/admin/users/:id- Update userDELETE /api/v1/admin/users/:id- Delete user
| Variable | Description | Default |
|---|---|---|
| DATABASE_URL | PostgreSQL connection string | - |
| JWT_SECRET | Secret for JWT signing | - |
| STORAGE_PATH | Path to media storage | ./storage |
| MAX_FILE_SIZE | Max upload size in bytes | 104857600 |
| CORS_ORIGIN | Allowed CORS origin | http://localhost:5173 |
MIT