moxie-backend/README.md
Z User b9dbd59e7d feat: add email notifications for contact form submissions
- Add nodemailer dependency for SMTP email delivery
- Create src/services/email.js with reusable email service
- Update POST /api/contact to send email notification after saving
- Email is sent fire-and-forget (doesn't block API response)
- Emails include both plain-text and HTML versions
- Reply-To header set to submitter's email for easy replies
- Add SMTP environment variables to .env.example
- Document email setup in README with provider-specific guides
2026-05-05 21:05:37 +00:00

293 lines
8.2 KiB
Markdown

# Moxie Backend
Express.js backend API for user management of an AI site, built with ESM syntax, Auth0 authentication, and SQLite database.
## Features
- **Auth0 Authentication**: Secure authentication via Auth0
- **User Management**: Auto-creation of users on first login, profile management
- **Credit System**: Track and manage user credits
- **API Keys**: Generate and manage API keys for programmatic access
- **Payment Webhooks**: Ready for Stripe and PayPal integration
- **Admin Endpoints**: User management for administrators
- **SQLite Database**: Lightweight, file-based storage
## Quick Start
```bash
# Install dependencies
npm install
# Copy environment file and configure
cp .env.example .env
# Edit .env with your Auth0 credentials
# Start the server
npm start
# Start in development mode (with auto-reload)
npm run dev
```
The server runs on port 9991 by default.
## Auth0 Setup
### 1. Create Auth0 Application
1. Go to Auth0 Dashboard > Applications > Applications
2. Create a new "Single Page Application" or "Regular Web Application"
3. Configure the following URLs:
- **Allowed Callback URLs**: `https://moxiegen.client.guacamolebox.net/api/callback`
- **Allowed Logout URLs**: `https://moxiegen.client.guacamolebox.net`
- **Allowed Web Origins**: `https://moxiegen.client.guacamolebox.net`
- **Application Login URI**: `https://moxiegen.client.guacamolebox.net/login`
### 2. Create Auth0 API (Optional)
For machine-to-machine authentication:
1. Go to Auth0 Dashboard > Applications > APIs
2. Create a new API
3. Set the identifier as your audience
4. Enable RBAC if needed
### 3. Configure Environment Variables
```env
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/
APP_URL=https://moxiegen.client.guacamolebox.net
```
## API Endpoints
### Auth Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/login` | Redirect to Auth0 login |
| GET | `/api/callback` | Handle Auth0 callback |
| GET | `/api/logout` | Logout and redirect |
### User Endpoints (Requires Auth0 Token)
All authenticated endpoints require `Authorization: Bearer <access_token>` header.
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/users/me` | Get current user profile |
| PUT | `/api/users/me` | Update profile |
| DELETE | `/api/users/me` | Deactivate account |
| GET | `/api/users/credits` | Get credits and history |
| GET | `/api/users/api-keys` | List API keys |
| POST | `/api/users/api-keys` | Create new API key |
| DELETE | `/api/users/api-keys/:keyId` | Revoke API key |
### Admin Endpoints (Requires `role: 'admin'`)
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/users` | List all users |
| GET | `/api/users/:userId` | Get user by ID |
| PUT | `/api/users/:userId` | Update user |
| DELETE | `/api/users/:userId` | Delete user |
| POST | `/api/users/:userId/credits` | Adjust user credits |
| PUT | `/api/users/:userId/role` | Change user role |
### Webhook Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/webhooks/stripe` | Stripe webhook handler |
| POST | `/api/webhooks/paypal` | PayPal webhook handler |
## Frontend Integration
### Login Flow
```javascript
// Redirect to Auth0 login
window.location.href = '/api/login';
// Handle callback (tokens in URL params)
const urlParams = new URLSearchParams(window.location.search);
const accessToken = urlParams.get('access_token');
const idToken = urlParams.get('id_token');
// Store token and use for API calls
localStorage.setItem('access_token', accessToken);
// Make authenticated requests
fetch('/api/users/me', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
```
### Using Auth0 SPA SDK
```javascript
import { Auth0Client } from '@auth0/auth0-spa-js';
const auth0 = new Auth0Client({
domain: 'your-tenant.auth0.com',
client_id: 'your-client-id',
redirect_uri: window.location.origin
});
// Login
await auth0.loginWithRedirect();
// Get token
const token = await auth0.getTokenSilently();
// Use token
fetch('/api/users/me', {
headers: {
'Authorization': `Bearer ${token}`
}
});
```
## Database Schema
### Users Table
- `id` - Primary key (UUID)
- `auth0_id` - Auth0 user ID (sub claim)
- `email` - Email address
- `name` - Display name
- `picture` - Profile picture URL
- `role` - User role ('user' or 'admin')
- `credits` - Available credits
- `subscription_status` - Subscription state
- `subscription_tier` - Subscription level
- `stripe_customer_id` - Stripe customer reference
- `paypal_customer_id` - PayPal customer reference
- `is_active` - Account status flag
### API Keys Table
- `id` - Key ID
- `user_id` - Foreign key to users
- `key_hash` - Hashed API key
- `name` - Key name/description
- `is_active` - Key status
### Credit Transactions Table
- `id` - Transaction ID
- `user_id` - Foreign key to users
- `amount` - Credit amount (+/-)
- `type` - 'credit' or 'debit'
- `description` - Transaction description
### Payments Table
- `id` - Payment ID
- `user_id` - Foreign key to users
- `amount` - Payment amount
- `provider` - 'stripe' or 'paypal'
- `status` - Payment status
## Caddy Configuration
```caddyfile
moxiegen.client.guacamolebox.net {
# Static site
root * /path/to/static/site
file_server
# API proxy
handle /api/* {
reverse_proxy localhost:9991
}
}
```
## Making a User Admin
To promote a user to admin role:
1. Find the user ID from the database
2. Use the admin API (requires an existing admin)
3. Or directly update the database:
```sql
UPDATE users SET role = 'admin' WHERE email = 'admin@example.com';
```
## Payment Integration
### Stripe Setup
1. Create a Stripe account and get API keys
2. Add keys to environment variables
3. Create a webhook endpoint in Stripe dashboard pointing to `https://moxiegen.client.guacamolebox.net/api/webhooks/stripe`
4. Copy the webhook signing secret to `STRIPE_WEBHOOK_SECRET`
### PayPal Setup
1. Create a PayPal Developer account
2. Create a REST API application
3. Add credentials to environment variables
4. Configure webhook in PayPal dashboard pointing to `https://moxiegen.client.guacamolebox.net/api/webhooks/paypal`
## Email Configuration (Contact Form)
Contact form submissions are automatically emailed to a configured address using Nodemailer with SMTP.
### Setup
Add the following to your `.env` file:
```env
# SMTP Email Configuration
SMTP_HOST=smtp.gmail.com # Your SMTP server
SMTP_PORT=587 # Usually 587 (TLS) or 465 (SSL)
SMTP_USER=your-email@gmail.com # Email address to send from
SMTP_PASS=your-app-password # Password or app-specific password
SMTP_SECURE=false # true for port 465, false for 587
SMTP_FROM=Moxie <your-email@gmail.com> # From display name & address
# Where contact form emails are sent (defaults to SMTP_USER)
CONTACT_EMAIL=notifications@yourdomain.com
```
### Gmail Users
If you use Gmail, you must generate an **App Password** because regular passwords no longer work with SMTP:
1. Go to [Google Account Security](https://myaccount.google.com/security)
2. Enable **2-Step Verification** (if not already enabled)
3. Go to **App passwords** (search in security settings)
4. Create a new app password for "Mail"
5. Use that 16-character password as `SMTP_PASS`
### Other Providers
| Provider | SMTP_HOST | SMTP_PORT | Notes |
|----------|-----------|-----------|-------|
| Gmail | smtp.gmail.com | 587 | Requires App Password |
| Outlook / Office 365 | smtp.office365.com | 587 | |
| SendGrid | smtp.sendgrid.net | 587 | Use API key as password |
| Mailgun | smtp.mailgun.org | 587 | |
| AWS SES | email-smtp.[region].amazonaws.com | 587 | Use SMTP credentials |
### How It Works
When someone submits the contact form (`POST /api/contact`):
1. The submission is **saved to the database** (always succeeds)
2. An email notification is **sent in the background** (fire-and-forget)
3. If email sending fails, the form still saves — a warning is logged but the user is not affected
The email includes:
- Plain-text and HTML versions
- The submitter's name, email, and company (if provided)
- The full message
- A reply-to header so you can reply directly to the submitter
## License
ISC