avc

MiniChat — Többfelhasználós chat alkalmazás — Rendszerterv (PRD)

Projekt célja

Többfelhasználós valós idejű chat alkalmazás, amelynek elsődleges célja az AI Vibe-Coding Ecosystem tesztelése összetett, backend-es feladaton. PHP 7.3 + MySQL + vanilla JS. Ez az eddigi legösszetettebb teszt: több fájl, szerver oldali logika, adatbázis, session kezelés, biztonsági követelmények.

Tech Stack

Időzítési konstansok (US-007)

Az online jelenlét detektálásának paraméterei a teszt alkalmazáshoz arányos B szint szerint:

ParaméterÉrtékMegjegyzés
last_seen timeout45 mpuser offline-nak minősül
Online-lista polling15 mpusers.php?action=online GET gyakoriság
Messages polling3 mpmessages.php?action=poll GET gyakoriság (ez frissíti a last_seen-t)
Explicit logout → offlinemax 15 mplogout-kor last_seen = NOW() - INTERVAL 60 SECOND vagy is_logged_out=1
Tab close → offlinemax 60 mp45 mp timeout + 15 mp polling

Ezek az aiQA regresszió szigorú SLA-jához kötöttek — az online lista időzítését stopperrel kell mérni, és 15/60 mp felett FAILED.

Szerver környezet

PHP 7.3.33 (LiteSpeed SAPI)
Apache + mod_rewrite
MySQL (mysqlnd 5.0.12-dev)
PDO drivers: mysql, odbc, pgsql, sqlite
Extensions: mysqli, pdo_mysql, session, json, mbstring, openssl, curl, gd, fileinfo
upload_max_filesize: 60M
post_max_size: 128M
memory_limit: 512M
max_execution_time: 90s

Környezetek

Elérhető Claude Code Skillek

Mappastruktúra

src/
├── index.html              ← Login oldal (belépő pont)
├── register.html           ← Regisztrációs oldal
├── chat.html               ← Fő chat felület (bejelentkezés szükséges)
├── profile.html            ← Profil szerkesztés
├── css/
│   └── style.css           ← Globális stílusok, téma változók
├── js/
│   ├── app.js              ← Közös logika (auth check, CSRF, téma, utils)
│   ├── chat.js             ← Chat logika (polling, küldés, szobák, értesítések)
│   └── profile.js          ← Profil oldal logika
├── api/
│   ├── config.php          ← DB connection, session beállítás, CORS, közös funkciók
│   ├── init_db.php         ← Séma inicializáló (egyszer futtatandó)
│   ├── auth.php            ← ?action=register|login|logout|csrf_token
│   ├── messages.php        ← ?action=send|poll|search|typing
│   ├── rooms.php           ← ?action=create|list|join
│   └── users.php           ← ?action=online|update_profile|get_profile
└── .htaccess               ← PHP session beállítások, biztonsági fejlécek

Adatbázis séma

users

OszlopTípusMegjegyzés
idINT AUTO_INCREMENTPK
usernameVARCHAR(50) UNIQUEmin 3 karakter
emailVARCHAR(100) UNIQUEvalidált
password_hashVARCHAR(255)password_hash()
bioTEXTmax 200 karakter (app szinten)
avatar_urlVARCHAR(500)NULL engedélyezett
created_atDATETIME DEFAULT NOW()
last_seenDATETIMEpolling frissíti

rooms

OszlopTípusMegjegyzés
idINT AUTO_INCREMENTPK
nameVARCHAR(50) UNIQUEmin 2, max 30
descriptionTEXTopcionális
created_byINTFK → users(id)
is_privateTINYINT(1) DEFAULT 0DM szobák: 1
created_atDATETIME DEFAULT NOW()

messages

OszlopTípusMegjegyzés
idINT AUTO_INCREMENTPK
room_idINTFK → rooms(id)
user_idINTFK → users(id)
contentTEXTmax 1000 karakter (app szinten)
created_atDATETIME DEFAULT NOW()
INDEX(room_id, created_at)polling gyorsítás

room_members

OszlopTípusMegjegyzés
room_idINTFK → rooms(id)
user_idINTFK → users(id)
joined_atDATETIME DEFAULT NOW()
PRIMARY KEY(room_id, user_id)

API Végpontok

auth.php

POST ?action=register  — body: {username, email, password, password_confirm, csrf_token}
                        → {success: true, user: {id, username}} | {success: false, error: "..."}

