refactor(core): restructure chat models and services, integrate route-based chat IDs

- Updated `Chat` and `ChatMessage` models for new table structures with UUIDs and attributes.
- Integrated `ChatPolicy` for authorization checks.
- Updated `ChatMessageController` with authorization and refined logic.
- Adjusted routes and state in the frontend to handle chat IDs from the URL.
- Enhanced `SocialMediaService` for handling chat-specific user prompts.
- Removed unused migrations related to chats and chat messages.
This commit is contained in:
kushal-saha 2026-04-29 15:36:56 +00:00
parent 6bd105632a
commit d818c5f05d
16 changed files with 238 additions and 245 deletions

2
.idea/.gitignore generated vendored
View File

@ -8,3 +8,5 @@
# Datasource local storage ignored files # Datasource local storage ignored files
/dataSources/ /dataSources/
/dataSources.local.xml /dataSources.local.xml
/laravel-idea-personal.xml
/jsLibraryMappings.xml

240
.idea/php.xml generated
View File

@ -3,6 +3,9 @@
<component name="LaravelPint"> <component name="LaravelPint">
<laravel_pint_settings> <laravel_pint_settings>
<LaravelPintConfiguration tool_path="$PROJECT_DIR$/../.config/composer/vendor/bin/pint" /> <LaravelPintConfiguration tool_path="$PROJECT_DIR$/../.config/composer/vendor/bin/pint" />
<laravel_pint_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" tool_path="/home/krbfx/.config/composer/vendor/bin/pint">
<option name="timeout" value="30000" />
</laravel_pint_by_interpreter>
</laravel_pint_settings> </laravel_pint_settings>
</component> </component>
<component name="MessDetectorOptionsConfiguration"> <component name="MessDetectorOptionsConfiguration">
@ -15,149 +18,159 @@
<option name="highlightLevel" value="WARNING" /> <option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" /> <option name="transferred" value="true" />
</component> </component>
<component name="PhpCodeSniffer">
<phpcs_settings>
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" timeout="30000" />
</phpcs_settings>
</component>
<component name="PhpExternalFormatter"> <component name="PhpExternalFormatter">
<option name="externalFormatter" value="LARAVEL_PINT" /> <option name="externalFormatter" value="LARAVEL_PINT" />
</component> </component>
<component name="PhpIncludePathManager"> <component name="PhpIncludePathManager">
<include_path> <include_path>
<path value="$PROJECT_DIR$/backend/vendor/nikic/php-parser" /> <path value="$PROJECT_DIR$/backend/vendor/aws/aws-crt-php" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-sdk-php" />
<path value="$PROJECT_DIR$/backend/vendor/bacon/bacon-qr-code" />
<path value="$PROJECT_DIR$/backend/vendor/brianium/paratest" />
<path value="$PROJECT_DIR$/backend/vendor/brick/math" />
<path value="$PROJECT_DIR$/backend/vendor/carbonphp/carbon-doctrine-types" />
<path value="$PROJECT_DIR$/backend/vendor/composer" />
<path value="$PROJECT_DIR$/backend/vendor/dasprid/enum" />
<path value="$PROJECT_DIR$/backend/vendor/dflydev/dot-access-data" /> <path value="$PROJECT_DIR$/backend/vendor/dflydev/dot-access-data" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/backend/vendor/dragonmantank/cron-expression" />
<path value="$PROJECT_DIR$/backend/vendor/egulias/email-validator" /> <path value="$PROJECT_DIR$/backend/vendor/egulias/email-validator" />
<path value="$PROJECT_DIR$/backend/vendor/ramsey/collection" /> <path value="$PROJECT_DIR$/backend/vendor/fakerphp/faker" />
<path value="$PROJECT_DIR$/backend/vendor/ramsey/uuid" /> <path value="$PROJECT_DIR$/backend/vendor/fidry/cpu-core-counter" />
<path value="$PROJECT_DIR$/backend/vendor/mockery/mockery" /> <path value="$PROJECT_DIR$/backend/vendor/filp/whoops" />
<path value="$PROJECT_DIR$/backend/vendor/nunomaduro/collision" /> <path value="$PROJECT_DIR$/backend/vendor/fruitcake/php-cors" />
<path value="$PROJECT_DIR$/backend/vendor/graham-campbell/result-type" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/promises" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/uri-template" />
<path value="$PROJECT_DIR$/backend/vendor/hamcrest/hamcrest-php" /> <path value="$PROJECT_DIR$/backend/vendor/hamcrest/hamcrest-php" />
<path value="$PROJECT_DIR$/backend/vendor/nunomaduro/termwind" />
<path value="$PROJECT_DIR$/backend/vendor/jean85/pretty-package-versions" /> <path value="$PROJECT_DIR$/backend/vendor/jean85/pretty-package-versions" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-timer" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/ai" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-file-iterator" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/fortify" />
<path value="$PROJECT_DIR$/backend/vendor/theseer/tokenizer" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/framework" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-code-coverage" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/pail" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/phpunit" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/prompts" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-text-template" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/sanctum" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-invoker" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/serializable-closure" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem" /> <path value="$PROJECT_DIR$/backend/vendor/laravel/tinker" />
<path value="$PROJECT_DIR$/backend/vendor/league/uri-interfaces" />
<path value="$PROJECT_DIR$/backend/vendor/league/commonmark" /> <path value="$PROJECT_DIR$/backend/vendor/league/commonmark" />
<path value="$PROJECT_DIR$/backend/vendor/league/config" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem-local" />
<path value="$PROJECT_DIR$/backend/vendor/league/mime-type-detection" /> <path value="$PROJECT_DIR$/backend/vendor/league/mime-type-detection" />
<path value="$PROJECT_DIR$/backend/vendor/league/uri" /> <path value="$PROJECT_DIR$/backend/vendor/league/uri" />
<path value="$PROJECT_DIR$/backend/vendor/league/config" /> <path value="$PROJECT_DIR$/backend/vendor/league/uri-interfaces" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem-local" /> <path value="$PROJECT_DIR$/backend/vendor/mockery/mockery" />
<path value="$PROJECT_DIR$/backend/vendor/brianium/paratest" /> <path value="$PROJECT_DIR$/backend/vendor/monolog/monolog" />
<path value="$PROJECT_DIR$/backend/vendor/mtdowling/jmespath.php" />
<path value="$PROJECT_DIR$/backend/vendor/myclabs/deep-copy" /> <path value="$PROJECT_DIR$/backend/vendor/myclabs/deep-copy" />
<path value="$PROJECT_DIR$/backend/vendor/composer" />
<path value="$PROJECT_DIR$/backend/vendor/nesbot/carbon" /> <path value="$PROJECT_DIR$/backend/vendor/nesbot/carbon" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/version" /> <path value="$PROJECT_DIR$/backend/vendor/nette/schema" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/manifest" /> <path value="$PROJECT_DIR$/backend/vendor/nette/utils" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/pail" /> <path value="$PROJECT_DIR$/backend/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/backend/vendor/filp/whoops" /> <path value="$PROJECT_DIR$/backend/vendor/nunomaduro/collision" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/tinker" /> <path value="$PROJECT_DIR$/backend/vendor/nunomaduro/termwind" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/serializable-closure" /> <path value="$PROJECT_DIR$/backend/vendor/paragonie/constant_time_encoding" />
<path value="$PROJECT_DIR$/backend/vendor/brick/math" /> <path value="$PROJECT_DIR$/backend/vendor/pestphp/pest" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/prompts" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/framework" />
<path value="$PROJECT_DIR$/backend/vendor/graham-campbell/result-type" />
<path value="$PROJECT_DIR$/backend/vendor/ta-tikoma/phpunit-architecture-test" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/backend/vendor/psr/container" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin" /> <path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin" />
<path value="$PROJECT_DIR$/backend/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-arch" /> <path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-arch" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-laravel" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-mutate" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-profanity" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-docblock" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/backend/vendor/phpoption/phpoption" />
<path value="$PROJECT_DIR$/backend/vendor/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/backend/vendor/pragmarx/google2fa" />
<path value="$PROJECT_DIR$/backend/vendor/psr/clock" />
<path value="$PROJECT_DIR$/backend/vendor/psr/container" />
<path value="$PROJECT_DIR$/backend/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-client" /> <path value="$PROJECT_DIR$/backend/vendor/psr/http-client" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-factory" /> <path value="$PROJECT_DIR$/backend/vendor/psr/http-factory" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest" /> <path value="$PROJECT_DIR$/backend/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/backend/vendor/psr/clock" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-profanity" />
<path value="$PROJECT_DIR$/backend/vendor/psr/log" /> <path value="$PROJECT_DIR$/backend/vendor/psr/log" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-mutate" />
<path value="$PROJECT_DIR$/backend/vendor/psr/simple-cache" /> <path value="$PROJECT_DIR$/backend/vendor/psr/simple-cache" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-laravel" /> <path value="$PROJECT_DIR$/backend/vendor/psy/psysh" />
<path value="$PROJECT_DIR$/backend/vendor/fidry/cpu-core-counter" />
<path value="$PROJECT_DIR$/backend/vendor/tijsverkoyen/css-to-inline-styles" />
<path value="$PROJECT_DIR$/backend/vendor/carbonphp/carbon-doctrine-types" />
<path value="$PROJECT_DIR$/backend/vendor/fruitcake/php-cors" />
<path value="$PROJECT_DIR$/backend/vendor/dragonmantank/cron-expression" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/string" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/backend/vendor/phpoption/phpoption" />
<path value="$PROJECT_DIR$/backend/vendor/webmozart/assert" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/backend/vendor/voku/portable-ascii" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php85" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/uid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/console" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/promises" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/backend/vendor/ralouphie/getallheaders" /> <path value="$PROJECT_DIR$/backend/vendor/ralouphie/getallheaders" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/uri-template" /> <path value="$PROJECT_DIR$/backend/vendor/ramsey/collection" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-docblock" /> <path value="$PROJECT_DIR$/backend/vendor/ramsey/uuid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/clock" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/backend/vendor/nette/schema" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/process" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/cli-parser" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/cli-parser" />
<path value="$PROJECT_DIR$/backend/vendor/nette/utils" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/mailer" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/recursion-context" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/finder" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/object-enumerator" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/object-enumerator" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation-contracts" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/type" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/type" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/version" /> <path value="$PROJECT_DIR$/backend/vendor/sebastian/version" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/backend/vendor/staabm/side-effects-detector" /> <path value="$PROJECT_DIR$/backend/vendor/staabm/side-effects-detector" />
<path value="$PROJECT_DIR$/backend/vendor/fakerphp/faker" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/clock" />
<path value="$PROJECT_DIR$/backend/vendor/monolog/monolog" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/console" />
<path value="$PROJECT_DIR$/backend/vendor/vlucas/phpdotenv" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/backend/vendor/phpstan/phpdoc-parser" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/psy/psysh" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/sanctum" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/filesystem" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/filesystem" />
<path value="$PROJECT_DIR$/backend/vendor/mtdowling/jmespath.php" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/ai" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-sdk-php" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-crt-php" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/mailer" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/fortify" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/backend/vendor/dasprid/enum" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/backend/vendor/paragonie/constant_time_encoding" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/backend/vendor/pragmarx/google2fa" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/backend/vendor/bacon/bacon-qr-code" /> <path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php85" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/process" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/string" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/uid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/backend/vendor/ta-tikoma/phpunit-architecture-test" />
<path value="$PROJECT_DIR$/backend/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/backend/vendor/tijsverkoyen/css-to-inline-styles" />
<path value="$PROJECT_DIR$/backend/vendor/vlucas/phpdotenv" />
<path value="$PROJECT_DIR$/backend/vendor/voku/portable-ascii" />
<path value="$PROJECT_DIR$/backend/vendor/webmozart/assert" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.3"> <component name="PhpProjectSharedConfiguration" php_language_level="8.3">
<option name="suggestChangeDefaultLanguageLevel" value="false" /> <option name="suggestChangeDefaultLanguageLevel" value="false" />
</component> </component>
<component name="PhpStan">
<PhpStan_settings>
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" timeout="60000" />
</PhpStan_settings>
</component>
<component name="PhpStanOptionsConfiguration"> <component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" /> <option name="transferred" value="true" />
</component> </component>
@ -166,6 +179,11 @@
<PhpUnitSettings configuration_file_path="$PROJECT_DIR$/backend/phpunit.xml" custom_loader_path="$PROJECT_DIR$/backend/vendor/autoload.php" paratest_path="$PROJECT_DIR$/backend/vendor/bin/paratest_for_phpstorm" use_configuration_file="true" /> <PhpUnitSettings configuration_file_path="$PROJECT_DIR$/backend/phpunit.xml" custom_loader_path="$PROJECT_DIR$/backend/vendor/autoload.php" paratest_path="$PROJECT_DIR$/backend/vendor/bin/paratest_for_phpstorm" use_configuration_file="true" />
</phpunit_settings> </phpunit_settings>
</component> </component>
<component name="Psalm">
<Psalm_settings>
<psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" timeout="60000" />
</Psalm_settings>
</component>
<component name="PsalmOptionsConfiguration"> <component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" /> <option name="transferred" value="true" />
</component> </component>

