Corejobtrack Server — Deployment Guide


> Audience: System administrators and DevOps engineers responsible for deploying Corejobtrack Server to production.


---


Table of Contents


1. Prerequisites

2. Server Requirements

3. PostgreSQL Database Setup

4. Application Installation

5. Environment Configuration

6. SSL Certificate Setup

7. Systemd Service Configuration

8. Firewall & Network Configuration

9. Email (SMTP) Configuration

10. Apple Push Notifications (APNs) Setup

11. File Upload Storage

12. Vector Search / AI Setup (Optional)

13. SMB Hot Folder (Optional)

14. Production Checklist

15. Upgrading & Redeployment

16. Troubleshooting


---


1. Prerequisites


Before deploying Corejobtrack Server, ensure you have:


RequirementMinimum VersionNotes
Linux ServerUbuntu 20.04+ / RHEL 8+Deployed on Linux with systemd
Python3.10+3.11 or 3.12 recommended
PostgreSQL14+15 or 16 recommended
Git2.25+For deployment via `git pull`
OpenSSL1.1+For SSL certificate generation

Required Python Packages


The key dependencies include:


  • **FastAPI** — Web framework
  • **Uvicorn** — ASGI server
  • **psycopg2-binary** or **psycopg[binary]** — PostgreSQL driver
  • **python-jose** — JWT token handling
  • **bcrypt** / **passlib** — Password hashing
  • **Jinja2** — HTML template rendering
  • **python-multipart** — File upload support
  • **httpx** — HTTP client for APNs (optional)
  • **smbprotocol** / **smbclient** — SMB hot folder support (optional)
  • **cryptography** — SSL certificate parsing (optional)

  • Install all dependencies:


    
    pip install -r requirements.txt
    

    ---


    2. Server Requirements


    Hardware Recommendations


    ComponentMinimumRecommended
    CPU2 cores4+ cores
    RAM2 GB4+ GB
    Disk20 GB50+ GB (depends on file uploads)
    Network100 Mbps1 Gbps

    Directory Structure


    The production deployment typically lives at:


    
    /opt/taskapp/
    ├── app/                    # Application code (git repository)
    │   ├── main.py
    │   ├── app/
    │   ├── uploads/            # File upload storage
    │   ├── taskapp.env         # Environment configuration (NOT in git)
    │   ├── server_cert.pem     # SSL certificate
    │   ├── server_key.pem      # SSL private key
    │   └── venv/               # Python virtual environment
    ├── restart_services.sh     # Deployment restart script
    └── .deploy_result.json     # Last deployment result
    

    ---


    3. PostgreSQL Database Setup


    Install PostgreSQL


    
    # Ubuntu/Debian
    sudo apt update
    sudo apt install postgresql postgresql-contrib
    
    # RHEL/CentOS
    sudo dnf install postgresql-server postgresql-contrib
    sudo postgresql-setup --initdb
    

    Create Database and User


    
    sudo -u postgres psql
    

    
    -- Create the database user
    CREATE USER corejobtrack_user WITH PASSWORD 'your_secure_password_here';
    
    -- Create the database
    CREATE DATABASE corejobtrack OWNER corejobtrack_user;
    
    -- Grant privileges
    GRANT ALL PRIVILEGES ON DATABASE corejobtrack TO corejobtrack_user;
    
    -- Connect to the database to set up extensions
    \c corejobtrack
    
    -- Required: enable UUID generation
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
    
    -- Optional: enable vector search (requires pgvector installed)
    -- CREATE EXTENSION IF NOT EXISTS vector;
    

    Configure Remote Access (if DB is on a separate server)


    Edit pg_hba.conf to allow connections from the application server:


    
    # Allow Corejobtrack server to connect
    host    corejobtrack    corejobtrack_user    10.0.0.0/24    scram-sha-256
    

    Edit postgresql.conf:


    
    listen_addresses = '*'    # Or specific IP
    port = 5432
    

    Restart PostgreSQL:


    
    sudo systemctl restart postgresql
    

    Schema Auto-Migration


    Corejobtrack automatically creates and patches the database schema on startup via ensure_schema(). You do not need to run SQL migration scripts manually. The first startup will create all required tables.


    For reference, the full schema is documented in corejobtrack_schema.sql.


    ---


    4. Application Installation


    Clone the Repository


    
    sudo mkdir -p /opt/taskapp
    cd /opt/taskapp
    git clone <your-repo-url> app
    cd app
    

    Create Virtual Environment


    
    python3 -m venv venv
    source venv/bin/activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

    Set Permissions


    
    # Create a dedicated service user (optional but recommended)
    sudo useradd -r -s /bin/false taskapp
    sudo chown -R taskapp:taskapp /opt/taskapp
    
    # Ensure uploads directory exists with correct permissions
    mkdir -p /opt/taskapp/app/uploads
    chmod 750 /opt/taskapp/app/uploads
    

    ---


    5. Environment Configuration


    Copy the sample environment file and edit it with your production values:


    
    cp sample.taskapp.env taskapp.env
    chmod 600 taskapp.env    # Restrict access to owner only
    

    Required Configuration


    Edit taskapp.env with your production settings:


    
    # ===================== DATABASE =====================
    DB_NAME=corejobtrack
    DB_USER=corejobtrack_user
    DB_PASSWORD=your_secure_password_here
    DB_HOST=localhost          # Or remote DB IP (see Guide 9 for breakout)
    DB_PORT=5432
    
    # ===================== SECURITY =====================
    # CRITICAL: Generate a unique, random secret key for production
    # Use: python3 -c "import secrets; print(secrets.token_urlsafe(64))"
    SECRET_KEY=your_random_64_char_secret_key_here
    
    # Token expiration (in minutes). Default: 720 (12 hours)
    ACCESS_TOKEN_EXPIRE_MINUTES=720
    
    # ===================== UPLOADS =====================
    UPLOAD_DIR=/opt/taskapp/app/uploads
    MAX_UPLOAD_FILE_SIZE=52428800    # 50 MB
    
    # ===================== COMPANY BRANDING =====================
    COMPANY_NAME=Your Company Name
    COMPANY_ADDRESS=123 Business Ave, Suite 100, City, ST 12345
    COMPANY_PHONE=(555) 123-4567
    [email protected]
    COMPANY_WEBSITE=www.yourcompany.com
    
    # ===================== PORTAL =====================
    PORTAL_BASE_URL=https://tasks.yourcompany.com
    

    Security Configuration


    
    # ===================== RATE LIMITING =====================
    RATE_LIMIT_ENABLED=true
    RATE_LIMIT_LOGIN_MAX=5               # Max login attempts per window
    RATE_LIMIT_LOGIN_WINDOW=300          # 5-minute window
    RATE_LIMIT_REGISTER_MAX=3            # Max registrations per window
    RATE_LIMIT_REGISTER_WINDOW=3600      # 1-hour window
    
    # ===================== ACCOUNT LOCKOUT =====================
    ACCOUNT_LOCKOUT_ENABLED=true
    ACCOUNT_LOCKOUT_THRESHOLD=10         # Lockout after 10 failed attempts
    ACCOUNT_LOCKOUT_DURATION=900         # 15-minute lockout
    
    # ===================== CORS =====================
    # Set specific origins for production (comma-separated)
    CORS_ORIGINS=https://tasks.yourcompany.com,https://app.yourcompany.com
    CORS_ALLOW_CREDENTIALS=true
    
    # ===================== REQUEST LIMITS =====================
    MAX_REQUEST_SIZE_BYTES=10485760      # 10 MB max request body
    

    Email Configuration


    
    # ===================== EMAIL (SMTP) =====================
    SMTP_HOST=smtp.gmail.com
    SMTP_PORT=587
    [email protected]
    SMTP_PASSWORD=xxxx xxxx xxxx xxxx    # Google App Password
    SMTP_FROM_NAME=Corejobtrack
    [email protected]
    SMTP_ENABLED=true
    
    # CRITICAL: Set to false for production!
    SMTP_DEV_MODE=false
    SMTP_DEV_REDIRECT_ADDRESS=
    
    # Admin email for deployment notifications
    [email protected]
    

    > Warning: When SMTP_DEV_MODE=true, ALL outgoing emails are redirected to SMTP_DEV_REDIRECT_ADDRESS instead of the actual recipient. Always set this to false in production.


    Connection Pool Configuration


    
    # ===================== DATABASE POOL =====================
    DB_POOL_ENABLED=true
    DB_POOL_MIN_CONNECTIONS=2
    DB_POOL_MAX_CONNECTIONS=20
    DB_MAX_RETRIES=5
    DB_RETRY_BASE_DELAY=1.0
    DB_RETRY_MAX_DELAY=30.0
    DB_HEALTH_CHECK_INTERVAL=30
    

    ---


    6. SSL Certificate Setup


    Corejobtrack Server should run with SSL in production.


    Option A: Self-Signed Certificate (Internal Use)


    If a generate_cert.py script is included:


    
    cd /opt/taskapp/app
    source venv/bin/activate
    python generate_cert.py
    

    This generates server_cert.pem and server_key.pem in the project root.


    Option B: Let's Encrypt (Public-Facing)


    
    sudo apt install certbot
    sudo certbot certonly --standalone -d tasks.yourcompany.com
    
    # Copy certificates
    sudo cp /etc/letsencrypt/live/tasks.yourcompany.com/fullchain.pem /opt/taskapp/app/server_cert.pem
    sudo cp /etc/letsencrypt/live/tasks.yourcompany.com/privkey.pem /opt/taskapp/app/server_key.pem
    sudo chown taskapp:taskapp /opt/taskapp/app/server_*.pem
    

    Option C: Commercial Certificate


    Place your certificate files at:


  • `/opt/taskapp/app/server_cert.pem` — Full certificate chain
  • `/opt/taskapp/app/server_key.pem` — Private key

  • ---


    7. Systemd Service Configuration


    Create a systemd service file for the main server:


    
    sudo nano /etc/systemd/system/taskmanager-ssl.service
    

    
    [Unit]
    Description=Corejobtrack Server (SSL)
    After=network.target postgresql.service
    Wants=postgresql.service
    
    [Service]
    Type=simple
    User=taskapp
    Group=taskapp
    WorkingDirectory=/opt/taskapp/app
    Environment=PATH=/opt/taskapp/app/venv/bin:/usr/bin
    EnvironmentFile=/opt/taskapp/app/taskapp.env
    ExecStart=/opt/taskapp/app/venv/bin/uvicorn main:app \
        --host 0.0.0.0 \
        --port 8443 \
        --ssl-keyfile=server_key.pem \
        --ssl-certfile=server_cert.pem \
        --workers 4
    Restart=always
    RestartSec=5
    StandardOutput=journal
    StandardError=journal
    
    [Install]
    WantedBy=multi-user.target
    

    Enable and start:


    
    sudo systemctl daemon-reload
    sudo systemctl enable taskmanager-ssl
    sudo systemctl start taskmanager-ssl
    

    Check Status


    
    sudo systemctl status taskmanager-ssl
    sudo journalctl -u taskmanager-ssl -f    # Follow logs
    

    ---


    8. Firewall & Network Configuration


    Open Required Ports


    
    # UFW (Ubuntu)
    sudo ufw allow 8443/tcp    # Corejobtrack API + Portal
    
    # firewalld (RHEL/CentOS)
    sudo firewall-cmd --permanent --add-port=8443/tcp
    sudo firewall-cmd --reload
    

    Reverse Proxy with Nginx (Optional)


    If you want to serve on standard port 443:


    
    server {
        listen 443 ssl;
        server_name tasks.yourcompany.com;
    
        ssl_certificate /etc/letsencrypt/live/tasks.yourcompany.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/tasks.yourcompany.com/privkey.pem;
    
        client_max_body_size 50M;
    
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    

    When using a reverse proxy, run Uvicorn without SSL flags:


    
    ExecStart=/opt/taskapp/app/venv/bin/uvicorn main:app \
        --host 127.0.0.1 \
        --port 8000 \
        --workers 4
    

    ---


    9. Email (SMTP) Configuration


    Corejobtrack uses email for:


  • **Magic link login** — Portal authentication
  • **Signature request emails** — Post-visit customer signature collection
  • **Ticket summary emails** — PDF summaries sent to customers
  • **Deployment notifications** — Admin alerts on server restart
  • **Account deletion requests** — Notification emails

  • Google Workspace Setup


    1. Create a service account email (e.g., [email protected]) in Google Admin Console

    2. Enable 2-Step Verification on the account

    3. Generate an App Password:

  • Go to myaccount.google.com > Security > 2-Step Verification > App passwords
  • Select "Mail" and generate
  • Copy the 16-character password to `SMTP_PASSWORD`

  • Verify Email Configuration


    After starting the server, check email status via the API:


    
    curl -s https://tasks.yourcompany.com:8443/email/status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN" | jq
    

    ---


    10. Apple Push Notifications (APNs) Setup


    Required for push notifications to iOS/macOS clients.


    Apple Developer Account Setup


    1. Log into Apple Developer Portal

    2. Go to Certificates, Identifiers & Profiles > Keys

    3. Create a new key with "Apple Push Notifications service (APNs)" enabled

    4. Download the .p8 file and note the Key ID

    5. Note your Team ID from Membership details


    Configuration


    
    APNS_KEY_ID=ABC1234567           # 10-character Key ID
    APNS_TEAM_ID=DEF1234567          # 10-character Team ID
    APNS_BUNDLE_ID=com.yourcompany.corejobtrack
    APNS_KEY_PATH=/opt/taskapp/app/AuthKey_ABC1234567.p8
    APNS_USE_SANDBOX=false           # Set to false for production
    

    Place the .p8 key file at the path specified in APNS_KEY_PATH.


    > Note: APNs configuration can also be managed through the admin API endpoints (/admin/apns/config). See the Admin Portal Guide for details.


    ---


    11. File Upload Storage


    Corejobtrack stores file attachments, profile pictures, and signature images on the local filesystem.


    
    UPLOAD_DIR=/opt/taskapp/app/uploads
    MAX_UPLOAD_FILE_SIZE=52428800    # 50 MB per file
    

    Allowed File Extensions


    The default allowed extensions cover common business documents, images, videos, and archives:


    
    pdf, doc, docx, xls, xlsx, csv, txt, rtf, png, jpg, jpeg, gif, bmp,
    tiff, tif, webp, svg, heic, mp4, mov, avi, mp3, wav, zip, rar, 7z,
    ppt, pptx, pages, numbers, keynote
    

    Backup Strategy


    Include the uploads/ directory in your backup plan. These files are referenced by database records and cannot be regenerated.


    ---


    12. Vector Search / AI Setup (Optional)


    Corejobtrack supports natural language search powered by OpenAI embeddings and PostgreSQL pgvector.


    Install pgvector Extension


    
    # Ubuntu/Debian
    sudo apt install postgresql-16-pgvector
    
    # Or compile from source
    cd /tmp
    git clone https://github.com/pgvector/pgvector.git
    cd pgvector
    make
    sudo make install
    

    Enable in your database:


    
    \c corejobtrack
    CREATE EXTENSION IF NOT EXISTS vector;
    

    Configure Embeddings


    
    EMBEDDING_ENABLED=true
    EMBEDDING_API_KEY=sk-your-openai-api-key
    EMBEDDING_MODEL=text-embedding-3-small
    EMBEDDING_DIMENSIONS=1536
    EMBEDDING_BATCH_SIZE=100
    EMBEDDING_MAX_TOKENS=8000
    

    When enabled, Corejobtrack will:

  • Automatically generate embeddings for new tasks and tickets
  • Run a background backfill for existing entities
  • Use vector similarity for the `/search` endpoint

  • > Note: This feature requires an OpenAI API key and incurs usage costs. You can manage the budget cap through the admin API.


    ---


    13. SMB Hot Folder (Optional)


    Corejobtrack can monitor an SMB network share for JSON files and automatically create tasks/tickets from them.


    Requirements


  • `smbprotocol` / `smbclient` Python package installed
  • Network access to the SMB share

  • Configuration


    SMB watch is configured through the admin API (/admin/smb-watch/config) rather than environment variables. See the Admin Portal Guide for setup instructions.


    ---


    14. Production Checklist


    Before going live, verify these items:


  • [ ] `SECRET_KEY` is a unique, randomly generated value
  • [ ] `SMTP_DEV_MODE` is set to `false`
  • [ ] `CORS_ORIGINS` lists specific allowed origins (not `*`)
  • [ ] `DB_PASSWORD` is a strong, unique password
  • [ ] `taskapp.env` has restrictive file permissions (`chmod 600`)
  • [ ] SSL certificates are in place and valid
  • [ ] Firewall allows only required ports
  • [ ] Upload directory exists with correct permissions
  • [ ] Database backups are configured
  • [ ] Log rotation is configured (Corejobtrack uses weekly rotating logs)
  • [ ] Systemd service is enabled for auto-start on boot
  • [ ] Admin user account is created and verified

  • ---


    15. Upgrading & Redeployment



    Admin users can trigger a redeployment from the client application:


    
    curl -X POST https://tasks.yourcompany.com:8443/admin/restart \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    This executes restart_services.sh, which:

    1. Performs git pull to fetch latest code

    2. Installs any new dependencies

    3. Restarts the systemd service

    4. Saves deployment results to .deploy_result.json

    5. Sends a deployment report email to ADMIN_EMAIL


    Method 2: Manual Deployment


    
    cd /opt/taskapp/app
    git pull origin main
    source venv/bin/activate
    pip install -r requirements.txt
    sudo systemctl restart taskmanager-ssl
    

    Check Deployment Status


    
    curl -s https://tasks.yourcompany.com:8443/admin/deploy-status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN" | jq
    

    ---


    16. Troubleshooting


    Server Won't Start


    
    # Check service status and logs
    sudo systemctl status taskmanager-ssl
    sudo journalctl -u taskmanager-ssl --no-pager -n 50
    
    # Test manually
    cd /opt/taskapp/app
    source venv/bin/activate
    uvicorn main:app --host 0.0.0.0 --port 8443 \
      --ssl-keyfile=server_key.pem --ssl-certfile=server_cert.pem
    

    Database Connection Failures


    
    # Test connectivity
    psql -h DB_HOST -U DB_USER -d corejobtrack -c "SELECT 1;"
    
    # Check DB status via API
    curl -s https://tasks.yourcompany.com:8443/dbhealth
    curl -s https://tasks.yourcompany.com:8443/db-status
    

    SSL Certificate Issues


    Check certificate via the admin API:


    
    curl -s https://tasks.yourcompany.com:8443/admin/ssl/cert-info \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN" | jq
    

    Or renew via API:


    
    curl -X POST https://tasks.yourcompany.com:8443/admin/ssl/renew-cert \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    Log File Locations


    Corejobtrack uses rotating log files stored in the application directory. Access logs via the admin API:


    
    # Get last 100 lines
    curl -s "https://tasks.yourcompany.com:8443/logs?lines=100" \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    
    # Export logs for a date range
    curl -s "https://tasks.yourcompany.com:8443/logs/export?date_from=2026-01-01&date_to=2026-01-31" \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    ---


    Next: Guide 2 — Onboarding Wizard | Guide 3 — Launch & Verify


    Corejobtrack Server — Onboarding Wizard


    > Audience: First-time administrators setting up Corejobtrack for their organization. This guide walks through the initial setup process step by step.


    ---


    Table of Contents


    1. Overview

    2. Step 1: Environment Setup

    3. Step 2: Database Initialization

    4. Step 3: Create the First Admin User

    5. Step 4: Company Branding Configuration

    6. Step 5: Configure Email Service

    7. Step 6: Set Up the Customer Portal

    8. Step 7: Configure Default Settings

    9. Step 8: Create Employee Accounts

    10. Step 9: Create Your First Customer

    11. Step 10: Verify Everything Works

    12. What's Next?


    ---


    1. Overview


    This guide walks you through setting up Corejobtrack from a freshly deployed server to a fully configured, ready-to-use system. By the end, you'll have:


  • A running server with SSL
  • An admin account
  • Company branding configured
  • Email service connected
  • Customer portal accessible
  • Employee accounts created
  • Your first customer and ticket

  • !Placeholder: Onboarding flow diagram


    Before You Begin


    Make sure you've completed the Deployment Guide. You should have:


  • Corejobtrack Server installed and running
  • PostgreSQL database accessible
  • `taskapp.env` file created from the sample

  • ---


    2. Step 1: Environment Setup


    Copy and Edit the Environment File


    
    cd /opt/taskapp/app    # Or your installation directory
    cp sample.taskapp.env taskapp.env
    

    Open taskapp.env in your preferred editor. At minimum, configure these fields:


    
    # Database connection
    DB_NAME=corejobtrack
    DB_USER=your_db_user
    DB_PASSWORD=your_db_password
    DB_HOST=localhost
    DB_PORT=5432
    
    # Security — GENERATE A UNIQUE KEY!
    # Run: python3 -c "import secrets; print(secrets.token_urlsafe(64))"
    SECRET_KEY=paste_your_generated_key_here
    

    Generate a Secure Secret Key


    
    python3 -c "import secrets; print(secrets.token_urlsafe(64))"
    

    Copy the output and paste it as your SECRET_KEY value.


    > Important: Never share your SECRET_KEY or commit it to version control. Each deployment should have its own unique key.


    ---


    3. Step 2: Database Initialization


    Start the Server for the First Time


    The database schema is created automatically on first startup:


    
    source venv/bin/activate
    uvicorn main:app --host 0.0.0.0 --port 8443 \
      --ssl-keyfile=server_key.pem --ssl-certfile=server_cert.pem
    

    Watch the console output for:


    
    INFO:     [DB] Schema migration complete
    INFO:     [DB] Created 'hotfolder' system user for SMB ingest
    INFO:     Uvicorn running on https://0.0.0.0:8443
    

    Verify Database Connection


    Open a new terminal and test:


    
    curl -k https://localhost:8443/health
    # Expected: {"ok": true}
    
    curl -k https://localhost:8443/dbhealth
    # Expected: {"db": "ok", "database": "corejobtrack", "server": "PostgreSQL 16.x"}
    

    !Placeholder: Health check response screenshot


    ---


    4. Step 3: Create the First Admin User


    Register Your Admin Account


    Send a registration request to create the first user:


    
    curl -k -X POST https://localhost:8443/register \
      -H "Content-Type: application/json" \
      -d '{
        "username": "admin",
        "password": "YourSecurePassword123!",
        "full_name": "System Administrator",
        "first_name": "System",
        "last_name": "Administrator",
        "email": "[email protected]",
        "phone": "(555) 123-4567"
      }'
    

    Promote to Admin


    New registrations start with role: "pending". You need to promote the first user directly in the database:


    
    sudo -u postgres psql corejobtrack
    

    
    -- View the registered user
    SELECT id, username, role, is_admin FROM users;
    
    -- Promote to admin
    UPDATE users SET role = 'admin', is_admin = TRUE WHERE username = 'admin';
    

    Verify Admin Login


    
    curl -k -X POST https://localhost:8443/token \
      -d "username=admin&password=YourSecurePassword123!" \
      -H "Content-Type: application/x-www-form-urlencoded"
    

    You should receive an access token:


    
    {
      "access_token": "eyJ...",
      "token_type": "bearer"
    }
    

    Save this token — you'll use it for the remaining setup steps.


    
    # Set as an environment variable for convenience
    export TOKEN="eyJ..."
    

    ---


    5. Step 4: Company Branding Configuration


    Company branding appears in PDF reports, email templates, and the customer portal.


    Configure in `taskapp.env`


    
    COMPANY_NAME=Acme Corporation
    COMPANY_ADDRESS=123 Main Street, Anytown, ST 12345
    COMPANY_PHONE=(555) 123-4567
    [email protected]
    COMPANY_WEBSITE=www.acme.com
    

    Restart to Apply


    
    sudo systemctl restart taskmanager-ssl
    

    The branding is used in:


  • **PDF ticket summaries** — Company letterhead
  • **Email templates** — Header and footer
  • **Portal pages** — Title and contact information

  • !Placeholder: PDF with company branding


    ---


    6. Step 5: Configure Email Service


    Email is required for the customer portal (magic link login) and signature requests.


    Google Workspace / Gmail Setup


    1. Create a service account — Use an email like [email protected]

    2. Enable 2-Step Verification — Required for App Passwords

    3. Generate an App Password:

  • Visit [Google App Passwords](https://myaccount.google.com/apppasswords)
  • Select "Mail" and your device
  • Copy the 16-character code

  • Update `taskapp.env`


    
    SMTP_HOST=smtp.gmail.com
    SMTP_PORT=587
    [email protected]
    SMTP_PASSWORD=xxxx xxxx xxxx xxxx    # Your App Password
    SMTP_FROM_NAME=Corejobtrack
    [email protected]
    SMTP_ENABLED=true
    
    # FOR TESTING: Keep true to redirect all emails to yourself
    SMTP_DEV_MODE=true
    [email protected]
    
    # FOR PRODUCTION: Set to false when ready
    # SMTP_DEV_MODE=false
    

    Test Email Configuration


    After restarting the server:


    
    curl -k -X POST https://localhost:8443/email/send \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "to": "[email protected]",
        "subject": "Corejobtrack Email Test",
        "body_text": "If you received this email, email is configured correctly!",
        "body_html": "<h1>Success!</h1><p>Corejobtrack email is working.</p>"
      }'
    

    Check Email Status


    
    curl -k https://localhost:8443/email/status \
      -H "Authorization: Bearer $TOKEN"
    

    > Tip: Start with SMTP_DEV_MODE=true during setup. This redirects ALL outgoing emails to your SMTP_DEV_REDIRECT_ADDRESS, so you can verify emails are formatted correctly without sending to real customers.


    ---


    7. Step 6: Set Up the Customer Portal


    The customer portal allows your customers to view their tickets, communicate with your team, and sign service documents online.


    Configure Portal URL


    In taskapp.env:


    
    PORTAL_BASE_URL=https://tasks.yourcompany.com:8443
    
    # Session settings
    PORTAL_MAGIC_LINK_EXPIRY_MINUTES=15
    PORTAL_SESSION_EXPIRY_DAYS=7
    PORTAL_REMEMBER_ME_DAYS=30
    

    Verify Portal Access


    Open a web browser and navigate to:


  • **Customer Portal:** `https://tasks.yourcompany.com:8443/customer/login`
  • **Admin Portal:** `https://tasks.yourcompany.com:8443/portal/admin/login`

  • !Placeholder: Customer portal login page


    The customer portal uses magic link authentication — customers enter their email, receive a link, and click to log in. No password is required for portal access.


    ---


    8. Step 7: Configure Default Settings


    Set Ticket Color Defaults


    Configure the default colors for new service and support tickets:


    
    curl -k -X PUT https://localhost:8443/settings/ticket-defaults \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "service_ticket": "#4A90D9",
        "support_ticket": "#E67E22"
      }'
    

    Set Up Dropdown Choices


    Configure the dropdown options available when creating tickets. Common fields include:


    
    # Task types
    curl -k -X POST https://localhost:8443/task_types/ \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "Installation"}'
    
    curl -k -X POST https://localhost:8443/task_types/ \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "Repair"}'
    
    curl -k -X POST https://localhost:8443/task_types/ \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "Maintenance"}'
    

    Set Up Dropdown Choices for Custom Fields


    
    # Dispatch types for service tickets
    curl -k -X PUT https://localhost:8443/settings/dropdown-choices/dispatch_type \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '[
        {"value": "Emergency", "label": "Emergency"},
        {"value": "Scheduled", "label": "Scheduled"},
        {"value": "Preventive Maintenance", "label": "Preventive Maintenance"}
      ]'
    

    ---


    9. Step 8: Create Employee Accounts


    Method 1: Admin Creates Users Directly


    
    curl -k -X POST https://localhost:8443/users/ \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "username": "jsmith",
        "password": "TempPassword123!",
        "full_name": "John Smith",
        "first_name": "John",
        "last_name": "Smith",
        "email": "[email protected]",
        "phone": "(555) 234-5678",
        "team": "Service"
      }'
    

    Method 2: Employee Self-Registration


    Employees can register at POST /register. Their accounts start with role: "pending" and must be approved by an admin:


    
    # Approve a pending user
    curl -k -X PUT https://localhost:8443/users/USER_ID \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"role": "user"}'
    

    User Roles


    RoleAccess LevelDescription
    `pending`NoneNewly registered, awaiting approval
    `user`StandardCan create/manage tasks and tickets
    `admin`FullAll user permissions + admin panel access

    Teams


    Teams are text strings that can be assigned to users and used for ticket visibility:


  • Users on the same team can see team-assigned tickets
  • Tickets can be assigned to specific users or teams
  • A user's team is set during account creation or via admin update

  • ---


    10. Step 9: Create Your First Customer


    Create a Customer


    
    curl -k -X POST https://localhost:8443/customers/ \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "company": "Customer Corp",
        "contact_id": "CUST001",
        "address_1": "456 Customer Ave",
        "city": "Townsville",
        "state": "ST",
        "zip": "67890",
        "account_status": "active"
      }'
    

    Add a Contact


    
    curl -k -X POST https://localhost:8443/customers/CUSTOMER_ID/contacts \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "first_name": "Jane",
        "last_name": "Doe",
        "phone": "(555) 345-6789",
        "email": "[email protected]",
        "is_primary": true
      }'
    

    Create a Test Ticket


    
    curl -k -X POST https://localhost:8443/service-tickets/ \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "customer_name": "Customer Corp",
        "title": "Initial Setup Verification",
        "description": "Test ticket to verify system is working correctly",
        "urgency": "Low",
        "status": "Pending"
      }'
    

    ---


    11. Step 10: Verify Everything Works


    Verification Checklist


    Run through this checklist to confirm your setup is complete:


    TestCommand / ActionExpected Result
    Server Health`curl -k https://localhost:8443/health``{"ok": true}`
    Database Health`curl -k https://localhost:8443/dbhealth``{"db": "ok", ...}`
    Server Version`curl -k https://localhost:8443/version`Version number
    Admin Login`POST /token` with admin credentialsAccess token returned
    List Users`GET /users/` with admin tokenUser list with your admin
    List Customers`GET /customers/list` with tokenYour test customer
    List Tickets`GET /service-tickets/` with tokenYour test ticket
    Portal Login PageOpen browser to `/customer/login`Login form renders
    Admin PortalOpen browser to `/portal/admin/login`Admin login form
    Email Test`POST /email/send`Email received

    Common Issues


    ProblemSolution
    `{"detail": "Not authenticated"}`Include `Authorization: Bearer TOKEN` header
    `{"detail": "Not authorized"}`User needs admin role for this endpoint
    Portal returns 404Check `PORTAL_BASE_URL` is correct
    Email not receivedCheck `SMTP_ENABLED=true` and verify credentials
    Database connection timeoutVerify `DB_HOST`, `DB_PORT`, and `pg_hba.conf`

    ---


    12. What's Next?


    Congratulations! Your Corejobtrack Server is set up and ready. Here's what to explore next:


    GuideWhat You'll Learn
    Launch & VerifyDetailed server startup, health monitoring, and diagnostics
    Customer PortalHow customers interact with the portal
    Employee GuideDay-to-day employee workflows
    Admin GuideSystem administration and management
    API ReferenceComplete API endpoint documentation
    JSON InputsRequest/response format reference
    Database BreakoutMoving the database to a separate server

    ---


    Previous: Guide 1 — Deployment | Next: Guide 3 — Launch & Verify


    Corejobtrack Server — Launch & Verify Guide


    > Audience: Administrators and developers who need to start the server, verify it's running correctly, and diagnose issues.


    ---


    Table of Contents


    1. Starting the Server

    2. Health Check Endpoints

    3. Startup Sequence

    4. Verifying Core Services

    5. Monitoring & Diagnostics

    6. Common Startup Issues

    7. Stopping & Restarting

    8. Log Files & Rotation


    ---


    1. Starting the Server


    Development Mode


    For local development with auto-reload:


    
    cd /path/to/corejobtrack-server
    source venv/bin/activate
    
    # Load environment variables
    export $(grep -v '^#' taskapp.env | xargs)
    
    # Start with auto-reload (restarts on code changes)
    uvicorn main:app --reload --host 0.0.0.0 --port 8000
    

    !Placeholder: Terminal showing uvicorn startup output


    Production Mode (SSL)


    
    uvicorn main:app --host 0.0.0.0 --port 8443 \
      --ssl-keyfile=server_key.pem \
      --ssl-certfile=server_cert.pem \
      --workers 4
    

    Production Mode (Systemd)


    
    # Start the service
    sudo systemctl start taskmanager-ssl
    
    # Enable auto-start on boot
    sudo systemctl enable taskmanager-ssl
    
    # Check status
    sudo systemctl status taskmanager-ssl
    

    What Happens at Startup


    When the server starts, it performs these operations in sequence:


    
    1. Load configuration from taskapp.env
    2. Create FastAPI application
    3. Register middleware (CORS, security headers, request limits, logging)
    4. Register all route modules (38 modules)
    5. Run ensure_schema() — create/migrate database tables
    6. Start DB health monitor thread
    7. Start SMB watch thread (if configured)
    8. Start signature reminder scheduler
    9. Send deployment report email (if server was restarted via admin)
    10. Initialize embedding/vector search (if configured)
    11. Begin accepting HTTP requests
    

    ---


    2. Health Check Endpoints


    Corejobtrack provides several health check endpoints that require no authentication. Use these to verify the server is running.


    Basic Health Check


    
    curl https://your-server:8443/health
    

    Response:

    
    {"ok": true}
    

    Use this endpoint for load balancer health probes and uptime monitoring.


    Server Version


    
    curl https://your-server:8443/version
    

    Response:

    
    {"version": "0.981"}
    

    Useful for confirming which version is deployed after an update.


    Database Health


    
    curl https://your-server:8443/dbhealth
    

    Response (healthy):

    
    {
      "db": "ok",
      "database": "corejobtrack",
      "server": "PostgreSQL 16.1 on x86_64-pc-linux-gnu"
    }
    

    Response (unhealthy):

    
    {
      "detail": "Database unavailable"
    }
    

    (HTTP 503)


    Detailed Database Status


    
    curl https://your-server:8443/db-status
    

    Response:

    
    {
      "available": true,
      "last_check": "2026-03-01T12:00:00Z",
      "last_error": null,
      "last_recovery": null,
      "consecutive_failures": 0,
      "total_recoveries": 0
    }
    

    This endpoint provides detailed information about database connectivity, including:


    FieldDescription
    `available`Whether the database is currently reachable
    `last_check`Timestamp of the last health check
    `last_error`Most recent error message (null if healthy)
    `last_recovery`When the database last recovered from a failure
    `consecutive_failures`Number of consecutive failed checks
    `total_recoveries`Total number of times the DB recovered

    Connection Pool Statistics (Admin Only)


    
    curl https://your-server:8443/db-pool-stats \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    Response:

    
    {
      "available": 5,
      "in_use": 2,
      "max": 20,
      "min": 2
    }
    

    Security Status (Admin Only)


    
    curl https://your-server:8443/security-status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    Returns the current security configuration including rate limiting, CORS, and lockout settings.


    ---


    3. Startup Sequence


    Successful Startup Log


    A healthy startup produces log output similar to:


    
    INFO:     [DB] Schema migration complete
    INFO:     [DB] Created 'hotfolder' system user for SMB ingest
    INFO:     [DB] Health monitor started (interval: 30s)
    INFO:     [SMB] Watcher did not start: SMB not configured
    INFO:     [SIGNATURE] Reminder scheduler started
    INFO:     [EMBED] pgvector not installed — vector search disabled, ILIKE fallback active
    INFO:     Uvicorn running on https://0.0.0.0:8443 (Press CTRL+C to quit)
    

    Schema Migration


    On first startup (or when updates add new columns), you'll see migration messages:


    
    INFO:     [DB] Added column 'change_log' to tasks
    INFO:     [DB] Added column 'task_type' to tasks
    INFO:     [DB] Added column 'color' to tasks
    INFO:     [DB] Created system user 'hotfolder'
    INFO:     [DB] Created system user 'portal'
    INFO:     [DB] Schema migration complete
    

    > Note: Schema migration is automatic and non-destructive. It only adds new columns — it never drops or modifies existing data.


    ---


    4. Verifying Core Services


    After startup, run these checks to verify all services are operational.


    Quick Verification Script


    
    #!/bin/bash
    SERVER="https://localhost:8443"
    TOKEN="YOUR_ADMIN_TOKEN"
    
    echo "=== Corejobtrack Server Verification ==="
    
    # 1. Health
    echo -n "Health Check: "
    curl -sk $SERVER/health | jq -r '.ok'
    
    # 2. Version
    echo -n "Version: "
    curl -sk $SERVER/version | jq -r '.version'
    
    # 3. Database
    echo -n "Database: "
    curl -sk $SERVER/dbhealth | jq -r '.db'
    
    # 4. DB Status
    echo -n "DB Available: "
    curl -sk $SERVER/db-status | jq -r '.available'
    
    # 5. Pool Stats
    echo -n "Pool Connections: "
    curl -sk $SERVER/db-pool-stats -H "Authorization: Bearer $TOKEN" | jq -r '"available=\(.available), in_use=\(.in_use)"'
    
    # 6. Auth Test
    echo -n "Auth Working: "
    curl -sk $SERVER/me -H "Authorization: Bearer $TOKEN" | jq -r '.username // "FAILED"'
    
    # 7. Email Status
    echo -n "Email Configured: "
    curl -sk $SERVER/email/status -H "Authorization: Bearer $TOKEN" | jq -r '.configured // "false"'
    
    echo "=== Verification Complete ==="
    

    Service-by-Service Verification


    #### Authentication Service


    
    # Login and get a token
    curl -sk -X POST https://localhost:8443/token \
      -d "username=admin&password=YourPassword" \
      -H "Content-Type: application/x-www-form-urlencoded"
    
    # Verify the token works
    curl -sk https://localhost:8443/me \
      -H "Authorization: Bearer YOUR_TOKEN"
    

    #### Database Connection


    
    # Basic connectivity
    curl -sk https://localhost:8443/dbhealth
    
    # Detailed status with recovery tracking
    curl -sk https://localhost:8443/db-status
    
    # Schema check (admin only)
    curl -sk https://localhost:8443/admin/db/schema-status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    #### Email Service


    
    curl -sk https://localhost:8443/email/status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    #### Push Notifications (APNs)


    
    curl -sk https://localhost:8443/admin/apns/status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    #### SSL Certificate


    
    curl -sk https://localhost:8443/admin/ssl/cert-info \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    #### SMB Hot Folder


    
    curl -sk https://localhost:8443/admin/smb-watch/status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    #### Embedding / Vector Search


    
    curl -sk https://localhost:8443/admin/embedding/status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    ---


    5. Monitoring & Diagnostics


    Continuous Monitoring


    For production environments, set up monitoring using the health endpoints:


    EndpointIntervalAlert On
    `GET /health`30 secondsNon-200 response
    `GET /dbhealth`60 secondsNon-200 response
    `GET /db-status`5 minutes`consecutive_failures > 3`
    `GET /version`After deploymentsVersion mismatch

    Systemd Journal Logs


    
    # Follow live logs
    sudo journalctl -u taskmanager-ssl -f
    
    # Last 100 lines
    sudo journalctl -u taskmanager-ssl --no-pager -n 100
    
    # Logs since specific time
    sudo journalctl -u taskmanager-ssl --since "2026-03-01 08:00:00"
    
    # Filter by priority
    sudo journalctl -u taskmanager-ssl -p err    # Only errors
    

    Application Logs (Admin API)


    
    # Get last 200 lines of server log
    curl -sk "https://localhost:8443/logs?lines=200" \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    
    # Export logs for a date range
    curl -sk "https://localhost:8443/logs/export?date_from=2026-02-28&date_to=2026-03-01" \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    Database Schema Diagnostics


    Check which optional columns exist and get SQL to add missing ones:


    
    curl -sk https://localhost:8443/admin/db/schema-status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    Response example:

    
    {
      "tasks": {
        "change_log": true,
        "task_type": true,
        "is_private": true,
        "archived_at": true,
        "color": true
      },
      "service_tickets": {
        "change_log": true
      },
      "task_steps": {
        "completed_at": true,
        "completed_by": true
      },
      "missing_sql": []
    }
    

    If missing_sql is not empty, run the provided SQL statements to bring the schema up to date, or simply restart the server to trigger auto-migration.


    ---


    6. Common Startup Issues


    Issue: "Database unavailable" on startup


    Symptoms: Server starts but returns 503 on database-related requests.


    Diagnosis:

    
    # Check if PostgreSQL is running
    sudo systemctl status postgresql
    
    # Test database connection directly
    psql -h DB_HOST -U DB_USER -d corejobtrack -c "SELECT 1;"
    
    # Check db-status endpoint
    curl -sk https://localhost:8443/db-status
    

    Solutions:

  • Verify `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASSWORD` in `taskapp.env`
  • Check `pg_hba.conf` allows connections from the app server
  • Ensure PostgreSQL is listening on the correct interface

  • Issue: "SECRET_KEY must be set in production"


    Symptoms: Server crashes immediately on startup.


    Solution: Set the SECRET_KEY environment variable:

    
    python3 -c "import secrets; print(secrets.token_urlsafe(64))"
    # Add the output to taskapp.env as SECRET_KEY=...
    

    Issue: SSL certificate not found


    Symptoms: Uvicorn errors about missing SSL files.


    Solution: Ensure server_cert.pem and server_key.pem exist in the working directory:

    
    ls -la server_cert.pem server_key.pem
    

    Issue: Port already in use


    Symptoms: OSError: [Errno 98] Address already in use


    Solution:

    
    # Find what's using the port
    sudo lsof -i :8443
    
    # Kill the process if needed, or use a different port
    

    Issue: Permission denied on uploads directory


    Symptoms: File uploads fail with 500 errors.


    Solution:

    
    mkdir -p uploads
    chmod 750 uploads
    chown taskapp:taskapp uploads
    

    ---


    7. Stopping & Restarting


    Graceful Shutdown


    
    # Systemd
    sudo systemctl stop taskmanager-ssl
    
    # Manual (Ctrl+C in terminal, or send SIGTERM)
    kill -TERM $(pgrep -f "uvicorn main:app")
    

    On shutdown, the server:

    1. Stops the signature scheduler

    2. Stops the DB health monitor

    3. Stops the embedding backfill (if running)

    4. Closes all database connections and shuts down the pool


    Restart


    
    # Systemd restart
    sudo systemctl restart taskmanager-ssl
    
    # Verify after restart
    curl -sk https://localhost:8443/health
    curl -sk https://localhost:8443/version
    

    Remote Restart via Admin API


    Admin users can trigger a full deployment restart remotely:


    
    curl -sk -X POST https://localhost:8443/admin/restart \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    This runs restart_services.sh which:

    1. Pulls latest code from git

    2. Installs dependencies

    3. Restarts systemd services

    4. Emails a deployment report


    Check the result after the server comes back up:


    
    curl -sk https://localhost:8443/admin/deploy-status \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    

    ---


    8. Log Files & Rotation


    Log Configuration


    SettingDefaultDescription
    `SERVER_LOG_RETENTION_WEEKS`52How many weekly log files to keep
    `CLIENT_LOG_RETENTION_WEEKS`52How many weekly client log files to keep

    Corejobtrack uses Python's TimedRotatingFileHandler with weekly rotation. Old log files are automatically deleted based on the retention setting.


    Log Categories


    Each log line is prefixed with a category for easy filtering:


    PrefixCategoryExample
    `[AUTH]`AuthenticationLogin, token validation, registration
    `[DB]`DatabaseConnection issues, query failures
    `[EMAIL]`Email serviceSend success/failure, SMTP errors
    `[PORTAL]`Customer/admin portalPage loads, form submissions
    `[ADMIN]`Server administrationRestart, deploy, config changes
    `[SMB]`SMB hot folderFile processing, connection issues
    `[APNS]`Push notificationsSend success/failure
    `[UPLOAD]`File uploadsUpload/download operations
    `[SIGNATURE]`Signature systemRequest, capture, reminder
    `[EMBED]`Vector searchEmbedding generation, backfill

    Viewing Logs


    
    # Via admin API
    curl -sk "https://localhost:8443/logs?lines=50" \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
    
    # Via admin portal
    # Navigate to Admin Area > Server Logs
    
    # Via systemd journal
    sudo journalctl -u taskmanager-ssl -f
    
    # Export for analysis
    curl -sk "https://localhost:8443/logs/export?log_type=server&date_from=2026-02-01&date_to=2026-03-01" \
      -H "Authorization: Bearer YOUR_ADMIN_TOKEN" > server_logs.txt
    

    Client Logs


    Client applications can submit logs to the server for centralized tracking:


    
    # Single log entry
    curl -sk -X POST https://localhost:8443/logs \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "message": "App launched successfully",
        "level": "info",
        "platform": "ios",
        "client_version": "2.1.0"
      }'
    
    # Batch submission
    curl -sk -X POST https://localhost:8443/logs/batch \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "entries": [
          {"message": "App launched", "level": "info"},
          {"message": "Network timeout", "level": "warning"}
        ],
        "platform": "ios",
        "client_version": "2.1.0"
      }'
    

    ---


    Previous: Guide 2 — Onboarding Wizard | Next: Guide 4 — Customer Portal


    Corejobtrack Server — Customer Portal Guide


    > Audience: End-user customers who access the Corejobtrack portal to view tickets, communicate with your team, and sign service documents. This guide assumes no technical background.


    ---


    Table of Contents


    1. What is the Customer Portal?

    2. Getting Started — Registration

    3. Logging In

    4. Your Dashboard

    5. Viewing Tickets

    6. Creating a New Service Ticket

    7. Creating a New Support Ticket

    8. Signing Service Documents

    9. Communicating with the Team

    10. Managing Your Equipment

    11. Notifications

    12. Account Settings

    13. Downloading Attachments & PDFs

    14. Frequently Asked Questions


    ---


    1. What is the Customer Portal?


    The Customer Portal is your self-service window into Corejobtrack. Through the portal, you can:


  • **View your service and support tickets** — See the status and history of all work being done for you
  • **Create new tickets** — Request service visits or open support cases
  • **Sign service documents** — Digitally sign after a service visit, right from your browser or phone
  • **Communicate** — Send messages directly to the team working on your tickets
  • **Track equipment** — See the equipment registered to your account
  • **Download PDFs** — Get professional summary reports of completed work

  • !Placeholder: Customer portal dashboard overview


    Accessing the Portal


    Open your web browser and go to the URL provided by your service provider. It typically looks like:


    
    https://tasks.yourcompany.com/customer/login
    

    The portal works on desktop computers, tablets, and phones.


    ---


    2. Getting Started — Registration


    If you don't have an account yet, you can register directly through the portal.


    Step 1: Navigate to Registration


    From the login page, click the "Register" link.


    Step 2: Enter Your Customer Number


    Enter the customer number or company name associated with your account. This links your portal account to your company's records.


    !Placeholder: Registration step 1 - customer number


    Step 3: Enter Your Information


    Fill in your personal details:

  • **First Name** and **Last Name**
  • **Email Address** — This is how you'll log in and receive notifications
  • **Password** — Must meet security requirements:
  • At least 8 characters
  • Mix of uppercase and lowercase letters
  • Include at least one number
  • Include at least one special character

  • !Placeholder: Registration step 2 - personal info


    Step 4: Wait for Approval


    After registering, your account will be in a pending state. An administrator will review and approve your registration — typically within 24 hours. You'll receive an email when your account is approved.


    !Placeholder: Registration pending screen


    ---


    3. Logging In


    Option A: Email & Password


    1. Go to the login page

    2. Enter your email address and password

    3. Check "Remember me" to stay logged in for up to 30 days

    4. Click "Sign In"


    !Placeholder: Login form



    If you prefer not to use a password, or if you've forgotten it:


    1. On the login page, click "Sign in with Magic Link"

    2. Enter your email address

    3. Click "Send Magic Link"

    4. Check your email inbox for a message from Corejobtrack

    5. Click the link in the email — you'll be logged in automatically


    > Note: Magic links expire after 15 minutes. If it expires, request a new one.


    Forgot Your Password?


    1. From the login page, click "Forgot Password?"

    2. Enter your email address

    3. Check your email for a password reset link

    4. Click the link and enter a new password


    ---


    4. Your Dashboard


    After logging in, you'll see your dashboard — the main hub for all your activity.


    !Placeholder: Customer dashboard with tickets


    What You'll See


    The dashboard shows two tables:


    #### Service Tickets


    These represent on-site service visits. Each row shows:


    ColumnWhat It Means
    **Ticket #**Unique ticket number (e.g., #456789) — click to view details
    **Title**Brief description of the service request
    **Status**Current state: Open, In Progress, Completed, Archived
    **Signature**Whether you've signed for the completed service
    **Created**When the ticket was created

    #### Support Tickets


    These represent remote support cases (phone, email, or remote desktop). Each row shows:


    ColumnWhat It Means
    **Ticket #**Unique ticket number — click to view details
    **Title**Brief description of the support request
    **Status**Current state: Open, In Progress, Completed, Archived
    **Created**When the ticket was created

    Status Badges


    StatusColorMeaning
    OpenBlueNew ticket, not yet started
    In ProgressYellowBeing actively worked on
    CompletedGreenWork is finished
    ArchivedGrayClosed and stored for records
    PendingOrangeWaiting for action

    Creating New Tickets


    Click the "New Ticket" button at the top of the dashboard. You'll be asked to choose between:


  • **Service Ticket** — For requesting a technician visit
  • **Support Ticket** — For remote support issues

  • ---


    5. Viewing Tickets


    Click any ticket number or row on the dashboard to view the full details.


    Ticket Detail Page


    !Placeholder: Ticket detail view


    The ticket detail page shows:


    #### Header Section

  • **Ticket Number** and **Title**
  • **Status Badge** — Current state of the ticket
  • **Signature Status** — (Service tickets only) Whether the work has been signed off
  • **PDF Export Button** — Download a professional PDF summary
  • **View History** — See the full change log

  • #### Customer & Contact Information

  • Your company name and address
  • Contact person, phone, and email
  • Customer PO number (if applicable)

  • #### Equipment (Service Tickets)

    A table of equipment involved in this service visit:

  • Make, Model, Serial Number
  • Count (quantity)
  • Problem description for each piece of equipment

  • #### Problem Description (Service Tickets)

    A detailed description of the issue being addressed.


    #### Time Entries (Service Tickets)

    A breakdown of the time spent on the service visit:

  • Start and stop times
  • Duration
  • Number of technicians
  • Type of time (regular, overtime, etc.)
  • Total time at the bottom

  • #### Attachments

  • **Media Gallery** — Photos and videos from the service visit
  • **Files** — Documents like invoices, manuals, or reports (click to download)

  • #### Signature Section (Service Tickets)

    If the service has been signed:

  • The signature image
  • Name of the person who signed
  • Date and time of signing

  • If a signature is still needed, you may see a "Sign Now" option.


    #### Notes & Communication (Support Tickets)

    A conversation thread where you can exchange messages with the support team.


    ---


    6. Creating a New Service Ticket


    Service tickets are for requesting an on-site technician visit.


    Step 1: Select Equipment


    Choose the equipment that needs service from your equipment inventory. For each piece selected:


    1. Check the box next to the equipment

    2. Describe the problem in the text field that appears

    3. Set the count if multiple units are affected


    You can also add new equipment if it's not in your inventory yet using the "Add Equipment" form.


    !Placeholder: Equipment selection step


    Step 2: Add Details


  • **Title** — A brief summary of the service request (e.g., "Paper jam in main copier")
  • **Description** — Detailed explanation of the issue

  • Step 3: Review & Submit


    Review all the information you've entered, then click "Submit Ticket".


    After submission, you'll be taken back to your dashboard where the new ticket will appear with a "Pending" status.


    ---


    7. Creating a New Support Ticket


    Support tickets are for remote assistance — phone support, email support, or remote desktop sessions.


    Step 1: Describe the Issue


  • **Title** — Brief summary (e.g., "Cannot connect to network printer")
  • **Description** — Full details of the problem

  • Step 2: Review & Submit


    Confirm the details and click "Submit Ticket".


    ---


    8. Signing Service Documents


    After a technician completes a service visit, you may be asked to sign digitally.


    Signing In Person (On-Site)


    The technician may present a signature screen on their device. Simply:


    1. Review the service summary

    2. Write your signature with your finger or stylus

    3. Enter your printed name

    4. Confirm


    Signing Online (Post-Visit)


    If you weren't available during the visit, you'll receive a signature request email:


    1. Open the email from Corejobtrack

    2. Click the "Sign Now" button

    3. You'll be taken to a secure signature page

    4. Review the service summary, equipment, and work performed

    5. Draw your signature on the canvas


    !Placeholder: Signature capture screen


    6. Enter your full name

    7. Check the safety covers checkbox if applicable

    8. Click "Submit Signature"


    > Note: Signature links expire after 7 days. If your link has expired, contact the service provider to send a new one.


    Declining a Signature


    If you need to decline signing (e.g., the work wasn't satisfactory):

  • Click **"Decline to Sign"**
  • Select a reason from the dropdown
  • The team will be notified

  • ---


    9. Communicating with the Team


    On support tickets, you can send and receive messages directly through the ticket detail page.


    Sending a Message


    1. Open the support ticket

    2. Scroll to the Communication Log section

    3. Type your message in the text box

    4. Click "Send"


    !Placeholder: Communication log with messages


    What You'll See


    Each message shows:

  • **Who sent it** — You or a team member
  • **When it was sent** — Date and time
  • **The message content**

  • Typing Indicators


    When someone on the team is typing a response, you'll see a "typing..." indicator so you know a reply is coming.


    Read Receipts


    The system tracks when messages are read by team members, so there's transparency about communication.


    ---


    10. Managing Your Equipment


    Your equipment inventory is linked to your customer account. Equipment appears in your service tickets.


    Viewing Equipment


    Equipment associated with a ticket is displayed in the Equipment section of the ticket detail page.


    Equipment Details


    Click on an equipment item to see:

  • **Make, Model, Serial Number**
  • **Current count** (quantity)
  • **Count history** — A log of all count changes over time
  • **Related tickets** — All service visits involving this equipment

  • ---


    11. Notifications


    Corejobtrack sends you notifications when important things happen.


    Types of Notifications


    NotificationWhen It's Sent
    Ticket CreatedA new ticket is created for your account
    Status ChangedYour ticket's status changes (e.g., to "In Progress")
    Message ReceivedA team member replies to your support ticket
    Signature RequestedA service visit needs your signature
    Account ApprovedYour registration has been approved

    Viewing Notifications


    Click the bell icon in the top navigation bar to see your latest notifications. Click "View All" to see the full notifications page.


    !Placeholder: Notification dropdown


    Managing Notifications


  • **Mark as Read** — Click a notification to mark it as read
  • **Mark All as Read** — Clear all unread indicators at once
  • **Delete** — Remove notifications you no longer need

  • Push Notifications (Mobile App)


    If you use the Corejobtrack mobile app, you can also receive push notifications on your phone. These are managed through the app's settings.


    ---


    12. Account Settings


    Access your account settings by clicking the gear icon or "Settings" link in the top navigation.


    !Placeholder: Account settings page


    Profile Picture


  • Click on the profile picture area to upload a new photo
  • Supported formats: PNG, JPG, GIF, WebP
  • Maximum size: 5 MB

  • Personal Information


    Update your name and contact details:

  • First Name
  • Last Name
  • Phone (display only in some cases)

  • Password Management


    To change your password:

    1. Enter your current password

    2. Enter your new password

    3. Confirm the new password

    4. Click "Change Password"


    Password requirements:

  • Minimum 8 characters
  • Must include uppercase and lowercase letters
  • Must include at least one number
  • Must include at least one special character

  • Email Verification


    If your email hasn't been verified:

  • Click **"Verify Email"**
  • Check your inbox for a verification link
  • Click the link to confirm your email

  • Account Deletion


    If you need to delete your account:

    1. Click "Request Delete Account"

    2. Read the warning about data loss

    3. Confirm your request

    4. An administrator will process the deletion


    > Warning: Account deletion is permanent. All your data, including ticket history, will be removed.


    ---


    13. Downloading Attachments & PDFs


    PDF Summaries


    Generate a professional PDF summary of any ticket:


    1. Open the ticket detail page

    2. Click the "PDF" or download icon button in the header

    3. The PDF will download to your device


    The PDF includes:

  • Company letterhead and branding
  • All ticket details (customer info, equipment, time entries)
  • Attached images (resized for print)
  • Signature (if signed)

  • File Attachments


    Download individual files attached to a ticket:


    1. Open the ticket detail page

    2. Scroll to the Attachments section

    3. Click on any file name to download it


    Download All Attachments


    Some tickets offer a "Download All" option to download all attachments as a single archive.


    ---


    14. Frequently Asked Questions


    I can't log in. What should I do?


    1. Check your email address — Make sure it matches what you registered with

    2. Try Magic Link — Click "Sign in with Magic Link" to avoid password issues

    3. Reset your password — Click "Forgot Password?" to get a reset link

    4. Account pending? — New accounts require admin approval (usually within 24 hours)

    5. Account locked? — After too many failed login attempts, your account is temporarily locked. Wait 15 minutes and try again.



  • Check your **spam/junk folder**
  • Make sure the email from Corejobtrack isn't being blocked by your email filters
  • Wait a minute — emails can take a short time to arrive
  • Try requesting a new magic link

  • What does "Pending Signature" mean?


    It means a service visit has been completed, but you haven't signed the service document yet. You should have received an email with a signature link, or you can sign through the ticket detail page.


    Can I create tickets for other companies?


    No. Your portal access is linked to your company's customer account. You can only view and create tickets for your own company.


    How do I contact support if the portal isn't working?


    Contact your service provider directly using the phone number or email listed in your portal or service documentation.


    Can I use the portal on my phone?


    Yes! The portal is fully responsive and works on all modern smartphones and tablets. Simply open your phone's web browser and navigate to the portal URL.


    ---


    Previous: Guide 3 — Launch & Verify | Next: Guide 5 — Employee Guide


    Corejobtrack Server — Employee Portal Guide


    > Audience: Employees (technicians, support staff, team leads) who use the admin portal for day-to-day work — creating tickets, managing tasks, and communicating with customers.


    ---


    Table of Contents


    1. Overview

    2. Logging In

    3. Dashboard

    4. Working with Service Tickets

    5. Working with Support Tickets

    6. Working with Tasks

    7. Customer Management

    8. Equipment Tracking

    9. Templates

    10. Attachments & Files

    11. Signatures

    12. Notifications

    13. Search

    14. Your Profile & Settings

    15. Using the Mobile App (API)


    ---


    1. Overview


    As an employee, you use the Admin Portal for daily work. Despite the name "admin," this portal is for all employees — both regular users and administrators. The features available to you depend on your role.


    What You Can Do


    FeatureRegular EmployeeAdmin
    View assigned tickets & tasksYesYes
    Create new tickets & tasksYesYes
    Edit tickets & tasksYesYes
    View all customersYesYes
    Manage customer contactsYesYes
    Upload attachmentsYesYes
    Capture signaturesYesYes
    Generate PDF summariesYesYes
    Approve new customer registrationsNoYes
    Manage employee accountsNoYes
    Access server administrationNoYes
    View server logsNoYes
    Manage trash/deleted itemsNoYes

    Accessing the Portal


    Navigate to:

    
    https://tasks.yourcompany.com/portal/admin/login
    

    Or use the unified login at:

    
    https://tasks.yourcompany.com/login
    

    Employee credentials are automatically routed to the admin portal.


    ---


    2. Logging In


    Username & Password


    1. Enter your username or email address

    2. Enter your password

    3. Optionally check "Remember me" (stays logged in for 30 days)

    4. Click "Sign In"



    1. Click "Sign in with Magic Link"

    2. Enter your email address

    3. Check your email and click the link

    4. You're logged in — no password needed


    !Placeholder: Admin portal login page


    First-Time Login


    If an admin created your account, use the credentials they provided. You should change your password after first login:


    1. Click the Settings icon in the top navigation

    2. Go to Password section

    3. Enter your current password and set a new one


    ---


    3. Dashboard


    The dashboard is your home base. It shows all tickets and tasks at a glance.


    !Placeholder: Employee dashboard overview



    The top navigation includes:


    TabWhat It Shows
    **Dashboard**Main view with all tickets and tasks
    **Notifications**Your notification center
    **Customers**Customer directory
    **Vendors**Vendor directory
    **Contacts**Customer contact list
    **Equipment**Equipment inventory
    **Templates**Task and ticket templates
    **Admin Area**Server administration (admin role only)

    Dashboard Tables


    The dashboard displays three tables:


    #### Service Tickets


    ColumnDescription
    Ticket #Auto-generated number (click to open)
    TitleBrief description
    CustomerCustomer company name
    StatusOpen, In Progress, Completed, Archived
    AssignedWho's working on it
    CreatedWhen it was created

    #### Support Tickets


    ColumnDescription
    Ticket #Auto-generated number (click to open)
    TitleBrief description
    CustomerCustomer company name
    StatusCurrent status
    CreatedWhen it was created

    #### Tasks


    ColumnDescription
    Task #Auto-generated task code
    TitleTask description
    StatusOpen, In Progress, Completed
    AssignedWho's responsible
    Due DateDeadline

    Creating New Items


    Click the "New" button to create:


  • **Service Ticket** — Schedule a service visit
  • **Support Ticket** — Open a support case
  • **Task from Template** — Create a task using a pre-built template
  • **Blank Task** — Create a task from scratch

  • Pending Customer Approvals


    If customers have registered and are awaiting approval, you'll see a Pending Approvals section (admin only) with:

  • Customer name, email, and company
  • **Approve** and **Deny** buttons

  • ---


    4. Working with Service Tickets


    Service tickets track on-site service visits — equipment repairs, installations, and maintenance.


    Creating a Service Ticket


    1. Click "New" > "Service Ticket"

    2. Fill in the required fields:

  • **Customer** — Select or type the customer name
  • **Title** — Brief summary
  • **Description** — Detailed problem description
  • 3. Optional fields:

  • **Equipment** — Select affected equipment
  • **Problem Description** — Per-equipment problem details
  • **Urgency** — Low, Medium, High, Critical
  • **Assigned To** — Technician(s) responsible
  • **Dispatch Type** — Emergency, Scheduled, PM
  • **Customer PO** — Purchase order number
  • 4. Click "Create Ticket"


    Viewing a Service Ticket


    Click any ticket number to open the detail view:


    !Placeholder: Service ticket detail view


    #### Key Sections


    Customer & Contact

  • Customer name and address
  • Contact person details

  • Equipment

  • Table of equipment involved
  • Make, model, serial number
  • Problem description per item

  • Time Entries

    Track time spent on the service visit:

  • Start and stop times for each session
  • Duration (in hours)
  • Number of technicians
  • Time type (regular, overtime, travel)
  • Lunch time deducted
  • Services performed during each session

  • Services Performed

    Free-text field summarizing the work done.


    Settings Recorded / Tasks Completed

    Checklists of settings that were documented and tasks that were performed.


    Attachments

    Photos, videos, and documents uploaded during the service visit.


    Signature

    Customer signature captured after service completion.


    Editing a Service Ticket


    1. Click the "Edit" button on the ticket detail page

    2. Modify any fields

    3. Click "Save"


    Changes are recorded in the ticket's Change Log (click "View History" to see all changes).


    Service Ticket Status Flow


    
    Pending → Open → In Progress → Completed → Archived
                                        ↓
                                      Trash
    

  • **Complete** — Click the "Complete" button when work is finished
  • **Archive** — Move completed tickets to archive for long-term storage
  • **Trash** — Soft-delete (admin can restore)

  • Generating a PDF Summary


    Click the PDF icon to download a professional summary including:

  • Company letterhead
  • All ticket details
  • Equipment list
  • Time entries
  • Attached images
  • Signature (if captured)

  • ---


    5. Working with Support Tickets


    Support tickets track remote support cases — phone calls, emails, and remote sessions.


    Creating a Support Ticket


    1. Click "New" > "Support Ticket"

    2. Fill in:

  • **Customer** — Company name
  • **Title** — Issue summary
  • **Description** — Full details
  • 3. Optional fields:

  • **Vendor Ticket Number** — If escalated to a vendor
  • **Ticket Type** — Category of support
  • **Urgency** — Priority level
  • **Assigned To** — Support agent(s)
  • 4. Click "Create Ticket"


    Communication Log


    Support tickets include a Communication Log — a conversation thread between your team and the customer.


    #### Sending Messages


    1. Open the support ticket

    2. Scroll to the Communication Log

    3. Type your message

    4. Click "Send"


    #### Features


  • **@Mentions** — Type `@` to mention a team member. They'll receive a notification.
  • **Typing Indicators** — See when others are typing
  • **Read Receipts** — Track who has seen each message
  • **Time Tracking** — Optionally log time spent per message

  • #### Inline Attachments


    Upload files directly into the communication thread:

    1. Click the attachment icon next to the message box

    2. Select files to upload

    3. The attachment appears in the conversation


    Support Ticket Status Flow


    
    Pending → Open → In Progress → Completed → Archived
                                        ↓
                                      Trash
    

    ---


    6. Working with Tasks


    Tasks are internal work items — things your team needs to do that aren't directly tied to a customer visit.


    Creating a Task


    #### From a Template


    1. Click "New" > "Task from Template"

    2. Select a template from the list

    3. The task is pre-filled with the template's title, description, steps, and assignments

    4. Modify as needed

    5. Click "Create"


    #### Blank Task


    1. Click "New" > "Blank Task"

    2. Fill in:

  • **Title** — What needs to be done
  • **Description** — Details and context
  • **Due Date** — Deadline
  • **Urgency** — Priority level
  • **Assigned To** — Who's responsible
  • **Task Type** — Category (Installation, Repair, Maintenance, etc.)
  • 3. Click "Create"


    Task Checklist (Steps)


    Tasks can have a checklist of steps:


    !Placeholder: Task with checklist steps


  • **Add steps** — Click "Add Step" and enter a description
  • **Complete steps** — Check the checkbox next to each step
  • **Reorder steps** — Drag steps to rearrange
  • **Delete steps** — Click the delete icon on a step

  • Each completed step records who completed it and when.


    Task Notes


    Add notes and comments to tasks:

    1. Scroll to the Notes section

    2. Type your note

    3. Click "Add Note"


    Notes are timestamped with the author's name.


    Cloning a Task


    Click the "Clone" button to create a copy of an existing task with the same details and steps.


    ---


    7. Customer Management


    Customer Directory


    Navigate to Customers in the top menu to see all customers:


    !Placeholder: Customer list view


  • Search by company name, city, or customer code
  • Click a customer to view their full profile

  • Customer Detail Page


    Each customer page shows:


  • **Company Information** — Name, address, phone, email
  • **Contacts** — People at the company with their contact details
  • **Equipment** — Equipment registered to this customer
  • **Tickets** — All service and support tickets for this customer

  • Adding a New Customer


    1. Click "New Customer"

    2. Enter company name, address, and contact details

    3. Click "Save"


    Managing Contacts


    Contacts are people at a customer's company. Each customer can have multiple contacts:


  • **Add Contact** — Click "Add Contact" on the customer detail page
  • **Edit Contact** — Click the edit icon
  • **Delete Contact** — Click the delete icon
  • **Primary Contact** — Mark one contact as primary

  • #### Contact Actions


    For each contact, you can:

  • **Send Password Reset** — Sends a reset link to the contact's email
  • **Send Magic Link** — Sends a login link for portal access
  • **Send Verification Email** — Sends an email verification link

  • ---


    8. Equipment Tracking


    Equipment Directory


    Navigate to Equipment in the top menu to see all equipment across all customers.


    Equipment on Customer Page


    Each customer's equipment is listed on their detail page:

  • Make, Model, Serial Number
  • Current Count
  • Notes

  • Adding Equipment


    1. Go to the customer's detail page

    2. Click "Add Equipment"

    3. Enter: Make, Model, Serial Number, Count, Notes

    4. Click "Save"


    Count Tracking


    Track equipment counts over time:

    1. Open the equipment detail page

    2. Click "Add Count"

    3. Enter the current count and optional notes

    4. The count history shows all changes with who recorded them and when


    ---


    9. Templates


    Templates pre-define tasks with steps, assignments, and default values — saving time when creating repetitive tasks.


    Viewing Templates


    Navigate to Templates to see all available templates.


    Creating a Template


    1. Click "New Template"

    2. Define:

  • **Name** — Template name (e.g., "Quarterly PM")
  • **Title** — Default task title
  • **Description** — Default task description
  • **Steps** — Checklist items with order
  • **Task Type** — Category
  • **Color** — Visual indicator
  • **Due Date Offset** — Days from creation to due date
  • **Default Assignees** — Users or teams
  • 3. Click "Save"


    Using a Template


    When creating a new task, select "Task from Template" and choose your template. The task is pre-filled with all the template's defaults.


    ---


    10. Attachments & Files


    Uploading Files


    You can attach files to any ticket or task:


    1. Open the ticket or task

    2. Find the Attachments section

    3. Click "Upload" or drag and drop files

    4. Files are uploaded immediately


    Supported File Types


    CategoryExtensions
    DocumentsPDF, DOC, DOCX, XLS, XLSX, CSV, TXT, RTF, PPT, PPTX
    ImagesPNG, JPG, JPEG, GIF, BMP, TIFF, WebP, SVG, HEIC
    VideoMP4, MOV, AVI
    AudioMP3, WAV
    ArchivesZIP, RAR, 7Z
    ApplePages, Numbers, Keynote

    File Size Limits


  • **Maximum file size:** 50 MB per file (configurable)
  • **Profile pictures:** 5 MB maximum

  • Viewing & Downloading


  • **Images** — Displayed inline in a media gallery
  • **Videos** — Playable inline
  • **Documents** — Click to download

  • ---


    11. Signatures


    Capturing On-Site Signatures


    When completing a service visit, capture the customer's signature:


    1. Open the service ticket

    2. Click "Request Signature" or present the signature screen

    3. The customer draws their signature on the canvas

    4. They enter their printed name

    5. Click "Submit"


    Requesting a Post-Visit Signature


    If the customer wasn't available during the visit:


    1. Open the service ticket

    2. Click "Request Signature"

    3. An email is sent to the customer with a secure link

    4. The customer signs online at their convenience


    Declining a Signature


    If a customer declines to sign:

    1. Click "Decline Signature"

    2. Select a reason:

  • Contact not around
  • Contact refused to sign
  • Contact prefers to sign online
  • Other
  • 3. The ticket records the decline with the reason


    Automatic Reminders


    Corejobtrack can automatically send reminder emails for unsigned service tickets. These are configured by an administrator.


    ---


    12. Notifications


    In-App Notifications


    Click the bell icon in the navigation bar to see notifications:


  • **Unread count** — The badge shows how many unread notifications you have
  • **Latest notifications** — Quick view of recent activity
  • **View All** — Full notification history

  • Types of Notifications


    EventWho Gets Notified
    Ticket createdAssigned users and teams
    Ticket status changedCreator, assigned users
    Message receivedTicket participants
    @MentionedThe mentioned user
    Ticket assigned to youYou
    Customer registeredAdmins
    Signature capturedTicket creator

    Managing Notifications


  • **Mark as Read** — Click a notification
  • **Mark All as Read** — Clear all unread indicators
  • **Delete** — Remove individual notifications

  • Push Notifications (Mobile)


    If you use the mobile app, register your device for push notifications. You'll receive alerts even when the app isn't open.


    ---




    Corejobtrack provides a powerful search across all tickets and tasks:


  • **Keyword Search** — Finds matches in titles, descriptions, customer names, and more
  • **Natural Language Search** — (If AI search is enabled) Ask questions like "copier jam tickets from last week"

  • Search from the API:

    
    GET /search?q=paper+jam&entity_types=service_ticket,support_ticket
    


    Each entity type has its own search endpoint:


  • **Tasks:** `GET /tasks/search/{query}`
  • **Customers:** `GET /customers/search?query=...`
  • **Vendors:** `GET /vendors/search?query=...`

  • Ticket Lookup by Number


    Look up any ticket by its auto-generated number:

    
    GET /ticket-number/456789
    

    ---


    14. Your Profile & Settings


    Accessing Settings


    Click the gear icon or Settings in the navigation.


    Profile Information


    Update your personal details:

  • First Name, Last Name, Nickname
  • Email
  • Phone
  • Team assignment

  • Profile Picture


  • Upload a profile picture (PNG, JPG, GIF, WebP — max 5 MB)
  • Your picture appears in the navigation and in communication logs

  • Change Password


    1. Enter your current password

    2. Enter and confirm your new password

    3. Click "Change Password"


    Chat Color


    Set a custom color for your name in communication logs. This helps identify messages at a glance.


    ---


    15. Using the Mobile App (API)


    The Corejobtrack mobile app connects via the same REST API as the portal. Key operations:


    Authentication


    
    POST /token
    

    Returns an access token for subsequent requests.


    Viewing Your Assignments


    
    GET /tasks/       — Your visible tasks
    GET /service-tickets/  — Service tickets
    GET /support-tickets/  — Support tickets
    

    Managing Notifications


    
    GET /notifications             — Your notifications
    POST /notifications/{id}/read  — Mark as read
    

    Device Registration (Push Notifications)


    
    POST /devices/register
    

    Register your device token to receive push notifications.


    For complete API documentation, see the API Endpoints Reference.


    ---


    Previous: Guide 4 — Customer Portal | Next: Guide 6 — Admin Guide


    Corejobtrack Server — Admin Guide


    > Audience: Administrators who manage the Corejobtrack system — user accounts, server configuration, security, and system maintenance.


    ---


    Table of Contents


    1. Admin Role Overview

    2. Accessing the Admin Area

    3. User Management

    4. Customer Registration Approvals

    5. Server Administration

    6. SSL Certificate Management

    7. Email Service Management

    8. Push Notification (APNs) Management

    9. Database Monitoring

    10. Embedding / AI Search Management

    11. SMB Hot Folder Configuration

    12. Trash & Recovery

    13. Log Management

    14. System Settings

    15. Deployment & Updates

    16. Security Configuration


    ---


    1. Admin Role Overview


    Admin users have full access to all Corejobtrack features plus system administration capabilities. Key admin-only functions:


    FunctionDescription
    User ManagementCreate, edit, delete employee accounts
    Registration ApprovalsApprove/deny customer registrations
    Server AdministrationRestart, deploy, view logs
    SSL ManagementView/renew SSL certificates
    Email ConfigurationMonitor email service status
    APNs ConfigurationConfigure push notifications
    Database MonitoringView schema status, pool stats
    AI/Search ConfigurationManage embedding service
    Trash ManagementRestore/permanently delete items
    System SettingsConfigure defaults, dropdown choices

    Becoming an Admin


    Admins are assigned the admin role in one of two ways:


    1. Database update (first admin):

    
       UPDATE users SET role = 'admin', is_admin = TRUE WHERE username = 'your_username';
    

    2. Admin promotes another user (subsequent admins):

    
       curl -X PUT https://server:8443/users/USER_ID \
         -H "Authorization: Bearer ADMIN_TOKEN" \
         -H "Content-Type: application/json" \
         -d '{"role": "admin"}'
    

    ---


    2. Accessing the Admin Area


    Via Portal


    1. Log into the admin portal

    2. Click "Admin Area" in the navigation bar (visible only to admins)


    !Placeholder: Admin Area dashboard


    The Admin Area provides a visual interface for:

  • Database status
  • Server information
  • SSL certificate management
  • Ticket defaults
  • AI/Embedding features
  • Email configuration
  • Signature settings
  • Deploy/Restart controls
  • User management
  • Log viewer
  • Trash recovery

  • Via API


    All admin endpoints are prefixed with /admin/ and require the require_admin dependency.


    ---


    3. User Management


    Viewing All Users


    Portal: Navigate to Admin Area > Users


    API:

    
    curl https://server:8443/users/ \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Returns all users with full details: username, role, email, team, status.


    Creating a New Employee


    Portal: Click "New User" in the Admin Area > Users section


    API:

    
    curl -X POST https://server:8443/users/ \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "username": "jdoe",
        "password": "SecurePass123!",
        "full_name": "John Doe",
        "first_name": "John",
        "last_name": "Doe",
        "email": "[email protected]",
        "phone": "(555) 234-5678",
        "team": "Service"
      }'
    

    Editing a User


    API:

    
    curl -X PUT https://server:8443/users/USER_ID \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "role": "admin",
        "team": "Management",
        "new_password": "NewSecurePass!"
      }'
    

    Available fields to update:

  • `username` — Change username
  • `full_name`, `first_name`, `last_name`, `nick_name` — Name fields
  • `email`, `phone` — Contact info
  • `team` — Team assignment
  • `role` — `pending`, `user`, or `admin`
  • `new_password` — Reset password
  • `hide_from_time_entries` — Hide from time entry dropdowns
  • `hidden_from_sharing` — Hide from assignment dropdowns

  • Approving Pending Users


    When employees self-register via POST /register, their accounts start with role: "pending" and cannot access anything until approved:


    
    curl -X PUT https://server:8443/users/USER_ID \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"role": "user"}'
    

    Deleting a User


    
    curl -X DELETE https://server:8443/users/USER_ID \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    > Note: Deleting a user reassigns all items created by that user to the admin who performed the deletion.


    User Roles Summary


    RoleCan LoginAPI AccessPortal AccessAdmin Area
    `pending`NoNoNoNo
    `user`YesYesYesNo
    `admin`YesYesYesYes

    ---


    4. Customer Registration Approvals


    When customers register through the portal, they appear in the Pending Approvals section on the admin dashboard.


    From the Portal


    1. Open the admin dashboard

    2. Scroll to Pending Customer Approvals

    3. Review the customer's name, email, and company

    4. Click "Approve" to grant access, or "Deny" to reject


    !Placeholder: Pending approvals section


    What Happens on Approval


  • The customer receives an **approval email**
  • Their account becomes active
  • They can log into the customer portal

  • What Happens on Denial


  • The customer receives a **rejection email**
  • Their account is removed
  • They can attempt to register again

  • Managing Contacts


    From the Admin Portal, you can also:


  • **Send Password Reset** — To any customer contact
  • **Send Magic Link** — Login link without password
  • **Send Verification Email** — Email address verification

  • Navigate to Contacts or the customer detail page to access these actions.


    ---


    5. Server Administration


    Server Restart / Deploy


    The admin portal and API provide remote deployment capabilities.


    #### Via Portal


    1. Navigate to Admin Area

    2. Click "Restart Server"

    3. Confirm in the dialog

    4. Wait for the server to restart (you'll briefly lose connection)


    #### Via API


    
    curl -X POST https://server:8443/admin/restart \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    What Happens:

    1. The restart_services.sh script is triggered

    2. Latest code is pulled from git

    3. Dependencies are updated

    4. Systemd services are restarted

    5. Deployment report is emailed to ADMIN_EMAIL


    Checking Deploy Status


    After a restart, check the deployment result:


    
    curl https://server:8443/admin/deploy-status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Response:

    
    {
      "last_deploy": {
        "status": "success",
        "version_before": "0.980",
        "version_after": "0.981",
        "branch": "main",
        "commit_count": 3,
        "commits": [
          {"hash": "abc1234", "message": "Fix login bug", "author": "dev"}
        ],
        "files_changed": "5 files changed",
        "initiated_at": "2026-03-01T10:00:00Z",
        "completed_at": "2026-03-01T10:01:30Z",
        "admin_username": "admin"
      }
    }
    

    ---


    6. SSL Certificate Management


    View Certificate Info


    
    curl https://server:8443/admin/ssl/cert-info \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Response:

    
    {
      "exists": true,
      "valid_from": "2026-01-01T00:00:00+00:00",
      "valid_until": "2027-01-01T00:00:00+00:00",
      "days_remaining": 305,
      "expires_soon": false,
      "expired": false,
      "path": "/opt/taskapp/app/server_cert.pem"
    }
    

    Key fields:

  • `days_remaining` — Days until expiration
  • `expires_soon` — True if less than 30 days remain
  • `expired` — True if the certificate has expired

  • Renew Certificate


    
    curl -X POST https://server:8443/admin/ssl/renew-cert \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    This runs the generate_cert.py script and restarts the SSL service.


    > Important: Set up monitoring for expires_soon to avoid service interruptions.


    ---


    7. Email Service Management


    Check Email Status


    
    curl https://server:8443/email/status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    View Email Log


    Portal: Admin Area > Email Log


    API:

    
    # Paginated email log
    curl "https://server:8443/email/log?limit=50&offset=0" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Filter by status
    curl "https://server:8443/email/log?status=failed" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Get stats
    curl https://server:8443/email/log/stats \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Email Dev Mode


    When SMTP_DEV_MODE=true:

  • ALL emails are redirected to `SMTP_DEV_REDIRECT_ADDRESS`
  • The original recipient is shown in the subject line
  • This is for testing — **set to false for production**

  • Send a Test Email


    
    curl -X POST https://server:8443/email/send \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "to": "[email protected]",
        "subject": "Corejobtrack Email Test",
        "body_text": "Test email from Corejobtrack",
        "body_html": "<h1>Test</h1><p>Email is working.</p>"
      }'
    

    ---


    8. Push Notification (APNs) Management


    Check APNs Status


    
    curl https://server:8443/admin/apns/status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Response:

    
    {
      "configured": true,
      "sandbox_mode": false,
      "bundle_id": "com.company.corejobtrack",
      "key_id_set": true,
      "team_id_set": true,
      "key_path_set": true,
      "httpx_available": true,
      "active_tokens": 15,
      "users_with_tokens": 8,
      "status": {
        "configured": true,
        "last_push_at": "2026-03-01T10:00:00Z",
        "pushes_sent": 150,
        "pushes_failed": 2
      }
    }
    

    Configure APNs


    
    curl -X POST https://server:8443/admin/apns/config \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "key_id": "ABC1234567",
        "team_id": "DEF1234567",
        "bundle_id": "com.company.corejobtrack",
        "use_sandbox": false,
        "key_content": "BASE64_ENCODED_P8_KEY"
      }'
    

    The .p8 key file can be uploaded as base64-encoded content. The server saves it to disk.


    Send a Test Push


    
    curl -X POST https://server:8443/admin/apns/test \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "user_id": 1,
        "title": "Test Notification",
        "body": "This is a test push notification"
      }'
    

    If user_id is omitted, the notification is sent to the admin's own devices.


    ---


    9. Database Monitoring


    Health Status


    
    # Basic health
    curl https://server:8443/dbhealth
    
    # Detailed status with recovery tracking
    curl https://server:8443/db-status
    
    # Connection pool statistics (admin only)
    curl https://server:8443/db-pool-stats \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Schema Status


    Check which optional columns exist and get SQL to fix missing ones:


    
    curl https://server:8443/admin/db/schema-status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    If missing_sql contains entries, you can either:

  • Run the SQL statements manually
  • Restart the server (auto-migration will apply them)

  • Pool Statistics


    
    {
      "available": 5,     // Idle connections waiting
      "in_use": 2,        // Connections currently serving requests
      "max": 20,          // Maximum pool size
      "min": 2            // Minimum connections to maintain
    }
    

    Warning signs:

  • `available: 0` with `in_use` near `max` — Pool exhaustion risk
  • Frequent 503 errors — Increase `DB_POOL_MAX_CONNECTIONS`

  • ---


    10. Embedding / AI Search Management


    Corejobtrack supports AI-powered natural language search using OpenAI embeddings.


    Check Status


    
    curl https://server:8443/admin/embedding/status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Response:

    
    {
      "enabled": true,
      "key_configured": true,
      "key_hint": "...a1b2",
      "model": "text-embedding-3-small",
      "dimensions": 1536,
      "pgvector_available": true,
      "usage": {
        "total_tokens": 50000,
        "total_cost": 0.25,
        "total_embeddings": 500,
        "budget_cap": 5.0
      }
    }
    

    Enable/Disable


    
    curl -X POST https://server:8443/admin/embedding/toggle \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"enabled": true}'
    

    Set API Key


    
    curl -X POST https://server:8443/admin/embedding/api-key \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"api_key": "sk-your-openai-key"}'
    

    Test API Key


    
    curl -X POST https://server:8443/admin/embedding/test-key \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Manage Budget


    
    # Set budget cap
    curl -X PUT https://server:8443/admin/embedding/budget \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"budget_cap": 10.0}'
    
    # Reset usage counters
    curl -X POST https://server:8443/admin/embedding/reset-usage \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Backfill Existing Data


    When enabling embeddings for the first time, run a backfill to generate embeddings for existing data:


    
    # Check backfill status
    curl https://server:8443/admin/embedding/backfill-status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Start backfill manually
    curl -X POST https://server:8443/admin/embedding/backfill-start \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    ---


    11. SMB Hot Folder Configuration


    SMB Watch monitors a shared folder (SMB network share or local directory) for JSON files and automatically creates tasks or tickets.


    Check Status


    
    curl https://server:8443/admin/smb-watch/status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Configure


    
    curl -X POST https://server:8443/admin/smb-watch/config \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "enabled": true,
        "path": "//server/share/hotfolder",
        "username": "smb_user",
        "password": "smb_password",
        "file_type": "json",
        "interval_seconds": 30
      }'
    

    FieldDescription
    `enabled`Toggle monitoring on/off
    `path`UNC path (`//server/share/`) or local path (`/path/to/folder`)
    `username`SMB authentication username
    `password`SMB authentication password
    `file_type`File format to process (currently only `json`)
    `interval_seconds`How often to check for new files (minimum: 5)

    How It Works


    1. JSON files placed in the hot folder are detected

    2. The file content is parsed and validated

    3. A task, service ticket, or support ticket is created automatically

    4. Processed files are moved to a processed/ subdirectory

    5. Failed files are moved to a failed/ subdirectory


    > Requirement: The smbprotocol / smbclient Python package must be installed for SMB (network) paths. Local paths work without it.


    ---


    12. Trash & Recovery


    Deleted items are soft-deleted (moved to "trash" status) and can be recovered by admins.


    View Trash


    Portal: Admin Area > Trash


    API:

    
    curl https://server:8443/admin/trash \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Filter by type
    curl "https://server:8443/admin/trash?item_type=service_ticket" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Restore an Item


    
    curl -X POST https://server:8443/admin/trash/ITEM_ID/restore \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    The item is restored to its previous status (typically "open").


    Permanently Delete


    
    curl -X DELETE https://server:8443/admin/trash/ITEM_ID \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    > Warning: Permanent deletion cannot be undone.


    Empty All Trash


    
    curl -X POST https://server:8443/admin/trash/empty \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    > Warning: This permanently deletes ALL items in trash.


    ---


    13. Log Management


    View Server Logs


    Portal: Admin Area > Server Log


    API:

    
    # Last 200 lines
    curl "https://server:8443/logs?lines=200" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Export Logs


    
    curl "https://server:8443/logs/export?log_type=server&date_from=2026-02-01&date_to=2026-03-01" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Parameters:

  • `log_type` — `server` or `client`
  • `date_from` — Start date (YYYY-MM-DD)
  • `date_to` — End date (YYYY-MM-DD)

  • Email Log


    View all sent emails and their delivery status:


    Portal: Admin Area > Email Log


    API:

    
    curl "https://server:8443/email/log?limit=50&status=failed" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Client Logs


    Client applications submit logs to the server for centralized tracking:


    
    # View submitted client logs in the export
    curl "https://server:8443/logs/export?log_type=client&date_from=2026-02-28" \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    ---


    14. System Settings


    Ticket Color Defaults


    Set the default colors for new tickets:


    
    # View defaults
    curl https://server:8443/settings/ticket-defaults \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Update defaults
    curl -X PUT https://server:8443/settings/ticket-defaults \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "service_ticket": "#4A90D9",
        "support_ticket": "#E67E22"
      }'
    


    Configure the dropdown options for various fields:


    
    # Get choices for a field
    curl https://server:8443/settings/dropdown-choices/dispatch_type \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Set choices
    curl -X PUT https://server:8443/settings/dropdown-choices/dispatch_type \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '[
        {"value": "Emergency", "label": "Emergency"},
        {"value": "Scheduled", "label": "Scheduled"},
        {"value": "PM", "label": "Preventive Maintenance"}
      ]'
    

    Task Types


    Manage the available task type categories:


    
    # List task types
    curl https://server:8443/task_types/ \
      -H "Authorization: Bearer ADMIN_TOKEN"
    
    # Add a task type
    curl -X POST https://server:8443/task_types/ \
      -H "Authorization: Bearer ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "Installation"}'
    
    # Delete a task type
    curl -X DELETE https://server:8443/task_types/Installation \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Signature Settings


    Configure post-visit signature reminders in taskapp.env:


    
    ENABLE_SIGNATURE_REMINDERS=true
    SIGNATURE_TOKEN_EXPIRY_DAYS=7
    

    Trigger reminders manually:


    
    curl -X POST https://server:8443/admin/send-signature-reminders \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    ---


    15. Deployment & Updates


    Automated Deployment


    Corejobtrack supports one-click deployment from the admin portal or API:


    
    curl -X POST https://server:8443/admin/restart \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Deployment Flow


    
    1. Admin triggers restart
    2. Metadata saved (who, when, current version)
    3. restart_services.sh executed:
       a. git pull (fetch latest code)
       b. pip install (update dependencies)
       c. systemctl restart (restart services)
    4. Server starts with new code
    5. ensure_schema() runs (auto-migration)
    6. Deployment report emailed to ADMIN_EMAIL
    7. Client can query /admin/deploy-status
    

    Version Tracking


    
    # Current version
    curl https://server:8443/version
    
    # Last deployment details
    curl https://server:8443/admin/deploy-status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    ---


    16. Security Configuration


    Rate Limiting


    Configured via environment variables:


    VariableDefaultDescription
    `RATE_LIMIT_ENABLED``true`Enable/disable rate limiting
    `RATE_LIMIT_LOGIN_MAX``5`Max login attempts per window
    `RATE_LIMIT_LOGIN_WINDOW``300`Window in seconds (5 min)
    `RATE_LIMIT_REGISTER_MAX``3`Max registrations per window
    `RATE_LIMIT_REGISTER_WINDOW``3600`Window in seconds (1 hour)
    `RATE_LIMIT_GENERAL_MAX``100`Max general requests per window
    `RATE_LIMIT_GENERAL_WINDOW``60`Window in seconds (1 min)

    Account Lockout


    VariableDefaultDescription
    `ACCOUNT_LOCKOUT_ENABLED``true`Enable/disable lockout
    `ACCOUNT_LOCKOUT_THRESHOLD``10`Failures before lockout
    `ACCOUNT_LOCKOUT_DURATION``900`Lockout duration (15 min)

    CORS Policy


    VariableDefaultDescription
    `CORS_ORIGINS``*`Allowed origins (comma-separated)
    `CORS_ALLOW_CREDENTIALS``true`Allow cookies/auth headers

    > Warning: Using CORS_ORIGINS=* with CORS_ALLOW_CREDENTIALS=true is insecure. Set specific origins in production.


    Security Status


    View all security settings at a glance:


    
    curl https://server:8443/security-status \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Password Policy


    VariableDefaultDescription
    `MIN_PASSWORD_LENGTH``8`Minimum password length
    `REQUIRE_PASSWORD_COMPLEXITY``true`Require uppercase, lowercase, numbers, symbols

    ---


    Previous: Guide 5 — Employee Guide | Next: Guide 7 — API Endpoints


    Corejobtrack Server — API Endpoints Reference


    > Audience: Developers building client applications, integrations, or automations against the Corejobtrack REST API.


    ---


    Table of Contents


    1. API Overview

    2. Authentication

    3. Public Endpoints (No Auth Required)

    4. Employee Endpoints (JWT Required)

    5. Admin Endpoints (Admin Role Required)

    6. Customer Endpoints (Customer JWT Required)

    7. Portal HTML Endpoints

    8. Error Handling

    9. Rate Limiting

    10. Pagination


    ---


    1. API Overview


    Base URL


    
    https://your-server:8443
    

    Content Type


    All request and response bodies use JSON:


    
    Content-Type: application/json
    

    Exceptions:

  • `POST /token` — Uses `application/x-www-form-urlencoded`
  • File uploads — Use `multipart/form-data`

  • Authentication Header


    
    Authorization: Bearer YOUR_ACCESS_TOKEN
    

    Response Format


    Success:

    
    {"ok": true, "id": 123, "status": "open"}
    

    Error:

    
    {"detail": "Error message description"}
    

    Server Error (500):

    
    {"detail": "Internal server error", "error_id": "a1b2c3d4"}
    

    The error_id is a hex string that can be used to correlate with server logs.


    Interactive API Docs


    FastAPI provides automatic interactive documentation:


  • **Swagger UI:** `https://your-server:8443/docs`
  • **ReDoc:** `https://your-server:8443/redoc`

  • ---


    2. Authentication


    Employee Login


    
    POST /token
    Content-Type: application/x-www-form-urlencoded
    
    username=admin&password=SecurePass123
    

    Response:

    
    {
      "access_token": "eyJhbGciOiJIUzI1NiIs...",
      "token_type": "bearer"
    }
    

    Token Refresh


    
    POST /token/refresh
    Authorization: Bearer YOUR_TOKEN
    

    Returns a new access token with refreshed expiration.


    Token Expiration


  • Default: 720 minutes (12 hours), configurable via `ACCESS_TOKEN_EXPIRE_MINUTES`
  • Expired tokens return `401 {"detail": "Token has expired"}`

  • Employee Registration


    
    POST /register
    Content-Type: application/json
    
    {
      "username": "jdoe",
      "password": "SecurePass123!",
      "full_name": "John Doe",
      "first_name": "John",
      "last_name": "Doe",
      "email": "[email protected]",
      "phone": "(555) 234-5678",
      "team": "Service"
    }
    

    New accounts start with role: "pending" — an admin must approve.


    ---


    3. Public Endpoints (No Auth Required)


    These endpoints are accessible without any authentication.


    Health & Status


    MethodEndpointDescription
    `GET``/health`Basic health check — returns `{"ok": true}`
    `GET``/version`Server version — returns `{"version": "0.981"}`
    `GET``/dbhealth`Database connectivity check
    `GET``/db-status`Detailed DB status with recovery tracking

    Authentication


    MethodEndpointDescription
    `POST``/register`Employee self-registration
    `POST``/token`Employee login (returns JWT)

    Customer Authentication


    MethodEndpointDescription
    `POST``/customer/api/register`Customer registration (join existing company)
    `POST``/customer/api/login`Customer login
    `POST``/customer/api/magic-link`Request magic link email
    `POST``/customer/api/verify-magic-link`Verify magic link token
    `POST``/customer/api/password-reset`Request password reset

    Feedback


    MethodEndpointDescription
    `POST``/feedback/`Submit feedback or bug report (auth optional)

    ---


    4. Employee Endpoints (JWT Required)


    All endpoints in this section require Authorization: Bearer TOKEN with a valid employee JWT.


    Current User Profile


    MethodEndpointDescription
    `GET``/me`Get current user profile with teams
    `PUT``/me`Update profile (name, email, phone, chat_color)
    `POST``/me/delete-account`Request account deactivation
    `POST``/me/profile-picture`Upload profile picture
    `DELETE``/me/profile-picture`Delete profile picture
    `GET``/users/{user_id}/profile-picture`Get any user's profile picture
    `POST``/token/refresh`Refresh access token

    PUT /me Request Body:

    
    {
      "full_name": "John Doe",
      "first_name": "John",
      "last_name": "Doe",
      "nick_name": "JD",
      "email": "[email protected]",
      "phone": "(555) 234-5678",
      "team": "Service",
      "chat_color": "#FF5733",
      "current_password": "old_pass",
      "new_password": "new_pass"
    }
    

    User List


    MethodEndpointDescription
    `GET``/users/list`Public user list (for assignment dropdowns)

    ---


    Tasks


    MethodEndpointDescription
    `GET``/tasks/`List visible tasks (paginated)
    `GET``/tasks/{task_id}`Get single task with assignments
    `POST``/tasks/`Create new task
    `PATCH``/tasks/{task_id}`Update task fields
    `PUT``/tasks/{task_id}`Update task (PATCH alias)
    `DELETE``/tasks/{task_id}`Soft-delete task (→ trash)
    `POST``/tasks/{task_id}/pause`Pause task
    `POST``/tasks/{task_id}/resume`Resume task
    `POST``/tasks/{task_id}/archive`Archive task
    `POST``/tasks/{task_id}/complete`Complete task
    `GET``/tasks/{task_id}/changelog`Get change history
    `GET``/tasks/search/{query}`Full-text search tasks

    POST /tasks/ Request Body:

    
    {
      "title": "Replace drum unit",
      "description": "Customer reports streaking on prints",
      "status": "open",
      "urgency": "Medium",
      "visibility": "private",
      "task_type": "Repair",
      "color": "#4A90D9",
      "due_date": "2026-03-15",
      "assigned_to": 5,
      "assigned_user_ids": [5, 8],
      "assigned_teams": ["Service"],
      "customer_name": "Acme Corp",
      "customer_number": "CUST001",
      "customer_address_1": "123 Main St",
      "city": "Anytown",
      "state": "ST",
      "zip": "12345",
      "customer_contact_first_name": "Jane",
      "customer_contact_last_name": "Doe",
      "customer_phone": "(555) 123-4567",
      "customer_email": "[email protected]",
      "equipment": [
        {
          "make": "HP",
          "model": "LaserJet Pro",
          "serial": "ABC123",
          "count": 1,
          "problem": "Streaking"
        }
      ],
      "template_id": 3
    }
    

    Task Steps (Checklists)


    MethodEndpointDescription
    `GET``/tasks/{task_id}/steps/`List steps
    `POST``/tasks/{task_id}/steps/`Add step
    `PATCH``/tasks/{task_id}/steps/{step_id}`Update step

    POST Step:

    
    {
      "step_description": "Remove old drum unit",
      "is_completed": false,
      "order_num": 1
    }
    

    Task Notes


    MethodEndpointDescription
    `GET``/tasks/{task_id}/notes/`List notes
    `POST``/tasks/{task_id}/notes/`Add note
    `DELETE``/tasks/{task_id}/notes/{note_id}`Delete own note

    POST Note:

    
    {
      "note": "Called customer to schedule — available Thursday"
    }
    

    ---


    Service Tickets


    MethodEndpointDescription
    `GET``/service-tickets/`List visible service tickets
    `GET``/service-tickets/{ticket_id}`Get single ticket
    `POST``/service-tickets/`Create service ticket
    `PATCH``/service-tickets/{ticket_id}`Update ticket
    `DELETE``/service-tickets/{ticket_id}`Soft-delete (→ trash)
    `POST``/service-tickets/{ticket_id}/archive`Archive ticket
    `POST``/service-tickets/{ticket_id}/complete`Complete ticket
    `POST``/service-tickets/{ticket_id}/restore`Restore from archive
    `GET``/service-tickets/{ticket_id}/summary.pdf`Download PDF summary
    `GET``/service-tickets/{ticket_id}/changelog`Get change history

    POST /service-tickets/ Request Body:

    
    {
      "customer_name": "Acme Corp",
      "title": "PM Visit - Q1 2026",
      "description": "Quarterly preventive maintenance",
      "status": "Pending",
      "urgency": "Medium",
      "visibility": "private",
      "task_type": "Maintenance",
      "due_date": "2026-03-15",
      "assigned_user_ids": [5],
      "assigned_teams": ["Service"],
      "dispatch_type": "Scheduled",
      "dispatch_number": "D-2026-001",
      "customer_po": "PO-12345",
      "equipment": [
        {
          "make": "Konica Minolta",
          "model": "bizhub C300i",
          "serial": "A9K123456",
          "count": 1,
          "problem": "PM Due",
          "problem_description": "Quarterly maintenance scheduled"
        }
      ],
      "session_timestamps": [
        {
          "start_time": "2026-03-01T09:00:00",
          "stop_time": "2026-03-01T12:30:00",
          "time_amount": 3.5,
          "time_type": "regular",
          "num_techs": 1,
          "lunch": 0
        }
      ],
      "services_performed": "Cleaned components, replaced rollers, calibrated",
      "liftgate": false,
      "sprinter": true,
      "remote": false,
      "phone_call": false
    }
    

    Signatures


    MethodEndpointDescription
    `POST``/service-tickets/{ticket_id}/sign`Submit signature
    `POST``/service-tickets/{ticket_id}/decline-signature`Decline signature
    `POST``/service-tickets/{ticket_id}/request-signature`Send signature email

    POST /sign Request Body:

    
    {
      "signature_data": "data:image/png;base64,iVBOR...",
      "signature_name": "Jane Doe",
      "send_summary_email": true,
      "safety_covers_ok": true,
      "safety_covers_notes": null
    }
    

    POST /decline-signature Request Body:

    
    {
      "decline_reason": "Contact not around",
      "send_summary_email": false,
      "send_signature_request": true
    }
    

    Valid decline reasons: "Contact not around", "Contact refused to sign", "Contact prefers to sign online", "Other"


    ---


    Support Tickets


    MethodEndpointDescription
    `GET``/support-tickets/`List support tickets
    `GET``/support-tickets/{ticket_id}`Get single ticket
    `POST``/support-tickets/`Create support ticket
    `PATCH``/support-tickets/{ticket_id}`Update ticket
    `DELETE``/support-tickets/{ticket_id}`Soft-delete (→ trash)
    `POST``/support-tickets/{ticket_id}/archive`Archive
    `POST``/support-tickets/{ticket_id}/complete`Complete
    `POST``/support-tickets/{ticket_id}/restore`Restore from archive
    `POST``/support-tickets/{ticket_id}/communication`Add communication message
    `GET``/support-tickets/{ticket_id}/comm-readers`Get read receipts
    `GET``/support-tickets/{ticket_id}/summary.pdf`Download PDF
    `GET``/support-tickets/{ticket_id}/changelog`Get change history

    POST /communication Request Body:

    
    {
      "message": "I've escalated this to the vendor. Will follow up tomorrow.",
      "time_spent": 0.5,
      "is_customer": false,
      "author_user_id": null
    }
    

    ---


    Customers


    MethodEndpointDescription
    `GET``/customers/list`List customers (paginated)
    `GET``/customers/search`Search by name/contact_id/address
    `GET``/customers/{customer_id}`Get customer with contacts
    `PATCH``/customers/{customer_id}`Update customer
    `DELETE``/customers/{customer_id}`Delete customer (cascades)
    `POST``/customers/{customer_id}/contacts`Create contact
    `PATCH``/customer-contacts/{contact_id}`Update contact
    `DELETE``/customer-contacts/{contact_id}`Delete contact
    `POST``/customers/{customer_id}/contacts/reorder`Reorder contacts

    GET /customers/search Query Parameters:

  • `query` — Search term
  • `search_field` — Field to search (name, contact_id, city)
  • `limit`, `offset` — Pagination

  • ---


    Equipment


    MethodEndpointDescription
    `GET``/customers/{customer_id}/equipment`List equipment
    `POST``/customers/{customer_id}/equipment`Add equipment
    `PATCH``/customer-equipment/{equipment_id}`Update equipment
    `DELETE``/customer-equipment/{equipment_id}`Delete equipment
    `POST``/customer-equipment/{equipment_id}/counts`Log count
    `GET``/customer-equipment/{equipment_id}/counts`Get count history

    POST Equipment:

    
    {
      "make": "HP",
      "model": "LaserJet Pro M428",
      "serial": "CNBJ1234",
      "count": 1,
      "notes": "Located in 2nd floor copy room"
    }
    

    ---


    Vendors


    MethodEndpointDescription
    `GET``/vendors/list`List vendors (paginated)
    `GET``/vendors/search`Search vendors

    ---


    Attachments


    MethodEndpointDescription
    `POST``/attachments/{entity_type}/{entity_id}/upload`Upload file(s)
    `GET``/attachments/download/{attachment_id}`Download file
    `GET``/attachments/{entity_type}/{entity_id}`List attachments
    `DELETE``/attachments/{attachment_id}`Delete attachment

    Upload uses multipart/form-data:

    
    curl -X POST https://server:8443/attachments/service_ticket/123/upload \
      -H "Authorization: Bearer TOKEN" \
      -F "[email protected]"
    

    Entity types: task, service_ticket, support_ticket


    ---


    Notifications


    MethodEndpointDescription
    `GET``/notifications`Get notifications
    `POST``/notifications/{id}/read`Mark as read
    `POST``/notifications/read-all`Mark all as read
    `DELETE``/notifications/{id}`Delete notification

    GET /notifications Query Parameters:

  • `limit` — Max results
  • `offset` — Skip first N
  • `unread_only` — Boolean filter

  • ---


    Ticket Read Status


    MethodEndpointDescription
    `GET``/tickets/{type}/{id}/read-status`Get section read status
    `POST``/tickets/{type}/{id}/mark-read`Mark sections as read

    POST /mark-read:

    
    {
      "sections": ["details", "notes", "messages", "attachments"]
    }
    

    Ticket types: task, service_ticket, support_ticket


    ---


    Typing Indicators


    MethodEndpointDescription
    `POST``/tickets/{type}/{id}/typing`Record user typing
    `GET``/tickets/{type}/{id}/typing`Get who's typing

    ---


    Archived Items


    MethodEndpointDescription
    `GET``/archived/`List archived items
    `GET``/archived/{id}/`Get archived item
    `PATCH``/archived/{id}/`Update archived item
    `POST``/archived/{id}/restore`Restore to open
    `DELETE``/archived/{id}/`Move to trash

    ---



    MethodEndpointDescription
    `GET``/customers/{customer_id}/related-items`Tickets for customer
    `GET``/equipment/{equipment_id}/related-items`Tickets for equipment

    ---


    Templates


    MethodEndpointDescription
    `GET``/templates/`List templates
    `POST``/templates/`Create template
    `PUT``/templates/{template_id}`Update template
    `DELETE``/templates/{template_id}`Delete template

    POST Template:

    
    {
      "name": "Quarterly PM",
      "title": "PM Visit - {{customer}}",
      "description": "Quarterly preventive maintenance visit",
      "steps": [
        {"step_description": "Clean all components", "is_completed": false, "order_num": 1},
        {"step_description": "Replace rollers", "is_completed": false, "order_num": 2},
        {"step_description": "Run calibration", "is_completed": false, "order_num": 3}
      ],
      "color": "#27AE60",
      "task_type": "Maintenance",
      "due_date_offset": 7,
      "assigned_user_ids": [5],
      "assigned_teams": ["Service"]
    }
    

    ---


    Ticket Lookup


    MethodEndpointDescription
    `GET``/ticket-number/{number}`Find ticket by number

    ---



    MethodEndpointDescription
    `GET``/search`Natural language / keyword search

    Query Parameters:

  • `q` — Search query
  • `entity_types` — Comma-separated filter (task, service_ticket, support_ticket)
  • `limit` — Max results
  • `threshold` — Similarity threshold (for vector search)

  • ---


    Leads


    MethodEndpointDescription
    `GET``/leads`List leads (paginated)
    `GET``/leads/{lead_id}`Get single lead
    `POST``/leads`Create lead
    `PATCH``/leads/{lead_id}`Update lead
    `DELETE``/leads/{lead_id}`Delete lead

    ---


    Quotes


    MethodEndpointDescription
    `GET``/quotes`List quotes
    `GET``/quotes/{quote_id}`Get single quote
    `POST``/quotes`Create quote
    `PATCH``/quotes/{quote_id}`Update quote
    `DELETE``/quotes/{quote_id}`Delete quote

    ---


    Lease Rates


    MethodEndpointDescription
    `GET``/lease-rates`List lease rates
    `POST``/lease-rates`Create lease rate
    `PATCH``/lease-rates/{id}`Update lease rate
    `DELETE``/lease-rates/{id}`Delete lease rate

    ---


    Device Tokens (Push Notifications)


    MethodEndpointDescription
    `POST``/devices/register`Register device for push
    `DELETE``/devices/{token}`Unregister device
    `GET``/devices`List registered devices

    POST /devices/register:

    
    {
      "token": "device_token_from_apns",
      "platform": "ios",
      "device_name": "iPhone 15 Pro",
      "app_version": "2.1.0"
    }
    

    ---


    Settings


    MethodEndpointDescription
    `GET``/settings/ticket-defaults`Get ticket color defaults
    `GET``/settings/dropdown-choices/{field}`Get dropdown options
    `PUT``/settings/dropdown-choices/{field}`Update dropdown options
    `GET``/task_types/`List task types
    `POST``/task_types/`Add task type
    `PUT``/task_types/{old_name}`Rename task type
    `DELETE``/task_types/{name}`Delete task type

    ---


    Email


    MethodEndpointDescription
    `POST``/email/send`Queue email for sending

    ---


    Logs (Client Submission)


    MethodEndpointDescription
    `POST``/logs`Submit single client log
    `POST``/log`Submit single client log (alias)
    `POST``/logs/batch`Submit batch of client logs

    ---


    5. Admin Endpoints (Admin Role Required)


    All endpoints require both a valid JWT and is_admin: true.


    User Management


    MethodEndpointDescription
    `GET``/users/`List all users with full details
    `POST``/users/`Create new user
    `PUT``/users/{user_id}`Update user
    `DELETE``/users/{user_id}`Delete user
    `DELETE``/users/{user_id}/profile-picture`Delete user's picture

    Trash Management


    MethodEndpointDescription
    `GET``/admin/trash`List trashed items
    `POST``/admin/trash/{id}/restore`Restore item
    `DELETE``/admin/trash/{id}`Permanently delete
    `POST``/admin/trash/empty`Empty all trash

    Server Administration


    MethodEndpointDescription
    `POST``/admin/restart`Deploy & restart server
    `GET``/admin/deploy-status`Last deployment details

    SSL Certificate


    MethodEndpointDescription
    `GET``/admin/ssl/cert-info`Certificate details
    `POST``/admin/ssl/renew-cert`Regenerate certificate

    APNs Management


    MethodEndpointDescription
    `GET``/admin/apns/status`APNs status & stats
    `GET``/admin/apns/config`Current APNs config
    `POST``/admin/apns/config`Save APNs config
    `POST``/admin/apns/test`Send test push

    Database


    MethodEndpointDescription
    `GET``/admin/db/schema-status`Schema diagnostics
    `GET``/db-pool-stats`Connection pool stats
    `GET``/security-status`Security config status


    MethodEndpointDescription
    `GET``/admin/embedding/status`Embedding service status
    `POST``/admin/embedding/toggle`Enable/disable embeddings
    `POST``/admin/embedding/api-key`Save OpenAI API key
    `DELETE``/admin/embedding/api-key`Remove API key
    `POST``/admin/embedding/test-key`Validate API key
    `PUT``/admin/embedding/budget`Set budget cap
    `POST``/admin/embedding/reset-usage`Reset usage counters
    `GET``/admin/embedding/backfill-status`Backfill progress
    `POST``/admin/embedding/backfill-start`Start backfill

    SMB Watch


    MethodEndpointDescription
    `GET``/admin/smb-watch/status`Monitor status
    `POST``/admin/smb-watch/config`Update configuration

    Logs (Admin Access)


    MethodEndpointDescription
    `GET``/logs`Get server log lines
    `GET``/logs/export`Export logs for date range

    Email (Admin Access)


    MethodEndpointDescription
    `GET``/email/status`Email service status
    `GET``/email/log`Paginated email log
    `GET``/email/log/stats`Email statistics
    `GET``/email/log/{log_id}`Single email log entry

    Settings (Admin Write)


    MethodEndpointDescription
    `PUT``/settings/ticket-defaults`Update ticket defaults

    Signatures (Admin)


    MethodEndpointDescription
    `POST``/admin/send-signature-reminders`Trigger reminders

    ---


    6. Customer Endpoints (Customer JWT Required)


    These endpoints use a separate customer authentication system.


    Customer Profile


    MethodEndpointDescription
    `GET``/customer/api/me`Customer profile
    `POST``/customer/api/change-password`Change password
    `POST``/customer/api/delete-account`Request deletion

    Customer Tickets


    MethodEndpointDescription
    `GET``/customer/api/service-tickets`List service tickets
    `GET``/customer/api/support-tickets`List support tickets

    Customer Devices


    MethodEndpointDescription
    `POST``/customer/api/devices/register`Register for push
    `DELETE``/customer/api/devices/{token}`Unregister
    `GET``/customer/api/devices`List devices

    Customer Notifications


    MethodEndpointDescription
    `GET``/customer/api/notifications`Get notifications
    `POST``/customer/api/notifications/{id}/read`Mark as read
    `POST``/customer/api/notifications/read-all`Mark all read
    `DELETE``/customer/api/notifications/{id}`Delete

    ---


    7. Portal HTML Endpoints


    These endpoints render server-side HTML pages (not JSON APIs).


    Customer Portal


    MethodPathDescription
    `GET``/login`Unified login page
    `GET``/register`Customer registration
    `GET``/customer/{slug}/`Customer dashboard
    `GET``/customer/{slug}/ticket/{type}/{number}`Ticket detail
    `GET``/customer/{slug}/new/service-ticket`New service ticket form
    `GET``/customer/{slug}/new/support-ticket`New support ticket form
    `GET``/customer/{slug}/settings`Account settings
    `GET``/customer/{slug}/notifications`Notifications page
    `GET``/customer/{slug}/equipment/{id}`Equipment detail

    Admin Portal


    MethodPathDescription
    `GET``/portal/admin/`Admin dashboard
    `GET``/portal/admin/ticket/{type}/{number}`Ticket detail
    `GET``/portal/admin/ticket/{type}/{number}/edit`Ticket editor
    `GET``/portal/admin/task/{id}`Task detail
    `GET``/portal/admin/task/{id}/edit`Task editor
    `GET``/portal/admin/customers`Customer list
    `GET``/portal/admin/customers/{id}`Customer detail
    `GET``/portal/admin/vendors`Vendor list
    `GET``/portal/admin/contacts`Contact list
    `GET``/portal/admin/equipment`Equipment list
    `GET``/portal/admin/templates`Template manager
    `GET``/portal/admin/notifications`Notifications
    `GET``/portal/admin/settings`Employee settings
    `GET``/portal/admin/admin-area`Admin area (admin only)

    Signature Capture


    MethodPathDescription
    `GET``/portal/sign/{token}`Signature page (token-based, no auth)
    `POST``/portal/sign/{token}`Submit signature

    ---


    8. Error Handling


    HTTP Status Codes


    CodeMeaningExample
    `200`SuccessSuccessful GET/POST/PUT/PATCH
    `201`CreatedResource created (some POST endpoints)
    `400`Bad RequestInvalid input, validation error
    `401`UnauthorizedMissing or invalid token
    `403`ForbiddenUser lacks permission
    `404`Not FoundResource doesn't exist
    `413`Payload Too LargeRequest exceeds size limit
    `422`Unprocessable EntityPydantic validation failure
    `429`Too Many RequestsRate limit exceeded
    `500`Server ErrorUnexpected error (check error_id)
    `503`Service UnavailableDatabase connection failure

    Error Response Format


    
    {
      "detail": "Human-readable error message"
    }
    

    For 500 errors:

    
    {
      "detail": "Internal server error",
      "error_id": "a1b2c3d4"
    }
    

    Use the error_id to find the corresponding log entry.


    Validation Errors (422)


    
    {
      "detail": [
        {
          "loc": ["body", "title"],
          "msg": "field required",
          "type": "value_error.missing"
        }
      ]
    }
    

    ---


    9. Rate Limiting


    Rate Limit Headers


    Responses include rate limit information:


    
    X-RateLimit-Limit: 100
    X-RateLimit-Remaining: 95
    X-RateLimit-Reset: 1709294400
    

    Default Limits


    Endpoint TypeMax RequestsWindow
    Login (`/token`)55 minutes
    Registration (`/register`)31 hour
    General API1001 minute

    Rate Limit Exceeded


    
    HTTP 429 Too Many Requests
    {"detail": "Rate limit exceeded. Try again later."}
    

    ---


    10. Pagination


    List Endpoints


    Most list endpoints support pagination:


    
    GET /tasks/?limit=20&offset=0
    GET /customers/list?limit=50&offset=100
    GET /notifications?limit=10&offset=0
    

    ParameterDefaultDescription
    `limit`50Max items per page
    `offset`0Skip first N items

    Response Pattern


    List endpoints typically return arrays directly or wrapped objects:


    
    [
      {"id": 1, "title": "Task 1", ...},
      {"id": 2, "title": "Task 2", ...}
    ]
    

    ---


    Previous: Guide 6 — Admin Guide | Next: Guide 8 — JSON Inputs


    Corejobtrack Server — JSON Inputs Guide


    > Audience: Developers who need to construct valid JSON request bodies for the Corejobtrack API. This guide covers every Pydantic model, field validation rules, and JSONB data structures.


    ---


    Table of Contents


    1. Overview

    2. User Models

    3. Task Models

    4. Service Ticket Models

    5. Support Ticket Models

    6. Customer & Contact Models

    7. Equipment Models

    8. Template Models

    9. Signature Models

    10. Notification & Read Status

    11. Device Token Models

    12. Log Models

    13. Settings Models

    14. Quote Models

    15. Lead Models

    16. Lease Rate Models

    17. JSONB Data Structures

    18. Validation Rules

    19. Sample Payloads


    ---


    1. Overview


    Content Type


    All JSON request bodies must be sent with:


    
    Content-Type: application/json
    

    Null vs. Omitted Fields


  • **Omitted fields** use their default values (typically `null` or empty string)
  • **Explicitly null fields** (`"field": null`) are treated the same as omitted
  • On **PATCH/PUT updates**, only include fields you want to change

  • Field Length Limits


    LimitDefaultEnvironment Variable
    Username64 chars`MAX_USERNAME_LENGTH`
    Password128 chars`MAX_PASSWORD_LENGTH`
    Title500 chars`MAX_TITLE_LENGTH`
    Description50,000 chars`MAX_DESCRIPTION_LENGTH`
    Note100,000 chars`MAX_NOTE_LENGTH`

    ---


    2. User Models


    Registration (`POST /register`)


    
    {
      "username": "jdoe",                    // Required, max 64 chars
      "password": "SecurePass123!",          // Required, max 128 chars
      "full_name": "John Doe",              // Optional
      "first_name": "John",                 // Optional
      "last_name": "Doe",                   // Optional
      "nick_name": "JD",                    // Optional
      "email": "[email protected]",          // Optional, validated format
      "phone": "(555) 234-5678",            // Optional
      "team": "Service"                      // Optional
    }
    

    Admin Create User (`POST /users/`)


    
    {
      "username": "jdoe",                    // Required
      "password": "SecurePass123!",          // Optional (or use new_password)
      "new_password": "SecurePass123!",      // Optional (alternative to password)
      "full_name": "John Doe",
      "first_name": "John",
      "last_name": "Doe",
      "nick_name": "JD",
      "email": "[email protected]",
      "phone": "(555) 234-5678",
      "team": "Service"
    }
    

    Admin Update User (`PUT /users/{id}`)


    
    {
      "username": "jdoe_updated",           // Optional
      "full_name": "John A. Doe",           // Optional
      "first_name": "John",                 // Optional
      "last_name": "Doe",                   // Optional
      "nick_name": "Johnny",                // Optional
      "email": "[email protected]",      // Optional, validated
      "phone": "(555) 234-5678",            // Optional
      "team": "Management",                 // Optional
      "role": "admin",                       // Optional: "pending", "user", "admin"
      "new_password": "NewSecurePass!",     // Optional
      "hide_from_time_entries": false,       // Optional: hide from time dropdowns
      "hidden_from_sharing": false           // Optional: hide from assignment dropdowns
    }
    

    Self-Update Profile (`PUT /me`)


    
    {
      "full_name": "John Doe",              // Optional
      "first_name": "John",                 // Optional
      "last_name": "Doe",                   // Optional
      "nick_name": "JD",                    // Optional
      "email": "[email protected]",          // Optional, validated
      "phone": "(555) 234-5678",            // Optional
      "team": "Service",                     // Optional
      "chat_color": "#FF5733",              // Optional: color for chat messages
      "current_password": "OldPass123!",    // Required if changing password
      "new_password": "NewPass456!"         // Optional, max 128 chars
    }
    

    ---


    3. Task Models


    Create Task (`POST /tasks/`)


    
    {
      "title": "Replace drum unit",                    // Required, max 500 chars
      "description": "Customer reports streaking",     // Optional, max 50,000 chars
      "status": "open",                                 // Default: "open"
      "visibility": "private",                          // Default: "private" or "public"
      "task_type": "Repair",                            // Optional
      "is_private": false,                              // Optional
      "color": "#4A90D9",                               // Optional: hex color
      "template_id": 3,                                 // Optional: create from template
      "urgency": "Medium",                              // Default: "Medium"
      "due_date": "2026-03-15",                         // Optional: ISO date
      "task_code": "TSK-001",                           // Optional: custom code
    
      // Assignment
      "assigned_to": 5,                                 // Optional: single user ID
      "assigned_team": "Service",                       // Optional: single team
      "assigned_user_ids": [5, 8],                      // Optional: multiple user IDs
      "assigned_teams": ["Service", "Support"],         // Optional: multiple teams
    
      // Customer (optional)
      "customer_name": "Acme Corp",
      "customer_number": "CUST001",
      "customer_address_1": "123 Main St",
      "customer_address_2": "Suite 200",
      "city": "Anytown",
      "state": "ST",
      "zip": "12345",
    
      // Contact (optional)
      "customer_contact_first_name": "Jane",
      "customer_contact_last_name": "Doe",
      "customer_contact_full_name": "Jane Doe",
      "customer_phone": "(555) 123-4567",
      "customer_email": "[email protected]",
      "customer_contact_preference": "email",
    
      // Equipment (optional)
      "equipment": [
        {
          "make": "HP",
          "model": "LaserJet Pro",
          "serial": "ABC123",
          "count": 1,
          "problem": "Streaking",
          "problem_description": "Lines across every page"
        }
      ]
    }
    

    Update Task (`PATCH /tasks/{id}`)


    Only include the fields you want to change:


    
    {
      "title": "Updated title",
      "status": "in_progress",
      "urgency": "High",
      "due_date": "2026-03-20",
      "assigned_user_ids": [5, 8, 12],
      "private_notes": "Internal note about this task"
    }
    

    ---


    4. Service Ticket Models


    Create Service Ticket (`POST /service-tickets/`)


    
    {
      // Required
      "customer_name": "Acme Corp",
    
      // Optional metadata
      "title": "PM Visit - Q1 2026",
      "description": "Quarterly preventive maintenance",
      "status": "Pending",                             // Default: "Pending"
      "urgency": "Medium",                             // Default: "Medium"
      "visibility": "private",
      "is_private": false,
      "task_type": "Maintenance",
      "color": "#4A90D9",
      "due_date": "2026-03-15",
      "task_code": "SVC-001",
    
      // Assignment
      "assigned_to": 5,
      "assigned_team": "Service",
      "assigned_user_ids": [5, 8],
      "assigned_teams": ["Service"],
    
      // Customer & Contact
      "customer_number": "CUST001",
      "customer_address_1": "123 Main St",
      "customer_address_2": "",
      "city": "Anytown",
      "state": "ST",
      "zip": "12345",
      "customer_contact_first_name": "Jane",
      "customer_contact_last_name": "Doe",
      "customer_contact_full_name": "Jane Doe",
      "customer_phone": "(555) 123-4567",
      "customer_email": "[email protected]",
      "customer_contact_preference": "phone",
    
      // Dispatch
      "dispatch_type": "Scheduled",                    // Emergency, Scheduled, PM
      "dispatch_number": "D-2026-001",
      "dispatch_status": "Dispatched",
      "customer_po": "PO-12345",
    
      // Equipment (JSONB array)
      "equipment": [
        {
          "make": "Konica Minolta",
          "model": "bizhub C300i",
          "serial": "A9K123456",
          "count": 1,
          "problem": "PM Due",
          "problem_description": "Quarterly maintenance scheduled"
        }
      ],
    
      // Problem
      "problem_description": "Customer reports paper jams and streaking",
    
      // Time tracking (JSONB array)
      "session_timestamps": [
        {
          "start_time": "2026-03-01T09:00:00",
          "stop_time": "2026-03-01T12:30:00",
          "time_amount": 3.5,                         // Hours
          "time_type": "regular",                      // regular, overtime, travel
          "num_techs": 1,
          "lunch": 0,                                  // Minutes
          "services_performed": "Cleaned and calibrated",
          "notes": "Used new drum unit",
          "ticketed_user_ids": [5],
          "start": "09:00",
          "end": "12:30",
          "duration_minutes": 210
        }
      ],
      "total_time_minutes": 210,
    
      // Work performed
      "services_performed": "Cleaned rollers, replaced drum, calibrated",
      "settings_recorded": ["Color profile", "Paper tray alignment"],
      "tasks_completed": ["Clean rollers", "Replace drum", "Run calibration"],
    
      // Resolution
      "resolved": true,
      "resolution": "All issues resolved during visit",
    
      // Service flags
      "liftgate": false,
      "sprinter": true,
      "remote": false,
      "phone_call": false,
    
      // Notes
      "public_notes": "Customer visible notes",
      "private_notes": "Internal team notes"
    }
    

    Update Service Ticket (`PATCH /service-tickets/{id}`)


    Same fields as create, all optional. Only send what changed.


    ---


    5. Support Ticket Models


    Create Support Ticket (`POST /support-tickets/`)


    
    {
      // Required
      "customer_name": "Acme Corp",
    
      // Optional metadata
      "title": "Cannot print from accounting app",
      "description": "Customer reports print jobs queue but never print",
      "status": "Pending",
      "urgency": "Medium",
      "due_date": "2026-03-10",
      "visibility": "private",
      "is_private": true,
      "task_type": "Support",
      "color": "#E67E22",
      "task_code": "SUP-001",
    
      // Assignment
      "assigned_to": 8,
      "assigned_team": "Support",
      "assigned_user_ids": [8],
      "assigned_teams": ["Support"],
    
      // Customer
      "customer_number": "CUST001",
      "customer_address_1": "123 Main St",
      "city": "Anytown",
      "state": "ST",
      "zip": "12345",
    
      // Contact
      "customer_contact_first_name": "Jane",
      "customer_contact_last_name": "Doe",
      "customer_phone": "(555) 123-4567",
      "customer_email": "[email protected]",
    
      // Vendor tracking
      "ticket_id": "VENDOR-2026-001",
      "vendor_ticket_number": "VT-789",
      "ticket_status": "New",                         // New, Open, Escalated, Resolved
      "ticket_type": "Software Issue",
      "customer_po": "PO-12345",
    
      // Equipment
      "equipment": [
        {
          "make": "HP",
          "model": "LaserJet Pro M428",
          "serial": "CNBJ1234",
          "count": 1
        }
      ],
    
      // Communication log (JSONB array)
      "communication_log": [
        {
          "timestamp": "2026-03-01T09:00:00Z",
          "type": "phone",
          "summary": "Customer called about print issue",
          "details": "Cannot print from accounting software since update",
          "user_id": 8
        }
      ],
    
      // Notes
      "private_notes": "May need to escalate to vendor",
      "public_notes": "Working on resolution",
    
      // Time
      "total_time": 1.5,
    
      // Resolution
      "resolved": false,
      "resolution": null
    }
    

    Add Communication Message (`POST /support-tickets/{id}/communication`)


    
    {
      "message": "I've tested the connection and identified the issue. The print driver needs updating.",
      "time_spent": 0.5,                              // Hours spent on this message/action
      "is_customer": false,                            // true if customer sent this
      "author_user_id": null                           // Auto-detected from token
    }
    

    ---


    6. Customer & Contact Models


    Create/Update Customer (`POST/PATCH /customers/{id}`)


    
    {
      "company": "Acme Corporation",
      "contact_id": "CUST001",
      "address_1": "123 Main Street",
      "address_2": "Suite 200",
      "city": "Anytown",
      "state": "ST",
      "zip": "12345",
      "phone": "(555) 123-4567",
      "email": "[email protected]",
      "account_status": "active"
    }
    

    Create Contact (`POST /customers/{id}/contacts`)


    
    {
      "first_name": "Jane",
      "last_name": "Doe",
      "phone": "(555) 234-5678",
      "email": "[email protected]",
      "is_primary": true
    }
    

    Reorder Contacts (`POST /customers/{id}/contacts/reorder`)


    
    {
      "contact_ids": [5, 3, 8, 1]
    }
    

    ---


    7. Equipment Models


    Create Equipment (`POST /customers/{id}/equipment`)


    
    {
      "make": "HP",
      "model": "LaserJet Pro M428fdn",
      "serial": "CNBJ123456",
      "count": 1,
      "notes": "Located in 2nd floor copy room"
    }
    

    Log Equipment Count (`POST /customer-equipment/{id}/counts`)


    
    {
      "count": 45230,                                  // Current meter reading
      "notes": "Monthly meter reading"                 // Optional
    }
    

    ---


    8. Template Models


    Create/Update Template (`POST /templates/`, `PUT /templates/{id}`)


    
    {
      "name": "Quarterly PM",                          // Required: template name
      "title": "PM Visit - Q1",                        // Optional: default task title
      "description": "Quarterly preventive maintenance visit",
      "steps": [                                        // Required: at least one step
        {
          "step_description": "Clean all components",
          "is_completed": false,
          "order_num": 1
        },
        {
          "step_description": "Replace consumable parts",
          "is_completed": false,
          "order_num": 2
        },
        {
          "step_description": "Run calibration",
          "is_completed": false,
          "order_num": 3
        },
        {
          "step_description": "Test print quality",
          "is_completed": false,
          "order_num": 4
        }
      ],
      "color": "#27AE60",                              // Optional: hex color
      "task_type": "Maintenance",                       // Optional
      "due_date_offset": 7,                             // Optional: days from creation
      "assigned_user_ids": [5],                         // Optional
      "assigned_teams": ["Service"]                     // Optional
    }
    

    ---


    9. Signature Models


    Submit Signature (Employee) (`POST /service-tickets/{id}/sign`)


    
    {
      "signature_data": "data:image/png;base64,iVBORw0KGgo...",  // Base64 PNG
      "signature_name": "Jane Doe",                                // Printed name
      "send_summary_email": true,                                  // Email PDF to customer
      "safety_covers_ok": true,                                    // Safety cover check
      "safety_covers_notes": null                                   // Optional notes
    }
    

    Submit Signature (Portal) (`POST /portal/sign/{token}`)


    
    {
      "signature_data": "data:image/png;base64,iVBORw0KGgo...",
      "signature_name": "Jane Doe",
      "safety_covers_ok": true,
      "safety_covers_notes": "All covers in place"
    }
    

    Decline Signature (`POST /service-tickets/{id}/decline-signature`)


    
    {
      "decline_reason": "Contact not around",           // Required, from valid set
      "send_summary_email": false,
      "send_signature_request": true                     // Send post-visit email
    }
    

    Valid decline_reason values:

  • `"Contact not around"`
  • `"Contact refused to sign"`
  • `"Contact prefers to sign online"`
  • `"Other"`

  • ---


    10. Notification & Read Status


    Mark Sections Read (`POST /tickets/{type}/{id}/mark-read`)


    
    {
      "sections": ["details", "notes", "messages", "attachments"]
    }
    

    Valid section names vary by entity type.


    ---


    11. Device Token Models


    Register Device (`POST /devices/register`)


    
    {
      "token": "apns_device_token_string",             // Required: from APNs
      "platform": "ios",                                // Default: "ios"
      "device_name": "iPhone 15 Pro",                   // Optional
      "app_version": "2.1.0"                            // Optional
    }
    

    Customer Register Device (`POST /customer/api/devices/register`)


    Same format as employee device registration.


    ---


    12. Log Models


    Single Client Log (`POST /logs`)


    
    {
      "message": "App launched successfully",          // Required
      "level": "info",                                  // Default: "info"
      "event_type": "app_launch",                       // Optional
      "context": {                                      // Optional: arbitrary data
        "screen": "dashboard",
        "connection": "wifi"
      },
      "client_version": "2.1.0",                        // Optional
      "platform": "ios",                                 // Optional
      "device_id": "device-uuid-123",                   // Optional
      "session_id": "session-uuid-456",                 // Optional
      "user": "jdoe",                                   // Optional
      "occurred_at": "2026-03-01T09:00:00Z"             // Optional
    }
    

    Batch Client Logs (`POST /logs/batch`)


    
    {
      "entries": [
        {
          "message": "App launched",
          "level": "info",
          "event_type": "app_launch"
        },
        {
          "message": "Network timeout on /tasks",
          "level": "warning",
          "event_type": "network_error",
          "context": {"endpoint": "/tasks/", "timeout_ms": 30000}
        },
        {
          "message": "Crash in TaskDetailView",
          "level": "error",
          "event_type": "crash",
          "context": {"stack_trace": "..."}
        }
      ],
      "client_version": "2.1.0",                        // Applies to all entries
      "platform": "ios",
      "device_id": "device-uuid-123",
      "session_id": "session-uuid-456"
    }
    

    ---


    13. Settings Models


    Ticket Color Defaults (`PUT /settings/ticket-defaults`)


    
    {
      "service_ticket": "#4A90D9",                      // Optional: hex color
      "support_ticket": "#E67E22"                       // Optional: hex color
    }
    


    
    [
      {"value": "Emergency", "label": "Emergency"},
      {"value": "Scheduled", "label": "Scheduled"},
      {"value": "PM", "label": "Preventive Maintenance"}
    ]
    

    Task Type (`POST /task_types/`)


    
    {
      "name": "Installation"
    }
    

    ---


    14. Quote Models


    Create Quote (`POST /quotes`)


    
    {
      "customer_id": 42,                                // Required
      "contact_person_id": 15,                          // Optional
      "summary": "New copier installation proposal",    // Optional
      "sales_lead_id": 7,                               // Optional: linked lead
    
      // Pricing
      "shipped_direct": false,
      "labor_warranty": 12,                              // Months
      "account_rep": "John Smith",
      "condense_pricing": false,
      "lease_enabled": true,
      "include_sales_tax": true,
      "tax_rate": 7.5,
      "quote_term": 60,                                  // Months
      "display_terms": "60 Month FMV Lease",
      "sale_closed": false,
      "monthly_pricing": true,
    
      // Service costs
      "rigging_price": 500.00,
      "rigging_cost": 300.00,
      "delivery_price": 250.00,
      "delivery_cost": 150.00,
      "installation_price": 1000.00,
      "installation_cost": 600.00,
      "training_price": 500.00,
      "training_cost": 200.00,
      "shipping_price": 800.00,
      "shipping_cost": 600.00,
      "parts_cost": 50.00,
    
      // Feature toggles
      "rigging_enabled": true,
      "rigging_description": "Crane and dock work",
      "installation_enabled": true,
      "installation_description": "Full installation with network setup",
      "setup_enabled": false,
      "training_enabled": true,
      "training_description": "2-hour on-site training",
    
      // Service agreements
      "sa1_title": "Standard Service Agreement",
      "sa1_price": 150.00,
      "sa1_emergency": 4,
      "sa1_pm": 4,
      "sa1_blade_changes": 0,
      "sa1_acceleration": 0.0,
      "sa1_parts_discount": 10.0,
      "sa1_service_discount": 0.0,
    
      // Trade-in
      "trade_enabled": true,
      "trade_condition": "Good",
      "trade_option": "Trade-In",
      "trade_moving_costs": 200.00,
      "trade_items": [
        {
          "sort_order": 1,
          "qty": 1,
          "description": "Old Copier Model XYZ",
          "value": 500.00
        }
      ],
    
      // Line items
      "line_items": [
        {
          "sort_order": 1,
          "qty": 1,
          "item_code": "BZ-C300i",
          "description": "bizhub C300i Color MFP",
          "msrp": 8500.00,
          "markup": 0.0,
          "discount": 15.0,
          "cost": 5200.00
        }
      ],
    
      // Options
      "options": [
        {
          "sort_order": 1,
          "enabled": true,
          "description": "Fax Kit FK-514",
          "product_code": "FK-514",
          "price": 350.00,
          "cost": 200.00,
          "purchased": false
        }
      ],
    
      // Other
      "warranty_notes": "1-year parts and labor warranty included",
      "freight": "FOB Destination",
      "customer_price": 12500.00,
      "availability": "2-3 weeks",
      "terms": "Net 30",
      "notes": "Customer interested in leasing options",
      "private_notes": "Margin on this deal is 35%"
    }
    

    ---


    15. Lead Models


    Create Lead (`POST /leads`)


    
    {
      "lead_id": "LEAD-2026-001",                       // Optional: custom ID
      "contact_id": 42,                                  // Required: customer ID
      "address_1": "123 Main St",
      "city": "Anytown",
      "state": "ST",
      "zip": "12345",
      "contact_name": "Jane Doe",
      "phone_number": "(555) 123-4567",
      "contact_email": "[email protected]",
      "company_rep": "John Smith",
      "lead_rating": "Hot",                              // Hot, Warm, Cold
      "lead_source": "Referral",                         // Referral, Website, Trade Show
      "master_status": "New",                            // Default: "New"
      "lead_for": "Color Copier",
      "lead_details": "Looking to replace aging fleet",
      "budget": 25000.00,
    
      // Funnel stages
      "contacted": true,
      "qualified": true,
      "created_configuration": false,
      "created_quote": false,
      "presented_quote": false,
      "samples": false,
      "demo": false,
      "demo_follow_up": false,
      "emailed": true,
    
      "lead_log": "3/1: Initial contact via referral from ABC Corp"
    }
    

    ---


    16. Lease Rate Models


    Create Lease Rate (`POST /lease-rates`)


    
    {
      "leasing_partner": "Partner Finance Corp",        // Required, non-empty
      "lease_rep_name": "Bob Johnson",                   // Optional
      "lease_rep_phone": "(555) 345-6789",              // Optional
      "min_price": 5000.00,                              // Required
      "max_price": 50000.00,                             // Required
      "term_length": 60,                                 // Required: months
      "lease_rate": 0.0189,                              // Required: rate factor
      "lease_type": "FMV"                                // Optional: "FTO" or "FMV"
    }
    

    ---


    17. JSONB Data Structures


    These structures are stored as JSONB columns in PostgreSQL and appear as arrays/objects in JSON request/response bodies.


    Equipment Array


    Used in tasks, service tickets, and support tickets:


    
    [
      {
        "make": "HP",
        "model": "LaserJet Pro M428fdn",
        "serial": "CNBJ123456",
        "count": 1,
        "problem": "Paper jam",
        "problem_description": "Jams occur when printing from tray 2"
      },
      {
        "make": "Konica Minolta",
        "model": "bizhub C300i",
        "serial": "A9K789012",
        "count": 1,
        "problem": "Streaking",
        "problem_description": "Cyan streaks on every page"
      }
    ]
    

    Session Timestamps Array


    Time entries on service tickets:


    
    [
      {
        "start_time": "2026-03-01T09:00:00",
        "stop_time": "2026-03-01T12:30:00",
        "time_amount": 3.5,
        "time_type": "regular",
        "num_techs": 2,
        "lunch": 30,
        "services_performed": "PM cleaning, roller replacement",
        "notes": "Used parts from van stock",
        "ticketed_user_ids": [5, 8],
        "start": "09:00",
        "end": "12:30",
        "duration_minutes": 210
      }
    ]
    

    Important notes:

  • `time_amount` is in **hours**
  • `lunch` is in **minutes**
  • `duration_minutes` is in **minutes**
  • `num_techs` multiplied by `time_amount` gives total person-hours

  • Communication Log Array


    Messages on support tickets:


    
    [
      {
        "timestamp": "2026-03-01T09:00:00Z",
        "type": "phone",
        "summary": "Customer called about print issue",
        "details": "Cannot print from accounting software since Windows update",
        "user_id": 8
      },
      {
        "timestamp": "2026-03-01T10:30:00Z",
        "type": "remote",
        "summary": "Remote session - updated print driver",
        "details": "Connected via remote desktop, updated driver to v3.2.1",
        "user_id": 8
      }
    ]
    

    Change Log (Audit Trail)


    Automatically generated, not user-input:


    
    [
      {
        "timestamp": "2026-03-01T09:00:00Z",
        "action": "created",
        "user_id": 5,
        "details": "Ticket created"
      },
      {
        "timestamp": "2026-03-01T14:00:00Z",
        "action": "updated",
        "user_id": 5,
        "details": "Status changed from 'open' to 'in_progress'"
      }
    ]
    

    Settings Recorded / Tasks Completed


    Simple string arrays on service tickets:


    
    {
      "settings_recorded": [
        "Color calibration: Standard",
        "Paper tray 1: Letter",
        "Paper tray 2: Legal",
        "Duplex: Enabled"
      ],
      "tasks_completed": [
        "Cleaned corona wires",
        "Replaced separation roller",
        "Updated firmware to v2.5",
        "Ran test prints (50 pages)"
      ]
    }
    

    ---


    18. Validation Rules


    Email Validation


    Emails must match: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$


    Password Requirements


    When REQUIRE_PASSWORD_COMPLEXITY=true:

  • Minimum length: 8 characters (configurable via `MIN_PASSWORD_LENGTH`)
  • Must contain uppercase letter
  • Must contain lowercase letter
  • Must contain digit
  • Must contain special character

  • Lease Type Validation


    Must be exactly "FTO" or "FMV" (case-insensitive, auto-uppercased).


    Decline Reason Validation


    Must be one of the exact strings:

  • `"Contact not around"`
  • `"Contact refused to sign"`
  • `"Contact prefers to sign online"`
  • `"Other"`

  • Status Values


    Tasks: open, in_progress, paused, completed, archived, trash


    Service Tickets: Pending, open, in_progress, completed, archived, trash


    Support Tickets: Pending, open, in_progress, completed, archived, trash


    Ticket Status (Support): New, Open, Escalated, Resolved


    User Roles: pending, user, admin


    ---


    19. Sample Payloads


    Complete Workflow: Create Customer → Service Ticket → Signature


    #### Step 1: Create Customer


    
    curl -X POST https://server:8443/customers/ \
      -H "Authorization: Bearer TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "company": "Acme Corp",
        "contact_id": "ACME001",
        "address_1": "123 Main St",
        "city": "Anytown",
        "state": "ST",
        "zip": "12345",
        "account_status": "active"
      }'
    

    #### Step 2: Add Contact


    
    curl -X POST https://server:8443/customers/1/contacts \
      -H "Authorization: Bearer TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "first_name": "Jane",
        "last_name": "Doe",
        "phone": "(555) 123-4567",
        "email": "[email protected]",
        "is_primary": true
      }'
    

    #### Step 3: Create Service Ticket


    
    curl -X POST https://server:8443/service-tickets/ \
      -H "Authorization: Bearer TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "customer_name": "Acme Corp",
        "title": "Emergency Service Call",
        "description": "Copier completely down",
        "urgency": "High",
        "dispatch_type": "Emergency",
        "equipment": [
          {"make": "HP", "model": "LaserJet", "serial": "ABC123", "count": 1, "problem": "Not printing"}
        ]
      }'
    

    #### Step 4: Update with Time Entry


    
    curl -X PATCH https://server:8443/service-tickets/1 \
      -H "Authorization: Bearer TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "status": "in_progress",
        "session_timestamps": [
          {
            "start_time": "2026-03-01T09:00:00",
            "stop_time": "2026-03-01T11:00:00",
            "time_amount": 2.0,
            "time_type": "regular",
            "num_techs": 1,
            "lunch": 0
          }
        ],
        "services_performed": "Replaced fuser unit, test prints OK"
      }'
    

    #### Step 5: Capture Signature


    
    curl -X POST https://server:8443/service-tickets/1/sign \
      -H "Authorization: Bearer TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "signature_data": "data:image/png;base64,iVBORw0KGgo...",
        "signature_name": "Jane Doe",
        "send_summary_email": true,
        "safety_covers_ok": true
      }'
    

    #### Step 6: Complete Ticket


    
    curl -X POST https://server:8443/service-tickets/1/complete \
      -H "Authorization: Bearer TOKEN"
    

    ---


    Previous: Guide 7 — API Endpoints | Next: Guide 9 — Database Breakout


    Corejobtrack Server — Database Breakout Guide


    > Audience: System administrators who want to move the PostgreSQL database to a separate server for performance, security, or scalability reasons.


    ---


    Table of Contents


    1. Why Break Out the Database?

    2. Architecture Overview

    3. Prerequisites

    4. Step 1: Prepare the Database Server

    5. Step 2: Migrate Existing Data

    6. Step 3: Configure Network Access

    7. Step 4: Update Corejobtrack Configuration

    8. Step 5: Test the Connection

    9. Step 6: Switch Over

    10. Connection Pooling Configuration

    11. SSL/TLS for Database Connections

    12. Backup Strategy

    13. Monitoring the Remote Connection

    14. Failover & High Availability

    15. Performance Tuning

    16. Troubleshooting

    17. Rollback Plan


    ---


    1. Why Break Out the Database?


    Running PostgreSQL on a separate server provides several benefits:


    BenefitDescription
    **Performance**Database and application don't compete for CPU/RAM
    **Scalability**Scale database and application servers independently
    **Security**Database server can be isolated on a private network
    **Backup**Dedicated backup infrastructure for data
    **Maintenance**Database maintenance (vacuuming, upgrades) doesn't affect app
    **Compliance**Data residency requirements may dictate separate storage

    When to Consider Breakout


  • Application server CPU usage is high during queries
  • Database size exceeds 10 GB
  • Multiple Corejobtrack instances need to share a database
  • Security policy requires database isolation
  • You need dedicated database backup infrastructure

  • !Placeholder: Before and after architecture diagram


    ---


    2. Architecture Overview


    Before (Single Server)


    
    ┌───────────────────────────────────┐
    │         Single Server             │
    │                                   │
    │   Corejobtrack App  ←→  PostgreSQL   │
    │   (Port 8443)       (Port 5432)   │
    │                                   │
    │   DB_HOST=localhost               │
    └───────────────────────────────────┘
    

    After (Separate Servers)


    
    ┌──────────────────┐         ┌──────────────────┐
    │   App Server     │  TCP    │   DB Server      │
    │                  │ ──────→ │                  │
    │  Corejobtrack App   │  5432   │  PostgreSQL      │
    │  (Port 8443)     │         │  (Port 5432)     │
    │                  │         │                  │
    │  DB_HOST=10.0.0.2│         │  10.0.0.2        │
    └──────────────────┘         └──────────────────┘
             │                            │
             └────── Private Network ─────┘
    

    Key Connection Parameters


    Corejobtrack connects to PostgreSQL using these environment variables:


    
    DB_HOST=10.0.0.2       # Database server IP/hostname
    DB_PORT=5432           # Database port
    DB_NAME=corejobtrack      # Database name
    DB_USER=corejobtrack_user # Database user
    DB_PASSWORD=secret     # Database password
    

    ---


    3. Prerequisites


    Database Server


    RequirementDetails
    OSLinux (Ubuntu 20.04+, RHEL 8+, etc.)
    PostgreSQL14+ (same or newer version as current)
    NetworkPrivate network connectivity to app server
    FirewallPort 5432 open to app server IP
    DiskSufficient storage for database + growth

    Application Server


    RequirementDetails
    NetworkCan reach database server on port 5432
    psycopg2Already installed with Corejobtrack


  • **pgvector extension** — If you use AI/vector search
  • **SSL certificates** — For encrypted database connections
  • **pgBouncer** — Connection pooling proxy (for high-traffic deployments)

  • ---


    4. Step 1: Prepare the Database Server


    Install PostgreSQL


    
    # Ubuntu/Debian
    sudo apt update
    sudo apt install postgresql postgresql-contrib
    
    # RHEL/CentOS
    sudo dnf install postgresql-server postgresql-contrib
    sudo postgresql-setup --initdb
    sudo systemctl start postgresql
    sudo systemctl enable postgresql
    

    Create Database and User


    
    sudo -u postgres psql
    

    
    -- Create the database user with a strong password
    CREATE USER corejobtrack_user WITH PASSWORD 'your_strong_password_here';
    
    -- Create the database
    CREATE DATABASE corejobtrack OWNER corejobtrack_user;
    
    -- Grant privileges
    GRANT ALL PRIVILEGES ON DATABASE corejobtrack TO corejobtrack_user;
    
    -- Connect and set up extensions
    \c corejobtrack
    
    -- Required
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
    CREATE EXTENSION IF NOT EXISTS "citext";
    
    -- Optional: for vector search
    -- CREATE EXTENSION IF NOT EXISTS vector;
    

    Optimize PostgreSQL Configuration


    Edit postgresql.conf for a dedicated database server:


    
    sudo nano /etc/postgresql/16/main/postgresql.conf
    

    Recommended settings for a dedicated DB server:


    
    # Connection Settings
    listen_addresses = '*'              # Listen on all interfaces
    port = 5432
    max_connections = 100               # Adjust based on expected load
    
    # Memory (adjust based on available RAM)
    shared_buffers = 1GB                # 25% of total RAM
    effective_cache_size = 3GB          # 75% of total RAM
    work_mem = 64MB
    maintenance_work_mem = 256MB
    
    # WAL Settings
    wal_buffers = 64MB
    checkpoint_completion_target = 0.9
    max_wal_size = 2GB
    
    # Query Planner
    random_page_cost = 1.1              # For SSD storage
    effective_io_concurrency = 200      # For SSD storage
    
    # Logging
    log_min_duration_statement = 1000   # Log queries over 1 second
    log_connections = on
    log_disconnections = on
    

    Restart PostgreSQL:


    
    sudo systemctl restart postgresql
    

    ---


    5. Step 2: Migrate Existing Data



    This is the safest method for migrating data.


    #### On the Current Server (Source)


    
    # Create a full database dump
    pg_dump -h localhost -U corejobtrack_user -d corejobtrack \
      --format=custom --file=corejobtrack_backup.dump
    
    # Or plain SQL for debugging
    pg_dump -h localhost -U corejobtrack_user -d corejobtrack \
      --file=corejobtrack_backup.sql
    

    #### Transfer to New Server


    
    scp corejobtrack_backup.dump [email protected]:/tmp/
    

    #### On the New Database Server


    
    # Restore the dump
    pg_restore -h localhost -U corejobtrack_user -d corejobtrack \
      --clean --if-exists --no-owner \
      /tmp/corejobtrack_backup.dump
    
    # Or for plain SQL:
    psql -h localhost -U corejobtrack_user -d corejobtrack < /tmp/corejobtrack_backup.sql
    

    Option B: pg_basebackup (For Large Databases)


    For databases larger than 10 GB, use streaming replication for a near-zero-downtime migration:


    
    # On the new server, create a base backup from the old server
    pg_basebackup -h old-server -U replication_user \
      -D /var/lib/postgresql/16/main \
      --wal-method=stream --progress
    

    Verify Data


    After migration, verify the data on the new server:


    
    psql -h 10.0.0.2 -U corejobtrack_user -d corejobtrack
    
    -- Check table counts
    SELECT 'users' AS table_name, COUNT(*) FROM users
    UNION ALL SELECT 'tasks', COUNT(*) FROM tasks
    UNION ALL SELECT 'service_tickets', COUNT(*) FROM service_tickets
    UNION ALL SELECT 'support_tickets', COUNT(*) FROM support_tickets;
    

    ---


    6. Step 3: Configure Network Access


    On the Database Server


    #### Configure pg_hba.conf


    Allow the application server to connect:


    
    sudo nano /etc/postgresql/16/main/pg_hba.conf
    

    Add a line for your app server:


    
    # Corejobtrack application server
    host    corejobtrack    corejobtrack_user    10.0.0.1/32    scram-sha-256
    
    # Or for a subnet
    host    corejobtrack    corejobtrack_user    10.0.0.0/24    scram-sha-256
    

    > Security: Use the most specific IP/subnet possible. Never use 0.0.0.0/0 in production.


    #### Configure postgresql.conf


    Ensure PostgreSQL listens on the correct interface:


    
    listen_addresses = '10.0.0.2'    # DB server's private IP
    # Or listen on all interfaces:
    listen_addresses = '*'
    

    Reload configuration:


    
    sudo systemctl reload postgresql
    

    #### Configure Firewall


    
    # UFW (Ubuntu)
    sudo ufw allow from 10.0.0.1 to any port 5432
    
    # firewalld (RHEL/CentOS)
    sudo firewall-cmd --permanent --add-rich-rule='
      rule family="ipv4"
      source address="10.0.0.1/32"
      port port="5432" protocol="tcp"
      accept'
    sudo firewall-cmd --reload
    
    # iptables
    sudo iptables -A INPUT -p tcp -s 10.0.0.1 --dport 5432 -j ACCEPT
    

    Test Network Connectivity


    From the application server:


    
    # Test TCP connectivity
    nc -zv 10.0.0.2 5432
    
    # Test PostgreSQL connectivity
    psql -h 10.0.0.2 -U corejobtrack_user -d corejobtrack -c "SELECT 1;"
    

    ---


    7. Step 4: Update Corejobtrack Configuration


    Edit `taskapp.env`


    On the application server, update the database connection settings:


    
    # Before (local)
    DB_HOST=localhost
    
    # After (remote)
    DB_HOST=10.0.0.2
    DB_PORT=5432
    DB_NAME=corejobtrack
    DB_USER=corejobtrack_user
    DB_PASSWORD=your_strong_password_here
    

    Adjust Connection Pool Settings


    For remote database connections, you may want to adjust the pool:


    
    # Connection pooling
    DB_POOL_ENABLED=true
    DB_POOL_MIN_CONNECTIONS=2
    DB_POOL_MAX_CONNECTIONS=20
    
    # Retry settings (important for network connections)
    DB_MAX_RETRIES=5
    DB_RETRY_BASE_DELAY=1.0
    DB_RETRY_MAX_DELAY=30.0
    DB_HEALTH_CHECK_INTERVAL=30
    

    ---


    8. Step 5: Test the Connection


    Test Before Switching


    You can test the remote connection without stopping the current server:


    
    # From the app server, test with psql
    psql -h 10.0.0.2 -U corejobtrack_user -d corejobtrack -c "
      SELECT COUNT(*) AS users FROM users;
      SELECT COUNT(*) AS tasks FROM tasks;
      SELECT COUNT(*) AS service_tickets FROM service_tickets;
      SELECT COUNT(*) AS support_tickets FROM support_tickets;
    "
    

    Test with Corejobtrack


    Temporarily start a second instance pointing to the remote database:


    
    # Export remote DB config
    export DB_HOST=10.0.0.2
    export DB_PORT=5432
    export DB_NAME=corejobtrack
    export DB_USER=corejobtrack_user
    export DB_PASSWORD=your_password
    
    # Start test instance on a different port
    uvicorn main:app --host 0.0.0.0 --port 9000
    

    Then test:


    
    curl http://localhost:9000/health
    curl http://localhost:9000/dbhealth
    curl http://localhost:9000/db-status
    

    ---


    9. Step 6: Switch Over


    Planned Switchover Procedure


    1. Notify users of brief downtime


    2. Stop the application server

    
       sudo systemctl stop taskmanager-ssl
    

    3. Final data sync (if using incremental migration)

    
       # On source server
       pg_dump -h localhost -U corejobtrack_user -d corejobtrack \
         --format=custom --file=final_backup.dump
    
       scp final_backup.dump [email protected]:/tmp/
    
       # On target server
       pg_restore -h localhost -U corejobtrack_user -d corejobtrack \
         --clean --if-exists --no-owner /tmp/final_backup.dump
    

    4. Update configuration

    
       # Edit taskapp.env
       DB_HOST=10.0.0.2
    

    5. Restart the application server

    
       sudo systemctl start taskmanager-ssl
    

    6. Verify

    
       curl -sk https://localhost:8443/health
       curl -sk https://localhost:8443/dbhealth
       curl -sk https://localhost:8443/db-status
    

    7. (Optional) Stop local PostgreSQL once confirmed working

    
       sudo systemctl stop postgresql
       sudo systemctl disable postgresql
    

    ---


    10. Connection Pooling Configuration


    Built-in Connection Pool


    Corejobtrack includes a thread-safe connection pool. Configure it for remote connections:


    
    # Enable pooling (recommended for remote DB)
    DB_POOL_ENABLED=true
    
    # Pool size
    DB_POOL_MIN_CONNECTIONS=2      # Minimum idle connections
    DB_POOL_MAX_CONNECTIONS=20     # Maximum concurrent connections
    
    # Retry on connection failure
    DB_MAX_RETRIES=5
    DB_RETRY_BASE_DELAY=1.0       # Initial retry delay (seconds)
    DB_RETRY_MAX_DELAY=30.0       # Maximum retry delay (seconds)
    

    How the Pool Works


    
    Request → Pool.get_connection()
               ├── Idle connection available? → Return it
               ├── Pool not full? → Create new connection → Return it
               └── Pool full? → Wait (up to 30s timeout) → Return or 503
             ↓
          Use connection
             ↓
         Pool.return_connection()
               ├── Connection alive? → Return to pool (after rollback)
               └── Connection dead? → Close it
    

    Monitoring Pool Health


    
    curl https://server:8443/db-pool-stats \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    Healthy pool:

    
    {
      "available": 5,
      "in_use": 2,
      "max": 20,
      "min": 2
    }
    

    Warning signs:

  • `available: 0` — All connections are in use
  • `in_use` near `max` — Pool is almost exhausted
  • Frequent 503 errors — Increase `DB_POOL_MAX_CONNECTIONS`

  • External Connection Pooler (Optional)


    For high-traffic deployments, consider pgBouncer:


    
    # Install on the DB server
    sudo apt install pgbouncer
    
    # Configure /etc/pgbouncer/pgbouncer.ini
    [databases]
    corejobtrack = host=localhost port=5432 dbname=corejobtrack
    
    [pgbouncer]
    listen_addr = 10.0.0.2
    listen_port = 6432
    auth_type = scram-sha-256
    pool_mode = transaction
    max_client_conn = 200
    default_pool_size = 25
    

    Then point Corejobtrack to pgBouncer:


    
    DB_HOST=10.0.0.2
    DB_PORT=6432    # pgBouncer port
    

    ---


    11. SSL/TLS for Database Connections


    For encrypted database connections over untrusted networks:


    On the Database Server


    Generate server certificate or use Let's Encrypt:


    
    # Generate self-signed for internal use
    openssl req -new -x509 -days 3650 -nodes \
      -out /etc/postgresql/16/main/server.crt \
      -keyout /etc/postgresql/16/main/server.key \
      -subj "/CN=db-server"
    
    chown postgres:postgres /etc/postgresql/16/main/server.*
    chmod 600 /etc/postgresql/16/main/server.key
    

    Enable SSL in postgresql.conf:


    
    ssl = on
    ssl_cert_file = 'server.crt'
    ssl_key_file = 'server.key'
    

    Require SSL in pg_hba.conf:


    
    hostssl    corejobtrack    corejobtrack_user    10.0.0.0/24    scram-sha-256
    

    On the Application Server


    The psycopg2 driver supports SSL parameters. You can set them as environment variables or pass them through the connection configuration.


    ---


    12. Backup Strategy


    Automated Backups on the Database Server


    Create a backup script:


    
    #!/bin/bash
    # /opt/backups/backup_corejobtrack.sh
    
    BACKUP_DIR="/opt/backups/corejobtrack"
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    KEEP_DAYS=30
    
    mkdir -p $BACKUP_DIR
    
    # Create compressed backup
    pg_dump -U corejobtrack_user -d corejobtrack \
      --format=custom --compress=9 \
      --file="$BACKUP_DIR/corejobtrack_$TIMESTAMP.dump"
    
    # Remove old backups
    find $BACKUP_DIR -name "*.dump" -mtime +$KEEP_DAYS -delete
    
    echo "Backup completed: corejobtrack_$TIMESTAMP.dump"
    

    Schedule with cron:


    
    # Daily at 2 AM
    0 2 * * * /opt/backups/backup_corejobtrack.sh >> /var/log/db-backup.log 2>&1
    

    Point-in-Time Recovery (PITR)


    For mission-critical deployments, enable WAL archiving:


    
    # postgresql.conf
    archive_mode = on
    archive_command = 'cp %p /opt/backups/wal/%f'
    

    Backup Verification


    Regularly test that backups can be restored:


    
    # Create test database
    createdb corejobtrack_test
    
    # Restore
    pg_restore -d corejobtrack_test corejobtrack_20260301_020000.dump
    
    # Verify
    psql -d corejobtrack_test -c "SELECT COUNT(*) FROM tasks;"
    
    # Clean up
    dropdb corejobtrack_test
    

    ---


    13. Monitoring the Remote Connection


    Corejobtrack Built-in Monitoring


    Corejobtrack includes a background health monitor that continuously checks database connectivity:


    
    # Health check interval (seconds)
    DB_HEALTH_CHECK_INTERVAL=30
    

    The monitor runs every 30 seconds and:

  • Tests the database connection
  • Tracks consecutive failures
  • Records recovery events
  • Updates the status available via `/db-status`

  • Check DB Status


    
    # Basic health
    curl https://server:8443/dbhealth
    
    # Detailed status with metrics
    curl https://server:8443/db-status
    
    # Pool statistics
    curl https://server:8443/db-pool-stats \
      -H "Authorization: Bearer ADMIN_TOKEN"
    

    External Monitoring


    Set up alerts for:


    CheckFrequencyAlert Condition
    `/dbhealth`30sHTTP 503
    `/db-status`1 min`consecutive_failures > 3`
    `/db-pool-stats`5 min`available = 0`
    DB disk space15 min< 20% free
    DB connections5 min> 80% of `max_connections`

    PostgreSQL Monitoring on DB Server


    
    # Active connections
    psql -c "SELECT count(*) FROM pg_stat_activity WHERE datname='corejobtrack';"
    
    # Long-running queries
    psql -c "
      SELECT pid, now() - pg_stat_activity.query_start AS duration, query
      FROM pg_stat_activity
      WHERE datname = 'corejobtrack' AND state != 'idle'
      ORDER BY duration DESC;"
    
    # Table sizes
    psql -d corejobtrack -c "
      SELECT relname AS table, pg_size_pretty(pg_total_relation_size(relid)) AS size
      FROM pg_catalog.pg_statio_user_tables
      ORDER BY pg_total_relation_size(relid) DESC;"
    

    ---


    14. Failover & High Availability


    PostgreSQL Streaming Replication


    For high availability, set up a standby server:


    #### On Primary (Master)


    
    # postgresql.conf
    wal_level = replica
    max_wal_senders = 5
    

    Create replication user:


    
    CREATE ROLE replication_user WITH REPLICATION LOGIN PASSWORD 'repl_password';
    

    #### On Standby (Replica)


    
    pg_basebackup -h primary-server -U replication_user \
      -D /var/lib/postgresql/16/main --wal-method=stream
    
    # Create standby.signal
    touch /var/lib/postgresql/16/main/standby.signal
    

    
    # postgresql.conf on standby
    primary_conninfo = 'host=primary-server user=replication_user password=repl_password'
    

    Failover Strategy


    If the primary database server fails:


    1. Promote the standby to primary:

    
       pg_ctl promote -D /var/lib/postgresql/16/main
    

    2. Update Corejobtrack configuration:

    
       DB_HOST=standby-server-ip
    

    3. Restart Corejobtrack:

    
       sudo systemctl restart taskmanager-ssl
    

    Corejobtrack's built-in retry logic will handle brief connection interruptions during failover.


    ---


    15. Performance Tuning


    Network Latency


    Remote database connections add network latency. Minimize impact:


    StrategyImplementation
    Private networkUse 10.x.x.x or 192.168.x.x between servers
    Same data centerKeep app and DB in the same facility
    Connection poolingEnable Corejobtrack's built-in pool
    Minimize round tripsCorejobtrack already batches queries

    PostgreSQL Tuning for Remote Connections


    
    # Allow more concurrent connections (remote clients may hold longer)
    max_connections = 150
    
    # Increase shared buffers for caching
    shared_buffers = 2GB
    
    # TCP keepalive (detect broken connections faster)
    tcp_keepalives_idle = 60
    tcp_keepalives_interval = 10
    tcp_keepalives_count = 5
    

    Corejobtrack Pool Tuning


    
    # For remote connections, increase pool size slightly
    DB_POOL_MAX_CONNECTIONS=25
    
    # Keep more idle connections warm
    DB_POOL_MIN_CONNECTIONS=5
    
    # Faster retry on network blips
    DB_RETRY_BASE_DELAY=0.5
    DB_MAX_RETRIES=3
    

    ---


    16. Troubleshooting


    Connection Refused


    
    psycopg2.OperationalError: could not connect to server: Connection refused
    

    Check:

    1. PostgreSQL is running on the DB server: sudo systemctl status postgresql

    2. Listening on correct interface: ss -tlnp | grep 5432

    3. Firewall allows the connection: sudo ufw status

    4. pg_hba.conf includes the app server IP

    5. listen_addresses includes the DB server IP or *


    Authentication Failed


    
    FATAL: password authentication failed for user "corejobtrack_user"
    

    Check:

    1. Password in taskapp.env matches the PostgreSQL user password

    2. Auth method in pg_hba.conf matches (scram-sha-256 vs md5)

    3. User exists: \du in psql


    Connection Timeout


    
    psycopg2.OperationalError: connection timed out
    

    Check:

    1. Network routing: traceroute 10.0.0.2

    2. Port open: nc -zv 10.0.0.2 5432

    3. No intermediate firewall blocking

    4. PostgreSQL is responding: pg_isready -h 10.0.0.2


    Pool Exhaustion


    
    HTTP 503: "Database connection pool exhausted"
    

    Fix:

    1. Increase DB_POOL_MAX_CONNECTIONS

    2. Check for long-running queries on the DB server

    3. Monitor with /db-pool-stats

    4. Consider pgBouncer for connection multiplexing


    Intermittent Disconnections


    Corejobtrack's built-in retry logic handles brief disconnections. If they persist:


    1. Check network stability between servers

    2. Enable TCP keepalives in postgresql.conf

    3. Monitor /db-status for consecutive_failures

    4. Check PostgreSQL logs for LOG: unexpected EOF on client connection


    ---


    17. Rollback Plan


    If the migration fails, you can roll back to the local database quickly:


    Before Migration


    1. Keep the local PostgreSQL running during the transition period

    2. Don't delete or disable local database immediately

    3. Keep a copy of the original taskapp.env


    Rollback Steps


    1. Stop Corejobtrack:

    
       sudo systemctl stop taskmanager-ssl
    

    2. Restore original config:

    
       # Revert to local database
       DB_HOST=localhost
    

    3. (Optional) Sync back any new data:

    
       # On remote server
       pg_dump -h 10.0.0.2 -U corejobtrack_user -d corejobtrack \
         --format=custom --file=rollback_data.dump
    
       # On local server
       pg_restore -h localhost -U corejobtrack_user -d corejobtrack \
         --clean --if-exists --no-owner rollback_data.dump
    

    4. Restart Corejobtrack:

    
       sudo systemctl start taskmanager-ssl
    

    5. Verify:

    
       curl -sk https://localhost:8443/dbhealth
    

    ---



    VariableDefaultDescription
    `DB_NAME``corejobtrack`Database name
    `DB_USER`(empty)Database user
    `DB_PASSWORD`(empty)Database password
    `DB_HOST``localhost`Database server hostname/IP
    `DB_PORT``5432`Database port
    `DB_POOL_ENABLED``true`Enable connection pooling
    `DB_POOL_MIN_CONNECTIONS``2`Minimum pool connections
    `DB_POOL_MAX_CONNECTIONS``20`Maximum pool connections
    `DB_MAX_RETRIES``5`Max connection retry attempts
    `DB_RETRY_BASE_DELAY``1.0`Initial retry delay (seconds)
    `DB_RETRY_MAX_DELAY``30.0`Maximum retry delay (seconds)
    `DB_HEALTH_CHECK_INTERVAL``30`Health check interval (seconds)

    ---


    Previous: Guide 8 — JSON Inputs | Back to: Guide Index