POST ?action=login     — body: {email, password, csrf_token}
                        → {success: true, user: {id, username}} | {success: false, error: "Hibás email vagy jelszó"}

POST ?action=logout    → {success: true}

GET  ?action=csrf_token → {token: "abc123..."}

messages.php

POST ?action=send      — body: {room_id, content, csrf_token}
                        → {success: true, message: {id, content, created_at}} | {success: false, error: "..."}

GET  ?action=poll      — params: room_id, after (last_msg_id)
                        → {messages: [...], typing: ["Anna", "Béla"]}

GET  ?action=search    — params: q (min 3 karakter), room_id
                        → {results: [{id, content, username, created_at}]}

POST ?action=typing    — body: {room_id}
                        → {success: true}

rooms.php

POST ?action=create    — body: {name, description, is_private, csrf_token}
                        → {success: true, room: {id, name}}

GET  ?action=list      → {rooms: [{id, name, description, member_count, is_private}], dm_rooms: [{id, name, other_user}]}

POST ?action=join      — body: {room_id}
                        → {success: true}

POST ?action=invite    — body: {room_id, invited_user_id VAGY invited_username, csrf_token}
                        → {success: true, user: {id, username}} | {success: false, error: "..."}
                        Csak privát (NEM DM) szoba tagja hívhat meg. Hibák: 403 (nem tag), 404 (nincs ilyen user), 409 (már tag).

GET  ?action=members   — params: room_id
                        → {users: [{id, username, avatar_url}]}
                        Csak tag kérheti le. Az invite modal használja a 'már tag' lista kitöltéséhez.

users.php

GET  ?action=online    — params: room_id
                        → {users: [{id, username, avatar_url, is_online}]}

POST ?action=update_profile — body: {email, bio, avatar_url, csrf_token}
                             → {success: true}

POST ?action=change_password — body: {old_password, new_password, new_password_confirm, csrf_token}
                              → {success: true} | {success: false, error: "Hibás régi jelszó"}

GET  ?action=get_profile    → {user: {id, username, email, bio, avatar_url, created_at}}

init_db.php (admin endpoint)

GET  (paraméter nélkül)     → séma inicializálás (CREATE TABLE IF NOT EXISTS), Lobby seed
GET  ?reset=1&secret=<S>    → RESET mód: TRUNCATE messages, room_members; DELETE rooms WHERE name!='Lobby';
                              DELETE users; AUTO_INCREMENT reset; Lobby újra-seedelés ha hiányzik
                              Secret egyezés kötelező (config.php ADMIN_SECRET) — hibás → 403
                              → {success: true, deleted: {users: N, rooms: M, messages: K}, lobby_id: <id>}

Biztonsági követelmények

  1. SQL Injection: MINDEN query prepared statement-tel (PDO). Nincs string concatenáció SQL-ben.
  2. XSS: htmlspecialchars($str, ENT_QUOTES, 'UTF-8') minden kimenetre. Kliens oldalon is escape.
  3. CSRF: Minden POST kéréshez token. Token generálás: bin2hex(random_bytes(32)), session-ben tárolva.
  4. Session: session_start() minden API hívás elején. session_regenerate_id(true) login után. HTTP-only cookie.
  5. Jelszó: password_hash(PASSWORD_DEFAULT) + password_verify(). Soha nem plain text.
  6. Rate limiting: Max 30 üzenet/perc/user. SQL: COUNT(*) WHERE user_id=? AND created_at > DATE_SUB(NOW(), INTERVAL 1 MINUTE).

Regressziós tesztelés

A regressziós szcenáriókat az aiqa-planner (Opus modell, dedikált scheduled task) tervezi meg dinamikusan a User Stories, AC-k, fejlesztés közbeni BUG-ok és a fenti üzleti logika alapján. Ebben a PRD-ben szándékosan NINCS előre megírt szcenárió lista — a regresszió kreatív, cross-funkcionális, a tényleges futás kontextusához igazodik. A planner output-ja a quality/REGRESSION.json fájlba kerül; a 5 aiqa-w-XX worker (Sonnet) párhuzamosan futtatja a dependsOn gráf alapján.

Lásd: agents/rules-aiqa-planner.md (output schema, minőségi követelmények) és agents/aiqa-planner-init-prompt.md (folyamat).

Fontos megjegyzések a fejlesztőnek (Ralph)