5.9 KiB
5.9 KiB
Fizika Admin Backend
A secure Node.js/Express backend for managing physics quiz questions and images for the Fizika website.
Features
- 🔒 JWT-based Authentication - Secure admin access with token-based auth
- 📝 Question Management - Full CRUD operations for quiz questions
- 🖼️ Image Management - Upload, view, and delete image files
- 🛡️ Security First - Rate limiting, input validation, CORS protection
- 📊 Public API - Serves data to the frontend application
- 🐳 Docker Ready - Containerized with multi-stage build
- 🚀 Production Ready - Health checks, proper error handling, logging
API Endpoints
Public Endpoints
GET /api/fizika- Get all questions (for frontend)GET /api/images- List all available imagesGET /api/pics/:filename- Serve image files
Authentication
POST /api/auth/login- Admin login (returns JWT token)
Admin Endpoints (Require Authentication)
GET /api/admin/questions- Get all questionsPOST /api/admin/questions- Create new questionPUT /api/admin/questions/:id- Update questionDELETE /api/admin/questions/:id- Delete questionPOST /api/admin/images/upload- Upload imageDELETE /api/admin/images/:filename- Delete image
Quick Start
Using Docker (Recommended)
-
Clone and navigate to the project:
git clone <repository-url> cd fizika -
Set up environment variables:
cp backend/.env.example backend/.env # Edit backend/.env with your configuration -
Run with Docker Compose:
# Production mode docker-compose up -d # Development mode with hot reload docker-compose --profile dev up fizika-admin-dev -
Access the admin interface:
- Open http://localhost:3001/admin.html
- Default password:
admin123(change this!)
Local Development
-
Install dependencies:
cd backend npm install -
Set up environment:
cp .env.example .env # Edit .env file with your settings -
Run the server:
npm run dev # Development with nodemon npm start # Production mode
Configuration
Environment Variables
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3001 |
NODE_ENV |
Environment | development |
JWT_SECRET |
JWT signing secret | Required in production |
ADMIN_PASSWORD_HASH |
Bcrypt hash of admin password | admin123 |
FRONTEND_URL |
CORS origin for frontend | http://localhost:8080 |
Generating Password Hash
node -e "console.log(require('bcrypt').hashSync('your-password', 10))"
Security Features
- Rate Limiting: 100 requests per 15 minutes, 5 auth attempts per 15 minutes
- Input Validation: All inputs validated and sanitized
- File Upload Security: Image-only uploads with size limits (5MB)
- JWT Authentication: Secure token-based admin authentication
- CORS Protection: Configurable cross-origin request handling
- Helmet.js: Security headers and protection middleware
Data Structure
Question Object
{
"id": 1,
"source": "2016/m1/1",
"description": "Question text...",
"a": "Option A",
"b": "Option B",
"c": "Option C",
"d": "Option D",
"correct": 2,
"type": "md",
"image": "image.jpg"
}
Question Types
md- Dinamika (Dynamics)me- Mechanika (Mechanics)mf- Folyadékok (Fluids)
Docker Deployment
Building the Image
docker build -t fizika-admin ./backend
Running with Docker
docker run -d \
-p 3001:3001 \
-e JWT_SECRET=your-secret-key \
-e ADMIN_PASSWORD_HASH='$2b$10$...' \
-v $(pwd)/fizika.json:/usr/src/app/fizika.json:ro \
-v $(pwd)/pics:/usr/src/app/pics \
fizika-admin
Docker Compose Production
# Set environment variables
export JWT_SECRET="your-super-secret-jwt-key"
export ADMIN_PASSWORD_HASH="$2b$10$your-bcrypt-hash"
export FRONTEND_URL="https://your-domain.com"
# Run
docker-compose up -d
GitHub Actions
The project includes a GitHub Actions workflow that:
- Builds multi-architecture Docker images (AMD64, ARM64)
- Pushes to GitHub Container Registry
- Signs images with Cosign
- Performs security scanning with Trivy
- Runs on pushes to main branch and releases
Admin Interface
Access the admin interface at /admin.html:
- Questions Tab: Add, edit, delete quiz questions
- Images Tab: Upload and manage image files
- Responsive Design: Works on desktop and mobile
- Real-time Updates: Changes reflect immediately
API Client Example
// Login
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password: 'your-password' })
});
const { token } = await response.json();
// Create question
await fetch('/api/admin/questions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
source: '2024/test/1',
description: 'What is physics?',
a: 'Science',
b: 'Art',
c: 'Math',
d: 'Biology',
correct: 1,
type: 'md'
})
});
Troubleshooting
Common Issues
- CORS Errors: Check
FRONTEND_URLenvironment variable - Authentication Fails: Verify
JWT_SECRETandADMIN_PASSWORD_HASH - File Upload Errors: Check write permissions on pics directory
- Health Check Fails: Ensure fizika.json exists and is readable
Logs
# Docker logs
docker logs fizika-admin
# Docker Compose logs
docker-compose logs fizika-admin
License
This project is part of the Fizika educational platform.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
For issues or questions, please open a GitHub issue.