# Job Application System A professional, accessible Flask web application for job applications with email-based resume functionality, file uploads, and HR notifications. ## Features - **Multi-step application process**: 5-page workflow with progress navigation - **Progress navigation bar**: Visual indicator with backward navigation to edit previous pages - **Email-based resume**: Applicants receive a unique link to resume their application - **HR notifications**: Automated email alerts to HR when applications are submitted - **Application review page**: Dedicated HR interface to view applications and download attachments - **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 - **Security features**: CSRF protection and rate limiting (5-second cooldown) - **Modular architecture**: Clean separation of concerns with application factory pattern - **Accessible design**: Minimal CSS, no JavaScript required, keyboard-friendly - **Validation**: Comprehensive server-side validation for all inputs - **Full test coverage**: 102 automated tests with 100% pass rate ## 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 ### Navigation Features - **Progress bar**: Visual indicator shows current step and completion status - **Backward navigation**: Users can click on completed steps to return and edit data - **Sequential progression**: Users must complete pages in order (cannot skip ahead) - **Data preservation**: All entered information is automatically saved when navigating ### HR Features - **Email notifications**: HR receives an email when an application is submitted - **Review interface**: Access applications at `/application/{session-id}/` - **Download attachments**: HR can download all uploaded documents - **Complete data view**: See all applicant information in one place ## Technology Stack - **Python** 3.8+ - **Flask** 3.0.0 (with application factory pattern) - **Flask-WTF** 1.2.1 (CSRF protection) - **Flask-Mail** 0.9.1 (email sending) - **PyYAML** 6.0.1 (data serialization) - **Werkzeug** 3.0.1 (file handling) - **pytest** 7.4.3 (testing framework) - 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 COMPANY_NAME=Your Company Name HR_EMAIL=hr@example.com APPLICATION_URL_BASE=http://localhost:5000 ``` ### Email Configuration The application defaults to **mailcatcher** for development (localhost:1025, no authentication required). #### For Development (Mailcatcher) 1. **Install mailcatcher**: ```bash gem install mailcatcher ``` 2. **Run mailcatcher**: ```bash mailcatcher ``` 3. **View emails**: Open http://localhost:1080 in your browser 4. **No .env changes needed** - the application uses mailcatcher by default #### For Production (Real SMTP) Add to your `.env` file: ``` MAIL_SERVER=smtp.gmail.com MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USERNAME=your-email@example.com MAIL_PASSWORD=your-app-password ``` For **Gmail**: 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 run.py ``` Or using Flask CLI: ```bash flask run ``` The application will run at `http://127.0.0.1:5000` ### Running Tests The application includes a comprehensive test suite with 102 tests: ```bash # Run all tests pytest tests/ -v # Run with coverage report pytest tests/ --cov=app --cov-report=html # Run specific test file pytest tests/test_routes.py -v ``` ### 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:create_app()" ``` 3. **Use a reverse proxy** (e.g., Nginx) in front of Gunicorn 4. **Update production settings** in `.env`: ``` WTF_CSRF_SSL_STRICT=True SESSION_COOKIE_SECURE=True MAIL_SERVER=your-production-smtp-server ``` ## 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 ``` . ├── run.py # Application entry point ├── config.py # Configuration settings ├── requirements.txt # Python dependencies ├── .env.example # Example environment variables ├── README.md # This file ├── app/ # Main application package │ ├── __init__.py # Application factory │ ├── routes.py # Route handlers (all endpoints) │ ├── models.py # Data persistence layer │ ├── validators.py # Input validation functions │ ├── email_service.py # Email sending functions │ └── utils.py # Utility functions ├── templates/ # HTML templates │ ├── base.html # Base template with navigation │ ├── _navigation.html # Progress bar component │ ├── page1_email.html # Email capture page │ ├── page2_personal.html # Personal information page │ ├── page3_motivation.html # Motivation questions page │ ├── page4_upload.html # Document upload page │ ├── page5_confirmation.html # Confirmation page │ └── application_view.html # HR application review page ├── static/ # Static files │ └── style.css # Styles (including navigation) ├── tests/ # Test suite (102 tests) │ ├── conftest.py # Test configuration and fixtures │ ├── test_routes.py # Route handler tests │ ├── test_validation.py # Validation function tests │ ├── test_email.py # Email functionality tests │ ├── test_storage.py # Data persistence tests │ ├── test_uploads.py # File upload tests │ ├── test_integration.py # End-to-end workflow tests │ ├── test_hr_notifications.py # HR email notification tests │ ├── test_application_view.py # Application review page tests │ └── test_config.py # Configuration tests └── applications/ # Application data (created automatically) └── {session-id}/ ├── data.yaml # Application data └── attachments/ # Uploaded files ``` ## 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: 5 status: "submitted" created_at: "2025-01-15T10:30:00" updated_at: "2025-01-15T11:45:00" submitted_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 Features ### CSRF Protection All forms are protected against Cross-Site Request Forgery (CSRF) attacks using Flask-WTF: - CSRF tokens required on all POST requests - Tokens included automatically in all forms - No token expiration (users can take time filling forms) - Configurable for production HTTPS environments ### Rate Limiting Built-in rate limiting prevents form spam and abuse: - 5-second cooldown between form submissions (configurable) - Session-based tracking - Customizable in `config.py`: `RATE_LIMIT_SECONDS = 5` ### Data Security - **Session IDs**: Cryptographically secure UUIDs (not guessable) - **File uploads**: Validated for size, type, and sanitized filenames - **Path traversal protection**: Secure filename handling prevents directory attacks - **Server-side validation**: All input validated on the server - **Environment variables**: Sensitive configuration kept in `.env` file - **No SQL injection**: File-based storage eliminates SQL vulnerabilities ### Production Security Checklist When deploying to production, update `.env`: ``` SECRET_KEY= WTF_CSRF_SSL_STRICT=True SESSION_COOKIE_SECURE=True SESSION_COOKIE_HTTPONLY=True SESSION_COOKIE_SAMESITE=Lax ``` ## HR Features ### Accessing Applications HR staff can review applications using the direct URL: ``` https://your-domain.com/application/{session-id}/ ``` The session ID is included in the HR notification email sent when an application is submitted. ### HR Notification Emails Configure HR email notifications in `.env`: ``` HR_EMAIL=hr@example.com APPLICATION_URL_BASE=https://your-domain.com ``` When an applicant submits their application (page 4), an email is automatically sent to the HR email address containing: - Applicant name and email - Position applied for - Submission timestamp - Number of uploaded documents - Direct link to the application review page ### Application Review Page The review page (`/application/{session-id}/`) displays: - Complete applicant information (all form fields) - All uploaded documents with download links - Submission timestamp and metadata - Professional formatting for easy review ### Downloading Attachments HR can download individual files directly from the review page: ``` https://your-domain.com/application/{session-id}/download/{filename} ``` Security: Only files listed in the application's uploaded_files list can be downloaded (prevents unauthorized access). ## 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. ## Architecture ### Application Factory Pattern The application uses Flask's application factory pattern for better testability and flexibility: - `app/__init__.py` contains the `create_app()` function - Extensions (Flask-Mail, CSRF) are initialized within the factory - Multiple app instances can be created (useful for testing) - Configuration can be passed as a parameter ### Modular Structure Code is organized by responsibility: - **routes.py** (473 lines): All route handlers and request processing - **models.py** (41 lines): Data persistence layer (YAML operations) - **validators.py** (48 lines): Input validation functions - **email_service.py** (85 lines): Email sending logic - **utils.py** (30 lines): Utility functions (rate limiting, etc.) Benefits: - Easy to test individual modules in isolation - Clear separation of concerns - Easier to navigate and maintain - Supports team collaboration ### Testing Strategy The application includes 102 automated tests organized by functionality: - **test_routes.py**: Route handler behavior - **test_validation.py**: Input validation logic - **test_email.py**: Email sending functionality - **test_storage.py**: YAML data persistence - **test_uploads.py**: File upload handling - **test_integration.py**: End-to-end workflows - **test_hr_notifications.py**: HR email notifications - **test_application_view.py**: Application review page - **test_config.py**: Configuration settings Run tests frequently during development to catch regressions early. ## Troubleshooting ### Email not sending in development **Using Mailcatcher (recommended for development):** 1. Verify mailcatcher is running: ```bash mailcatcher ``` 2. Check mailcatcher web interface at http://localhost:1080 3. Verify application is configured for mailcatcher: - Default settings work out of the box (localhost:1025) - No `.env` email configuration needed for development **Using real SMTP:** - 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 ### Tests failing If tests fail after making changes: ```bash # Run specific test file to identify the issue pytest tests/test_routes.py -v # Run with detailed output pytest tests/ -vv # Check test coverage pytest tests/ --cov=app --cov-report=term-missing ``` Common issues: - Import errors: Check module structure in `app/` package - Template errors: Verify templates exist in `templates/` directory - CSRF errors: Tests disable CSRF in `conftest.py` ### File upload errors - Ensure the `./applications/` folder exists and is writable - Check file size limits in your web server configuration - Verify allowed file extensions in `config.py` - Check that storage path is correct in config ### Session not resuming - Check that the `./applications/{session-id}/` folder exists - Verify that `data.yaml` is valid YAML format - Check application logs for errors - Ensure session ID in URL is correct (UUID format) ### Navigation not working - Verify `current_page` is being passed to templates - Check that navigation component is included in `base.html` - Ensure session data contains valid `current_page` value - Check browser console for CSS/styling issues ### Rate limiting preventing form submission - Check `RATE_LIMIT_SECONDS` in `config.py` (default: 5 seconds) - Wait the specified time between submissions - For testing, set to 0 in `.env`: `RATE_LIMIT_SECONDS=0` ## License This project is provided as-is for use in job application processes. ## Support For issues or questions, please contact your system administrator.