Files
gurix 8294f89956 docs: update README with current project features and architecture
- Updated features list with navigation bar, HR notifications, and security features
- Added navigation and HR features sections with usage examples
- Updated file structure to show modular app/ package
- Changed running instructions from app.py to run.py
- Added mailcatcher as default SMTP configuration
- Included testing instructions and architecture documentation
- Updated data.yaml example with status and submitted_at fields
- Added comprehensive Security Features section (CSRF, rate limiting)
- Added Architecture section explaining factory pattern and modular structure
- Enhanced Troubleshooting section with mailcatcher, testing, and navigation issues
- Updated technology stack with all dependencies and versions
2025-12-27 23:15:55 +01:00

16 KiB

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):

    python -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
  3. Install dependencies:

    pip install -r requirements.txt
    
  4. Configure environment variables:

    • Copy .env.example to .env:
      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:

    gem install mailcatcher
    
  2. Run mailcatcher:

    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

python run.py

Or using Flask CLI:

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:

# 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:

    pip install gunicorn
    
  2. Run with Gunicorn:

    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:

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=<strong-random-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:

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:

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:

    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:

# 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.