[FIX] Fix the documentations of the project.
This commit is contained in:
@@ -1,295 +1,236 @@
|
||||
# AGENTS.md - Development Guidelines
|
||||
|
||||
This file contains essential information for AI agents working on this codebase.
|
||||
Essential information for AI agents and developers working on this codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
PHP website for "Harmonie de Montpellier-Jacou" (music band) with a Vue.js 2 frontend for score management.
|
||||
- **Backend**: PHP with MySQL (legacy codebase)
|
||||
- **Frontend**: Vue.js 2 + Bootstrap Vue (in `frontend/score/`)
|
||||
- **API**: RESTful PHP API in `api/` directory
|
||||
Web application for "Harmonie de Montpellier-Jacou" (music band) to manage and share sheet music (partitions).
|
||||
|
||||
## Build Commands
|
||||
- **Frontend**: SvelteKit (Svelte 5, runes) + Tailwind CSS in `partitions/`
|
||||
- **Backend**: PHP 8.5 REST API in `api/` (no framework)
|
||||
- **Storage**: flat files under `legacy/Scores/` (no database)
|
||||
- **Auth**: JWT (HS256), see `api/lib/Auth.php`
|
||||
- **Production**: `https://partitions.c.nadal-fr.com` (front) + `https://ohmj-api.c.nadal-fr.com` (API)
|
||||
|
||||
### Frontend (Vue.js)
|
||||
```bash
|
||||
cd frontend/score
|
||||
npm install
|
||||
npm run serve # Development server
|
||||
npm run build # Production build
|
||||
npm run lint # ESLint check
|
||||
```
|
||||
There is **no MySQL** and **no Vue.js** in the active codebase. The old Vue.js 2 / MySQL
|
||||
site is archived in `legacy/` and must not be modified.
|
||||
|
||||
### PHP
|
||||
No build step required. Deploy to PHP-enabled web server.
|
||||
## Stack & Versions
|
||||
|
||||
## Deployment
|
||||
- Node.js 26 / npm 11
|
||||
- Svelte 5, SvelteKit 2, `@sveltejs/adapter-static`, Vite 5, Tailwind 3
|
||||
- PHP 8.5 (CLI built-in server in development)
|
||||
- Dependencies: `axios`, `pdfjs-dist`, `lucide-svelte` (front); `setasign/fpdi`, `setasign/fpdf`, `tecnickcom/tcpdf` (back)
|
||||
|
||||
### Create Deploy ZIP
|
||||
```bash
|
||||
cd /home/jbnadal/sources/jb/ohmj/ohmj2
|
||||
./deploy/deploy.sh
|
||||
```
|
||||
> PHP 8.5 note: nullable parameters MUST use explicit `?type` syntax
|
||||
> (e.g. `?string $x = null`). Implicit nullable is deprecated and pollutes API output.
|
||||
|
||||
**Important:**
|
||||
- Do NOT include `legacy/` folder in the zip
|
||||
- Do NOT include `tests.php` in the zip
|
||||
- The `.env` file is included with JWT_SECRET
|
||||
- Frontend build must be in `frontend/` directory
|
||||
## Build & Run Commands
|
||||
|
||||
## Testing
|
||||
|
||||
### PHP API Tests
|
||||
|
||||
Run functional tests for the PHP API:
|
||||
### Backend (PHP)
|
||||
|
||||
```bash
|
||||
cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php
|
||||
```
|
||||
|
||||
- `-c php-upload.ini` is **required** so PDF uploads work (`upload_max_filesize`/`post_max_size` = 64M).
|
||||
`ini_set()` cannot change those directives at runtime.
|
||||
- API base URL: `http://localhost:8000` (paths have **no** `/api` prefix in the client).
|
||||
- Copy `api/.env.example` to `api/.env` and set a strong `JWT_SECRET`.
|
||||
|
||||
### Frontend (SvelteKit)
|
||||
|
||||
```bash
|
||||
cd partitions
|
||||
npm install
|
||||
npm run dev # http://localhost:5173
|
||||
npm run build # outputs to partitions/build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
- `frontend` is a symlink to `partitions/build` (the deployed static site).
|
||||
- No ESLint / test framework is configured for the frontend.
|
||||
- `VITE_API_URL` is defined but currently unused (base URL is chosen from `import.meta.env.DEV`).
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
./deploy/deploy.sh
|
||||
```
|
||||
|
||||
- Do NOT include `legacy/` or `api/tests.php` in the deploy archive.
|
||||
- `api/.env` (with `JWT_SECRET`) is part of the deployment.
|
||||
- The frontend build must be present in `frontend/`.
|
||||
|
||||
## Testing
|
||||
|
||||
### PHP API tests
|
||||
|
||||
```bash
|
||||
cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php & # if not already running
|
||||
rm -f /tmp/rate_* 2>/dev/null # clear rate limiting first
|
||||
php tests.php
|
||||
```
|
||||
|
||||
The tests cover:
|
||||
- **Auth**: Login, bad credentials, missing token, invalid token
|
||||
- **Scores**: CRUD operations, error handling for non-existent resources
|
||||
- **Create Score with Pieces**: Functional tests with pieces verification
|
||||
- **Files**: Get files tree, delete file error handling
|
||||
- Expected: **53/53 tests passed (100%)**.
|
||||
- Covers: auth (login, bad credentials, missing/invalid token), scores CRUD,
|
||||
create-score-with-pieces, files tree, path traversal, rate limiting, upload
|
||||
validation, INI injection, security headers.
|
||||
- `tests.php` is kept for development only and MUST NOT be shipped in the deploy zip.
|
||||
|
||||
**Note**: tests.php is kept in source for development but must NOT be included in deploy zip.
|
||||
## Authentication
|
||||
|
||||
### Vue/Svelte
|
||||
- Login: `POST /login` with `{"username":"admin","password":"password"}` (development).
|
||||
- Token: JWT HS256 signed with `JWT_SECRET`, 1 hour expiry.
|
||||
- API calls: send `Authorization: Bearer <token>`.
|
||||
- Token is stored in `localStorage` on the frontend and attached via an axios request interceptor.
|
||||
- Roles: `admin` (full access) and `user` (read-only). Admin routes live under `/admin/...`.
|
||||
- Frontend dev login page: http://localhost:5173
|
||||
|
||||
No test framework configured for frontend.
|
||||
## API Endpoints
|
||||
|
||||
Run single test (when configured):
|
||||
```bash
|
||||
# Example for Jest (not yet configured)
|
||||
npm test -- --testNamePattern="test name"
|
||||
```
|
||||
Public / all authenticated users:
|
||||
|
||||
## Code Style Guidelines
|
||||
- `POST /login`
|
||||
- `GET /scores`
|
||||
- `GET /scores/:id`
|
||||
- `GET /scores/:id/instruments[?piece=N]`
|
||||
- `GET /pieces/:scoreId`
|
||||
- `GET /download/:path` (token via `Authorization` header or `?token=`)
|
||||
|
||||
### PHP
|
||||
- Use `<?php` opening tags (avoid short `<?` tags for consistency)
|
||||
- Classes: PascalCase (e.g., `Score`, `Database`)
|
||||
- Methods: camelCase (e.g., `readScore`, `getEntryName`)
|
||||
- Variables: snake_case or camelCase (be consistent within files)
|
||||
- Indent: 3 spaces (legacy style) - maintain consistency with surrounding code
|
||||
- Place opening braces on same line as class/function declaration
|
||||
- Use `include_once` for required files
|
||||
- **Note**: Uses legacy MySQL functions (consider upgrading to PDO/MySQLi)
|
||||
Admin only (`role === 'admin'`):
|
||||
|
||||
### JavaScript/Vue
|
||||
- ESLint configuration in `package.json`:
|
||||
- Extends: `plugin:vue/essential`, `eslint:recommended`
|
||||
- Parser: `babel-eslint`
|
||||
- Use ES6+ features (async/await, arrow functions)
|
||||
- Components: PascalCase
|
||||
- Data properties: camelCase
|
||||
- Use 2-space indentation
|
||||
- Semicolons required
|
||||
|
||||
### General
|
||||
- UTF-8 encoding for all files
|
||||
- French language for user-facing content
|
||||
- Maintain GPL v2 license headers in PHP files
|
||||
- `POST /admin/scores`
|
||||
- `PUT /admin/scores/:id`
|
||||
- `PUT /admin/scores/:id/pieces`
|
||||
- `DELETE /admin/scores/:id`
|
||||
- `POST /admin/scores/:id/upload`
|
||||
- `GET /admin/scores/:id/files`
|
||||
- `DELETE /admin/scores/:id/files?path=...`
|
||||
|
||||
## File Organization
|
||||
|
||||
```
|
||||
/
|
||||
├── api/ # REST API endpoints
|
||||
│ ├── config/ # Database configuration
|
||||
│ ├── objects/ # Data models
|
||||
│ └── score/ # API endpoints
|
||||
├── frontend/score/ # Vue.js application
|
||||
│ ├── src/ # Source code
|
||||
│ └── public/ # Static assets
|
||||
├── Scripts/ # PHP page controllers
|
||||
├── fpdf/ # PDF generation library
|
||||
├── Imgs/ # Image assets
|
||||
├── Textes/ # Text content files
|
||||
└── index.php # Main entry point
|
||||
├── api/ # PHP REST API (active)
|
||||
│ ├── index.php # Router / entry point
|
||||
│ ├── router.php # Dev server router (+ CORS, .env loading)
|
||||
│ ├── lib/Auth.php # JWT auth
|
||||
│ ├── lib/ScoreScanner.php# File-based score index
|
||||
│ ├── config/users.json # Users (bcrypt hashes)
|
||||
│ ├── tests.php # Functional tests (dev only)
|
||||
│ └── .env # JWT_SECRET, SCORES_PATH
|
||||
├── partitions/ # SvelteKit app (active)
|
||||
│ ├── src/lib/api.ts # Axios client + apiService
|
||||
│ ├── src/lib/stores/ # auth store
|
||||
│ ├── src/lib/components/ # PdfViewer
|
||||
│ ├── src/routes/ # pages (login, scores, admin)
|
||||
│ └── build/ # static output (gitignored)
|
||||
├── frontend -> partitions/build # symlink used for deployment
|
||||
├── deploy/deploy.sh # deploy archive builder
|
||||
├── scripts/convert_final_v2.js # one-off filename converter
|
||||
├── legacy/ # archived old site + Scores/ (do not modify)
|
||||
└── _builds/ # temporary work files (gitignored)
|
||||
```
|
||||
|
||||
## Database
|
||||
## Data Model (files)
|
||||
|
||||
MySQL database connection configured in `api/config/database.php`:
|
||||
- Uses legacy `mysql_*` functions
|
||||
- Database name: `ohmj2`
|
||||
- Tables: `repertoire` (for scores)
|
||||
```
|
||||
legacy/Scores/<NUM>/<PIECE>/<INSTRUMENT>/<VERSION>/<PARTIE>.pdf
|
||||
legacy/Scores/<NUM>/score.ini
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
`score.ini`:
|
||||
|
||||
- PHP: Uses `@` error suppression operator in some places
|
||||
- Vue: Uses try/catch with console.log for errors
|
||||
- Return HTTP 200 on success in API responses
|
||||
```ini
|
||||
[info]
|
||||
name = Nom du morceau
|
||||
compositor = Compositeur
|
||||
ressource = https://... # optional external link
|
||||
|
||||
## Security Notes
|
||||
[pieces]
|
||||
count = 1
|
||||
```
|
||||
|
||||
- API uses `Access-Control-Allow-Origin: *` (CORS enabled for all)
|
||||
- SQL queries use string concatenation (vulnerable to SQL injection)
|
||||
- Database credentials stored in plain text in `api/config/database.php`
|
||||
- Sanitize user inputs before database queries
|
||||
- `NUM` = score id (zero-padded, e.g. `102`).
|
||||
- `PIECE` = movement/piece number (1 for single-piece scores).
|
||||
- `INSTRUMENT` = trigram code (see below).
|
||||
- `VERSION` = version number.
|
||||
- `PARTIE` = part number.
|
||||
|
||||
## Git
|
||||
Instrument codes: `dir`, `pic`, `flu`, `cla`, `clb`, `sax`, `sat`, `sab`, `coa`,
|
||||
`cba`, `cor`, `trp`, `trb`, `tub`, `htb`, `bas`, `per`, `crn`, `eup`, `har`, `pia`,
|
||||
plus `sup`/`par` for combined parts.
|
||||
|
||||
- No CI/CD configured
|
||||
- Commit to main branch
|
||||
- Standard `.gitignore` for Node.js projects
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Frontend
|
||||
- Vue 2.6.11
|
||||
- Bootstrap Vue 2.17.3
|
||||
- Axios 0.21.0
|
||||
- Vue CLI 4.5.0
|
||||
## Code Style
|
||||
|
||||
### PHP
|
||||
- FPDF library for PDF generation
|
||||
- MySQL extension (legacy)
|
||||
- `<?php` opening tags, PascalCase classes, camelCase methods.
|
||||
- 3-space indentation, opening brace on the same line (legacy style).
|
||||
- Consistent with surrounding code; prefer `include_once`/`require_once` for includes.
|
||||
- No database layer: file operations via `ScoreScanner.php`.
|
||||
|
||||
## Important Notes
|
||||
### JavaScript / Svelte
|
||||
- Svelte 5 runes (`$state`, `$props`, `$derived`, `$effect`); prefer `$app/state` over the deprecated `$app/stores`.
|
||||
- TypeScript, camelCase variables, PascalCase components, 2-space indent, semicolons.
|
||||
|
||||
- **NEVER delete files or directories** - Always ask before removing anything
|
||||
- This is a legacy codebase with mixed coding styles
|
||||
- Prefer consistency with existing code over strict style enforcement
|
||||
- Site targets French-speaking users
|
||||
- Production URL: `ohmj2.free.fr`
|
||||
### General
|
||||
- UTF-8, French for user-facing content.
|
||||
- Do not add comments unless necessary.
|
||||
- **NEVER delete files or directories without asking first.**
|
||||
|
||||
## Design Guidelines
|
||||
|
||||
- **Style**: Clean, sober, and modern
|
||||
- **Icons**: Use SVG icons instead of emojis for better consistency
|
||||
- **Buttons**: Integrate related actions (view + download) in a single row with consistent styling
|
||||
- **Hide unnecessary labels**: Don't show "Piece 1" or "Version 1" when there's only one
|
||||
- **Visual hierarchy**: Use spacing, subtle borders, and hover effects for interactivity
|
||||
- Clean, sober, modern.
|
||||
- Use SVG icons instead of emojis.
|
||||
- Integrate related actions (view + download) in a single row with consistent styling.
|
||||
- Hide redundant labels ("Piece 1", "Version 1") when there is only one.
|
||||
- Use spacing, subtle borders, and hover effects for visual hierarchy.
|
||||
|
||||
## Temporary Work Files
|
||||
## Security Checklist (before deployment)
|
||||
|
||||
- Use `_builds/` directory for temporary scripts and working files
|
||||
- Only `scripts/convert_final_v2.js` should be kept in the scripts folder (committed to git)
|
||||
- CSV output files belong in `_builds/`
|
||||
- [ ] `JWT_SECRET` is strong and unique (`openssl rand -base64 32`); never commit `api/.env`.
|
||||
- [ ] `api/config/users.json` uses non-default credentials (change `admin`/`user`).
|
||||
- [ ] CORS origins restricted to the real domains (no wildcard fallback).
|
||||
- [ ] HTTPS enforced in production.
|
||||
- [ ] Rate limiting active (clear `/tmp/rate_*` only in tests, never in prod).
|
||||
- [ ] `php tests.php` passes 53/53.
|
||||
- [ ] `npm audit` reviewed.
|
||||
- [ ] No secrets in code or git history.
|
||||
|
||||
## Authentication
|
||||
|
||||
- **Login**: Use `apiService.login('admin', 'password')` from frontend
|
||||
- **API calls**: Include token in Authorization header:
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
- **Token format**: JWT (HS256) - see `api/lib/Auth.php`
|
||||
- **Frontend**: Token stored in localStorage, auto-attached to API requests via axios interceptor
|
||||
- **Test**: http://localhost:5173 - login with admin/password
|
||||
- **API base URL**: http://localhost:8000/api/
|
||||
|
||||
### Starting the PHP Server
|
||||
|
||||
**Important:** Always use the custom upload config for file uploads to work:
|
||||
```bash
|
||||
cd api
|
||||
php -c php-upload.ini -S localhost:8000 router.php &
|
||||
```
|
||||
|
||||
Le serveur doit être lancé avec `-c php-upload.ini` pour autoriser l'upload de fichiers PDF (64M max).
|
||||
|
||||
### Upload de partitions
|
||||
|
||||
Lors de l'upload d'un PDF, deux options sont disponibles :
|
||||
- **Ajouter le numéro** : ajoute le numéro de partition dans le coin du PDF
|
||||
- **Position** : choix entre "Gauche" ou "Droite" pour placer le numéro
|
||||
|
||||
## Current Tech Stack (2024)
|
||||
|
||||
- **Frontend**: SvelteKit (NOT Vue.js 2) in `/partitions/`
|
||||
- **Backend**: PHP API in `/api/`
|
||||
- **Scores storage**: `/legacy/Scores/` (directory-based, not MySQL)
|
||||
|
||||
## Security Audit Commands
|
||||
|
||||
When modifying backend or frontend code, run these security audits:
|
||||
|
||||
### Backend Security Audit
|
||||
Manual checks:
|
||||
|
||||
```bash
|
||||
# 1. Start the PHP server
|
||||
cd api
|
||||
php -S localhost:8000 router.php &
|
||||
|
||||
# 2. Clear rate limiting files (important!)
|
||||
rm -f /tmp/rate_* 2>/dev/null
|
||||
|
||||
# 3. Run all security tests
|
||||
php tests.php
|
||||
|
||||
# Expected: 50/50 tests passed (100%)
|
||||
```
|
||||
|
||||
### Frontend Security Check
|
||||
|
||||
```bash
|
||||
cd partitions
|
||||
|
||||
# 1. Check for security issues in dependencies
|
||||
npm audit
|
||||
|
||||
# 2. Build and check for CSP violations
|
||||
npm run build
|
||||
|
||||
# 3. Check that environment variables are configured
|
||||
cp .env.example .env
|
||||
# Edit .env and set VITE_API_URL to your backend URL
|
||||
```
|
||||
|
||||
### Manual Security Verification
|
||||
|
||||
```bash
|
||||
# Test JWT authentication
|
||||
curl -s http://localhost:8000/login \
|
||||
-X POST \
|
||||
# JWT login
|
||||
curl -s http://localhost:8000/login -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"password"}'
|
||||
|
||||
# Test CORS headers
|
||||
curl -s -I http://localhost:8000/scores \
|
||||
-H "Origin: https://evil.com"
|
||||
|
||||
# Test directory traversal protection
|
||||
# Directory traversal must NOT return 200
|
||||
curl -s http://localhost:8000/download/../../../etc/passwd \
|
||||
-H "Authorization: Bearer <token>"
|
||||
# Expected: 403 or 404 (not 200)
|
||||
|
||||
# Test security headers
|
||||
curl -s -I http://localhost:8000/login \
|
||||
-X POST \
|
||||
# Security headers on any response
|
||||
curl -s -I http://localhost:8000/login -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"password"}'
|
||||
# Check for: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, HSTS
|
||||
```
|
||||
|
||||
### Environment Setup for Security
|
||||
> Known security findings from the latest review (not yet fixed): static file
|
||||
> passthrough in `api/router.php` exposes `.env`/`users.json`; `deleteScoreFile`
|
||||
> lacks path containment; `api/.env` is tracked by git; JWT is standard base64
|
||||
> (not base64url) and expiry is optional; stored XSS via the `ressource` link.
|
||||
> See the project issue tracker / recent review notes.
|
||||
|
||||
**Backend (api/.env):**
|
||||
```bash
|
||||
JWT_SECRET=your_very_long_random_secret_key_here
|
||||
```
|
||||
## Temporary Files
|
||||
|
||||
**Frontend (partitions/.env):**
|
||||
```bash
|
||||
# Development
|
||||
VITE_API_URL=http://localhost:8000
|
||||
- Put temporary scripts and outputs in `_builds/` (gitignored).
|
||||
- `scripts/convert_final_v2.js` is the only committed script in `scripts/`.
|
||||
|
||||
# Production (use HTTPS!)
|
||||
VITE_API_URL=https://api.yourdomain.com
|
||||
```
|
||||
## Git
|
||||
|
||||
### Security Checklist Before Deployment
|
||||
|
||||
- [ ] JWT_SECRET is set and strong (use: `openssl rand -base64 32`)
|
||||
- [ ] CORS origins are restricted to your domain only
|
||||
- [ ] HTTPS is enforced in production
|
||||
- [ ] Rate limiting is active
|
||||
- [ ] All 50 tests pass
|
||||
- [ ] npm audit shows no critical vulnerabilities
|
||||
- [ ] CSP headers are configured
|
||||
- [ ] No secrets in code or git history
|
||||
- Default branch: `master`.
|
||||
- No CI/CD configured.
|
||||
- Only commit when explicitly requested.
|
||||
|
||||
Reference in New Issue
Block a user