1
backend/.gitignore vendored
View File

@ -24,3 +24,4 @@ _ide_helper.php
Homestead.json Homestead.json
Homestead.yaml Homestead.yaml
Thumbs.db Thumbs.db
.idea/

View File

@ -3,19 +3,17 @@
namespace App\Ai\Agents; namespace App\Ai\Agents;
use Laravel\Ai\Attributes\Provider; use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent; use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational; use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab; use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable; use Laravel\Ai\Promptable;
use Stringable; use Stringable;
#[Provider(Lab::Groq)] #[Provider(Lab::Groq)]
class ContentWriterAgent implements Agent, Conversational, HasTools class ContentWriterAgent implements Agent, Conversational
{ {
use Promptable; use Promptable, RemembersConversations;
/** /**
* Get the instructions that the agent should follow. * Get the instructions that the agent should follow.
@ -53,24 +51,4 @@ public function instructions(): Stringable|string
- Do not include a platform label (e.g. "For Instagram:"). - Do not include a platform label (e.g. "For Instagram:").
INSTRUCTIONS; INSTRUCTIONS;
} }
/**
* Get the list of messages comprising the conversation so far.
*
* @return Message[]
*/
public function messages(): iterable
{
return [];
}
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [];
}
} }

View File

@ -3,19 +3,17 @@
namespace App\Ai\Agents; namespace App\Ai\Agents;
use Laravel\Ai\Attributes\Provider; use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent; use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational; use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab; use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable; use Laravel\Ai\Promptable;
use Stringable; use Stringable;
#[Provider(Lab::Groq)] #[Provider(Lab::Groq)]
class CreativeDirectorAgent implements Agent, Conversational, HasTools class CreativeDirectorAgent implements Agent, Conversational
{ {
use Promptable; use Promptable, RemembersConversations;
/** /**
* Get the instructions that the agent should follow. * Get the instructions that the agent should follow.
@ -27,24 +25,4 @@ public function instructions(): Stringable|string
'AI image generator. The scene must be visually compelling and directly '. 'AI image generator. The scene must be visually compelling and directly '.
"relevant to the post's topic. Return ONLY the image prompt — nothing else."; "relevant to the post's topic. Return ONLY the image prompt — nothing else.";
} }
/**
* Get the list of messages comprising the conversation so far.
*
* @return Message[]
*/
public function messages(): iterable
{
return [];
}
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [];
}
} }

