Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Changelog

All notable changes to this project will be documented in this file.

Stage 1 — What has been added and why

index.html

  • Removed data.js from <head> — it's now loaded just before chat.js at the bottom of <body>, after the DOM is ready. This avoids race conditions.
  • Removed jQuery — it's unused now. Bootstrap's bundle is sufficient.
  • Chat list is now empty markup (<div id="chatList">) — populated entirely by JS, so adding/removing chats later requires zero HTML changes.
  • <form id="messageForm"> replaces the bare <button> — enables native Enter-to-submit and proper submit event handling.
  • id attributes added to all interactive elements for clean, unambiguous JS targeting.

Later utilised as index.php:

  • Session bootstrap — session_start() and reading $_SESSION for the current user. When you add real auth later, this is the only file you touch.
  • Injecting APP_CONFIG into the page — the $jsConfig block emits a <script>const APP_CONFIG = {...}</script> with the API endpoint and current user. JS reads this at startup. No hardcoded values in JS, no extra HTTP round-trip to ask "who am I?".
  • HTML escaping — htmlspecialchars() on any server-rendered values (like the username in the nav).

chat.js — restructured into 4 modules

Module Responsibility
ChatStore Single source of truth. Holds chat metadata, messages (seeded from data.js), and active chat ID.
ChatAPI All fetch() calls to api/ws.php. GET for history, POST to send. Isolated — swap the endpoint later without touching anything else.
ChatUI Pure DOM rendering. Never reads or mutates state. Takes data in, writes HTML out.
ChatApp Orchestration layer. Wires events, handles ?chat= URL routing via history.pushState, coordinates the other three modules.

Key behaviours added: SPA routing (no page reload on chat switch), browser back/forward support, typing indicator, error bubble on API failure, send-button disabled state during inflight requests.

Key changes: -ChatAPI._call() is the one place that knows about the action/POST protocol. Every method just calls _call('action_name', payload) and returns json.data directly — the { success, message, data } envelope is unwrapped there, so callers never see it. If the driver changes its envelope format, you fix it in one place.

  • getUserChats → loadChatList — on init, the sidebar is populated from the API, not from data.js. The data.js file can be deleted entirely once the DB is live.

  • sendMessage flow — after the user's message is optimistically appended, it POSTs send_message, then immediately calls getMessages again to pick up the bot's reply. It's a deliberate short-term trade-off: one extra fetch instead of building a polling loop now. The comment flags this as the WebSocket/SSE replacement point for Stage 3.

  • deleteChat — wired to the new "Delete Chat" dropdown item, calls delete_chat action, hides chatbox, refreshes sidebar, clears URL param.

  • clearChat — UI-only, doesn't call the API. Messages stay in the DB; it just clears the local store and re-renders. If you want a "clear for me" feature later, that's a separate delete_messages_for_user endpoint, not this.

  • Config object reads from APP_CONFIG with a safe fallback — so the JS still runs if you open the HTML file directly for local testing.

ws.php (new — api/ws.php)

  • GET ?chat_id=X → returns { chat_id, messages: [] } (empty stub; client falls back to data.js seed)
  • POST { chat_id, message } → returns a fully-formed bot reply JSON object
  • Keyword-based dummy reply logic, easy to swap for real AI/workflow
  • Response contract is identical to what the real DB layer will return, so chat.js needs no changes in Stage 2

Stage 2 — Proposed DB schema

Schema proposed for chat database, designed with Stage 2 in mind:

-- Users (agents, bots, customers)
CREATE TABLE users (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid        CHAR(36)     NOT NULL UNIQUE,          -- public-facing ID
    name        VARCHAR(120) NOT NULL,
    role        ENUM('customer','agent','bot') NOT NULL DEFAULT 'customer',
    avatar_url  VARCHAR(255),
    created_at  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- Chat sessions
CREATE TABLE chats (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid        CHAR(36)     NOT NULL UNIQUE,          -- maps to ?chat= param
    subject     VARCHAR(255),
    status      ENUM('open','closed','pending') NOT NULL DEFAULT 'open',
    created_by  INT UNSIGNED NOT NULL,                 -- FK → users.id
    created_at  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (created_by) REFERENCES users(id)
);

-- Chat participants (many-to-many: chats ↔ users)
CREATE TABLE chat_participants (
    chat_id     INT UNSIGNED NOT NULL,
    user_id     INT UNSIGNED NOT NULL,
    joined_at   DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (chat_id, user_id),
    FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Messages
CREATE TABLE messages (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    uuid        CHAR(36)     NOT NULL UNIQUE,
    chat_id     INT UNSIGNED NOT NULL,
    user_id     INT UNSIGNED NOT NULL,                 -- who sent it
    type        ENUM('sender','reply') NOT NULL,       -- matches your JS convention
    body        TEXT         NOT NULL,
    read_status TINYINT(1)   NOT NULL DEFAULT 0,
    created_at  DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),  -- ms precision for ordering
    FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE,
    FOREIGN KEY (user_id) REFERENCES users(id),
    INDEX idx_chat_created (chat_id, created_at)      -- the query you'll run most
);

-- Attachments (separate table, not a JSON blob)
CREATE TABLE attachments (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    message_id  INT UNSIGNED NOT NULL,
    filename    VARCHAR(255) NOT NULL,
    mime_type   VARCHAR(100) NOT NULL,
    size_bytes  INT UNSIGNED NOT NULL,
    storage_path VARCHAR(500) NOT NULL,               -- S3 key or local path
    created_at  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE
);

Design rationale:

  • uuid columns everywhere — the ?chat= param becomes the chat's UUID, never exposing internal auto-increment IDs to the frontend
  • chat_participants makes the model multi-agent-ready (a chat can have a customer + multiple agents + a bot)
  • attachments as its own table (not a JSON column) — queryable, reportable, and avoids JSON parsing overhead
  • DATETIME(3) on messages.created_at — millisecond precision ensures correct ordering when messages arrive in the same second
  • The idx_chat_created index covers the most common query: "give me all messages for chat X, oldest first"

Feature List

applicable as of version v1.2

Implemented

  • Responsive layout
  • Functional JS/PHP + Database
  • CRUD-on message storage and Chat sessions

Pending

  • Renaming new chats
  • soft-deleting chats
  • unsend (soft-delete) messages
  • Authentication and user/bot discovery
  • Search bar not working
  • read_status not getting updated

Open/Known Issues

  • pagination feature not tested

About

Functional, Responsive and simple full-stack PHP Chat interface capable of message store & render.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages