6c35393f1fcfc146dc182513d24ff4d837ccf16a
Updates the user registration and new account creation endpoints to require email confirmation. - Sets the 'confirmed' flag to 'false' by default for all new user accounts. - Generates a unique confirmation token for each new user. - Logs the confirmation link to the console for development purposes. This change ensures that users cannot log in without first verifying their email address, enhancing account security.
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:
cp .env.example .env.dev
Edit .env.dev with your settings:
# 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):
cd deploy
docker compose -f docker-compose.dev.yml up --build
Local Network Testing:
cd deploy
docker compose -f docker-compose.local.yml up --build
Production:
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:
# 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)
# 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.
Description
Languages
Python
100%