View File

@ -5,7 +5,7 @@
use App\Actions\Chats\CreateChatAction; use App\Actions\Chats\CreateChatAction;
use App\Http\Requests\CreateChatRequest; use App\Http\Requests\CreateChatRequest;
use App\Http\Resources\ChatResponseResource; use App\Http\Resources\ChatResponseResource;
use Illuminate\Http\Request; use App\Models\Chat;
class ChatController extends Controller class ChatController extends Controller
{ {
@ -14,7 +14,7 @@ public function index(Request $request) {}
public function store(CreateChatRequest $request, CreateChatAction $createChatAction) public function store(CreateChatRequest $request, CreateChatAction $createChatAction)
{ {
return new ChatResponseResource( return new ChatResponseResource(
$createChatAction->create($request->user(), $request->input('title', null)) $createChatAction->create($request->user(), $request->input('title', 'New Chat'))
); );
} }
} }

View File

@ -6,9 +6,12 @@
use App\Http\Resources\GeneratedPostResource; use App\Http\Resources\GeneratedPostResource;
use App\Models\Chat; use App\Models\Chat;
use App\Services\SocialMediaService; use App\Services\SocialMediaService;
use Illuminate\Http\Request;
use Illuminate\Routing\Attributes\Controllers\Authorize;
class ChatMessageController extends Controller class ChatMessageController extends Controller
{ {
#[Authorize('update', 'chat')]
public function store(GeneratePostRequest $request, Chat $chat, SocialMediaService $socialMediaService) public function store(GeneratePostRequest $request, Chat $chat, SocialMediaService $socialMediaService)
{ {
return new GeneratedPostResource( return new GeneratedPostResource(

View File

@ -3,20 +3,25 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable(['user_id', 'title'])] #[Fillable(['user_id', 'title'])]
#[Table('agent_conversations')]
class Chat extends Model class Chat extends Model
{ {
use HasUuids;
public function user(): BelongsTo public function user(): BelongsTo
{ {
return $this->belongsTo(User::class); return $this->belongsTo(User::class, 'user_id');
} }
public function messages(): HasMany public function messages(): HasMany
{ {
return $this->hasMany(ChatMessage::class); return $this->hasMany(ChatMessage::class, 'conversation_id', 'id')->orderBy('created_at', 'asc');
} }
} }

View File

@ -3,14 +3,19 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
#[Fillable(['chat_id', 'role', 'content', 'user_id'])] #[Fillable(['conversation_id', 'agent_id', 'role', 'content', 'attachment', 'tool_calls', 'tool_results', 'usage', 'meta', 'content', 'user_id'])]
#[Table('agent_conversation_messages')]
class ChatMessage extends Model class ChatMessage extends Model
{ {
use HasUuids;
public function chat(): BelongsTo public function chat(): BelongsTo
{ {
return $this->belongsTo(Chat::class); return $this->belongsTo(Chat::class, 'conversation_id', 'id');
} }
} }

View File

@ -0,0 +1,47 @@
<?php
namespace App\Policies;
use App\Models\Chat;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class ChatPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
return false;
}
public function view(User $user, Chat $chat): bool
{
return $chat->user()->is($user);
}
public function create(User $user): bool
{
return false;
}
public function update(User $user, Chat $chat): bool
{
return $chat->user()->is($user);
}
public function delete(User $user, Chat $chat): bool
{
return false;
}
public function restore(User $user, Chat $chat): bool
{
return false;
}
public function forceDelete(User $user, Chat $chat): bool
{
return false;
}
}

View File

@ -6,9 +6,7 @@
use App\Ai\Agents\ContentWriterAgent; use App\Ai\Agents\ContentWriterAgent;
use App\Ai\Agents\CreativeDirectorAgent; use App\Ai\Agents\CreativeDirectorAgent;
use App\Data\SocialMediaPostResponseDto; use App\Data\SocialMediaPostResponseDto;
use App\Enums\Chats\ChatRoles;
use App\Models\Chat; use App\Models\Chat;
use App\Models\ChatMessage;
readonly class SocialMediaService readonly class SocialMediaService
{ {
@ -25,17 +23,13 @@ public function __construct(
*/ */
public function generatePostWithImage(string $prompt, Chat $chat): SocialMediaPostResponseDto public function generatePostWithImage(string $prompt, Chat $chat): SocialMediaPostResponseDto
{ {
$this->chatMessage->store($chat, ChatRoles::USER, $prompt); $socialMediaResponse = $this->contentWriterAgent->forUser($chat->user)->prompt($prompt);
$socialMediaResponse = $this->contentWriterAgent->prompt($prompt);
$postText = $socialMediaResponse->text; $postText = $socialMediaResponse->text;
/* @var ChatMessage $aiChat */ // Generate image prompt via creative director agent
$aiChat = $this->chatMessage->store($chat, ChatRoles::AI, $postText);
$imagePromptResponse = $this->creativeDirectorAgent->prompt($postText); $imagePromptResponse = $this->creativeDirectorAgent->prompt($postText);
$imagePrompt = $imagePromptResponse->text; $imagePrompt = $imagePromptResponse->text;
return new SocialMediaPostResponseDto($aiChat->id, $postText, $imagePrompt, now()); return new SocialMediaPostResponseDto($socialMediaResponse->conversationId, $postText, $imagePrompt, now());
} }
} }

View File

@ -1,30 +0,0 @@
<?php
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chats', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class, 'user_id')->constrained()->cascadeOnDelete();
$table->string('title')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('chats');
}
};

View File

@ -1,31 +0,0 @@
<?php
use App\Models\Chat;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_messages', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(Chat::class, 'chat_id')->constrained()->cascadeOnDelete();
$table->string('role');
$table->text('content');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('chat_messages');
}
};

