275 lines
7.2 KiB
Markdown
275 lines
7.2 KiB
Markdown
# Job Application System
|
|||
|
|
|
||
|
|
A simple, accessible Flask web application for job applications with email-based resume functionality and file uploads.
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
- **Multi-step application process**: 5-page workflow from email capture to confirmation
|
||
|
|
- **Email-based resume**: Applicants receive a unique link to resume their application
|
||
|
|
- **Stateful sessions**: Applications can be paused and resumed at any time
|
||
|
|
- **File uploads**: Support for CV, cover letter, and other documents (up to 3 files, 4 MB each)
|
||
|
|
- **German interface**: All user-facing content in German
|
||
|
|
- **File-based storage**: No database required - uses YAML for data serialization
|
||
|
|
- **Accessible design**: Minimal CSS, no JavaScript required, keyboard-friendly
|
||
|
|
- **Validation**: Comprehensive server-side validation for all inputs
|
||
|
|
|
||
|
|
## Application Workflow
|
||
|
|
|
||
|
|
1. **Email Capture**: User enters email and receives a resume link
|
||
|
|
2. **Personal Information**: Name, address, phone, birth year, etc.
|
||
|
|
3. **Motivation Questions**: Current job situation, motivation, qualifications, salary expectations
|
||
|
|
4. **Document Upload**: Upload up to 3 documents (CV, cover letter, etc.)
|
||
|
|
5. **Confirmation**: Success message with next steps
|
||
|
|
|
||
|
|
## Technology Stack
|
||
|
|
|
||
|
|
- Python 3
|
||
|
|
- Flask 3.0.0
|
||
|
|
- PyYAML for data serialization
|
||
|
|
- Flask-Mail for email sending
|
||
|
|
- Minimal CSS for styling
|
||
|
|
- No JavaScript required
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
### Prerequisites
|
||
|
|
|
||
|
|
- Python 3.8 or higher
|
||
|
|
- pip (Python package manager)
|
||
|
|
|
||
|
|
### Setup Steps
|
||
|
|
|
||
|
|
1. **Clone or download this repository**
|
||
|
|
|
||
|
|
2. **Create a virtual environment** (recommended):
|
||
|
|
```bash
|
||
|
|
python -m venv venv
|
||
|
|
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Install dependencies**:
|
||
|
|
```bash
|
||
|
|
pip install -r requirements.txt
|
||
|
|
```
|
||
|
|
|
||
|
|
4. **Configure environment variables**:
|
||
|
|
- Copy `.env.example` to `.env`:
|
||
|
|
```bash
|
||
|
|
cp .env.example .env
|
||
|
|
```
|
||
|
|
- Edit `.env` and configure your settings:
|
||
|
|
```
|
||
|
|
SECRET_KEY=your-secret-key-here
|
||
|
|
MAIL_SERVER=smtp.gmail.com
|
||
|
|
MAIL_PORT=587
|
||
|
|
MAIL_USE_TLS=True
|
||
|
|
MAIL_USERNAME=your-email@example.com
|
||
|
|
MAIL_PASSWORD=your-app-password
|
||
|
|
MAIL_DEFAULT_SENDER=noreply@example.com
|
||
|
|
COMPANY_NAME=Your Company Name
|
||
|
|
```
|
||
|
|
|
||
|
|
### Email Configuration
|
||
|
|
|
||
|
|
For **Gmail**, you need to:
|
||
|
|
1. Enable 2-factor authentication on your Google account
|
||
|
|
2. Generate an "App Password" at https://myaccount.google.com/apppasswords
|
||
|
|
3. Use the app password (not your regular password) in `MAIL_PASSWORD`
|
||
|
|
|
||
|
|
For **other email providers**, adjust `MAIL_SERVER` and `MAIL_PORT` accordingly.
|
||
|
|
|
||
|
|
## Running the Application
|
||
|
|
|
||
|
|
### Development Mode
|
||
|
|
|
||
|
|
```bash
|
||
|
|
python app.py
|
||
|
|
```
|
||
|
|
|
||
|
|
The application will run at `http://127.0.0.1:5000`
|
||
|
|
|
||
|
|
### Production Deployment
|
||
|
|
|
||
|
|
For production, use a WSGI server like Gunicorn:
|
||
|
|
|
||
|
|
1. **Install Gunicorn**:
|
||
|
|
```bash
|
||
|
|
pip install gunicorn
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Run with Gunicorn**:
|
||
|
|
```bash
|
||
|
|
gunicorn -w 4 -b 0.0.0.0:8000 app:app
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Use a reverse proxy** (e.g., Nginx) in front of Gunicorn
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
### Linking from Job Postings
|
||
|
|
|
||
|
|
Link to the application with a job parameter:
|
||
|
|
|
||
|
|
```
|
||
|
|
https://your-domain.com/apply?job=JuniorMarketingAssistant
|
||
|
|
```
|
||
|
|
|
||
|
|
The `job` parameter will be displayed throughout the application and stored with the application data.
|
||
|
|
|
||
|
|
### Resume Functionality
|
||
|
|
|
||
|
|
When applicants enter their email, they receive a link like:
|
||
|
|
|
||
|
|
```
|
||
|
|
https://your-domain.com/resume/{session-id}
|
||
|
|
```
|
||
|
|
|
||
|
|
This link allows them to resume their application at any time.
|
||
|
|
|
||
|
|
## File Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
.
|
||
|
|
├── app.py # Main Flask application
|
||
|
|
├── config.py # Configuration settings
|
||
|
|
├── requirements.txt # Python dependencies
|
||
|
|
├── .env.example # Example environment variables
|
||
|
|
├── README.md # This file
|
||
|
|
├── templates/ # HTML templates
|
||
|
|
│ ├── base.html
|
||
|
|
│ ├── page1_email.html
|
||
|
|
│ ├── page2_personal.html
|
||
|
|
│ ├── page3_motivation.html
|
||
|
|
│ ├── page4_upload.html
|
||
|
|
│ └── page5_confirmation.html
|
||
|
|
├── static/ # Static files
|
||
|
|
│ └── style.css
|
||
|
|
└── applications/ # Application data (created automatically)
|
||
|
|
└── {session-id}/
|
||
|
|
├── data.yaml
|
||
|
|
└── attachments/
|
||
|
|
```
|
||
|
|
|
||
|
|
## Data Storage
|
||
|
|
|
||
|
|
Each application is stored in its own folder under `./applications/{session-id}/`:
|
||
|
|
|
||
|
|
- `data.yaml`: Application data (personal info, answers, metadata)
|
||
|
|
- `attachments/`: Uploaded documents
|
||
|
|
|
||
|
|
### Example data.yaml structure:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
session_id: "abc123-def456-..."
|
||
|
|
email: "applicant@example.com"
|
||
|
|
job_name: "Junior Marketing Assistant"
|
||
|
|
current_page: 4
|
||
|
|
created_at: "2025-01-15T10:30:00"
|
||
|
|
updated_at: "2025-01-15T11:45:00"
|
||
|
|
personal_info:
|
||
|
|
name: "Müller"
|
||
|
|
firstname: "Anna"
|
||
|
|
address: "Hauptstrasse 123"
|
||
|
|
zip_code: "8001"
|
||
|
|
city: "Zürich"
|
||
|
|
phone: "+41 79 123 45 67"
|
||
|
|
birth_year: "1990"
|
||
|
|
civil_status: "ledig"
|
||
|
|
motivation_answers:
|
||
|
|
current_job: "..."
|
||
|
|
motivation: "..."
|
||
|
|
qualifications: "..."
|
||
|
|
salary: "..."
|
||
|
|
uploaded_files:
|
||
|
|
- original_name: "CV.pdf"
|
||
|
|
stored_name: "20250115_103000_CV.pdf"
|
||
|
|
uploaded_at: "2025-01-15T10:30:00"
|
||
|
|
size: 1048576
|
||
|
|
```
|
||
|
|
|
||
|
|
## Validation Rules
|
||
|
|
|
||
|
|
### Email (Page 1)
|
||
|
|
- Valid email format required
|
||
|
|
|
||
|
|
### Personal Information (Page 2)
|
||
|
|
- **Name**: Required, max 255 characters
|
||
|
|
- **Firstname**: Required, max 255 characters
|
||
|
|
- **Address**: Required, max 255 characters
|
||
|
|
- **ZIP Code**: Required, numeric, max 10 digits
|
||
|
|
- **City**: Required, max 255 characters
|
||
|
|
- **Phone**: Required, international format (e.g., +41 79 123 45 67)
|
||
|
|
- **Birth Year**: Required, 4 digits, between 1940 and 2010
|
||
|
|
- **Civil Status**: Optional, max 255 characters
|
||
|
|
|
||
|
|
### Motivation (Page 3)
|
||
|
|
- All fields optional
|
||
|
|
- Each textarea limited to 3000 characters (~1 A4 page)
|
||
|
|
|
||
|
|
### File Upload (Page 4)
|
||
|
|
- Maximum 3 files
|
||
|
|
- Maximum 4 MB per file
|
||
|
|
- Allowed formats: PDF, DOC, DOCX, TXT, JPG, JPEG, PNG
|
||
|
|
|
||
|
|
## Security Considerations
|
||
|
|
|
||
|
|
- Session IDs use cryptographically secure UUIDs
|
||
|
|
- File uploads are validated for size and type
|
||
|
|
- Filenames are sanitized to prevent path traversal
|
||
|
|
- All validation is server-side
|
||
|
|
- Email configuration uses environment variables
|
||
|
|
|
||
|
|
## Customization
|
||
|
|
|
||
|
|
### Changing Text Limits
|
||
|
|
|
||
|
|
Edit `config.py`:
|
||
|
|
|
||
|
|
```python
|
||
|
|
MAX_STRING_LENGTH = 255
|
||
|
|
MAX_TEXT_AREA_LENGTH = 3000
|
||
|
|
MAX_FILE_SIZE = 4 * 1024 * 1024 # 4 MB
|
||
|
|
MAX_FILES = 3
|
||
|
|
```
|
||
|
|
|
||
|
|
### Changing Allowed File Types
|
||
|
|
|
||
|
|
Edit `config.py`:
|
||
|
|
|
||
|
|
```python
|
||
|
|
ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx', 'txt', 'jpg', 'jpeg', 'png'}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Translating to Another Language
|
||
|
|
|
||
|
|
Edit all templates in `./templates/` - they contain German text that can be translated.
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Email not sending
|
||
|
|
|
||
|
|
- Check your email credentials in `.env`
|
||
|
|
- For Gmail, ensure you're using an app password, not your regular password
|
||
|
|
- Check that `MAIL_USE_TLS` is set correctly for your email provider
|
||
|
|
- Check application logs for error messages
|
||
|
|
|
||
|
|
### File upload errors
|
||
|
|
|
||
|
|
- Ensure the `./applications/` folder is writable
|
||
|
|
- Check file size limits in your web server configuration
|
||
|
|
- Verify allowed file extensions in `config.py`
|
||
|
|
|
||
|
|
### Session not resuming
|
||
|
|
|
||
|
|
- Check that the `./applications/{session-id}/` folder exists
|
||
|
|
- Verify that `data.yaml` is valid YAML format
|
||
|
|
- Check application logs for errors
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
This project is provided as-is for use in job application processes.
|
||
|
|
|
||
|
|
## Support
|
||
|
|
|
||
|
|
For issues or questions, please contact your system administrator.
|