first working version
This commit is contained in:
203
exam_system/README.md
Normal file
203
exam_system/README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user