View File

@ -3,10 +3,14 @@ import { Routes } from '@angular/router';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
loadComponent: () => import('./chat/chat').then(m => m.Chat) loadComponent: () => import('./chat/chat').then((m) => m.Chat),
},
{
path: ':id',
loadComponent: () => import('./chat/chat').then((m) => m.Chat),
}, },
{ {
path: 'user', path: 'user',
loadChildren: () => import('./auth/auth.routes').then(m => m.authRoutes) loadChildren: () => import('./auth/auth.routes').then((m) => m.authRoutes),
} },
]; ];

View File

@ -4,6 +4,7 @@ import { HttpErrorResponse } from '@angular/common/http';
import { ChatService } from './chat-service'; import { ChatService } from './chat-service';
import { ChatState, Message } from './chat.types'; import { ChatState, Message } from './chat.types';
import { lastValueFrom } from 'rxjs'; import { lastValueFrom } from 'rxjs';
import { Router } from '@angular/router';
const initialState: ChatState = { const initialState: ChatState = {
messages: [ messages: [
@ -23,12 +24,16 @@ export const ChatStore = signalStore(
withState(initialState), withState(initialState),
withMethods((store) => { withMethods((store) => {
const chatService = inject(ChatService); const chatService = inject(ChatService);
const router = inject(Router);
const newChat = async () => { const newChat = async () => {
try { try {
const response = await lastValueFrom(chatService.newChat()); const response = await lastValueFrom(chatService.newChat());
patchState(store, { id: response.data.id }); const chatId = response.data.id;
return response.data.id;
patchState(store, { id: chatId });
await router.navigate(['/', chatId], { replaceUrl: true });
return chatId;
} catch (error) { } catch (error) {
console.error('Failed to create a new chat:', error); console.error('Failed to create a new chat:', error);
throw error; throw error;
@ -37,7 +42,9 @@ export const ChatStore = signalStore(
return { return {
newChat, newChat,
setChatId: (chatId: string) => {
patchState(store, { id: chatId });
},
sendMessage: async (content: string) => { sendMessage: async (content: string) => {
if (!store.id()) { if (!store.id()) {
try { try {

View File

@ -2,16 +2,18 @@ import { Component, ElementRef, ViewChild, effect, inject } from '@angular/core'
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { ChatStore } from './chat.store'; import { ChatStore } from './chat.store';
import { ActivatedRoute } from '@angular/router';
@Component({ @Component({
selector: 'app-chat', selector: 'app-chat',
standalone: true, standalone: true,
imports: [CommonModule, ReactiveFormsModule], imports: [CommonModule, ReactiveFormsModule],
templateUrl: './chat.html', templateUrl: './chat.html',
styleUrl: './chat.css' styleUrl: './chat.css',
}) })
export class Chat { export class Chat {
readonly chatStore = inject(ChatStore); readonly chatStore = inject(ChatStore);
private route = inject(ActivatedRoute);
@ViewChild('scrollContainer') private scrollContainer!: ElementRef; @ViewChild('scrollContainer') private scrollContainer!: ElementRef;
@ -30,6 +32,16 @@ export class Chat {
}); });
} }
ngOnInit() {
this.route.paramMap.subscribe((params) => {
const urlId = params.get('id');
if (urlId) {
// If an ID exists in the URL, populate it in the store
this.chatStore.setChatId(urlId);
}
});
}
errorMessage = ''; errorMessage = '';
sendMessage() { sendMessage() {
@ -50,6 +62,6 @@ export class Chat {
try { try {
const el = this.scrollContainer.nativeElement; const el = this.scrollContainer.nativeElement;
el.scrollTop = el.scrollHeight; el.scrollTop = el.scrollHeight;
} catch(err) { } } catch (err) {}
} }
} }