A modern, secure React/TypeScript customer portal with full TeselaGen API integration, featuring white-labeling and comprehensive request management.
- Secure Authentication: JWT-based auth with bcrypt password hashing + API token support
- File Upload: Multi-file support with file-format validation
- Request Management: Real-time status tracking and ELN report access
- User Management: Complete admin user management with CRUD operations
- White-labeling: Customizable portal branding (name, logo, colors)
- Transaction System: User balance tracking and API token spending limits
- Frontend: React 18 + TypeScript (custom styling, no external UI libraries)
- Backend: Express.js + PostgreSQL + TypeScript
- Authentication: JWT with bcrypt (email/password)
- Deployment: Docker containerization and easy deployment
- Node.js 18+
- PostgreSQL 12+
- Docker & Docker Compose (for containerized deployment)
Install Git Security Hooks (Recommended):
# Install pre-commit hooks to prevent accidental secret commits
./scripts/install-git-hooks.shCreate environment files:
# Backend environment
cp packages/backend/.env.example packages/backend/.envEdit packages/backend/.env:
# Database
DATABASE_URL=postgresql://username:password@localhost:5432/customer_portal
DB_HOST=localhost
DB_PORT=5432
DB_NAME=customer_portal
DB_USER=your_username
DB_PASSWORD=your_password
# Security
# CRITICAL: Generate strong secrets for production!
# Generate JWT_SECRET: openssl rand -hex 64
# Generate ENCRYPTION_KEY: openssl rand -hex 32
JWT_SECRET=your-super-secret-jwt-key-here
BCRYPT_ROUNDS=12
ENCRYPTION_KEY=your-256-bit-encryption-key-for-sensitive-data
# Server
PORT=8080
NODE_ENV=development
FRONTEND_URL=http://localhost:3000
# File Upload
UPLOAD_DIR=./uploads
MAX_FILE_SIZE=52428800
MAX_FILES_PER_REQUEST=10
# Optional: Firebase (for GCP deployment)
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
FIREBASE_CLIENT_EMAIL=your-service-account@project.iam.gserviceaccount.com
# Optional: ClamAV Antivirus
CLAMAV_HOST=localhost
CLAMAV_PORT=3310# Create database
createdb customer_portal
# Run migrations
psql -d customer_portal -f docker/init.sql# Install all dependencies
npm install
# Install backend dependencies
cd packages/backend && npm install
# Install frontend dependencies
cd ../frontend && npm install# Build backend
cd packages/backend && npm run build
# Build frontend
cd ../frontend && npm run build# Terminal 1: Backend development server
cd packages/backend && npm run dev
# Terminal 2: Frontend development server
cd packages/frontend && npm run devFrontend: http://localhost:3000 Backend API: http://localhost:8080
# Navigate to docker directory
cd docker
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose downServices:
- Frontend: http://localhost:3000
- Backend: http://localhost:8080
- PostgreSQL: localhost:5432
Login with these test credentials:
Admin User:
- Email:
admin@teselagen.com - Password:
password - Features: Full admin access, TeselaGen integration settings
Regular User:
- Email:
user@teselagen.com - Password:
password - Features: Submit requests, view own requests and reports
# Build production images
docker-compose -f docker-compose.prod.yml build
# Deploy to production
docker-compose -f docker-compose.prod.yml up -d- Login as admin user (
admin@teselagen.com/password) - Navigate to Settings in the sidebar menu (admin only)
- Select "TeselaGen Integration" tab
- Configure TeselaGen API settings:
- API URL:
https://your-teselagen-instance.com - User Email: Your TeselaGen account email
- API Key: Your TeselaGen API key (encrypted at rest)
- Lab ID: Your TeselaGen lab identifier
- API URL:
- Click "Test Connection" to verify integration
- Save settings
- Select "Portal Branding" tab
- Customize your portal appearance:
- Portal Name: Custom portal title
- Portal Logo URL: URL to your organization's logo
- Header Background Color: Choose header color
- Button Background Color: Choose button color
- Save settings to apply changes immediately
- Select "User Management" tab
- View all registered users with details
- Actions available:
- Create New User: Add users with admin privileges
- Edit User: Modify name, email, and admin status
- Delete User: Remove users (cannot delete yourself)
Once configured, all user requests will automatically be forwarded to TeselaGen API, reports will be pulled from TeselaGen ELN entries, and files can be downloaded directly from TeselaGen.
The portal supports programmatic access through API tokens for integration with external systems.
- Login as any user (admin or regular)
- Navigate to your Profile page
- Scroll to the "API Tokens" section
- Click "Create New Token"
- Set a token name and spending limit
- Save the generated token securely (it won't be shown again)
# Check token balance
curl -H "Authorization: Token your-api-token" \
http://localhost:8080/api/portal/balance
# Create a transaction
curl -X POST \
-H "Authorization: Token your-api-token" \
-H "Content-Type: application/json" \
-d '{"amount": 10.50, "description": "API usage"}' \
http://localhost:8080/api/portal/transaction
# List token transactions
curl -H "Authorization: Token your-api-token" \
http://localhost:8080/api/portal/transactions- Individual Spending Limits: Each token has its own balance limit
- Transaction Tracking: All API usage is logged per token
- Secure Storage: Token secrets are hashed and cannot be retrieved
- Flexible Management: Users can create/delete multiple tokens
The system implements multiple security layers:
- File Type Validation: Only CSV, TXT, ZIP files allowed
- Size Limits: 50MB per file, 10 files max per request
- Magic Number Validation: Checks actual file content
- ZIP Security: ZIP slip and ZIP bomb protection
- Antivirus Scanning: Optional ClamAV integration
- Rate Limiting: 20 uploads per 15 minutes per IP
Create Admin User:
-- Connect to database
psql -d customer_portal
-- Create admin user (password will be 'password')
INSERT INTO users (email, password_hash, first_name, last_name, is_admin, created_at)
VALUES ('admin@yourcompany.com', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdPJj9XUl2GqjbO', 'Admin', 'User', true, NOW());Create Regular User:
- Use the registration form at
/register - Or create via admin Settings → User Management tab
- Admin can promote users to admin status after creation
The portal includes a comprehensive financial tracking system for API usage and billing.
- Each user has a main balance account
- Balances are updated automatically via database triggers
- Transaction history tracks all debits and credits
- Monthly statistics provide usage analytics
- Each API token has an individual spending limit
- Token balances are separate from user balances
- Spending is tracked per token for detailed analytics
- Automatic enforcement of token limits
tg-customer-portal/
├── packages/
│ ├── backend/ # Express.js API server
│ │ ├── src/
│ │ │ ├── models/ # Database models (users, requests)
│ │ │ ├── routes/ # API routes (auth, requests, settings)
│ │ │ ├── services/ # Business logic (TeselaGen API, encryption, validation)
│ │ │ ├── middleware/ # Security, auth
│ │ │ └── utils/ # Encryption, validation utilities
│ │ └── dist/ # Compiled JavaScript
│ └── frontend/ # React application
│ ├── src/
│ │ ├── components/ # React components (forms, modals, tables)
│ │ ├── contexts/ # State management
│ │ ├── types/ # TypeScript definitions
│ │ └── services/ # API clients
│ └── build/ # Production build
└── docker/ # Docker configuration
├── docker-compose.yml # Development setup
├── docker-compose.prod.yml # Production setup
└── init.sql # Database schema with all tables
- Authentication: JWT tokens with secure cookies + API token support
- Password Security: bcrypt hashing with 12 rounds
- Data Encryption: AES-256-GCM encryption for sensitive data (API keys, settings)
- Input Validation: express-validator + DOMPurify sanitization
- Rate Limiting: Multiple tiers (auth, file upload, admin, API endpoints)
- Security Headers: Helmet.js with CSP
- File Security: Multi-layer validation, virus scanning, and magic number validation
- SQL Injection Protection: Parameterized queries
- XSS Protection: Input sanitization and CSP headers
- API Security: Token-based authentication with spending limits
- Pre-commit Hooks: Automated secret detection to prevent credential leaks
IMPORTANT: The following environment variables MUST be changed before deploying to production:
Used for signing authentication tokens. A weak or default secret compromises all user sessions.
# Generate a strong JWT secret (128 characters):
openssl rand -hex 64Set in .env:
JWT_SECRET=<output-from-command-above>Used for encrypting sensitive data like TeselaGen API keys. Must be exactly 32 bytes (64 hex characters).
# Generate a 256-bit encryption key:
openssl rand -hex 32Set in .env:
ENCRYPTION_KEY=<output-from-command-above>WARNING: Changing ENCRYPTION_KEY after data is encrypted will make existing encrypted data unrecoverable. Store this key securely and back it up!
For production deployments, use the production-ready template:
cp packages/backend/.env.example.production packages/backend/.envThen edit and replace all CHANGE_ME placeholders with actual secure values.
Install pre-commit hooks to prevent accidental secret commits:
./scripts/install-git-hooks.shThis will automatically check for:
- Hardcoded API keys and secrets
- Private keys and certificates
- Database credentials
.envfiles (except.env.example)
# Backend tests
cd packages/backend && npm test
# Frontend tests
cd packages/frontend && npm test
# Linting
npm run lint
# Type checking
npm run typecheckcurl http://localhost:8080/health# Docker logs
docker-compose logs backend
docker-compose logs frontend
# Application logs (if using file logging)
tail -f packages/backend/logs/app.logDatabase Connection:
# Check PostgreSQL is running
pg_isready -h localhost -p 5432
# Test connection
psql -h localhost -p 5432 -U username -d customer_portalFile Upload Issues:
- Check
UPLOAD_DIRpermissions:chmod 755 ./uploads - Verify file size limits in environment
- Check ClamAV service:
systemctl status clamav-daemon
Build Errors:
# Clear node modules and reinstall
rm -rf node_modules package-lock.json
npm install
# Clear build cache
rm -rf packages/*/dist packages/*/build
npm run buildEncryption Key Issues:
- Ensure
ENCRYPTION_KEYis exactly 32 bytes (256 bits) - Generate secure key:
openssl rand -hex 32 - Missing encryption key will cause API key storage failures
TeselaGen Integration Issues:
- Verify API URL format:
https://your-instance.com(no trailing slash) - Test connection via Settings → TeselaGen Integration → Test Connection
- Check TeselaGen user credentials and permissions
- Ensure lab ID matches your TeselaGen configuration
API Token Issues:
- Tokens use
Authorization: Token <token>header format - Verify token balance before making requests
- Check token spending limits in user profile
- API tokens are separate from JWT session tokens
Firebase Warnings:
- Node.js 18 compatibility warnings are non-blocking
- Upgrade to Node.js 20+ for full Firebase support
Database:
-- Add indexes for better performance
CREATE INDEX idx_requests_user_id ON customer_requests(user_id);
CREATE INDEX idx_files_request_id ON request_files(request_id);
CREATE INDEX idx_files_virus_status ON request_files(virus_scan_status);File Storage:
- Use object storage (S3, GCS) for production
- Implement CDN for file downloads
- Configure log rotation
- CRITICAL: Generate and set
JWT_SECRETusingopenssl rand -hex 64 - CRITICAL: Generate and set
ENCRYPTION_KEYusingopenssl rand -hex 32 - Install git security hooks:
./scripts/install-git-hooks.sh - Review
.envfile - no placeholder values (CHANGE_ME, your-password, etc.) - Verify no secrets committed to git:
git log --all -S "CHANGE_ME" - SSL/TLS certificates installed and configured
- Database uses strong password (not default/development password)
- Database connection uses SSL/TLS encryption
- Environment variables configured (use
.env.example.productionas template) - Database migrations applied (all tables created)
- ClamAV antivirus configured and running (recommended for production)
- File upload directory has correct permissions and storage limits
- Admin user created with strong password
- Portal branding configured (if using white-labeling)
- TeselaGen API credentials tested via admin settings
- Health checks passing
- File upload functionality tested
- TeselaGen integration working (connection test passes)
- File download from TeselaGen working
- User registration/login working
- Admin user management working (create/edit/delete users)
- API token creation and usage working
- Transaction system recording properly
- Security headers configured
- Settings page accessible by admin users only
- Monitoring/alerting setup
For issues and questions:
- Check this README
- Review application logs
- Check database connections
- Verify environment configuration
- Test with minimal setup
To update the application:
# Pull latest code
git pull origin main
# Update dependencies
npm install
# Rebuild applications
npm run build
# Restart services
docker-compose restartThis project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Copyright 2025 TeselaGen Biotechnology, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.