CopyForward (CFP) is a web-based research repository system that allows authors to share academic work (theses, articles, datasets, etc.) while supporting children's charities through donations. The system includes plagiarism committee voting, item approval workflows, and user roles (Regular, Author, Moderator).
- Backend: PHP 7.4 (configurable in
.env) - Frontend: React 19 with Vite
- Database: MySQL 8.0 (configurable to MariaDB or MySQL 5.7)
- Infrastructure: Docker Compose with LAMP stack
- Services: Apache webserver, MySQL/MariaDB, phpMyAdmin, Redis
- Database Connection:
db.php- Database connection via MySQLi (uses environment variables) - Authentication:
login.php,signup.php,logout.php- Session-based auth with password hashing - API Endpoints: Individual PHP files serve as REST-like endpoints (e.g.,
items.php,members.php,donations.php) - Database:
ovc353_2database with tables for Members, Items, Comments, Downloads, Donations, Committees, Discussions, etc.
- Build Output: Vite builds to
www/directory - Routing: Hash-based routing in
App.jsx(e.g.,#/items/123,#/authors) - State Management: useState/useEffect hooks, localStorage for auth state
- API Communication: Direct fetch calls to PHP endpoints (no centralized API client)
- Member System: Roles (Regular/Author/Moderator), ORCID support, blacklisting
- Item Workflow: Upload → Under Review → Approved/Removed
- Committee System: Plagiarism Committee (ID=1) and Appeal Committee (ID=2)
- Discussion & Voting: Committee members vote on plagiarism reports and appeals
- Automated Processing: MySQL Events run every minute to process voting deadlines
process_due_plagiarism_vote(): Handles plagiarism votes (2/3 majority removes item, 3+ removals blacklists author)process_due_appeal_vote(): Handles appeal votes (>50% majority reinstates item)
# Start all services (webserver, database, phpMyAdmin, Redis)
docker-compose up -d
# Stop all services
docker-compose down
# Rebuild containers (after .env changes)
docker-compose up -d --build --force-recreate
# View logs
docker-compose logs -f
# View specific service logs
docker-compose logs -f webserver
docker-compose logs -f databaseWorking directory: react/lamp-react/
# Install dependencies
npm install
# Development server (runs on Vite's default port, typically 5173)
npm run dev
# Build for production (outputs to www/)
npm run build
# Lint code
npm run lint
# Preview production build
npm run previewAccess phpMyAdmin: http://localhost:8080 (port configurable in .env)
- Username:
rootordocker - Password: See
.env(MYSQL_ROOT_PASSWORDorMYSQL_PASSWORD)
Import database schema:
# Copy SQL file into container and import
docker cp database_new.sql lamp-database:/tmp/database_new.sql
docker exec -i lamp-database mysql -uroot -ptiger ovc353_2 < database_new.sql
# Or via phpMyAdmin Import tabRun SQL from command line:
docker exec -it lamp-database mysql -uroot -ptiger ovc353_2- Main Application:
http://localhost(or configuredHOST_MACHINE_UNSECURE_HOST_PORT) - React Frontend:
http://localhost/react/ - phpMyAdmin:
http://localhost:8080 - Test Pages:
http://localhost/test_db.php,http://localhost/phpinfo.php
- Create new PHP file in
www/directory - Include
db.phpfor database connection:require __DIR__ . '/db.php'; - Use prepared statements with MySQLi:
$mysqli->prepare() - Return JSON responses:
echo json_encode(['success' => true, 'data' => $result]); - Set proper headers:
header('Content-Type: application/json');
- Create component in
react/lamp-react/src/pages/ - Add route matching in
App.jsx(hash-based routing) - Use fetch to call PHP endpoints:
await fetch('/endpoint.php') - Build and deploy:
npm run build(outputs towww/)
- Modify
database_new.sqlwith new tables/columns - For existing data, create migration scripts in
config/initdb/(runs on container init) - Test locally before deploying
- Consider impact on stored procedures and events
- Login stores member ID in
localStorageaslogged_in_id - PHP sessions store
member_id,role,email - Frontend checks
localStorage.getItem('logged_in_id')for auth state - Backend verifies session with
session_start()and$_SESSION['member_id']
PHP Version: PHPVERSION (php74, php8, php81, php82, php83, php84)
Database: DATABASE (mysql8, mysql57, mariadb103-106)
Ports:
HOST_MACHINE_UNSECURE_HOST_PORT(default: 80)HOST_MACHINE_MYSQL_PORT(default: 3306)HOST_MACHINE_PMA_PORT(default: 8080)
Database Credentials:
MYSQL_HOST(local: database, AITS: ovc353.encs.concordia.ca)MYSQL_USER(local: docker, AITS: ovc353_2)MYSQL_PASSWORD(local: docker, AITS: darkjade89)MYSQL_ROOT_PASSWORD(local: tiger)MYSQL_DATABASE(local & AITS: ovc353_2 )MYSQL_PORT(local & AITS: 3306 )
Note: The application uses database name ovc353_2 locally, as well as on AITS
- Backend uses PHP sessions (
$_SESSION) - Frontend stores auth in localStorage (
logged_in_id) - No JWT or token-based auth - relies on session cookies
- Under Review (Upload): Newly uploaded items awaiting moderator approval
- Available: Approved and publicly accessible
- Under Review (Plagiarism): Flagged for plagiarism review
- Removed: Committee voted to remove (can be appealed)
- Deleted (Author): Author deleted their own item
- Plagiarism Committee (ID=1): 2/3 majority required to remove items
- Appeal Committee (ID=2): >50% majority required to reinstate items
- Automated processing via MySQL Events every minute
- Authors automatically blacklisted after 3 removed items
- Members can download one item per 7-day window (enforced in
can_download.php) - Download tracking in
Downloadtable
- Minimum 60% to children's charity
- Remaining split between author and CFP
- Constraint:
AuthorPercent + ChildrenCharityPercent + CFPPercent = 100
CopyForward-Web-System/
├── bin/ # Docker build contexts for PHP/DB versions
├── config/
│ ├── initdb/ # Database initialization scripts
│ ├── php/php.ini # PHP configuration
│ ├── ssl/ # SSL certificates
│ └── vhosts/ # Apache virtual hosts
├── data/mysql/ # MySQL data directory (persisted)
├── logs/ # Apache, MySQL, Xdebug logs
├── react/lamp-react/ # React frontend source
│ ├── src/
│ │ ├── pages/ # React page components
│ │ ├── App.jsx # Main app with routing
│ │ └── Header.jsx # Navigation header
│ ├── package.json
│ └── vite.config.js # Removes old files and builds new static files to www/
├── www/ # PHP backend & built frontend
│ ├── assets/ # Static assets (CSS, images)
│ ├── react/ # Unused/deprecated
│ ├── index-<hash>.js # JavaScript Static build file
│ ├── index-<hash>.css # CSS Static build file
│ ├── index.html # Main HTML Static build file
│ ├── db.php # Database connection
│ ├── login.php # Authentication endpoint
│ ├── items.php # Item listing/search
│ ├── item.php # Individual item details
│ ├── members.php # Member management
│ └── [other endpoints]
├── .env # Environment configuration
├── database_new.sql # Complete database schema
├── docker-compose.yml # Service definitions
└── seed.sql # Sample data
└── README.md # This documentation file
No automated test framework is configured. Manual testing workflow:
- Test backend endpoints via browser or curl
- Check phpMyAdmin for data integrity
- Test React frontend via browser
- Verify logs in
logs/directory for errors
If ports 80, 443, 3306, or 8080 are in use, modify .env port variables and restart containers.
- Ensure database container is running:
docker-compose ps - Check credentials in
.envmatchdb.php - Database name is hardcoded as
ovc353_2indb.php
- Run
npm run buildinreact/lamp-react/ - Verify output in
www/ - Clear browser cache
Check event scheduler status:
SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler = ON;