TMCACSA
Time Management Challenges Among College Student-Athletes
Technical Requirement Document
Version 1.0
Document Control
| Field | Value |
|---|---|
| Document | Technical Requirement Document (TRD) |
| Product | TMCACSA - student-athlete time-management and wellbeing portal |
| Version | 1.0 |
| Generated | November 7, 2026 |
| Prepared by | Student Name |
| Course / Subject | Final Project |
| Related document | Product Requirement Document (help/prd.php) |
| Status | Describes the code as it exists today; planned items are labeled Planned and listed in Section 18. |
Table of Contents
- 1. Introduction
- 2. System Overview and Architecture
- 3. Technology Stack
- 4. Application Structure
- 5. Database Design
- 6. Module Design
- 7. Authentication, Session, and Access Control
- 8. Security Design
- 9. Audit Trail Design
- 10. Backup and Restore Design
- 11. Page and Route Reference
- 12. Input Validation and Error Handling
- 13. Reports, Filtering, and Print Design
- 14. Deployment and Environment Requirements
- 15. Testing Strategy and Test Cases
- 16. Performance Considerations
- 17. Known Limitations and Future Enhancements
- 18. Current Implementation Status
1. Introduction
1.1 Purpose
This Technical Requirement Document (TRD) describes how TMCACSA is built: its architecture, technology stack, database, security controls, pages, and deployment needs. It is written from the source code of the application, so it records what the system really does today. Features that are specified but not yet built are clearly labeled Planned.
1.2 Scope
TMCACSA is a web application that lets college student-athletes record their schedule, time use, and tasks, answer a research survey, and view dashboards. Administrators review program-wide statistics, manage athlete records, read anonymous survey summaries, and export reports.
1.3 Intended audience
Instructors evaluating the project, developers who maintain it, and the system administrator who deploys it.
1.4 Related documents
The Product Requirement Document (help/prd.php) defines what the product must do and why. This document defines how it is implemented.
2. System Overview and Architecture
2.1 Architecture style
TMCACSA is a classic three-tier web application written in procedural PHP. There is no framework and no Composer dependency. Each page file contains its own request handling at the top and its HTML below, and shared logic lives in the includes folder.
2.2 Block diagram
| Tier 1: Client | Tier 2: Application server | Tier 3: Data |
|---|---|---|
| Web browser (desktop or phone) HTML5 pages, one stylesheet, vanilla JavaScript, Chart.js charts |
PHP application behind the PHP built-in server (development) or Apache (hosting) Pages, includes, session handling, security headers |
MySQL database student_athlete_db Accessed only through PDO prepared statements |
| Request path: Browser → HTTP or HTTPS → PHP page → PDO → MySQL → PHP builds HTML → Browser | ||
2.3 Request flow
- The browser requests a page such as /athlete/timelog.php.
- The page loads config/config.php, config/db.php (PDO connection), includes/auth.php, and includes/functions.php.
- includes/auth.php configures the session cookie, starts the session, applies HTTPS enforcement when enabled, sends the security headers, and checks the idle timeout.
- The page calls require_role() or require_login() when it is protected.
- On a POST request the page verifies the CSRF token, validates the input, and runs prepared statements.
- After a successful change the page stores a flash message and redirects (Post/Redirect/Get).
- On a GET request the page queries the database, includes includes/header.php, renders HTML, and includes includes/footer.php.
3. Technology Stack
| Layer | Technology | Use in TMCACSA |
|---|---|---|
| Server language | PHP 8 (development machine runs PHP 8.5) | All page logic, sessions, validation, and report export. README requires PHP 8.0 or newer. |
| Database access | PDO with the pdo_mysql driver | Prepared statements, exception error mode, associative fetch mode, native (non-emulated) prepares. |
| Database | MySQL 8.x, character set utf8mb4 | Stores users, records, survey data, logs, and login attempts. |
| Markup | HTML5 | Server-rendered pages with semantic elements. |
| Styling | CSS3 in assets/css/style.css | Single hand-written stylesheet: sidebar layout, cards, tables, forms, responsive rules, print rules. |
| Client scripting | Vanilla JavaScript (assets/js/main.js, assets/js/charts.js) | Sidebar and menu toggles, confirm dialogs, form checks, print and copy buttons, chart drawing. |
| Charts | Chart.js loaded from cdn.jsdelivr.net | Doughnut, bar, and line charts on dashboards and survey results. |
| Development tools | Visual Studio Code, GitHub Copilot, MySQL Workbench | Coding, AI-assisted generation, and database design. |
| Local server | PHP built-in server (php -S localhost:8000) | Local testing. XAMPP or MAMP with Apache is also supported. |
| Hosting (target) | Shared hosting or VPS with Apache, PHP, MySQL, and SSL | Public deployment on a domain or subdomain. |
4. Application Structure
4.1 Folder and file reference
| Path | Purpose |
|---|---|
| index.php | Public landing page. Redirects a logged-in user to the correct dashboard. |
| create_admin.php | One-time form that creates the first administrator. It refuses to run once an admin exists and should be deleted after setup. |
| .htaccess | Disables directory listing (Options -Indexes) on Apache. |
| README.md | Setup, run, and admin creation instructions. |
| config/config.php | Application constants (name, base URL, environment, HTTPS flag, session and lockout limits, backup settings). |
| config/db.php | Creates the PDO connection from the database settings variables. |
| includes/auth.php | Session cookie settings, session start, HTTPS and header setup, idle timeout, current_user, require_login, require_role, csrf_token, csrf_verify. |
| includes/functions.php | Helpers: e, redirect, flash, get_flash_messages, get_client_ip, set_security_headers, enforce_https, generate_captcha, verify_captcha, is_locked_out, record_login_attempt, clear_login_attempts, log_activity. |
| includes/header.php | HTML head, role-based sidebar, mobile top bar, Help menu, profile menu, flash messages. |
| includes/footer.php | Closes the layout and loads main.js. |
| auth/login.php | Login with username, password, and CAPTCHA. |
| auth/register.php | Athlete self-registration with CAPTCHA. |
| auth/logout.php | POST-only logout with CSRF check. |
| auth/settings.php | Profile update and password change for any logged-in user. |
| athlete/dashboard.php | Athlete statistics, charts, tasks, schedule, and balance alert. |
| athlete/schedule.php | Weekly schedule create, view, and delete. |
| athlete/timelog.php | Time log create, view, edit, delete, filter, and paginate. |
| athlete/tasks.php | Task create, view, edit, status change, delete, and filter. |
| athlete/survey.php | Consent-based survey with save and update. |
| admin/dashboard.php | Program-wide statistics, charts, and overload table. |
| admin/athletes.php | Athlete search, filters, profile view, and delete. |
| admin/survey_results.php | Anonymous survey averages, distributions, and text answers. |
| admin/reports.php | Filtered reports and CSV exports. |
| help/prd.php and help/trd.php | Product and Technical Requirement Documents, printable. |
| assets/css/style.css | The only stylesheet. |
| assets/js/main.js | Page behavior without inline scripts. |
| assets/js/charts.js | Reads page data and draws the Chart.js charts. |
4.2 Design conventions
- Procedural PHP, no classes, no autoloader, no framework.
- Every database query that uses input is a prepared statement.
- All output is escaped with the e() helper.
- No inline JavaScript event handlers. Confirmations use a data-confirm attribute handled in main.js.
- Relative links are built from the BASE_URL constant.
5. Database Design
Database name: student_athlete_db. Engine: InnoDB. Character set: utf8mb4.
5.1 users
| Column | Type | Constraints and notes |
|---|---|---|
| user_id | INT UNSIGNED | Primary key, auto increment |
| full_name | VARCHAR(100) | Required |
| username | VARCHAR(50) | Required, unique. Used for login. |
| VARCHAR(120) | Optional (NULL allowed), unique. Not used for login. | |
| password_hash | VARCHAR(255) | Required. Output of password_hash(). |
| role | ENUM(athlete, admin) | Default athlete |
| sport | VARCHAR(60) | Optional |
| year_level | ENUM(1st Year, 2nd Year, 3rd Year, 4th Year) | Optional |
| course | VARCHAR(100) | Optional |
| created_at | TIMESTAMP | Default current timestamp |
5.2 categories
| Column | Type | Constraints and notes |
|---|---|---|
| category_id | INT UNSIGNED | Primary key, auto increment |
| name | VARCHAR(50) | Unique. Seeded values: Class, Training, Game / Competition, Study, Rest / Sleep, Travel, Work, Personal / Social, Other. |
5.3 time_logs
| Column | Type | Constraints and notes |
|---|---|---|
| log_id | INT UNSIGNED | Primary key, auto increment |
| user_id | INT UNSIGNED | Foreign key to users, ON DELETE CASCADE |
| category_id | INT UNSIGNED | Foreign key to categories |
| log_date | DATE | Required |
| start_time, end_time | TIME | Required. The application requires end time later than start time. |
| hours | DECIMAL(4,2) | GENERATED ALWAYS (stored): seconds between end and start divided by 3600. Never written by the application. |
| notes | VARCHAR(255) | Optional |
| created_at | TIMESTAMP | Default current timestamp |
| Index | idx_logs_user_date | On (user_id, log_date) |
5.4 schedules
| Column | Type | Constraints and notes |
|---|---|---|
| schedule_id | INT UNSIGNED | Primary key, auto increment |
| user_id | INT UNSIGNED | Foreign key to users, ON DELETE CASCADE |
| category_id | INT UNSIGNED | Foreign key to categories |
| day_of_week | ENUM(Mon, Tue, Wed, Thu, Fri, Sat, Sun) | Required |
| start_time, end_time | TIME | Required |
| description | VARCHAR(150) | Optional |
5.5 tasks
| Column | Type | Constraints and notes |
|---|---|---|
| task_id | INT UNSIGNED | Primary key, auto increment |
| user_id | INT UNSIGNED | Foreign key to users, ON DELETE CASCADE |
| title | VARCHAR(150) | Required |
| due_date | DATE | Required |
| priority | ENUM(Low, Medium, High) | Default Medium |
| status | ENUM(Pending, In Progress, Done) | Default Pending |
| created_at | TIMESTAMP | Default current timestamp |
| Index | idx_tasks_user_due | On (user_id, due_date) |
5.6 survey_questions
| Column | Type | Constraints and notes |
|---|---|---|
| question_id | INT UNSIGNED | Primary key, auto increment |
| question_text | VARCHAR(300) | Required |
| question_type | ENUM(likert, text) | Default likert |
| domain | VARCHAR(60) | Group heading. Seeded: 14 Likert and 2 open-ended questions. |
5.7 survey_responses
| Column | Type | Constraints and notes |
|---|---|---|
| response_id | INT UNSIGNED | Primary key, auto increment |
| user_id | INT UNSIGNED | Foreign key to users, ON DELETE CASCADE |
| question_id | INT UNSIGNED | Foreign key to survey_questions, ON DELETE CASCADE |
| answer_value | TINYINT UNSIGNED | NULL allowed. CHECK value between 1 and 5. |
| answer_text | TEXT | NULL allowed. Used by text questions. |
| submitted_at | TIMESTAMP | Default current timestamp |
| Unique key | uq_user_question | On (user_id, question_id): one answer per question per athlete. |
5.8 activity_logs
| Column | Type | Constraints and notes |
|---|---|---|
| log_id | BIGINT UNSIGNED | Primary key, auto increment |
| user_id | INT UNSIGNED | NULL allowed. Foreign key to users, ON DELETE SET NULL. |
| username, role | VARCHAR(50), VARCHAR(10) | Copied into the row so history stays readable if the account is deleted. |
| action | VARCHAR(40) | Required. Action name such as LOGIN_SUCCESS. |
| details | VARCHAR(255) | Readable description. Never contains passwords. |
| ip_address, user_agent | VARCHAR(45), VARCHAR(255) | Request origin |
| created_at | TIMESTAMP | Holds both the date and the time of the activity. |
| Indexes | idx_activity_created, idx_activity_user, idx_activity_action | Support filtering by date, user, and action. |
5.9 login_attempts
| Column | Type | Constraints and notes |
|---|---|---|
| attempt_id | BIGINT UNSIGNED | Primary key, auto increment |
| username | VARCHAR(50) | Username typed on the login form |
| ip_address | VARCHAR(45) | Client address |
| success | TINYINT(1) | Default 0 |
| attempted_at | TIMESTAMP | Default current timestamp |
| Indexes | idx_attempt_user_time, idx_attempt_ip_time | On (username, attempted_at) and (ip_address, attempted_at) |
5.10 Views
| View | Purpose | Used by |
|---|---|---|
| v_hours_per_category | Total hours per athlete per category | Defined in the database; not used by a page yet. |
| v_survey_averages | Average Likert score and response count per question | admin/survey_results.php |
| v_weekly_balance | Training, study, and rest hours per athlete for the last 7 days | admin/dashboard.php (overload table) |
5.11 Relationships (entity relationship summary)
| Parent table | Child table | Relationship | On delete |
|---|---|---|---|
| users | time_logs | One user has many time logs | CASCADE |
| users | schedules | One user has many schedule items | CASCADE |
| users | tasks | One user has many tasks | CASCADE |
| users | survey_responses | One user has many survey answers | CASCADE |
| users | activity_logs | One user has many log entries | SET NULL |
| categories | time_logs | One category is used by many time logs | Restrict (default) |
| categories | schedules | One category is used by many schedule items | Restrict (default) |
| survey_questions | survey_responses | One question has many answers | CASCADE |
6. Module Design
| Module | Pages | Inputs | Processing | Tables used | Outputs |
|---|---|---|---|---|---|
| Authentication | auth/login.php, auth/register.php, auth/logout.php | Username, password, CAPTCHA answer, registration fields, CSRF token | CAPTCHA check, lockout check, password_verify, session creation, password_hash on registration | users, login_attempts, activity_logs | Session, redirect to dashboard, flash messages |
| Settings | auth/settings.php | Name, optional email, sport, year, course, current and new password | Validation, update by session user id, password re-hash | users, activity_logs | Updated profile, flash message |
| Weekly schedule | athlete/schedule.php | Category, day, start and end time, description | Validation, overlap check (warning only), insert, delete by owner | schedules, categories | Weekly table grouped by day |
| Time log | athlete/timelog.php | Date, category, start and end time, notes, filters, page number | Validation, insert, update, delete by owner, filtered and paginated query, total hours | time_logs, categories | Log table, total hours, pagination links |
| Tasks | athlete/tasks.php | Title, due date, priority, status, status filter | Validation, insert, update, status change, delete by owner, overdue detection | tasks | Task table with priority badges and overdue label |
| Survey | athlete/survey.php | Consent checkbox, Likert answers 1 to 5, text answers | Consent check, required Likert check, transaction with INSERT ... ON DUPLICATE KEY UPDATE | survey_questions, survey_responses | Saved answers, pre-filled form |
| Athlete dashboard | athlete/dashboard.php | Session user | Weekly aggregates, task counts, today schedule, balance alert rule | time_logs, categories, tasks, schedules, users | Summary cards, charts, lists |
| Admin dashboard | admin/dashboard.php | None | Program-wide aggregates and overload query | users, time_logs, categories, survey_responses, v_weekly_balance | Cards, chart, overload table |
| Athlete management | admin/athletes.php | Search text, sport, year level, profile id, delete request | Filtered query, profile query, delete with CSRF | users, time_logs, categories, survey_questions, survey_responses | Athlete table, profile section |
| Survey results | admin/survey_results.php | None | View query for averages, distribution counts, anonymous text answers | v_survey_averages, survey_questions, survey_responses, users | Tables and charts per domain |
| Reports | admin/reports.php | Sport, year, date range, export type | Filtered queries, CSV streaming with fputcsv and UTF-8 BOM | users, time_logs, categories, survey_questions, survey_responses, tasks | On-screen tables and CSV downloads |
7. Authentication, Session, and Access Control
7.1 Login flow
- A GET request to auth/login.php generates a new arithmetic CAPTCHA (addition of two whole numbers from 1 to 10) and stores only the answer in the session.
- On POST the page verifies the CSRF token.
- The CAPTCHA is checked first and is single use: the stored answer is removed after every check. A wrong answer stops processing and does not count as a login attempt.
- Empty username or password returns the generic message Invalid username or password.
- The lockout check runs next. If the limit is reached the page shows the remaining minutes and records LOGIN_LOCKED without checking the password.
- The user is looked up by username with a prepared statement. If the username does not exist, password_verify runs against a dummy hash so the response time does not reveal which usernames exist.
- On success the session receives the user data, session_regenerate_id(true) is called, failed attempts for that username are cleared, the password hash is upgraded if password_needs_rehash is true, LOGIN_SUCCESS is logged, and the user is redirected by role.
- On failure the attempt is stored in login_attempts, LOGIN_FAILED is logged, and a new CAPTCHA is generated.
7.2 Session settings
| Setting | Value |
|---|---|
| Cookie lifetime | Session cookie (ends when the browser closes) |
| HttpOnly | Enabled |
| SameSite | Lax |
| Secure flag | Enabled when the request is HTTPS and the host is not localhost |
| Strict mode | session.use_strict_mode enabled |
| Idle timeout | SESSION_IDLE_MINUTES (30). On timeout the session is destroyed and the user sees "Your session expired. Please log in again." |
| Regeneration | On successful login |
| Logout | POST only with CSRF check; session cleared, cookie expired, session destroyed |
7.3 Access control matrix
| Page group | Guest | Athlete | Admin |
|---|---|---|---|
| index.php, help pages | Allowed | Allowed | Allowed |
| auth/login.php, auth/register.php | Allowed | Redirected to dashboard | Redirected to dashboard |
| create_admin.php | Allowed only while no admin exists | Not applicable | Not applicable |
| auth/settings.php, auth/logout.php | Redirected to login | Allowed | Allowed |
| athlete/* pages | Redirected to login | Allowed (own data only) | Redirected to admin dashboard with an error message |
| admin/* pages | Redirected to login | Redirected to athlete dashboard with an error message | Allowed |
Every athlete query that reads or changes a record includes the session user id in its WHERE clause (for example WHERE log_id = :id AND user_id = :uid), so one athlete cannot read or change another athlete data.
8. Security Design
| Threat | Control | Where implemented |
|---|---|---|
| SQL injection | PDO prepared statements with real (non-emulated) prepares; integer values validated and bound as integers | config/db.php and every page that queries the database |
| Cross-site scripting (XSS) | Output escaped with htmlspecialchars through e(); Content-Security-Policy limits scripts to the same site and cdn.jsdelivr.net; no inline event handlers | includes/functions.php, all pages |
| Cross-site request forgery (CSRF) | Random 32-byte session token in every POST form, compared with hash_equals | includes/auth.php, all POST forms |
| Brute-force login | Arithmetic CAPTCHA plus lockout after 5 failed attempts per username, or 20 failed attempts per IP address, within 15 minutes | auth/login.php, includes/functions.php, table login_attempts |
| Username enumeration | Generic login error and dummy password verification for unknown usernames | auth/login.php |
| Weak password storage | password_hash with PASSWORD_DEFAULT; automatic re-hash when the algorithm changes; no plain text or MD5 | auth/register.php, auth/settings.php, create_admin.php, auth/login.php |
| Weak passwords | Minimum 8 characters with at least one letter and one number on registration | auth/register.php |
| Session hijacking and fixation | HttpOnly, SameSite, strict mode, secure flag on HTTPS, regeneration at login, idle timeout | includes/auth.php, auth/login.php |
| Clickjacking | X-Frame-Options DENY and CSP frame-ancestors none | includes/functions.php |
| MIME sniffing and information leakage | X-Content-Type-Options nosniff, Referrer-Policy, Permissions-Policy | includes/functions.php |
| Data in transit | Strict-Transport-Security header on HTTPS and optional redirect to HTTPS controlled by FORCE_HTTPS | includes/functions.php, config/config.php |
| Directory listing | Options -Indexes | .htaccess |
| Privilege escalation | require_role() on every protected page; role never accepted from a form | includes/auth.php, all protected pages |
| Respondent privacy | Survey text answers are shown to admins without names | admin/survey_results.php |
| Insecure access to backups (Planned) | Backups stored outside the web folder and served only through an admin-only page | Planned with the backup module |
9. Audit Trail Design
9.1 Table structure
Audit entries are stored in the activity_logs table (see Section 5.8). Each entry stores the user, role, action, details, IP address, browser, and a timestamp that holds both the date and the time.
9.2 Recording function
log_activity() in includes/functions.php inserts one row using the current session user. It is wrapped so that a logging failure is written to the server error log and never breaks the page.
9.3 Actions recorded today
| Action | Recorded when | File |
|---|---|---|
| LOGIN_SUCCESS | A user logs in successfully | auth/login.php |
| LOGIN_FAILED | A login attempt fails | auth/login.php |
| LOGIN_LOCKED | A login is refused because of the lockout | auth/login.php |
| LOGOUT | A user logs out | auth/logout.php |
| REGISTER | An athlete registers | auth/register.php |
| PROFILE_UPDATE | A user updates the profile | auth/settings.php |
| PASSWORD_CHANGE | A user changes the password | auth/settings.php |
9.4 Planned audit coverage
Planned: record every create, update, and delete of schedule items, time logs, tasks, athletes, and survey submissions, CSV exports, and backup actions, and add an administrator page to view, filter, print, and export the log.
9.5 Rules
- Passwords, password hashes, tokens, and CAPTCHA answers are never written to the log.
- The application has no function to edit or delete log entries.
10. Backup and Restore Design
Status: Planned. The configuration constants BACKUP_DIR and BACKUP_KEEP already exist in config/config.php, but no backup page or script has been built yet. The design below is the intended implementation.
| Topic | Design |
|---|---|
| Backup types | Database backup (.sql), files backup (.zip), and full backup (database plus files). |
| Database dump | Generated in PHP through PDO: DROP TABLE, SHOW CREATE TABLE, and batched INSERT statements. The generated column time_logs.hours is excluded from the INSERT statements. Views are included. |
| File backup | ZipArchive of the project folder, excluding the backup folder and log files. |
| File naming | tmcacsa_{db|files|full}_{date}_{time}_{random}.{sql|zip} |
| Storage location | BACKUP_DIR, a folder outside the public web folder. |
| Download | Only through an admin-only page that validates the file name; never by direct link. |
| Retention | The newest BACKUP_KEEP backups are kept per type. |
| Scheduled backup | A command-line script run by cron weekly (daily for transaction-heavy use) that creates a full backup. |
| Restore safeguards | Admin password re-entry, a typed confirmation word, CSRF check, an automatic pre-restore backup, and zip-slip protection when extracting files. |
| Audit | Every backup, download, delete, and restore is recorded in activity_logs. |
11. Page and Route Reference
| URL | Methods | Allowed roles | Purpose |
|---|---|---|---|
| /index.php | GET | Guest (logged-in users are redirected) | Landing page |
| /auth/login.php | GET, POST | Guest | Log in |
| /auth/register.php | GET, POST | Guest | Register an athlete |
| /auth/logout.php | POST | Athlete, Admin | Log out |
| /auth/settings.php | GET, POST | Athlete, Admin | Profile and password |
| /create_admin.php | GET, POST | Guest, only while no admin exists | Create the first admin |
| /athlete/dashboard.php | GET | Athlete | Athlete dashboard |
| /athlete/schedule.php | GET, POST | Athlete | Weekly schedule |
| /athlete/timelog.php | GET, POST | Athlete | Time log with filters and pagination |
| /athlete/tasks.php | GET, POST | Athlete | Tasks |
| /athlete/survey.php | GET, POST | Athlete | Survey |
| /admin/dashboard.php | GET | Admin | Admin dashboard |
| /admin/athletes.php | GET, POST | Admin | Athlete list, profile, delete |
| /admin/survey_results.php | GET | Admin | Survey results |
| /admin/reports.php | GET | Admin | Reports and CSV export (export=time_logs, survey_responses, athlete_summary) |
| /help/prd.php | GET | Everyone | Product Requirement Document |
| /help/trd.php | GET | Everyone | Technical Requirement Document |
12. Input Validation and Error Handling
12.1 Validation rules
| Form | Rules |
|---|---|
| Registration | Full name, username, sport, year level, and course required. Username 4 to 30 characters using letters, numbers, and underscore, and unique. Email optional but must be valid when given. Password at least 8 characters with a letter and a number, and must match the confirmation. CAPTCHA required. |
| Login | Username, password, and CAPTCHA required. Generic error messages. |
| Schedule | Valid category, valid day, start and end time required, end time later than start time. Overlap produces a warning and the item is still saved. |
| Time log | Valid date, category, start and end time, end time later than start time. The hours column is calculated by MySQL. |
| Task | Title required, due date must be a real date in Y-m-d format, priority and status must be one of the allowed values. |
| Survey | Consent checkbox required. Every Likert question must have an answer from 1 to 5. |
| Filters and ids | GET values are validated (integers with FILTER_VALIDATE_INT, dates, allowed lists) and used only as bound parameters. |
Validation runs on the server for every form. The data-validate attribute adds extra checks in the browser through main.js, but the server never relies on them.
12.2 Error handling
- Validation errors and results are shown as flash messages.
- Successful changes use Post/Redirect/Get so refreshing the page does not repeat the action.
- In production (APP_ENV set to production) display_errors is turned off and log_errors is turned on.
- A failed database connection throws an exception from config/db.php. A friendlier production error page is a planned improvement.
13. Reports, Filtering, and Print Design
13.1 Filters
| Page | Filters |
|---|---|
| athlete/timelog.php | Date from, date to, category, page number |
| athlete/tasks.php | Status |
| admin/athletes.php | Search text, sport, year level |
| admin/reports.php | Sport, year level, date from, date to |
13.2 Reports and exports
admin/reports.php shows filtered data and offers three CSV exports: time logs, survey responses, and athlete summary. The export is a GET request with an allowed-list check on the export parameter. The file is sent with a text/csv content type, a dated file name, and a UTF-8 byte order mark so Excel opens it correctly.
13.3 Print design
The stylesheet contains @media print rules, and the header supports a print mode through the print=1 query string that hides the sidebar and navigation. The two Help documents have a Print / Save as PDF button (data-print) and a Copy content button. Planned: a Print Preview button on every report page and a personal report page for athletes.
14. Deployment and Environment Requirements
14.1 Server requirements
| Item | Requirement |
|---|---|
| PHP | 8.0 or newer |
| PHP extensions | pdo_mysql and mbstring. The zip extension is needed for the planned file backup. |
| MySQL | 8.0 or newer, utf8mb4 |
| Web server | PHP built-in server for development; Apache for hosting (the .htaccess file is for Apache) |
| Browser | Current Chrome, Safari, Firefox, or Edge, on desktop or phone |
| Network | Internet access to load Chart.js from cdn.jsdelivr.net |
14.2 Configuration (names and meaning only)
| Name | Meaning |
|---|---|
| APP_NAME | Application name shown in pages |
| BASE_URL | URL prefix for links. Empty when served from the web root. |
| APP_ENV | development or production |
| FORCE_HTTPS | When true, HTTP requests are redirected to HTTPS |
| SESSION_IDLE_MINUTES | Idle time before automatic logout |
| LOGIN_MAX_ATTEMPTS | Failed logins allowed before lockout |
| LOGIN_LOCKOUT_MINUTES | Length of the lockout window |
| BACKUP_DIR, BACKUP_KEEP | Backup folder and number of backups to keep (backup module is planned) |
| DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASS, DB_CHARSET | Database connection settings in config/db.php |
14.3 Production deployment checklist
- Create a domain or subdomain in the hosting panel and upload the project files.
- Create a database and a dedicated database user, then import the database scripts.
- Edit config/db.php with the hosting credentials and use a strong password.
- Set APP_ENV to production and set BASE_URL for the install location.
- Install an SSL certificate, then set FORCE_HTTPS to true.
- Create the admin account with create_admin.php, then delete that file.
- Confirm directory listing is disabled and that errors are not displayed to visitors.
- Test login, CAPTCHA, lockout, every module, and the phone layout over HTTPS.
15. Testing Strategy and Test Cases
Testing is manual and functional, done in the browser on a desktop and on a phone, with one athlete account and one admin account. Database results are confirmed in MySQL Workbench.
| ID | Scenario | Steps | Expected result |
|---|---|---|---|
| TC-01 | Register an athlete | Open Register, fill all fields, answer the CAPTCHA, submit | Account is created and the user is sent to Login |
| TC-02 | Duplicate username | Register again with the same username | Error says the username is taken |
| TC-03 | Weak password | Register with a password of 6 characters | Validation error is shown |
| TC-04 | Correct login | Log in with valid credentials and the correct CAPTCHA | Redirected to the dashboard for the role |
| TC-05 | Wrong CAPTCHA | Log in with a wrong CAPTCHA answer | Message Incorrect CAPTCHA answer; no login |
| TC-06 | Wrong password | Log in with a wrong password | Generic Invalid username or password message |
| TC-07 | Lockout | Fail login 5 times for one username | Lockout message with remaining minutes |
| TC-08 | Logout | Click Logout in the profile menu | Session ends and Login page is shown |
| TC-09 | Idle timeout | Stay idle longer than the timeout and reload | Session-expired message and login page |
| TC-10 | Role protection | Logged in as athlete, open an admin URL | Access is blocked with an error message |
| TC-11 | Guest protection | Logged out, open a dashboard URL | Redirected to Login |
| TC-12 | Add time log | Enter a valid log and submit | Row appears and hours are calculated |
| TC-13 | Invalid time range | Enter an end time earlier than the start time | Validation error; nothing saved |
| TC-14 | Edit and delete time log | Edit a log, then delete it with confirmation | Changes saved; row removed after confirmation |
| TC-15 | Time log filter and pagination | Filter by date and category; create more than 10 logs | Only matching rows appear; pagination works |
| TC-16 | Schedule overlap | Add two overlapping items on one day | Warning is shown and both are saved |
| TC-17 | Tasks | Add a task with a past due date | Task is marked Overdue until set to Done |
| TC-18 | Survey | Submit without consent, then with consent and all Likert answers | First is rejected; second saves; reopening shows saved answers |
| TC-19 | Ownership | Try to edit another athlete record by changing the id in the URL | Record is not shown or changed |
| TC-20 | Admin dashboard | Log in as admin with data present | Statistics, charts, and overload table appear |
| TC-21 | Athlete search and delete | Search an athlete, then delete with confirmation | Athlete and related records are removed |
| TC-22 | CSV export | Apply a filter and export time logs | CSV downloads and opens correctly in Excel |
| TC-23 | Audit entries | Log in, fail a login, and log out; query activity_logs | Rows exist for each action with date and time |
| TC-24 | Phone layout | Open the site on a phone | Menu drawer works, no sideways scrolling, tables are readable |
| TC-25 | Print Help document | Open a Help page and use Print / Save as PDF | Clean A4 output without the sidebar |
16. Performance Considerations
- Indexes on (user_id, log_date), (user_id, due_date), and the audit and login attempt columns support the most common filters.
- The time log list is paginated with 10 rows per page using LIMIT and OFFSET.
- Totals and averages are calculated in SQL (SUM, AVG, COUNT, GROUP BY) rather than in PHP loops.
- The hours value is a stored generated column, so it is not recalculated for every report.
- Old login attempts are deleted automatically after one day.
- The interface uses one stylesheet and two small scripts, and has no image-heavy assets.
17. Known Limitations and Future Enhancements
| Item | Description |
|---|---|
| Audit coverage | Only authentication, registration, profile, and password events are recorded. Data changes are not yet logged. |
| Activity log page | There is no administrator page to view or export the audit trail yet. |
| Backup and restore | Not yet built. Only the configuration constants exist. |
| Report print preview | Report pages have no print preview button yet, and athletes have no personal report page. |
| Admin athlete management | Administrators can search, view, and delete athletes. Adding and editing athletes from the admin page is planned. |
| Chart.js version | Chart.js is loaded from the CDN without a pinned version. Pinning an exact version is recommended before deployment. |
| Database credentials | Stored in config/db.php. For hosting, use a dedicated database user and keep the file out of version control. |
| Database error page | A failed connection raises an exception. A friendly production error page is planned. |
| Help documents | The PRD and TRD pages are public. They can be restricted to administrators after the project is graded. |
| HTTPS | Supported through FORCE_HTTPS but disabled during local development. |
| Future ideas | Password reset, email notifications, calendar sync, coach accounts per team, and data visualizations by sport. |
18. Current Implementation Status
| Module or feature | Status | Notes |
|---|---|---|
| Registration, login, logout, sessions, CAPTCHA, lockout | Implemented | Arithmetic CAPTCHA, 5-attempt lockout, CSRF, idle timeout. |
| Password hashing | Implemented | password_hash with automatic re-hash. |
| Settings (profile and password) | Implemented | auth/settings.php |
| Weekly schedule | Implemented | Create, view, delete, overlap warning. |
| Time log | Implemented | Create, view, edit, delete, filter, paginate. |
| Tasks | Implemented | Create, view, edit, status change, delete, filter. |
| Survey | Implemented | Consent, Likert and text questions, update answers. |
| Athlete dashboard | Implemented | Cards, charts, tasks, schedule, balance alert. |
| Admin dashboard | Implemented | Cards, chart, overload table. |
| Admin athlete management | In progress | Search, filters, profile, and delete are done; add and edit are planned. |
| Survey results | Implemented | Anonymous averages, distributions, text answers. |
| Reports and CSV export | Implemented | Three filtered CSV exports. |
| Report print preview and athlete personal report | Planned | Menu link already guarded by file_exists. |
| Audit trail recording | In progress | Authentication, registration, profile, and password events recorded; data changes planned. |
| Activity log viewer | Planned | Admin page to filter, print, and export logs. |
| Backup and restore | Planned | Configuration constants exist; no page or script yet. |
| Responsive phone layout | Implemented | Sidebar drawer, stacked tables, touch-friendly controls. |
| HTTPS and domain deployment | In progress | FORCE_HTTPS available but off; no production domain configured yet. |
| Product and Technical Requirement Documents | Implemented | help/prd.php and help/trd.php |