- Changed logout to use window.location.href for full page reload - Ensures all components refresh and show correct unauthenticated state - Fixes issue where logout appeared to do nothing until manual refresh - Menu, notes section, and all auth-dependent UI now update immediately Previously, using navigateTo() to the same page didn't trigger a refresh, leaving stale authenticated UI visible. Full page reload ensures clean state. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
New Life Christian Church - Sermon Itinerary
A web application for managing and displaying weekly sermons for New Life Christian Church.
Features
- 📝 Sermon Management: Create and manage sermon content with a user-friendly form
- 🔐 Enterprise Security: OWASP-compliant authentication with CSRF protection, session management, and account lockout
- 👥 User Management: Full admin panel for managing users, roles, and account security
- 🔒 Password Security: Bcrypt hashing, strong password requirements, and secure password reset with 8-character alphanumeric codes
- 🛡️ Account Protection: Dual-layer brute force protection (IP-based + per-account lockout)
- 📱 QR Codes: Generate QR codes for easy sermon sharing
- 📅 Date-based URLs: Sermons accessible via
sermon-MMDDYYYYformat - 🎨 Modern UI: Clean, responsive design using Tailwind CSS and Inter font
- 📊 Three Sections: Bible References, Personal Appliance, and Pastor's Challenge
- 🗂️ Smart Organization: Recent sermons (last 3 months) displayed by default, older sermons in dropdown
- 📧 Email Notifications: Password reset codes and sermon notes via SMTP
- 🐳 Docker Ready: Fully containerized for easy deployment with auto-generated secrets
Technology Stack
- Frontend: Nuxt 3 (Vue.js)
- Styling: Tailwind CSS with Inter font from Google Fonts
- Database: SQLite
- QR Codes: qrcode library
- Deployment: Docker & Docker Compose
Configuration
This application uses environment variables configured directly in docker-compose.yml. Edit the file to customize your deployment settings.
Environment Variables
| Variable | Description | Default | Required |
|---|---|---|---|
SITE_URL |
Public URL where the app is hosted (used for QR codes) | https://church.example.com |
Yes |
AUTH_SECRET |
Secret key for authentication sessions | Auto-generated | No |
ADMIN_USERNAME |
Initial admin login username | admin |
No |
ADMIN_PASSWORD |
Initial admin login password | Auto-generated | No |
EMAIL_HOST |
SMTP server hostname | smtp.example.com |
Yes |
EMAIL_PORT |
SMTP server port | 587 |
Yes |
EMAIL_USER |
SMTP authentication username | noreply@example.com |
Yes |
EMAIL_PASSWORD |
SMTP authentication password | Required | Yes |
EMAIL_FROM |
Email sender address and name | New Life Christian Church <noreply@example.com> |
Yes |
Security Note: AUTH_SECRET and ADMIN_PASSWORD are now automatically generated on first launch using cryptographically secure random generation. They are stored in the database and logged once to container logs.
Customizing Configuration
Edit docker-compose.yml and update the required values:
services:
nlcc-itinerary:
environment:
- SITE_URL=https://your-church-domain.com
# Optional: customize admin username (default: "admin")
# - ADMIN_USERNAME=your-admin-username
# Optional: set custom admin password (otherwise auto-generated)
# - ADMIN_PASSWORD=your-secure-password
# Email configuration (required for password resets)
- EMAIL_HOST=smtp.gmail.com
- EMAIL_PORT=587
- EMAIL_USER=your-email@gmail.com
- EMAIL_PASSWORD=your-app-password
- EMAIL_FROM=Your Church Name <your-email@gmail.com>
Note: AUTH_SECRET is no longer needed in configuration - it's automatically generated and stored in the database on first launch.
Getting Started
Prerequisites
- Docker and Docker Compose installed on your system
Installation & Deployment
- Clone the repository:
git clone <repository-url>
cd nlcc-itinerary
-
Edit
docker-compose.ymland configure your settings:- Update
SITE_URLto your public domain - Configure email settings (required for password resets)
- Optionally set
ADMIN_USERNAMEandADMIN_PASSWORD(otherwise auto-generated)
- Update
-
Build and run with Docker Compose:
docker-compose up -d --build
The Docker volume will be automatically created as nlcc-itinerary_data.
The application will be available at http://localhost:3002 (or your configured port)
Important: The SITE_URL must be set correctly for QR codes to work. This should be the public URL where your application is accessible (e.g., https://church.example.com).
Initial Admin Account
The initial admin account is created automatically on first run with secure auto-generated credentials:
Default behavior:
- Username:
admin(can be customized withADMIN_USERNAMEenv var) - Password: Auto-generated (cryptographically secure 16-character password)
Retrieving Auto-Generated Credentials:
# View the auto-generated admin password from container logs
docker logs nlcc-itinerary 2>&1 | grep "ADMIN CREDENTIALS"
The output will show:
╔════════════════════════════════════════════════════════╗
║ 🔐 ADMIN CREDENTIALS (SAVE THESE!) ║
╠════════════════════════════════════════════════════════╣
║ Username: admin ║
║ Password: <randomly-generated-password> ║
╚════════════════════════════════════════════════════════╝
⚠️ Important:
- Credentials are logged only once on first startup
- Save the credentials immediately - they won't be shown again
- Alternatively, set
ADMIN_PASSWORDindocker-compose.ymlto use a custom password - Change admin password after first login via the profile page
- Additional users and admins can be created through the user management interface
Project Structure
nlcc-itinerary/
├── assets/css/ # Global styles
├── components/ # Vue components
│ ├── SermonCard.vue
│ ├── QRCodeButton.vue
│ └── QRCodeModal.vue
├── middleware/ # Route middleware
│ └── auth.ts
├── pages/ # Application pages
│ ├── index.vue # Main sermon listing
│ ├── login.vue # Login page
│ ├── register.vue # User registration
│ ├── admin.vue # Sermon creation form
│ ├── users.vue # User management (admin only)
│ ├── profile.vue # User profile settings
│ └── [slug].vue # Individual sermon page
├── plugins/ # Nuxt plugins
│ └── csrf.client.ts # CSRF auto-injection
├── server/
│ ├── api/ # API endpoints
│ │ ├── auth/ # Authentication endpoints
│ │ ├── sermons/ # Sermon CRUD endpoints
│ │ ├── users/ # User management endpoints
│ │ └── profile/ # Profile management
│ ├── middleware/ # Server middleware
│ │ └── csrf.ts # CSRF validation
│ └── utils/ # Server utilities
│ ├── database.ts # SQLite database functions
│ ├── auth.ts # Authentication helpers
│ ├── csrf.ts # CSRF protection utilities
│ └── email.ts # Email sending functions
├── logos/ # Church logos
├── Dockerfile # Docker configuration
├── docker-compose.yml # Docker Compose configuration
└── nuxt.config.ts # Nuxt configuration
Usage
Creating a Sermon
- Navigate to
/loginand sign in with admin credentials - You'll be redirected to
/admin - Fill in the sermon details:
- Date: Select the sermon date (URL will be auto-generated as
sermon-MMDDYYYY) - Title: Enter the sermon title
- Bible References: Add one or more Bible verses (use +/- buttons)
- Personal Appliance: Enter personal application content
- Pastor's Challenge: Enter the pastor's challenge content
- Date: Select the sermon date (URL will be auto-generated as
- Click "Create Sermon"
Viewing Sermons
- Main Page (
/): Shows recent sermons (last 3 months) with option to view older ones - Individual Sermon (
/sermon-MMDDYYYY): Full sermon details with QR code - QR Code: Click the QR code button on any sermon card or page to generate a scannable code
Database
The application uses SQLite with the following schema:
Sermons Table
id: Primary keyslug: Unique sermon identifier (e.g., sermon-09282025)title: Sermon titledate: Sermon datebible_references: Newline-separated Bible versespersonal_appliance: Personal application contentpastors_challenge: Pastor's challenge contentcreated_at: Timestamp
Users Table
id: Primary keyusername: User's username (unique)password: User's password (bcrypt hashed)first_name: User's first namelast_name: User's last nameemail: User's email addressis_admin: Admin flag (0 or 1)failed_login_attempts: Failed login counterlocked_until: Account lock expiration timestampcreated_at: Account creation timestamp
Sessions Table
id: Primary keytoken: Session token (unique)username: Associated usernameexpires_at: Session expiration timestampcsrf_token: CSRF token for request validationcreated_at: Session creation timestamp
Settings Table
key: Setting key (primary)value: Setting valuecreated_at: Creation timestampupdated_at: Last update timestamp
Security Features
This application implements enterprise-grade security following OWASP best practices:
✅ Implemented Security Features
-
Auto-Generated Secrets
AUTH_SECRETautomatically generated using cryptographic randomness- Admin password auto-generated with 16 characters (uppercase, lowercase, numbers, symbols)
- All secrets stored securely in database
-
Password Security
- Bcrypt hashing with 10 salt rounds
- Strong password requirements (8+ chars, uppercase, lowercase, number/symbol)
- Secure password reset with 8-character alphanumeric codes (1.8 trillion combinations)
- Session invalidation on password changes
-
CSRF Protection
- Double-submit cookie pattern implementation
- Automatic token injection on all API requests
- Three-way validation (cookie, header, session database)
- Zero configuration needed in components
-
Session Management
- Secure session tokens with HTTP-only cookies
- Automatic session expiration (24 hours)
- Session invalidation on security events (password changes, admin resets)
- Protection against session fixation attacks
-
Account Lockout (Dual-Layer Brute Force Protection)
- IP-based rate limiting: 5 failed attempts = 15 minute lockout
- Per-account lockout: 5 failed attempts = 15 minute lock
- Automatic unlock after expiration
- Admin manual unlock capability via UI
-
User Management
- Role-based access control (admin/user)
- Admin dashboard for user management
- Account lock status visibility
- Password reset functionality
🔒 Production Recommendations
- ✅ Strong passwords - Enforced by application
- ✅ Password hashing - Bcrypt with salt rounds
- ✅ CSRF protection - Implemented
- ✅ Session security - HTTP-only cookies with expiration
- ✅ Account lockout - Dual-layer protection
- ✅ Secrets management - Auto-generated and stored securely
- Enable HTTPS - Configure reverse proxy (nginx/Caddy)
- Regular backups - Backup
/app/datadirectory - Email security - Use app-specific passwords for SMTP
- Monitor logs - Review failed login attempts
🛡️ Security Compliance
- OWASP Top 10 2021: Addressed broken authentication, injection, security misconfiguration
- Password Storage: NIST-compliant bcrypt hashing
- CSRF Protection: Industry-standard double-submit pattern
- Session Security: Secure cookie attributes and expiration
- Brute Force Protection: Account lockout + rate limiting
Docker Commands
# Build and start
docker-compose up -d
# View logs
docker-compose logs -f
# Stop containers
docker-compose down
# Rebuild after changes
docker-compose up -d --build
# Access container shell
docker exec -it nlcc-itinerary sh
Data Persistence
The SQLite database is stored in a Docker named volume (nlcc-itinerary_data) which is mounted to /app/data in the container. This ensures:
- Data persists across container restarts and rebuilds
- Better portability across different environments
- Easier backup and restore operations
- Managed by Docker volume system
- Automatic creation on first
docker-compose up
Volume Management Commands:
# Inspect volume location and details
docker volume inspect nlcc-itinerary_data
# Backup the database
docker run --rm -v nlcc-itinerary_data:/data -v $(pwd):/backup alpine tar czf /backup/nlcc-backup.tar.gz -C /data .
# Restore from backup
docker run --rm -v nlcc-itinerary_data:/data -v $(pwd):/backup alpine tar xzf /backup/nlcc-backup.tar.gz -C /data
# Remove volume (WARNING: deletes all data!)
docker volume rm nlcc-itinerary_data
License
This project is created for New Life Christian Church.
Support
For issues or questions, please contact the development team.