204 lines
4.8 KiB
Markdown
204 lines
4.8 KiB
Markdown
# Exam System (Single Docker Environment)
|
|
|
|
## Overview
|
|
A minimal exam system using Django + Angular + Nginx in a unified Docker environment. Reads exam JSON files, renders online exams, autosaves progress, and outputs bundled results.
|
|
|
|
## Architecture
|
|
- **exam_server**: Django REST API (port 8000 internal)
|
|
- **exam_web**: Angular SPA (port 4200 internal)
|
|
- **nginx**: Reverse proxy (port 80 external)
|
|
- `/` → exam_web
|
|
- `/api/` → exam_server
|
|
|
|
## Folder Structure
|
|
```
|
|
exam_system/
|
|
├── exam_server/ # Django REST API
|
|
│ ├── Dockerfile
|
|
│ ├── requirements.txt
|
|
│ └── env.example
|
|
├── exam_web/ # Angular SPA
|
|
│ ├── Dockerfile
|
|
│ └── package.json
|
|
├── data/ # File-based storage
|
|
│ ├── input/ # Source exam JSON files
|
|
│ ├── attempts/ # In-progress attempts
|
|
│ ├── output/ # Final bundled results
|
|
│ ├── progress/ # User progress snapshots
|
|
│ └── manifest.json # Exam registry
|
|
├── nginx.conf # Nginx reverse proxy config
|
|
├── Dockerfile.nginx # Nginx container
|
|
├── docker-compose.yml # Orchestration
|
|
└── README.md
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
- Docker 20.10+
|
|
- Docker Compose 2.0+
|
|
|
|
### 1. Build and Start
|
|
```bash
|
|
cd exam_system
|
|
docker-compose up --build
|
|
```
|
|
|
|
This starts all three services in one environment:
|
|
- Nginx listening on http://localhost
|
|
- Django backend (internal)
|
|
- Angular frontend (internal)
|
|
|
|
### 2. Access
|
|
- **Main app**: http://localhost (via Nginx)
|
|
- Access logs: `docker-compose logs -f`
|
|
|
|
### 3. Stop
|
|
```bash
|
|
docker-compose down
|
|
```
|
|
|
|
## Development
|
|
|
|
### Backend (exam_server)
|
|
```bash
|
|
# Shell access
|
|
docker-compose exec exam_server bash
|
|
|
|
# Run migrations (when Django app is initialized)
|
|
docker-compose exec exam_server python manage.py migrate
|
|
|
|
# Create superuser
|
|
docker-compose exec exam_server python manage.py createsuperuser
|
|
```
|
|
|
|
### Frontend (exam_web)
|
|
```bash
|
|
# Shell access
|
|
docker-compose exec exam_web sh
|
|
|
|
# Install new dependencies
|
|
docker-compose exec exam_web npm install <package>
|
|
```
|
|
|
|
### View Logs
|
|
```bash
|
|
# All services
|
|
docker-compose logs -f
|
|
|
|
# Specific service
|
|
docker-compose logs -f exam_server
|
|
docker-compose logs -f exam_web
|
|
docker-compose logs -f nginx
|
|
```
|
|
|
|
## Data Management
|
|
|
|
### Add an Exam
|
|
1. Place exam JSON file in `data/input/your-exam.json` (see `/docs/exam-format.md` for format)
|
|
2. Update `data/manifest.json`:
|
|
```json
|
|
{
|
|
"exams": [
|
|
{
|
|
"examId": "your-exam",
|
|
"path": "input/your-exam.json",
|
|
"published": true,
|
|
"version": "1.0.0"
|
|
}
|
|
],
|
|
"users": {}
|
|
}
|
|
```
|
|
|
|
### View Results
|
|
- Output bundles written to `data/output/{examId}_{attemptId}.json`
|
|
- Contains `{ exam, attempt }` with all answers
|
|
|
|
### Reset User Progress
|
|
- Remove user from `manifest.json` `users` object
|
|
- Delete corresponding files in `data/attempts/{userId}/` and `data/output/`
|
|
|
|
## Production
|
|
|
|
### Environment Variables
|
|
Copy `exam_server/env.example` to `exam_server/.env` and update:
|
|
- `DEBUG=False`
|
|
- `SECRET_KEY=<strong-random-key>`
|
|
- `ALLOWED_HOSTS=yourdomain.com`
|
|
- `CORS_ALLOWED_ORIGINS=https://yourdomain.com`
|
|
|
|
### Production Build
|
|
For production, modify `exam_web/Dockerfile` to use production build:
|
|
```dockerfile
|
|
FROM node:18-alpine AS builder
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
COPY . .
|
|
RUN npm run build --prod
|
|
|
|
FROM nginx:alpine
|
|
COPY --from=builder /app/dist/exam-web /usr/share/nginx/html
|
|
EXPOSE 80
|
|
CMD ["nginx", "-g", "daemon off;"]
|
|
```
|
|
|
|
### Backup
|
|
```bash
|
|
# Backup data folder
|
|
tar -czf backup-$(date +%Y%m%d).tar.gz data/
|
|
```
|
|
|
|
## Documentation
|
|
See `/docs` folder for detailed specifications:
|
|
- `exam-format.md` - Exam JSON format (5 question types)
|
|
- `stack-architecture.md` - System architecture overview
|
|
- `django-backend-spec.md` - Backend API endpoints
|
|
- `angular-frontend-spec.md` - Frontend routes and behavior
|
|
- `json-io-and-state.md` - State machine and file structure
|
|
- `deploy-minimal.md` - Deployment guide
|
|
|
|
## Workflow
|
|
1. Create exam JSON → place in `data/input/`
|
|
2. Publish exam → update `manifest.json`
|
|
3. User starts exam → creates attempt in `data/attempts/`
|
|
4. Autosave progress → updates attempt JSON
|
|
5. Submit exam → writes bundle to `data/output/`
|
|
|
|
## Troubleshooting
|
|
|
|
### Port 80 already in use
|
|
```bash
|
|
# Edit docker-compose.yml
|
|
# Change "80:80" to "8080:80" under nginx ports
|
|
# Then access via http://localhost:8080
|
|
```
|
|
|
|
### Permission errors
|
|
```bash
|
|
# Fix data folder permissions
|
|
chmod -R 755 data/
|
|
```
|
|
|
|
### Container won't start
|
|
```bash
|
|
# Check logs
|
|
docker-compose logs exam_server
|
|
|
|
# Rebuild from scratch
|
|
docker-compose down -v
|
|
docker-compose up --build
|
|
```
|
|
|
|
### Can't access from browser
|
|
```bash
|
|
# Verify all containers running
|
|
docker-compose ps
|
|
|
|
# Should show 3 services: exam_server, exam_web, nginx
|
|
```
|
|
|
|
## License
|
|
MIT
|