A Dockerized web application for tracking shared repair fund contributions with multi-user support, admin controls, and multiple UI themes.
- Multi-user authentication with JWT-based session management
- Shared fund tracking — all users see all contributions in real-time
- Admin controls:
- Create and delete user accounts
- Force password resets on users
- View all contributions and user list
- Forced password changes — admin-reset passwords require immediate change on next login
- Fund balance tracking — real-time total of all contributions
- 6 selectable themes — dark and light options, switched per-browser via the admin panel
- Responsive design — works on desktop and mobile browsers
- Docker & Docker Compose
# Start the containers
docker compose up --build -d
# App will be available at http://localhost:3000Username: admin
Password: (set via ADMIN_INITIAL_PASS in .env)
The admin account is created by the application only when the database has no admin. The initial password must be at least 8 characters, and the admin is required to change it on first login. Existing admin passwords are not overwritten during normal startup.
Older installations containing the former admin123 seed are detected at
startup and migrated to ADMIN_INITIAL_PASS, with a password change required
on the next login.
Before deploying this security update, rotate JWT_SECRET to a new random
value. This signs out existing sessions so every user receives the new
identity-only token format.
- Navigate to
http://localhost:3000 - Enter your username and password
- If your password was reset, you'll be directed to change it
- Total Fund Balance — displays the sum of all contributions
- Add Contribution — submit a dollar amount with optional description and date
- All Contributions — view all contributions from all users (newest first)
- Account Info — view your username and role
- Add New User — create new user accounts with initial passwords
- Manage Users — reset passwords or delete users
- Appearance — switch the UI theme (saved per-browser)
- Password Reset Flow:
- Click "Reset Password" on a user
- A temporary password is generated and displayed (show-once)
- Share this with the user
- User logs in with temp password → forced to change it
- User sets their new password → redirected to dashboard
Click the "Logout" button in the navbar to end your session.
7 selectable themes (dark and light). See THEMES.md for screenshots and details.
- Node.js + Express — HTTP server and API
- MariaDB — persistent data storage
- JWT — authentication tokens (stored in httpOnly cookies)
- bcryptjs — password hashing
- HTML5 — semantic markup
- Bootstrap 5 — responsive components
- CSS custom properties — per-theme variable system
- Vanilla JavaScript — dynamic interactions
users table
id, username, password_hash, role (admin|user), force_password_change, created_at
entries table
id, user_id, amount, description, entry_date, created_at
POST /api/auth/login— Login with credentialsPOST /api/auth/logout— Logout
POST /api/auth/change-password— Change password (forced after admin reset)
GET /api/entries— Get all contributions (all users)GET /api/entries/summary— Get total fund balancePOST /api/entries— Create new contributionDELETE /api/entries/:id— Delete own contribution (admin can delete any)
GET /api/users— List all usersPOST /api/users— Create new userDELETE /api/users/:id— Delete userPOST /api/users/:id/reset-password— Reset user password
Copy .env.example to .env and fill in your values:
cp .env.example .envDB_HOST=db
DB_USER=repair_user
DB_PASS=repair_password_123
DB_NAME=repair_fund
JWT_SECRET=your_jwt_secret_key_change_in_production
ADMIN_INITIAL_PASS=Admin1234!
NODE_ENV=development- Passwords are hashed with bcryptjs (10 salt rounds)
- JWTs are stored in httpOnly cookies (prevents XSS theft)
- Tokens contain only the user ID; current role and account status are loaded from the database on every authenticated request
- Admin functions are role-gated on the backend
- SQL injection protected via parameterized queries
- CORS restricted to localhost during development
docker compose down
docker compose upCheck that the MariaDB container is running and healthy:
docker compose ps- On a fresh install or legacy-seed migration, verify credentials match
ADMIN_INITIAL_PASSin.env - On an existing installation, continue using the admin's current password; startup does not replace it
- Check the browser console for error messages
- Ensure cookies are enabled
To modify the app:
- Edit frontend files in
frontend/(changes are live via volume mount — no rebuild needed) - Edit backend files in
backend/(restart the container to apply changes) - Modify the database schema in
backend/db/init.sql(only applies on a fresh database volume)
To rebuild after backend changes:
docker compose down
docker compose up --build