From a5a76743c7838314c124f599a03ce7ae1f5c2ec9 Mon Sep 17 00:00:00 2001 From: Edwin Eames Date: Sat, 17 Jan 2026 15:41:05 -0500 Subject: [PATCH] add readme and .env files --- .env.dev | 31 ++++++ .env.example | 58 ++++++++++ .env.prod | 33 ++++++ .gitignore | 47 +++++++- README.md | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 466 insertions(+), 2 deletions(-) create mode 100644 .env.dev create mode 100644 .env.example create mode 100644 .env.prod diff --git a/.env.dev b/.env.dev new file mode 100644 index 0000000..94fa410 --- /dev/null +++ b/.env.dev @@ -0,0 +1,31 @@ +# =========================================== +# Oil Customer Gateway - DEVELOPMENT Environment +# =========================================== + +# Database Configuration +POSTGRES_USERNAME=postgres +POSTGRES_PASSWORD=password +POSTGRES_SERVER=192.168.1.204 +POSTGRES_PORT=5432 +POSTGRES_DBNAME=eamco + +# JWT Configuration +# Generate with: python -c "import secrets; print(secrets.token_hex(32))" +JWT_SECRET_KEY=CHANGE_ME_GENERATE_A_SECURE_KEY +JWT_ALGORITHM=HS256 +# Longer expiry for development convenience +JWT_ACCESS_TOKEN_EXPIRE_MINUTES=525600 + +# Authorize.Net (Sandbox/Test credentials) +AUTH_NET_API_LOGIN_ID=9U6w96gZmX +AUTH_NET_TRANSACTION_KEY=94s6Qy458mMNJr7G + +# SMTP Configuration +SMTP_SERVER=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=CHANGE_ME_TO_YOUR_EMAIL +SMTP_PASSWORD=CHANGE_ME_TO_YOUR_APP_PASSWORD +SMTP_FROM_EMAIL=CHANGE_ME_TO_YOUR_EMAIL + +# Frontend URL +FRONTEND_URL=http://localhost:3000 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5604c4e --- /dev/null +++ b/.env.example @@ -0,0 +1,58 @@ +# =========================================== +# Oil Customer Gateway - Environment Configuration +# =========================================== +# Copy this file to .env.dev, .env.local, or .env.prod +# and fill in the appropriate values for each environment. +# +# IMPORTANT: Never commit actual .env files to version control! +# =========================================== + +# =========================================== +# DATABASE CONFIGURATION (Required) +# =========================================== +POSTGRES_USERNAME=postgres +POSTGRES_PASSWORD=your_database_password_here +POSTGRES_SERVER=192.168.1.204 +POSTGRES_PORT=5432 +POSTGRES_DBNAME=eamco + +# =========================================== +# JWT CONFIGURATION (Required) +# =========================================== +# Generate a secure secret key using: python -c "import secrets; print(secrets.token_hex(32))" +# IMPORTANT: Use a unique, strong key for production (at least 32 characters) +JWT_SECRET_KEY=generate_a_secure_random_key_here_at_least_32_chars +JWT_ALGORITHM=HS256 +# Token expiry in minutes (30 for production, can use longer for dev) +JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30 + +# =========================================== +# AUTHORIZE.NET PAYMENT GATEWAY (Required for payments) +# =========================================== +# Get these from your Authorize.Net merchant account +# Use sandbox credentials for development/testing +AUTH_NET_API_LOGIN_ID=your_api_login_id +AUTH_NET_TRANSACTION_KEY=your_transaction_key + +# =========================================== +# SMTP EMAIL CONFIGURATION (Required for password reset) +# =========================================== +SMTP_SERVER=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=your_email@gmail.com +# For Gmail, use an App Password (not your regular password) +# Generate at: https://myaccount.google.com/apppasswords +SMTP_PASSWORD=your_app_password_here +SMTP_FROM_EMAIL=your_email@gmail.com + +# =========================================== +# FRONTEND URL (Required for password reset links) +# =========================================== +FRONTEND_URL=http://localhost:3000 + +# =========================================== +# CORS ORIGINS (Optional - defaults based on MODE) +# =========================================== +# Comma-separated list of allowed origins +# Leave empty to use default origins for the current MODE +# CORS_ORIGINS=http://localhost:5173,http://localhost:8000 diff --git a/.env.prod b/.env.prod new file mode 100644 index 0000000..30de8a9 --- /dev/null +++ b/.env.prod @@ -0,0 +1,33 @@ +# =========================================== +# Oil Customer Gateway - PRODUCTION Environment +# =========================================== +# CRITICAL: Use strong, unique values for all secrets! + +# Database Configuration +POSTGRES_USERNAME=postgres +POSTGRES_PASSWORD=CHANGE_ME_TO_YOUR_PROD_DB_PASSWORD +POSTGRES_SERVER=192.168.1.204 +POSTGRES_PORT=5432 +POSTGRES_DBNAME=auburnoil + +# JWT Configuration +# Generate with: python -c "import secrets; print(secrets.token_hex(32))" +# IMPORTANT: Must be unique and at least 32 characters +JWT_SECRET_KEY=CHANGE_ME_GENERATE_A_SECURE_KEY_FOR_PRODUCTION +JWT_ALGORITHM=HS256 +# Short expiry for production security (30 minutes) +JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30 + +# Authorize.Net (PRODUCTION credentials) +AUTH_NET_API_LOGIN_ID=CHANGE_ME_TO_YOUR_PROD_LOGIN_ID +AUTH_NET_TRANSACTION_KEY=CHANGE_ME_TO_YOUR_PROD_KEY + +# SMTP Configuration +SMTP_SERVER=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=CHANGE_ME_TO_YOUR_EMAIL +SMTP_PASSWORD=CHANGE_ME_TO_YOUR_APP_PASSWORD +SMTP_FROM_EMAIL=CHANGE_ME_TO_YOUR_EMAIL + +# Frontend URL +FRONTEND_URL=https://portal.auburnoil.com diff --git a/.gitignore b/.gitignore index 4c87328..bb93ad7 100644 --- a/.gitignore +++ b/.gitignore @@ -119,4 +119,49 @@ helperfunctions/ test.py tools/ nginx.txt -app/node_modules/ \ No newline at end of file +app/node_modules/ + +# Database files +*.db +*.sqlite +*.sqlite3 + +# Docker +.dockerignore + +# Local development +.env.local +.env.development +.env.production + +# Logs +*.log +logs/ + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.bak +*.swp +*.swo + +# Coverage reports +.coverage +htmlcov/ +coverage.xml + +# Migrations (if using Alembic or similar) +alembic/versions/*.py +!alembic/versions/ + +# Testing +.tox/ +.cache/ +.pytest_cache/ diff --git a/README.md b/README.md index c3684bb..b84fff1 100644 --- a/README.md +++ b/README.md @@ -1 +1,298 @@ -# API \ No newline at end of file +# Auburn Oil Customer Gateway - API + +A modern, high-performance REST API powering the Auburn Oil customer self-service portal. Built with FastAPI and designed for reliability, security, and ease of deployment. + +``` + ___ __ ____ _ __ + / | __ __/ /_ __ ___________ / __ \(_) / + / /| |/ / / / __ \/ / / / ___/ __ \ / / / / / / + / ___ / /_/ / /_/ / /_/ / / / / / / / /_/ / / / +/_/ |_\__,_/_.___/\__,_/_/ /_/ /_/ \____/_/_/ + + Customer Gateway API +``` + +## What This Does + +This API serves as the backbone for Auburn Oil's customer portal, enabling: + +| Feature | Description | +|---------|-------------| +| **Customer Onboarding** | Multi-step registration for new customers with tank photo uploads | +| **Order Management** | Place heating oil delivery orders with real-time pricing | +| **Payment Processing** | Secure credit card handling via Authorize.net (PCI-compliant) | +| **Account Management** | Password reset, profile updates, delivery history | +| **Tank Inspections** | Upload and manage annual tank inspection photos | + +## Tech Stack + +- **Framework**: FastAPI 0.104 (async Python) +- **Database**: PostgreSQL with SQLAlchemy 2.0 (async) +- **Authentication**: JWT tokens with bcrypt password hashing +- **Payments**: Authorize.net CIM (tokenized card storage) +- **Server**: Uvicorn ASGI + +## Quick Start + +### Prerequisites + +- Docker & Docker Compose +- PostgreSQL database (can be remote) +- Authorize.net merchant account (sandbox for development) + +### 1. Configure Environment + +Copy the example environment file and customize: + +```bash +cp .env.example .env.dev +``` + +Edit `.env.dev` with your settings: + +```env +# Database +POSTGRES_SERVER=your-db-host +POSTGRES_PORT=5432 +POSTGRES_DBNAME=auburnoil +POSTGRES_USERNAME=postgres +POSTGRES_PASSWORD=your-secure-password + +# Security (generate a strong key!) +JWT_SECRET_KEY=your-256-bit-secret-key +JWT_ALGORITHM=HS256 +JWT_ACCESS_TOKEN_EXPIRE_MINUTES=1440 + +# Payments (use sandbox credentials for dev) +AUTH_NET_API_LOGIN_ID=your-login-id +AUTH_NET_TRANSACTION_KEY=your-transaction-key + +# Email (for password resets) +SMTP_SERVER=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=your-email@gmail.com +SMTP_PASSWORD=your-app-password +SMTP_FROM_EMAIL=noreply@yourdomain.com + +# Frontend URL (for password reset links) +FRONTEND_URL=http://localhost:3000 +``` + +### 2. Deploy with Docker + +**Development** (with hot-reload): +```bash +cd deploy +docker compose -f docker-compose.dev.yml up --build +``` + +**Local Network Testing**: +```bash +cd deploy +docker compose -f docker-compose.local.yml up --build +``` + +**Production**: +```bash +cd deploy +docker compose -f docker-compose.prod.yml up -d --build +``` + +### 3. Access the API + +| Environment | API URL | Docs | +|-------------|---------|------| +| Development | http://localhost:8000 | http://localhost:8000/docs | +| Production | https://api.portal.auburnoil.com | https://api.portal.auburnoil.com/docs | + +## API Endpoints + +### Authentication (`/auth`) + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `POST` | `/auth/login` | Login with email/password, returns JWT | +| `POST` | `/auth/register` | Register existing customer (requires account #) | +| `POST` | `/auth/new` | New customer single-step registration | +| `POST` | `/auth/step1` | New customer wizard - Step 1 (info) | +| `POST` | `/auth/step2` | New customer wizard - Step 2 (credentials) | +| `POST` | `/auth/step3` | New customer wizard - Step 3 (tank photos) | +| `GET` | `/auth/me` | Get current user profile | +| `POST` | `/auth/forgot-password` | Request password reset email | +| `POST` | `/auth/reset-password` | Complete password reset | +| `POST` | `/auth/change-password` | Change password (authenticated) | +| `POST` | `/auth/upload-tank-images` | Upload tank inspection photos | +| `GET` | `/auth/tank-images/{account}` | Get tank image history | + +### Orders (`/order`) + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `POST` | `/order/` | Place new delivery order (min 100 gallons) | + +### Customer Info (`/info`) + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/info/deliveries` | Get delivery history (last 20) | +| `GET` | `/info/pricing/current` | Get current oil price per gallon | + +### Payments (`/payment`) + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `POST` | `/payment/process` | Process payment (saved or new card) | +| `GET` | `/payment/cards` | List saved payment methods | +| `POST` | `/payment/cards` | Save new card (tokenize) | +| `PUT` | `/payment/cards/{id}` | Update card details | +| `DELETE` | `/payment/cards/{id}` | Remove saved card | +| `POST` | `/payment/cards/{id}/set-default` | Set default payment method | +| `POST` | `/payment/sync-billing-info` | Sync billing to Authorize.net | + +## Database Setup + +### Run Migrations + +Apply database migrations in order: + +```bash +# Connect to your PostgreSQL database +psql -h your-host -U postgres -d auburnoil + +# Run migrations +\i migrations/20240108_create_portal_user_table.sql +\i migrations/20240108_add_tank_image_upload_dates.sql +``` + +### Key Tables + +| Table | Purpose | +|-------|---------| +| `customer_customer` | Customer profiles and addresses | +| `portal_user` | Portal login credentials | +| `delivery_delivery` | Delivery orders and history | +| `card_card` | Saved payment methods (tokenized) | +| `transactions` | Payment transaction records | +| `customer_tank` | Tank inspection metadata | +| `pricing_oil_oil` | Daily oil pricing | + +## Project Structure + +``` +api/ +├── main.py # FastAPI app entry point +├── config.py # Environment configuration +├── database.py # Database connection (async) +├── models.py # SQLAlchemy ORM models +├── schemas.py # Pydantic request/response schemas +├── routers/ +│ ├── auth.py # Authentication endpoints +│ ├── info.py # Customer info endpoints +│ ├── order.py # Order management +│ └── payment.py # Payment processing +├── services/ +│ └── authorizenet.py # Authorize.net integration +├── .env.example # Environment template +├── .env.dev # Development config +├── .env.local # Local network config +├── .env.prod # Production config +├── Dockerfile.dev # Development container +├── Dockerfile.local # Local network container +├── Dockerfile.prod # Production container +└── requirements.txt # Python dependencies +``` + +## Security Features + +- **JWT Authentication**: Stateless token-based auth with configurable expiration +- **Password Hashing**: bcrypt with automatic truncation for compatibility +- **PCI Compliance**: Card data never stored locally (Authorize.net tokenization) +- **Image Sanitization**: Uploaded images resized, metadata stripped +- **CORS Protection**: Environment-specific allowed origins +- **Input Validation**: Pydantic schemas validate all inputs + +## Environment Variables Reference + +| Variable | Required | Description | +|----------|----------|-------------| +| `MODE` | Yes | `DEVELOPMENT`, `LOCAL`, or `PRODUCTION` | +| `POSTGRES_SERVER` | Yes | Database host | +| `POSTGRES_PORT` | Yes | Database port (usually 5432) | +| `POSTGRES_DBNAME` | Yes | Database name | +| `POSTGRES_USERNAME` | Yes | Database user | +| `POSTGRES_PASSWORD` | Yes | Database password | +| `JWT_SECRET_KEY` | Yes | Secret for signing tokens (use 256+ bits) | +| `JWT_ALGORITHM` | Yes | Algorithm (HS256 recommended) | +| `JWT_ACCESS_TOKEN_EXPIRE_MINUTES` | Yes | Token lifetime in minutes | +| `AUTH_NET_API_LOGIN_ID` | Yes | Authorize.net API Login ID | +| `AUTH_NET_TRANSACTION_KEY` | Yes | Authorize.net Transaction Key | +| `SMTP_SERVER` | Yes | SMTP server for emails | +| `SMTP_PORT` | Yes | SMTP port (587 for TLS) | +| `SMTP_USERNAME` | Yes | SMTP username | +| `SMTP_PASSWORD` | Yes | SMTP password/app password | +| `SMTP_FROM_EMAIL` | Yes | From address for emails | +| `FRONTEND_URL` | Yes | Frontend URL for reset links | + +## Troubleshooting + +### Common Issues + +**Database connection failed** +``` +Check POSTGRES_* environment variables +Ensure database is accessible from Docker network +Verify firewall allows connections on port 5432 +``` + +**JWT token invalid** +``` +Ensure JWT_SECRET_KEY is the same across restarts +Check token hasn't expired +Verify JWT_ALGORITHM matches what was used to sign +``` + +**Authorize.net errors** +``` +Sandbox vs Production: Use correct credentials for each +Test cards: Use Authorize.net test card numbers in sandbox +Check API Login ID and Transaction Key are correct +``` + +**Image upload fails** +``` +Max file size: 20MB per image +Supported formats: JPEG, PNG +Check /images volume is mounted correctly +``` + +## Development + +### Running Locally (without Docker) + +```bash +# Create virtual environment +python -m venv venv +source venv/bin/activate # Windows: venv\Scripts\activate + +# Install dependencies +pip install -r requirements.txt + +# Set environment variables +export MODE=DEVELOPMENT +# ... set other variables + +# Run with hot-reload +uvicorn main:app --reload --host 0.0.0.0 --port 8000 +``` + +### API Documentation + +FastAPI auto-generates interactive documentation: + +- **Swagger UI**: http://localhost:8000/docs +- **ReDoc**: http://localhost:8000/redoc +- **OpenAPI JSON**: http://localhost:8000/openapi.json + +--- + +**Auburn Oil Customer Gateway** - Built with reliability in mind for New Hampshire and Massachusetts heating oil customers.