Configuration - gabrielmaialva33/innkeeper GitHub Wiki
Customize your Innkeeper installation for optimal performance
This guide covers all configuration options available in Innkeeper, from basic environment variables to advanced system settings. Proper configuration ensures optimal performance, security, and functionality for your hotel management system.
Prerequisites: Complete the Installation Guide and Quick Start first.
Create or update your .env
file with these essential settings:
# Application Settings
NODE_ENV=production
PORT=3333
HOST=0.0.0.0
LOG_LEVEL=info
APP_KEY=your-32-character-secret-key
# Application URLs
APP_URL=https://yourdomain.com
FRONTEND_URL=https://yourdomain.com
API_URL=https://yourdomain.com/api
# Database Configuration
DB_CONNECTION=pg
DB_HOST=localhost
DB_PORT=5432
DB_USER=innkeeper
DB_PASSWORD=your-secure-password
DB_DATABASE=innkeeper
# Redis Configuration (for sessions and cache)
REDIS_CONNECTION=local
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=your-redis-password
# Email Configuration
MAIL_MAILER=smtp
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=your-app-password
[email protected]
MAIL_FROM_NAME="Innkeeper System"
# File Storage
DRIVE_DISK=local
# For S3 storage:
# DRIVE_DISK=s3
# S3_KEY=your-s3-access-key
# S3_SECRET=your-s3-secret-key
# S3_BUCKET=your-bucket-name
# S3_REGION=us-east-1
# Security Settings
SESSION_DRIVER=redis
HASH_DRIVER=bcrypt
ENCRYPTION_CIPHER=aes-256-cbc
# Rate Limiting
RATE_LIMITER_STORE=redis
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_DURATION=60
# Logging
LOG_DRIVER=file
LOG_FILE_PATH=./logs/app.log
LOG_MAX_FILES=10
LOG_MAX_SIZE=10mb
NODE_ENV=development
LOG_LEVEL=debug
APP_URL=http://localhost:3333
FRONTEND_URL=http://localhost:3000
# Enable debug features
DEBUG=true
VITE_DEV_SERVER_URL=http://localhost:5173
NODE_ENV=production
LOG_LEVEL=warn
APP_URL=https://yourdomain.com
FRONTEND_URL=https://yourdomain.com
# Security enhancements
SECURE_COOKIES=true
TRUST_PROXY=true
FORCE_HTTPS=true
// config/database.ts
export default defineConfig({
connection: Env.get('DB_CONNECTION'),
connections: {
pg: {
client: 'pg',
connection: {
host: Env.get('DB_HOST'),
port: Env.get('DB_PORT'),
user: Env.get('DB_USER'),
password: Env.get('DB_PASSWORD'),
database: Env.get('DB_DATABASE'),
},
pool: {
min: 2,
max: 20,
acquireTimeoutMillis: 60000,
createTimeoutMillis: 30000,
destroyTimeoutMillis: 5000,
idleTimeoutMillis: 30000,
reapIntervalMillis: 1000,
createRetryIntervalMillis: 200,
},
migrations: {
naturalSort: true,
paths: ['./database/migrations'],
},
seeders: {
paths: ['./database/seeders'],
},
},
},
})
-- PostgreSQL configuration recommendations
-- Add to postgresql.conf
-- Memory Settings
shared_buffers = 256MB;
effective_cache_size = 1GB;
work_mem = 4MB;
maintenance_work_mem = 64MB;
-- Connection Settings
max_connections = 100;
shared_preload_libraries = 'pg_stat_statements';
-- Logging
log_statement = 'mod';
log_min_duration_statement = 1000;
log_checkpoints = on;
log_connections = on;
log_disconnections = on;
Ensure these indexes exist for optimal performance:
-- Reservations performance indexes
CREATE INDEX CONCURRENTLY idx_reservations_dates ON reservations (check_in_date, check_out_date);
CREATE INDEX CONCURRENTLY idx_reservations_status ON reservations (status);
CREATE INDEX CONCURRENTLY idx_reservations_hotel ON reservations (hotel_id);
CREATE INDEX CONCURRENTLY idx_reservations_guest ON reservations (guest_id);
-- Rooms performance indexes
CREATE INDEX CONCURRENTLY idx_rooms_hotel_status ON rooms (hotel_id, status);
CREATE INDEX CONCURRENTLY idx_rooms_type ON rooms (room_type_id);
-- Guests search indexes
CREATE INDEX CONCURRENTLY idx_guests_email ON guests (email);
CREATE INDEX CONCURRENTLY idx_guests_phone ON guests (phone);
CREATE INDEX CONCURRENTLY idx_guests_name ON guests (first_name, last_name);
-- Audit logs indexes
CREATE INDEX CONCURRENTLY idx_audit_logs_user ON audit_logs (user_id);
CREATE INDEX CONCURRENTLY idx_audit_logs_resource ON audit_logs (resource, resource_id);
CREATE INDEX CONCURRENTLY idx_audit_logs_created ON audit_logs (created_at);
MAIL_MAILER=smtp
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=your-app-password
SMTP_ENCRYPTION=tls
MAIL_MAILER=smtp
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USERNAME=apikey
SMTP_PASSWORD=your-sendgrid-api-key
SMTP_ENCRYPTION=tls
MAIL_MAILER=ses
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_DEFAULT_REGION=us-east-1
SES_VERSION=2010-12-01
Configure email templates in config/mail.ts
:
export default defineConfig({
default: Env.get('MAIL_MAILER'),
mailers: {
smtp: {
driver: 'smtp',
host: Env.get('SMTP_HOST'),
port: Env.get('SMTP_PORT'),
auth: {
user: Env.get('SMTP_USERNAME'),
pass: Env.get('SMTP_PASSWORD'),
},
},
},
// Email templates configuration
templates: {
reservation_confirmation: {
subject: 'Booking Confirmation - {{hotel_name}}',
template: 'emails/reservation_confirmation',
},
check_in_instructions: {
subject: 'Check-in Instructions - {{hotel_name}}',
template: 'emails/check_in_instructions',
},
payment_receipt: {
subject: 'Payment Receipt - {{confirmation_number}}',
template: 'emails/payment_receipt',
},
},
})
// config/auth.ts
export default defineConfig({
default: 'web',
guards: {
web: {
driver: 'session',
provider: 'users',
},
api: {
driver: 'access_tokens',
provider: 'users',
},
},
providers: {
users: {
driver: 'lucid',
identifierKey: 'id',
uids: ['email', 'username'],
model: () => import('#models/user'),
},
},
// Session configuration
session: {
cookieName: 'innkeeper_session',
clearWithBrowser: false,
age: '2h',
sameSite: 'lax',
secure: Env.get('NODE_ENV') === 'production',
},
// Token configuration
tokens: {
default_expiry: '30d',
refresh_token_expiry: '90d',
},
})
// config/cors.ts
export default defineConfig({
enabled: true,
origin: [
'http://localhost:3000',
'http://localhost:3333',
'https://yourdomain.com',
],
methods: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'],
headers: true,
exposeHeaders: [
'cache-control',
'content-language',
'content-type',
'expires',
'last-modified',
'pragma',
],
credentials: true,
maxAge: 90,
})
// config/limiter.ts
export default defineConfig({
default: 'redis',
stores: {
redis: {
connectionName: 'main',
},
},
// Rate limiting rules
rules: {
api: {
requests: 100,
duration: '1m',
},
auth: {
requests: 5,
duration: '15m',
},
reservation: {
requests: 10,
duration: '1m',
},
},
})
// config/drive.ts
export default defineConfig({
default: 'local',
disks: {
local: {
driver: 'fs',
root: './uploads',
serveFiles: true,
basePath: '/uploads',
},
},
})
# Environment variables
DRIVE_DISK=s3
S3_KEY=your-access-key
S3_SECRET=your-secret-key
S3_BUCKET=innkeeper-files
S3_REGION=us-east-1
S3_ENDPOINT=https://s3.amazonaws.com
// config/drive.ts - S3 configuration
export default defineConfig({
default: 's3',
disks: {
s3: {
driver: 's3',
key: Env.get('S3_KEY'),
secret: Env.get('S3_SECRET'),
region: Env.get('S3_REGION'),
bucket: Env.get('S3_BUCKET'),
endpoint: Env.get('S3_ENDPOINT'),
// Optional: Custom domain for file URLs
cdnUrl: 'https://cdn.yourdomain.com',
},
},
})
// config/bodyparser.ts
export default defineConfig({
whitelistedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
json: {
encoding: 'utf8',
limit: '1mb',
strict: true,
types: ['application/json', 'application/json-patch+json'],
},
form: {
encoding: 'utf8',
limit: '1mb',
queryString: {},
types: ['application/x-www-form-urlencoded'],
},
raw: {
encoding: 'utf8',
limit: '1mb',
types: ['text/*'],
},
multipart: {
autoProcess: true,
processManually: [],
encoding: 'utf8',
maxFields: 1000,
limit: '20mb',
types: ['multipart/form-data'],
},
})
// config/tenant.ts
export default defineConfig({
// Tenant identification strategy
identification: {
strategy: 'subdomain', // 'subdomain' | 'domain' | 'header'
header: 'X-Tenant-ID',
},
// Database strategy
database: {
strategy: 'single_db', // 'single_db' | 'multi_db'
tenant_column: 'organization_id',
},
// Cache strategy
cache: {
prefix_with_tenant: true,
tenant_separator: ':',
},
// File storage strategy
storage: {
tenant_folders: true,
folder_structure: 'organization_id/hotel_id',
},
})
// config/business.ts
export default defineConfig({
reservations: {
// Advance booking limits
max_advance_days: 365,
min_advance_hours: 2,
// Cancellation policies
free_cancellation_hours: 24,
partial_refund_hours: 48,
// Overbooking settings
allow_overbooking: false,
overbooking_percentage: 5,
},
rooms: {
// Housekeeping settings
cleaning_time_minutes: 30,
inspection_required: true,
maintenance_window_hours: 2,
},
payments: {
// Payment processing
require_deposit: true,
deposit_percentage: 50,
payment_timeout_minutes: 15,
// Supported currencies
default_currency: 'USD',
supported_currencies: ['USD', 'EUR', 'GBP', 'BRL'],
},
notifications: {
// Email notifications
send_confirmation: true,
send_reminders: true,
reminder_hours_before: 24,
// SMS notifications (if enabled)
sms_enabled: false,
sms_provider: 'twilio',
},
})
// config/logger.ts
export default defineConfig({
default: 'app',
loggers: {
app: {
enabled: true,
name: Env.get('APP_NAME'),
level: Env.get('LOG_LEVEL', 'info'),
redact: {
paths: ['password', 'email', 'phone'],
censor: '***REDACTED***',
},
},
},
// Log targets
targets: [
{
target: 'pino/file',
options: {
destination: './logs/app.log',
},
level: 'info',
},
{
target: 'pino-pretty',
options: {
colorize: true,
},
level: 'debug',
},
],
})
# Environment variables for monitoring
MONITORING_ENABLED=true
METRICS_ENDPOINT=/metrics
HEALTH_CHECK_ENDPOINT=/health
# APM Integration (optional)
APM_SERVICE_NAME=innkeeper
APM_SERVER_URL=https://apm.yourdomain.com
APM_SECRET_TOKEN=your-apm-token
// config/health.ts
export default defineConfig({
checks: [
{
name: 'database',
checker: 'database',
timeout: 5000,
},
{
name: 'redis',
checker: 'redis',
timeout: 3000,
},
{
name: 'disk_space',
checker: 'disk_space',
threshold: '80%',
},
{
name: 'memory',
checker: 'memory',
threshold: '90%',
},
],
})
#!/bin/bash
# backup-database.sh
DB_NAME="innkeeper"
DB_USER="innkeeper"
BACKUP_DIR="/var/backups/innkeeper"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p $BACKUP_DIR
# Create database backup
pg_dump -U $DB_USER -h localhost $DB_NAME | gzip > $BACKUP_DIR/db_backup_$DATE.sql.gz
# Keep only last 7 days of backups
find $BACKUP_DIR -name "db_backup_*.sql.gz" -mtime +7 -delete
echo "Database backup completed: db_backup_$DATE.sql.gz"
#!/bin/bash
# backup-files.sh
SOURCE_DIR="/path/to/innkeeper/uploads"
BACKUP_DIR="/var/backups/innkeeper/files"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p $BACKUP_DIR
# Create file backup
tar -czf $BACKUP_DIR/files_backup_$DATE.tar.gz -C $SOURCE_DIR .
# Keep only last 30 days of file backups
find $BACKUP_DIR -name "files_backup_*.tar.gz" -mtime +30 -delete
echo "Files backup completed: files_backup_$DATE.tar.gz"
# Add to crontab (crontab -e)
# Database backup every 6 hours
0 */6 * * * /path/to/backup-database.sh
# File backup daily at 2 AM
0 2 * * * /path/to/backup-files.sh
# Weekly full system backup
0 3 * * 0 /path/to/full-backup.sh
// config/app.ts - Performance settings
export default defineConfig({
// Enable HTTP compression
compression: {
enabled: true,
level: 6,
threshold: 1024,
},
// Static file caching
static: {
enabled: true,
maxAge: '1y',
etag: true,
},
// Request timeout
timeout: 30000,
// Body parser limits
bodyParser: {
limit: '10mb',
},
})
// Enable query logging in development
if (Env.get('NODE_ENV') === 'development') {
Database.on('query', (query) => {
console.log('Query:', query.sql)
console.log('Bindings:', query.bindings)
console.log('Duration:', query.duration, 'ms')
})
}
// config/cache.ts
export default defineConfig({
default: 'redis',
stores: {
redis: {
driver: 'redis',
connectionName: 'main',
ttl: 3600, // 1 hour default TTL
},
},
// Cache strategies
strategies: {
hotels: {ttl: 86400}, // 24 hours
room_types: {ttl: 43200}, // 12 hours
amenities: {ttl: 86400}, // 24 hours
user_sessions: {ttl: 7200}, // 2 hours
},
})
// config/kernel.ts
export default defineConfig({
middleware: {
global: [
() => import('#middleware/container_bindings_middleware'),
() => import('#middleware/force_json_response_middleware'),
() => import('#middleware/cors_middleware'),
() => import('#middleware/tenant_context_middleware'),
],
named: {
auth: () => import('#middleware/auth_middleware'),
guest: () => import('#middleware/guest_middleware'),
admin: () => import('#middleware/admin_middleware'),
rateLimit: () => import('#middleware/rate_limit_middleware'),
},
},
})
// config/validator.ts
export default defineConfig({
bail: true,
existsStrict: true,
// Custom validation rules
rules: {
phone: () => import('#validators/rules/phone'),
currency: () => import('#validators/rules/currency'),
dateRange: () => import('#validators/rules/date_range'),
roomAvailability: () => import('#validators/rules/room_availability'),
},
})
// config/queue.ts
export default defineConfig({
default: 'redis',
queues: {
redis: {
driver: 'redis',
connectionName: 'main',
// Queue settings
defaultJobOptions: {
removeOnComplete: 10,
removeOnFail: 50,
attempts: 3,
backoff: {
type: 'exponential',
delay: 2000,
},
},
},
},
// Job types
jobs: {
email: {
queue: 'emails',
attempts: 5,
delay: 1000,
},
reports: {
queue: 'reports',
attempts: 3,
delay: 5000,
},
cleanup: {
queue: 'maintenance',
attempts: 1,
delay: 0,
},
},
})
Create a validation script to check your configuration:
#!/bin/bash
# validate-config.sh
echo "🔍 Validating Innkeeper Configuration..."
# Check required environment variables
required_vars=(
"NODE_ENV"
"PORT"
"APP_KEY"
"DB_CONNECTION"
"DB_HOST"
"DB_USER"
"DB_PASSWORD"
"DB_DATABASE"
)
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
echo "❌ Missing required environment variable: $var"
exit 1
else
echo "✅ $var is set"
fi
done
# Test database connection
echo "🔍 Testing database connection..."
node ace db:check || exit 1
# Test Redis connection
echo "🔍 Testing Redis connection..."
node ace redis:check || exit 1
# Validate configuration files
echo "🔍 Validating configuration files..."
node ace config:validate || exit 1
echo "🎉 Configuration validation completed successfully!"
- Environment variables properly set
- Database connection working
- Redis connection established
- Email configuration tested
- File storage accessible
- Security settings configured
- Logging properly configured
- Backup scripts in place
- Performance optimizations applied
- Health checks responding
# Test database connection
node ace db:check
# Check database logs
tail -f /var/log/postgresql/postgresql-*.log
# Test Redis connection
redis-cli ping
# Check Redis logs
tail -f /var/log/redis/redis-server.log
# Test email configuration
node ace mail:test [email protected]
# Check file permissions
ls -la uploads/
chmod -R 755 uploads/
chown -R www-data:www-data uploads/
After completing the configuration:
- System Architecture - Understand the system design
- Security Model - Learn about security features
- API Documentation - Explore the API endpoints
- Performance Optimization - Advanced performance tuning
- 📖 Documentation: Wiki Home
- 🐛 Issues: GitHub Issues
- 💬 Community: GitHub Discussions
- 📧 Support: Contact the development team
← Previous: Quick Start | Wiki Home | Next: System Architecture →