# Code Runtime And Architecture Report

Date: July 2, 2026
Product: VejalNai Chatbot
Purpose: Explain how the code runs today

## Runtime Summary

Current local runtime from `php artisan about`:

| Item | Value |
| --- | --- |
| Application | VejalNai Chatbot |
| Laravel | 13.18.0 |
| PHP | 8.4.22 |
| Composer | 2.10.1 |
| Environment | local |
| Debug mode | enabled |
| URL | localhost:8000 |
| Timezone | UTC |
| Locale | en |
| Config cache | not cached |
| Event cache | not cached |
| Route cache | not cached |
| View cache | not cached |
| Broadcasting | log |
| Cache | file |
| Database | sqlite |
| Mail | log |
| Queue | sync |
| Session | file |
| Public storage link | linked |

Important mismatch:

- `.env.example` and `README.md` describe PostgreSQL and Redis for production-like local development.
- The active local runtime currently uses SQLite, file cache, sync queue, and file sessions.
- This is fine for local dev, but production documentation and actual deploy configuration must be aligned before launch.

## How A Request Enters The App

1. Web server receives the HTTP request.
2. `public/index.php` boots Laravel.
3. `bootstrap/app.php` configures routing, middleware, and exception behavior.
4. Routes are loaded from:
   - `routes/web.php`
   - `routes/api.php`
5. The matching controller handles the request.
6. Controllers use Eloquent models and services.
7. Blade views render dashboard pages, or JSON responses return from API controllers.

## Route Surface

The app currently registers 39 routes.

Main web routes:

- `/`
- `/health`
- `/ready`
- `/widget.js`
- `/login`
- `/logout`
- `/dashboard`
- `/conversations`
- `/conversations-sidebar`
- `/conversations/{conversation}`
- `/unknown-questions`
- `/callback-requests`
- `/teams`
- `/chat-widget`
- `/settings/appearance`
- `/settings/channels`

Main API routes:

- `/api/health`
- `/api/widget/config`
- `/api/widget/messages`
- `/api/webhooks/meta/{provider}`

## Major Code Units

### Models

- `User`: application users and assigned work relationships.
- `Organization`: tenant/workspace root, widget settings, appearance, channel relationships.
- `Membership`: user role, privileges, last activity.
- `Contact`: customer identity per organization/channel.
- `Conversation`: support thread per contact/channel.
- `Message`: customer, bot, or human message.
- `Intent`: bot intent definition.
- `IntentPhrase`: approved trigger phrases.
- `ResponseTemplate`: approved bot answer.
- `UnknownQuestion`: low-confidence customer messages needing training.
- `CallbackRequest`: human follow-up task.
- `ChannelIntegration`: Facebook/WhatsApp credentials and settings.
- `TypoCorrection`: organization-level spelling correction map.

### Services

- `MatchIncomingMessage`: normalizes text, applies typo corrections, scores against intent phrases.
- `ProcessIncomingCustomerMessage`: stores incoming customer messages, sends bot answers or clarifications, creates unknown questions and callback requests, and activates human takeover.

### Controllers

- Auth controllers handle login/logout.
- Dashboard and list controllers render operator pages.
- Conversation controllers handle inbox, polling, assignment, and human replies.
- Widget controllers serve the public widget, widget config, and widget messages.
- Channel controllers save Facebook/WhatsApp settings and receive Meta webhooks.
- Team controllers manage members, roles, and privileges.
- Appearance controller saves widget branding and colors.

## Core Data Flow: Website Widget Message

1. Website loads `/widget.js`.
2. The script reads widget key from script attributes or `window.VejalNaiChat`.
3. The script calls `/api/widget/config?widget_key=...`.
4. The widget applies saved appearance settings.
5. A visitor sends a message.
6. The script posts JSON to `/api/widget/messages`.
7. `WidgetMessageController@store` validates widget key and origin.
8. It creates or updates `Contact`.
9. It creates or reuses an open/pending `Conversation`.
10. It calls `ProcessIncomingCustomerMessage`.
11. The service stores the customer message.
12. The bot either:
    - answers from an approved response,
    - asks for clarification,
    - creates unknown question and callback request,
    - or stays quiet if human takeover is active.
13. API returns customer message id and optional bot message.
14. Widget renders the reply and continues polling history every 5 seconds while open.

## Core Data Flow: Admin Human Reply

1. Agent opens `/conversations/{conversation}`.
2. Browser submits reply to `/conversations/{conversation}/messages`.
3. `StoreConversationMessageRequest` verifies user belongs to the organization.
4. `ConversationMessageController@store` creates a `human` message.
5. AJAX response returns the saved message.

Current limitation:

- The message is not delivered to Facebook or WhatsApp.
- Web widget users can see human replies only through history polling.
- There is no delivery status model yet.

## Core Data Flow: Meta Webhook

1. Meta calls `/api/webhooks/meta/{provider}`.
2. `MetaWebhookController` checks provider is `facebook` or `whatsapp`.
3. It identifies a matching enabled `ChannelIntegration`.
4. It optionally verifies signature based on integration settings.
5. It extracts inbound events from Facebook or WhatsApp payloads.
6. It creates/updates `Contact`.
7. It creates/reuses `Conversation`.
8. It calls `ProcessIncomingCustomerMessage`.
9. It returns processed count.

Current limitation:

- Provider message IDs are not persisted for idempotency.
- Outbound replies are not sent to Meta channels.

## Core Data Flow: Bot Matching

1. Incoming text is lowercased, punctuation is removed, and whitespace is normalized.
2. Organization typo corrections are applied token-by-token.
3. Active intents load approved phrases and approved response templates.
4. Scoring checks:
   - exact match,
   - contains match,
   - token overlap,
   - Levenshtein fuzzy match.
5. Best candidate is returned with confidence.
6. Processor compares confidence to intent threshold.
7. High confidence returns approved response.
8. Medium confidence asks a clarification.
9. Low confidence creates unknown question and callback request.

## Database Shape

Migrations applied in local database:

- Users, password reset tokens, sessions.
- Cache and queue tables.
- Organizations and memberships.
- Contacts, conversations, messages.
- Intents and response templates.
- Intent phrases.
- Unknown questions and callback requests.
- Widget settings and appearance fields.
- Channel integrations.
- Membership privileges.
- Typo corrections.
- Widget accessibility options.
- Conversation current page.

Important indexes already present:

- Contact unique key: organization, channel, external id.
- Conversation indexes by organization/status/time and contact/status.
- Message indexes by conversation/time and sender/time.
- Intent unique key by organization/slug.
- Channel integration unique key by organization/provider.
- Typo correction unique key by organization/input word.

Important missing schema for production:

- Provider inbound idempotency fields.
- Outbound delivery status fields.
- Audit log table.
- Widget session/token table.
- Channel health table or status fields.

## Environment And Startup

Local setup from README:

```bash
php composer.phar install
cp .env.example .env
php artisan key:generate
docker compose up -d postgres redis
php artisan migrate --seed
php artisan serve
```

Current local server responds at:

- `http://127.0.0.1:8000/health`
- `http://127.0.0.1:8000/ready`
- `http://127.0.0.1:8000/api/health`
- `http://127.0.0.1:8000/widget.js`

There is no `package.json`, so there is no active Node/Vite build pipeline in this workspace. Frontend UI is Blade plus inline/public JavaScript.

## Production Runtime Expectation

Production should use:

- PHP 8.4+
- PostgreSQL
- Redis for cache, sessions, queues, and maintenance mode
- Queue worker: `php artisan queue:work --tries=3`
- HTTPS with `APP_FORCE_HTTPS=true`
- `APP_DEBUG=false`
- `SESSION_ENCRYPT=true`
- `SESSION_SECURE_COOKIE=true`
- Cached config/routes/views
- Secret manager for app key, DB credentials, Redis credentials, channel tokens, and admin credentials

## Verification Commands Used

```bash
php artisan route:list
php artisan about
vendor\bin\phpunit --configuration phpunit.xml
vendor\bin\pint --test
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan migrate:status
php artisan view:clear
```

HTTP probes used:

```bash
GET http://127.0.0.1:8000/health
GET http://127.0.0.1:8000/ready
GET http://127.0.0.1:8000/api/health
GET http://127.0.0.1:8000/widget.js
```

## Current Operational State

Working:

- Laravel app boots.
- Auth/dashboard route surface exists.
- Health and readiness endpoints work.
- Widget script is served.
- Widget API handles config, history, and messages.
- Bot matching and handoff work in tests.
- Teams and roles exist.
- Facebook/WhatsApp inbound webhook intake exists.
- Channel secrets are encrypted at rest by Eloquent casts.

Not production-complete:

- External channel outbound sending.
- Webhook idempotency.
- Full privilege enforcement.
- Widget signed sessions.
- Rate limiting.
- Audit log.
- Provider health checks.
- AI monitor workflow.
- CI gate.

## Developer Handoff Notes

- Keep business logic in services and jobs, not Blade or controllers.
- Move authorization into policies/FormRequests.
- Keep channel provider differences behind adapter classes.
- Keep public widget API backward compatible when adding signed sessions.
- Add migrations before changing message delivery behavior.
- Do not add new channel providers until Facebook and WhatsApp are fully two-way.
