18 Commits
Author SHA1 Message Date
Frank 38d134bbac Message on reload to hopefully stop the user. 2026-01-06 20:20:33 +01:00
Frank 25664bbc4f Layout done, probably need rework later on 2026-01-06 20:20:33 +01:00
Frank 4dfc8e7b15 Rechten van setup.sh 2026-01-06 20:20:17 +01:00
Frank van den Berg bf7d1ee379 Made it workable on docker containers 2026-01-06 19:48:33 +01:00
Frank 5188b6e697 Merge pull request 'Commando's-given' (#3) from Commando's-given into main
Reviewed-on: #3
2026-01-06 11:05:48 +00:00
Frank 812dc06988 Toevoeging van meer responses op messages 2026-01-05 23:37:36 +01:00
Frank 376ed3f592 Updated rechten voor speler. Settings toegevoegd en onderdelen voor game1 toegevoegd. 2026-01-05 17:07:32 +01:00
Frank 0543ed43b9 Messages handling voor spel 1 2026-01-05 15:27:37 +01:00
Frank b486ca64d3 Message ipv echo voor route 2026-01-05 12:16:30 +01:00
Frank 50b7300649 Ignored 2026-01-05 12:16:01 +01:00
Frank c9294d6df8 ignore idea 2026-01-05 12:15:41 +01:00
Frank 93f162b306 Merge pull request 'Registration' (#2) from Registration into main
Reviewed-on: #2
2026-01-05 11:13:03 +00:00
Frank 55a46a42b2 Forgot password 2026-01-03 22:57:45 +01:00
Frank 9cf04be857 Maillog 2026-01-03 22:35:56 +01:00
Frank 654b4036b4 Quite some work done here. 2026-01-03 22:12:51 +01:00
Frank b58da74967 Some settings 2026-01-03 13:16:58 +01:00
Frank 18821e2463 Startup 2026-01-02 20:27:56 +01:00
Frank 3b071eec9b Setup 2025-09-06 16:50:16 +02:00
160 changed files with 27160 additions and 49 deletions
+17
View File
@@ -0,0 +1,17 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[{compose.yaml,compose.*.yaml}]
indent_size = 2
[*.md]
trim_trailing_whitespace = false
+22 -47
View File
@@ -1,54 +1,29 @@
# ---> Symfony
# Cache and logs (Symfony2)
/app/cache/*
/app/logs/*
!app/cache/.gitkeep
!app/logs/.gitkeep
# Email spool folder ###> symfony/framework-bundle ###
/app/spool/* /.env.local
/.env.local.php
# Cache, session files and logs (Symfony3) /.env.*.local
/var/cache/* /config/secrets/prod/prod.decrypt.private.php
/var/logs/* /public/bundles/
/var/sessions/* /var/
!var/cache/.gitkeep
!var/logs/.gitkeep
!var/sessions/.gitkeep
# Logs (Symfony4)
/var/log/*
!var/log/.gitkeep
# Parameters
/app/config/parameters.yml
/app/config/parameters.ini
# Managed by Composer
/app/bootstrap.php.cache
/var/bootstrap.php.cache
/bin/*
!bin/console
!bin/symfony_requirements
/vendor/ /vendor/
###< symfony/framework-bundle ###
# Assets and user uploads ###> phpunit/phpunit ###
/web/bundles/
/web/uploads/
# PHPUnit
/app/phpunit.xml
/phpunit.xml /phpunit.xml
/.phpunit.cache/
###< phpunit/phpunit ###
# Build data ###> symfony/asset-mapper ###
/build/ /public/assets/
/assets/vendor/
###< symfony/asset-mapper ###
# Composer PHAR ###> symfony/webpack-encore-bundle ###
/composer.phar /node_modules/
/public/build/
# Backup entities generated with doctrine:generate:entities command npm-debug.log
**/Entity/*~ yarn-error.log
###< symfony/webpack-encore-bundle ###
# Embedded web-server pid file
/.web-server-pid
/.idea
+8
View File
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="framework" type="frameworkType"/>
<xs:complexType name="commandType">
<xs:all>
<xs:element type="xs:string" name="name" minOccurs="1" maxOccurs="1"/>
<xs:element type="xs:string" name="params" minOccurs="0" maxOccurs="1"/>
<xs:element type="xs:string" name="help" minOccurs="0" maxOccurs="1"/>
<xs:element type="optionsBeforeType" name="optionsBefore" minOccurs="0" maxOccurs="1"/>
</xs:all>
</xs:complexType>
<xs:complexType name="frameworkType">
<xs:sequence>
<xs:element type="xs:string" name="extraData" minOccurs="0" maxOccurs="1"/>
<xs:element type="commandType" name="command" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="xs:string" name="help" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="required"/>
<xs:attribute type="xs:string" name="invoke" use="required"/>
<xs:attribute type="xs:string" name="alias" use="required"/>
<xs:attribute type="xs:boolean" name="enabled" use="required"/>
<xs:attribute type="xs:integer" name="version" use="required"/>
<xs:attribute type="xs:string" name="frameworkId" use="optional"/>
</xs:complexType>
<xs:complexType name="optionsBeforeType">
<xs:sequence>
<xs:element type="optionType" name="option" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="optionType">
<xs:sequence>
<xs:element type="xs:string" name="help" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="required"/>
<xs:attribute type="xs:string" name="shortcut" use="optional"/>
<xs:attribute name="pattern" use="optional">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="space"/>
<xs:enumeration value="equals"/>
<xs:enumeration value="unknown"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>
+147
View File
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/migrations" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/orm" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/persistence" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/sql-formatter" />
<excludeFolder url="file://$MODULE_DIR$/vendor/egulias/email-validator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/masterminds/html5" />
<excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" />
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-common" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-docblock" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpstan/phpdoc-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/clock" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/link" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
<excludeFolder url="file://$MODULE_DIR$/vendor/staabm/side-effects-detector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/asset" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/asset-mapper" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/browser-kit" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/clock" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/config" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/css-selector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/debug-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dependency-injection" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/doctrine-bridge" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/doctrine-messenger" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dom-crawler" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dotenv" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/expression-language" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/filesystem" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/flex" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/form" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/framework-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/intl" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mailer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/messenger" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/monolog-bridge" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/monolog-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/notifier" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/options-resolver" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/password-hasher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-icu" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php83" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php84" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-access" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/runtime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-core" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-csrf" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-http" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/serializer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/stimulus-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/stopwatch" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bridge" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/type-info" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/ux-turbo" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/validator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/web-link" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/web-profiler-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/extra-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
<excludeFolder url="file://$MODULE_DIR$/vendor/lcobucci/jwt" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mercure" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mercure-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/sendgrid-mailer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/webpack-encore-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfonycasts/reset-password-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfonycasts/verify-email-bundle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="InertiaPackage">
<option name="directoryPaths">
<list />
</option>
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/escapepage.iml" filepath="$PROJECT_DIR$/.idea/escapepage.iml" />
</modules>
</component>
</project>
Generated
+180
View File
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpCodeSniffer">
<phpcs_settings>
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="5505d524-8d4c-4fe7-a2cb-82e334156ed6" timeout="30000" />
</phpcs_settings>
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/vendor/symfony/config" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
<path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/vendor/symfony/string" />
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/psr/cache" />
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/psr/log" />
<path value="$PROJECT_DIR$/vendor/psr/container" />
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
<path value="$PROJECT_DIR$/vendor/psr/link" />
<path value="$PROJECT_DIR$/vendor/psr/clock" />
<path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/twig/extra-bundle" />
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bundle" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-icu" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/vendor/symfony/asset-mapper" />
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-messenger" />
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
<path value="$PROJECT_DIR$/vendor/symfony/mailer" />
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
<path value="$PROJECT_DIR$/vendor/symfony/web-profiler-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-turbo" />
<path value="$PROJECT_DIR$/vendor/symfony/stimulus-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
<path value="$PROJECT_DIR$/vendor/symfony/debug-bundle" />
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
<path value="$PROJECT_DIR$/vendor/symfony/notifier" />
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
<path value="$PROJECT_DIR$/vendor/symfony/process" />
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
<path value="$PROJECT_DIR$/vendor/symfony/intl" />
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
<path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
<path value="$PROJECT_DIR$/vendor/symfony/messenger" />
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bridge" />
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/vendor/egulias/email-validator" />
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/vendor/symfony/sendgrid-mailer" />
<path value="$PROJECT_DIR$/vendor/symfony/webpack-encore-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/mercure" />
<path value="$PROJECT_DIR$/vendor/symfony/mercure-bundle" />
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
<path value="$PROJECT_DIR$/vendor/symfonycasts/verify-email-bundle" />
<path value="$PROJECT_DIR$/vendor/symfonycasts/reset-password-bundle" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
<component name="PhpStan">
<PhpStan_settings>
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="5505d524-8d4c-4fe7-a2cb-82e334156ed6" timeout="60000" />
</PhpStan_settings>
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
</phpunit_settings>
</component>
<component name="Psalm">
<Psalm_settings>
<psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="5505d524-8d4c-4fe7-a2cb-82e334156ed6" timeout="60000" />
</Psalm_settings>
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+118 -2
View File
@@ -1,3 +1,119 @@
# Escapepage # EscapePage — Online Escape Room
De Escapepage This repository contains a Symfony 7.3 (PHP >= 8.5.1) application for a collaborative online escape room experience.
- Start here: doc/FILES.md — quick file index.
- Development standards and workflows: doc/CONTRIBUTING.md
- All documentation is located under the doc/ directory.
## Getting Started (brief)
- Local machine (no Docker):
1. Copy `.env` to `.env.local` and set database and `APP_SECRET`.
2. Install PHP deps: `composer install`
3. Create database and run migrations (when present): `php bin/console doctrine:database:create --if-not-exists && php bin/console doctrine:migrations:migrate -n`
4. Install/import JS deps: `php bin/console importmap:install`
5. Run the server: `symfony server:start -d` (or your preferred web server)
6. Run tests: `vendor/bin/phpunit`
- With Docker:
1. From `docker/`: `docker compose up -d`
2. Install vendors inside the PHP container:
- `docker compose exec php bash`
- `composer install`
3. Initialize DB:
- `php bin/console doctrine:database:create --if-not-exists`
- `php bin/console doctrine:migrations:migrate -n`
4. App is at http://localhost:8080
## Email (Mailpit in dev, SendGrid for prod)
- Dev: a `mailer` service (Mailpit) runs in Docker.
- SMTP DSN in `.env`: `MAILER_DSN=smtp://mailer:1025`
- Mailpit UI: http://localhost:8025
- Send a test mail: `php bin/console app:mail:test you@example.com`
- Staging/Prod: use SendGrid.
- Require package (already in composer): `symfony/sendgrid-mailer`.
- Set environment variables (do NOT commit secrets):
- `MAILER_DSN=sendgrid+api://%env(SENDGRID_API_KEY)%`
- `SENDGRID_API_KEY=YOUR_REAL_KEY`
- Optional: `MAILER_FROM=no-reply@your-domain.tld`
- Alternatively via SMTP (no extra package):
- `MAILER_DSN="smtp://apikey:%env(SENDGRID_API_KEY)%@smtp.sendgrid.net:587?encryption=tls"`
Troubleshooting:
- If emails dont appear in dev, open Mailpit at http://localhost:8025 and verify messages.
- In prod, check logs for HTTP 2xx responses from SendGrid and verify sender domain is verified in SendGrid.
## Frontend assets with Webpack Encore
We use Webpack Encore to build and minify JS/CSS from the `assets/` directory into `public/build/`.
Install Node dependencies (on your host machine):
```
npm install
```
Common commands:
```
# One-time dev build
npm run dev
# Watch & rebuild on changes
npm run watch
# Production build (minified, versioned filenames)
npm run build
```
How its wired:
- Entry file: `assets/app.js` (imports `assets/styles/app.css`).
- Webpack config: `webpack.config.js` outputs to `public/build/`.
- Twig template includes built assets via Encore:
- In `templates/base.html.twig`:
- `{{ encore_entry_link_tags('app') }}` (CSS)
- `{{ encore_entry_script_tags('app') }}` (JS)
Notes:
- The PHP Docker image does not include Node. Run the build commands on your host, or ask to add a Node build container if you prefer fully containerized builds.
- Built files are ignored by git except for `public/build/.gitignore` to keep the directory.
See doc/CONTRIBUTING.md for code style and more details.
## Realtime updates with Mercure
We use a Mercure hub (Docker service) to push server updates to browsers via ServerSent Events (SSE).
Quick start (dev):
1. Start Docker stack from `docker/`:
```
docker compose up -d
```
This starts `mercure` at http://localhost:8090 and the app at http://localhost:8080.
2. Install PHP deps inside the PHP container if you haven't yet:
```
docker compose exec php bash
composer install
```
3. Open the Game Hub page in your browser: http://localhost:8080/game
- The page subscribes to a demo topic and logs messages in the console.
4. Publish a test update (in the PHP container):
```
php bin/console app:mercure:publish
```
You should see a console log like `[Mercure] Update received: { ... }` on the Game Hub page.
Configuration:
- Env vars (defined in `.env`, override in `.env.local` as needed):
- `MERCURE_URL=http://mercure/.well-known/mercure` (internal URL from PHP to the hub)
- `MERCURE_PUBLIC_URL=http://localhost:8090/.well-known/mercure` (browser URL)
- `MERCURE_JWT_SECRET=!ChangeThisMercureJWT!` (dev secret; do not use in prod)
- `MERCURE_TOPIC_BASE=https://escapepage.dev` (base topic URL)
- Docker service `mercure` is based on `dunglas/mercure` and allows anonymous subscribers in dev.
Topics:
- Topics must be URLs. We use `MERCURE_TOPIC_BASE` to control the domain per environment.
- Dev: `.env` sets `https://escapepage.dev`
- Prod: set `MERCURE_TOPIC_BASE=https://escapepage.com`
- The Game Hub demo topic is `${MERCURE_TOPIC_BASE}/game/hub`.
Production notes:
- Disable anonymous subscribers and require JWTs for subscriptions (configure the Mercure container accordingly).
- Use a strong, rotated `MERCURE_JWT_SECRET` and keep it out of VCS (use real env/secrets).
- Serve Mercure over HTTPS and set proper CORS/allowed origins for your production domain(s).
+6
View File
@@ -0,0 +1,6 @@
/*
* Welcome to your app's main JavaScript file!
*/
import './styles/app.css';
console.log('This log comes from assets/app.js built by Webpack Encore! 🎉');
+5
View File
@@ -0,0 +1,5 @@
import { startStimulusApp } from '@symfony/stimulus-bundle';
const app = startStimulusApp();
// register any custom, 3rd party controllers here
// app.register('some_controller_name', SomeImportedController);
+15
View File
@@ -0,0 +1,15 @@
{
"controllers": {
"@symfony/ux-turbo": {
"turbo-core": {
"enabled": true,
"fetch": "eager"
},
"mercure-turbo-stream": {
"enabled": false,
"fetch": "eager"
}
}
},
"entrypoints": []
}
@@ -0,0 +1,79 @@
const nameCheck = /^[-_a-zA-Z0-9]{4,22}$/;
const tokenCheck = /^[-_/+a-zA-Z0-9]{24,}$/;
// Generate and double-submit a CSRF token in a form field and a cookie, as defined by Symfony's SameOriginCsrfTokenManager
document.addEventListener('submit', function (event) {
generateCsrfToken(event.target);
}, true);
// When @hotwired/turbo handles form submissions, send the CSRF token in a header in addition to a cookie
// The `framework.csrf_protection.check_header` config option needs to be enabled for the header to be checked
document.addEventListener('turbo:submit-start', function (event) {
const h = generateCsrfHeaders(event.detail.formSubmission.formElement);
Object.keys(h).map(function (k) {
event.detail.formSubmission.fetchRequest.headers[k] = h[k];
});
});
// When @hotwired/turbo handles form submissions, remove the CSRF cookie once a form has been submitted
document.addEventListener('turbo:submit-end', function (event) {
removeCsrfToken(event.detail.formSubmission.formElement);
});
export function generateCsrfToken (formElement) {
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
if (!csrfField) {
return;
}
let csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
let csrfToken = csrfField.value;
if (!csrfCookie && nameCheck.test(csrfToken)) {
csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken);
csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18))));
}
csrfField.dispatchEvent(new Event('change', { bubbles: true }));
if (csrfCookie && tokenCheck.test(csrfToken)) {
const cookie = csrfCookie + '_' + csrfToken + '=' + csrfCookie + '; path=/; samesite=strict';
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
}
}
export function generateCsrfHeaders (formElement) {
const headers = {};
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
if (!csrfField) {
return headers;
}
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
headers[csrfCookie] = csrfField.value;
}
return headers;
}
export function removeCsrfToken (formElement) {
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
if (!csrfField) {
return;
}
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
const cookie = csrfCookie + '_' + csrfField.value + '=0; path=/; samesite=strict; max-age=0';
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
}
}
/* stimulusFetch: 'lazy' */
export default 'csrf-protection-controller';
+16
View File
@@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus';
/*
* This is an example Stimulus controller!
*
* Any element with a data-controller="hello" attribute will cause
* this controller to be executed. The name "hello" comes from the filename:
* hello_controller.js -> "hello"
*
* Delete this file or adapt it for your use!
*/
export default class extends Controller {
connect() {
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
}
}
+172
View File
@@ -0,0 +1,172 @@
/* Game1 entry point built with Webpack Encore */
import './styles/game1.css';
function subscribeToMercure(mercurePublicUrl, topic) {
try {
const url = mercurePublicUrl + '?topic=' + encodeURIComponent(topic);
const es = new EventSource(url);
es.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log('[Mercure][game1] Update:', data);
} catch (e) {
console.log('[Mercure][game1] Raw event:', event.data);
}
};
es.onerror = (err) => {
console.warn('[Mercure][game1] EventSource error:', err);
};
console.log('[Mercure][game1] Subscribed to', url);
} catch (e) {
console.error('[Mercure][game1] Failed to subscribe:', e);
}
}
async function fetchJson(url, options = {}) {
const opts = { ...options };
const headers = new Headers(opts.headers || {});
headers.set('Accept', 'application/json');
if (opts.body !== undefined && typeof opts.body !== 'string') {
headers.set('Content-Type', 'application/json');
opts.body = JSON.stringify(opts.body);
}
// Useful convention for server-side checks
if (!headers.has('X-Requested-With')) {
headers.set('X-Requested-With', 'XMLHttpRequest');
}
opts.headers = headers;
const res = await fetch(url, opts);
const text = await res.text();
let data;
try { data = text ? JSON.parse(text) : null; } catch (e) { data = text; }
if (!res.ok) {
const err = new Error('HTTP ' + res.status + ' ' + res.statusText);
console.error('[API][game1]', err, data);
throw err;
}
return data;
}
document.addEventListener('DOMContentLoaded', async () => {
// Simple boot log so you can verify it in the browser console
// and confirm this specific bundle is loaded on the Game Hub page.
console.log('Game1 bundle loaded');
// Example: add a CSS class to <body> so page-specific styles can apply
document.body.classList.add('game1-page');
// Look for config injected by Twig in the page
const cfgEl = document.getElementById('mercure-config');
// Prevent/warn on page reload
window.addEventListener('beforeunload', (event) => {
// Standard way to trigger the browser's confirmation dialog
event.preventDefault();
// Included for compatibility with older browsers
event.returnValue = '';
});
if (!cfgEl) {
console.warn('[Mercure][game1] #mercure-config element not found on page');
return;
}
const mercurePublicUrl = cfgEl.dataset.mercurePublicUrl;
const topic = cfgEl.dataset.topic;
const apiPingUrl = cfgEl.dataset.apiPingUrl;
const apiEchoUrl = cfgEl.dataset.apiEchoUrl;
if (mercurePublicUrl && topic) {
subscribeToMercure(mercurePublicUrl, topic);
} else {
console.warn('[Mercure][game1] Missing data attributes on #mercure-config');
}
// Demo API calls
try {
if (apiPingUrl) {
const ping = await fetchJson(apiPingUrl);
console.log('[API][game1] ping →', ping);
} else {
console.warn('[API][game1] data-api-ping-url missing');
}
if (apiEchoUrl) {
const echo = await fetchJson(apiEchoUrl, {
method: 'POST',
body: { message: 'from game1.js', ts: new Date().toISOString() },
});
console.log('[API][game1] echo →', echo);
} else {
console.warn('[API][game1] data-api-echo-url missing');
}
} catch (e) {
console.error('[API][game1] Request failed:', e);
}
// Add messages to message-container
const messageContainer = document.getElementById('message-container');
if (messageContainer) {
let messages = [
['System initializing...', 500],
['Connection established.', 200],
['Welcome agent to the mainframe.', 1000],
['Scanning...', 3000],
['Virus detected.', 500],
['Starting Mainframe help modus...', 2000],
['Help modus activated.', 500],
['Blocking virus activated', 0]
];
let currentMessageIndex = 0;
const printNextMessage = () => {
if (currentMessageIndex < messages.length) {
const msg = messages[currentMessageIndex];
const msgEl = document.createElement('div');
msgEl.className = 'message';
msgEl.textContent = msg[0];
msgEl.style.color = '#F00';
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
currentMessageIndex++;
setTimeout(printNextMessage, msg[1]);
} else {
// After it has printed a set of messages, it has to start a timer of 2 seconds
console.log('[Game1] All messages printed. Starting 2s timer to expand message-container height...');
setTimeout(() => {
messageContainer.style.height = '400vh';
const inputField = document.getElementById('input-message');
inputField.disabled = false;
// Add event listener for Enter key
inputField.addEventListener('keypress', async (e) => {
if (e.key === 'Enter') {
const message = inputField.value.trim();
if (message && apiEchoUrl) {
inputField.value = '';
try {
const response = await fetchJson(apiEchoUrl, {
method: 'POST',
body: { message, ts: new Date().toISOString() },
});
console.log('[API][game1] message sent →', response);
} catch (err) {
console.error('[API][game1] Failed to send message:', err);
}
}
}
});
console.log('[Game1] message-container height changed to 400vh and input enabled');
}, 2000);
}
};
printNextMessage();
}
});
@@ -0,0 +1,10 @@
Undercover Report Case File 145-93
Agent: Carver (cover identity)
Date: 02/18 02/22
Subject operates a rural safehouse rumored to shelter fugitives and serve as a transient waypoint. Agents cover as a drifter seeking work provided entry in exchange for chores. On 02/19, visitors with gang tattoos arrived after midnight and were housed in separate rooms. Vehicles were parked under tree cover, and license plates were mudsmeared. On 02/20, the subject warned of “new heat in town” and began burning scrap papers in a barrel.
Later that night, a duffel of documents was left unattended. The agent briefly photographed maps with marked backroad routes and coded notes. The handwriting matches samples from a related case. On 02/21, the subject probed the agents story with pointed questions about prior arrests. Cover held after the agent recited the rehearsed backstory.
Cover credible but timelimited. Recommend immediate analysis of the photographed maps, ID of transient visitors via tattoos and vehicle features, and a synchronized warrant service before the location rotates to a fresh site.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,11 @@
Undercover Report Case File 19-52
Agent: Harper (cover identity)
Date: 07/22 07/26
Subject controls a pawnshop that exhibits transaction volumes and cash handling inconsistent with normal retail activity. Cover identity as electronics repair tech granted backroom access to the testing bench, DVR cabinet, and inventory cage. On 07/23, the subject hosted a closeddoor meeting with four associates who arrived separately and staggered departures. Through the vent grate, agent heard references to “offshore wires,” “clean accounts,” and “quarterend flush.” Subject maintained a spiral ledger with denominations recorded in columns that do not match typical pointofsale exports.
On 07/24, the subject ordered cameras repositioned to avoid capturing the safe directly. Agent was subtly tested regarding loyalty—assigned an afterhours soldering task while the subject counted bundled currency on the shop floor. Later that night, an unmarked van delivered two duffel bags that were moved to the vault without intake paperwork. Subject personally signed a receipt on blank stationery and pocketed the copy.
On 07/25, subject complained about “Treasury heat” and instructed the bookkeeper to route payments through two new accounts, both named with common surnames. Names did not match any employee records. Agent retrieved partial account numbers from a discarded note.
Cover remains credible. Recommend immediate financial taskforce review of the ledger, subpoena of the newly referenced accounts, and discreet licenseplate canvass for the van. Surveillance continuity is advised; subject exhibits rising paranoia yet continues to centralize cash at the location.
@@ -0,0 +1,10 @@
Undercover Report Case File 130-62
Agent: Lennox (cover identity)
Date: 12/02 12/06
Subject runs an art gallery suspected of laundering through inflated valuations and forged provenance. Agent embedded as gallery assistant. On 12/03, the subject finalized a cash sale for a painting at five times market value to an anonymous buyer. On 12/04, the subject ordered an assistant to “adjust provenance papers,” instructing edits to dates and prior ownership. The font choice and printer bleed matched a stack of older certificates in a locked drawer.
On 12/05, a private viewing hosted foreign clients who avoided staff contact. One carried a briefcase later exchanged for a wrapped canvas in the loading alcove. On 12/06, the subject cautioned staff not to speak with authorities and appeared tense while counting cash in the office.
Cover secure. Recommend seizure of the forged documents, liaison with culturalproperty experts to authenticate inventory, and identification of the foreign clients via travel manifests and nearby CCTV.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,12 @@
Undercover Report Case File 94-31
Agent: Donovan (cover identity)
Date: 06/01 06/05
Subject operates a private marina suspected of facilitating smuggling. Agents cover as a yacht mechanic provides daily access to slips and latenight maintenance calls. On 06/02, the subject directed the agent to assist with unloading three sealed crates from a speedboat arriving past midnight. Crates bore generic “marine supplies” stickers; handlers treated them with unusual care. Opening was not feasible without tipping the crew.
On 06/03, a heated exchange with a subordinate revealed concerns over “late payments” from overseas. The subject warned that debts must be cleared “before customs comes sniffing.” The tone suggested reliance on offshore accounts. On 06/04, the subject introduced an associate known only as “Captain,” who exhibited military bearing and carried a sidearm; conversation centered on moving delivery windows to avoid routine patrol sweeps.
On 06/05, the subject carried a heavy duffel into the office and drew blinds for over an hour. Subsequent demeanor was relaxed, implying a successful cash reconciliation.
Cover intact. Recommend forensic review of marina accounting, financial tracing of suspected offshore links, and coordination with harbor patrol to flag vessels matching the speedboats profile.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,10 @@
Undercover Report Case File 98-07
Agent: Fletcher (cover identity)
Date: 07/11 07/14
Subject serves as a lieutenant managing a distribution hub inside an abandoned textile mill. Cover identity as a shellcompany delivery driver grants entrance to the loading dock and elevator cages. On 07/12, the subject assigned the agent to ferry sealed packages to a storagelocker complex registered under a false name. Package weight and precautions suggest narcotics. Keys on a ring were photographed; several cuts matched lockers in Row C.
On 07/13, the subject referenced “Chicago buyers,” instructing the crew to increase output despite lawenforcement chatter. Morale appeared strained. On 07/14, the subject gathered the crew, delivered a loyalty speech about “traitors,” and scanned faces while the enforcer lingered by the door. No direct challenge to the agent, but suspicion is rising.
Cover holds but the environment is volatile. Recommend warrants for the locker complex keyed to the photographed cuts, discreet traffic stops on the distribution couriers, and a contingency extraction plan should violence erupt at the mill.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,10 @@
Undercover Report Case File 123-88
Agent: Holloway (cover identity)
Date: 11/04 11/08
Subject leverages a regional trucking firm to move contraband under cover of legitimate freight. Agents cover as a dispatcher assistant enables access to GPS routes and driver notes. On 11/05, routing orders labeled “detour deliveries” consistently bypassed weigh stations, and manifests showed weight mismatches. On 11/06, the subject instructed a driver to deliver “straight to the mountain cabin,” providing coordinates later confirmed by GPS ping.
On 11/07, news of lawenforcement activity near the interstate caused the subject to cancel multiple runs. Crew anxiety rose. On 11/08, the subject praised the agent for rerouting a truck around a checkpoint, further legitimizing the cover.
Cover intact. Recommend aerial survey of the coordinates to identify storage, placement of covert trackers on the detour fleet, and financial review of the dispatch accounts to map the laundering flow.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,11 @@
Undercover Report Case File 31-11
Agent: Vega (cover identity)
Date: 09/04 09/07
Subject runs a rural pharmacy with unusually high order volumes for specific controlled substances. Agents cover as a delivery technician enabled access to loading doors and packing slips. On 09/05, the subject accepted a pallet of blister packs outside normal receiving hours, directing it straight to a side room. Labels were legitimate, but lot numbers did not appear in the chainofcustody app used elsewhere in the store. Staff avoided eye contact and deferred to the subject for every deviation.
On 09/06, two sedan drivers arrived within minutes of each other, both collecting “returns” in sealed totes. Agent observed the subject bypassing the returns register and printing generic labels from a standalone thermal unit. Drivers refused signatures and left via the alley. The subject later shredded a stack of thermal drafts without balancing the counts.
On 09/07, agent overheard a phone call in which the subject referenced “doctor packs,” “holiday traffic,” and “quota pressure.” The cadence suggested coordination with a prescriber and an external distributor. The subjects mood shifted sharply after the call; staff were told to “keep it to cash only” for the remainder of the day.
Cover remains viable. Recommend a joint audit with state pharmacy regulators, review of the lot numbers observed, and controlled buys through the returns channel to document diversion.
@@ -0,0 +1,12 @@
Undercover Report Case File 53-28
Agent: Navarro (cover identity)
Date: 02/01 02/04
Subject owns a private courier service that advertises sameday delivery for tech firms. Shipment profiles and driver chatter suggest the operation moves highend electronics and cryptomining components off the books. Agents cover as a dispatch assistant provided map access and driver rotations. On 02/02, the subject created a route labeled “white run” that bypassed weigh stations and used alley handoffs. Driver later returned with a sealed envelope and no signature trail.
On 02/03, a pallet bearing unfamiliar consignee codes was loaded into a van with interior panels removed—consistent with contraband concealment. Subject lectured staff about “never opening the blue totes,” then carried one into a locked server closet. Agent heard a fan spinup and a brief data sync tone from a nearby laptop, implying a quickclone procedure.
On 02/04, the subject hinted the agent could “graduate to vest access” if weekend performance stayed quiet. A senior driver mentioned “hash boards” failing in transit and needing replacements before “the buyer from Reno flies out.”
Cover stable. Recommend covert GPS beacons on the whiterun vans, subpoena of the couriers API logs for the locked server closet, and coordination with aircargo teams for the Reno timeline.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,10 @@
Undercover Report Case File 117-56
Agent: OConnor (cover identity)
Date: 10/15 10/18
Subject operates an illegal backroom poker circuit that attracts midtier executives and local power brokers. Agents cover as a wealthy gambler provided entry. On 10/16, buyins far exceeded legal thresholds, and the subject boasted of protection from “friends in city hall.”
On 10/17, an argument erupted between the subject and an enforcer over unpaid debts. Threats were made, but play resumed. On 10/18, the subject introduced an associate known as “Silver,” carrying a distinctive lighter described in other investigations. Presence of Silver indicates links to a broader network handling collections and intimidation.
Cover stable. Recommend financial surveillance on the regular players, quiet corruption probe on the purported city contacts, and a tailored raid plan that mitigates risk to civilians at the gaming site.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,12 @@
Undercover Report Case File 72-90
Agent: Quinn (cover identity)
Date: 08/09 08/12
Subject fronts a small software firm that has attracted highrisk clients seeking datascraping and intrusion services. Agent embedded as a temporary QA tester, which offered proximity to build pipelines and the staging server. On 08/10, the subject approved a latenight push titled “crawlerplus” that contained modules for credential stuffing and proxy rotation. The code branch was kept off the main repository and shared via encrypted zip.
On 08/11, two visitors arrived with no badges and were escorted directly to the conference room. Subject requested the agent run a “sandbox smoke test” while the visitors watched a dashboard of login attempts against thirdparty targets. Conversation referenced “clean lists,” “UID harvest,” and “deliverables by Friday.”
On 08/12, the subject floated a contract expansion involving a custom build for “telecom metadata capture.” When the agent hesitated, the subject advised to “just test the pipeline; leave the contracts to me.” Security posture inside the firm is lax; logs rotate every twentyfour hours without retention.
Cover credible. Recommend rapid legal hold to preserve server images, quiet outreach to targeted platforms to harden defenses, and preparation for a coordinated search warrant before the next deliverables window.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,12 @@
Undercover Report Case File 61-05
Agent: Carter (cover identity)
Date: 03/14 03/17
Subject operates a livestock auction and feed cooperative used as a cashhandling hub for a broader laundering scheme. Agents cover as a regional feed rep granted access to the back office and the weighticket printer. On 03/15, the subject directed staff to reprint weights for three lots and staple them over originals, inflating values by roughly thirty percent. Cash payouts were then split into smaller envelopes labeled as “hauler fees.”
On 03/16, a trailer arrived after closing with no consignor paperwork. Subject ushered the driver to the scales, then recorded a manual weight entry without zeroing the platform. Later, agent noted the same trailer departed with bales stacked higher than safety guidelines, suggesting a swap onsite.
On 03/17, the subject met with a banker in the café booth. Heard fragments: “seasonal float,” “parcel deposits,” and “dont trigger CTRs.” The banker left through the side door, avoiding cameras.
Cover remains intact. Recommend forensic review of scale logs, unannounced compliance checks tied to animalwelfare authorities as legitimate cover, and analysis of deposit structuring patterns that match the inflated weightickets.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,12 @@
Undercover Report Case File 46-77
Agent: Ellis (cover identity)
Date: 11/08 11/11
Subject supervises a containeryard subcontractor with access to highvalue import bays. Agent entered as a craneoperator trainee assigned to night shifts. On 11/09, subject instructed the crew to reposition a fortyfooter from the manifest queue to an unnumbered slot behind the scrap pile. The container seal had a fresh dab of paint across the latch consistent with a reapplied counterfeit seal. Yard cameras were left panning, creating reliable blind spots of twenty to thirty seconds.
On 11/10, the subject met with two visitors at the fence line and exchanged a clipboard without approaching the office. Agent overheard them discuss “blank HS codes” and “holiday backlog.” The conversation implies a counterfeitelectronics shipment misdeclared to avoid inspection. Later, subject distributed burner keycards for the east pedestrian gate, instructing workers to “switch badges” if stopped.
On 11/11, a third party attempted to tip the agent to accept overtime in exchange for keeping a particular bay unsupervised. Agent declined while maintaining cover as rulebound but inexperienced. The subject appeared satisfied the lane would remain quiet.
Cover intact. Recommend customs partnership to flag the suspect container by serial, deploy a mobile Xray with minimal yard disruption, and audit badge access logs for the east gate.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,12 @@
Undercover Report Case File 89-47
Agent: Dalton (cover identity)
Date: 10/05 10/08
Subject leads a motorcycle club that moonlights as a gunrunning and protection outfit. Agent entered as an auto detailer offering cutrate work on club vehicles. On 10/06, the subject invited the agent to a backlot barbecue where patched members traded cash for small boxes moved from saddlebag to saddlebag. A prospect muttered about “.30 cal uppers” and a “desert range test.”
On 10/07, the club sergeantatarms demanded that the agent fix a VIPs truck immediately, creating a loyalty test. While retrieving tools, the agent observed a crate under a tarp with oilpaperwrapped parts and a stencil for a defunct manufacturer. Numbers were partially filed. The subject later bragged about buyers “east of the pass.”
On 10/08, a convoy departed in staggered pairs. The subject ordered phones in airplane mode and handed out paper maps with predrawn detours. A follower crashed a bike on loose gravel; the group paused in a blind spot, repositioned a crate, and continued.
Cover remains plausible. Recommend roadside interdiction coordinated with Highway Patrol, ballistics work on recovered parts, and asset development targeting the prospect who appears chatty under alcohol.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,11 @@
Undercover Report Case File 25-39
Agent: Doyle (cover identity)
Date: 04/03 04/06
Subject operates a small river ferry and maintenance dock that appear to facilitate contraband transfers between barges at offschedule hours. Agents cover as an outofwork boat mechanic provided routine access to bilge areas and tool lockers. On 04/04, subject instructed the crew to keep the north slip unlit after midnight and to disable the dock camera claiming a blown fuse. The camera was found unplugged rather than damaged. Two crates moved from a barge to a skiff without paperwork.
On 04/05, agent overheard the subject arguing with a radio contact over “ore purity” and “assay timing.” The phrasing suggests smuggling of highvalue metals rather than typical street narcotics. Crew members wore gloves and avoided scraping the crates corners, reinforcing the inference of dense contents. A handheld Geiger counter case was observed in the tool cage, but no reading event was witnessed.
On 04/06, the subject requested help fabricating a false enginerepair ticket to explain downtime for Barge 12. Ticket was signed under a false corporate name and backdated. Subject appeared calm after the forgery, then paid crew in cash envelopes with inconsistent denominations.
Cover intact. Recommend discreet sampling of riverbed residue near the north slip, crosschecking barge manifests for Barge 12, and coordination with environmental regulators to justify covert inspections without alerting the subject.
@@ -0,0 +1,10 @@
Undercover Report Case File 102-45
Agent: Sanders (cover identity)
Date: 08/19 08/23
Subject manages an upscale restaurant suspected of laundering illicit gambling proceeds. Agent embedded as a sommelier, granting access to private dining rooms and basement storage. On 08/20, the subject hosted three suited men; the room was sealed and guarded. While pouring, the agent heard references to “clearing accounts” and “westcoast expansion.” The subject kept a handwritten ledger with columns that do not reconcile with the pointofsale exports.
On 08/22, a delivery van bypassed normal suppliers and offloaded crates into the walkin freezer with no perishables labeling. Handlers displayed tactical posture inconsistent with food service. On 08/23, the subject warned staff about inspections and emphasized silence, revealing controlled anxiety.
Cover remains secure; agent perceived as competent and unthreatening. Recommend parallel financial audit, supplierchain verification, and a timed inspection aligned with the offcycle delivery pattern.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,12 @@
Undercover Report Case File 81-33
Agent: Raines (cover identity)
Date: 01/18 01/21
Subject manages a boutique hotel that periodically closes floors for “private events.” Agents cover as nightshift concierge grants exposure to guest registries and keyencoder logs. On 01/19, the subject blocked out Level 5 under a shell company and delivered sealed envelopes to three suites. Noise and foot traffic suggested an invitationonly auction. Staff were instructed to use service stairs only and disable the lobby feed for two hours citing maintenance.
On 01/20, two SUVs with obscured plates arrived at the loading bay. Items resembling art crates and a locked pelican case were transferred to Suite 512. A known broker briefly appeared in the hallway, then vanished into the service lift. The minibar inventory showed no consumption despite the headcount—common during short, transactional gatherings.
On 01/21, the subject praised the agent for “discretion” and hinted at a permanent role. Later, housekeeping turned over a discarded bidder paddlestick with handwritten totals. Figures exceeded declared room revenue by a wide margin.
Cover holds. Recommend targeted warrants for the shell company, a parallel probe into the broker, and a controlled interruption on the next “private” floor closure to preserve evidence while minimizing guest disruption.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,10 @@
Undercover Report Case File 138-24
Agent: Bennett (cover identity)
Date: 01/12 01/15
Subject manages a modest construction company that appears to use job sites for concealment and cash skimming. Agent hired as temporary labor. On 01/13, a hidden compartment beneath scaffolding yielded two heavy duffels that the subject moved to a pickup without logging materials. The foreman kept crew distant with a noisecontrol pretext.
On 01/14, the subject argued with a partner about “federal contracts” and “kickbacks,” implying bidrigging and publiccorruption exposure. On 01/15, the subject praised the agents work and hinted at “bigger projects,” a sign of attempted grooming for riskier tasks.
Cover maintained. Recommend forensic review of procurement records, site searches keyed to concealed compartments, and interviews with subcontractors likely aware of the skimming practice.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,10 @@
Undercover Report Case File 110-19
Agent: Mitchell (cover identity)
Date: 09/07 09/10
Subject runs a repair garage that doubles as a weapons workshop. Agent embedded as a parttime apprentice. On 09/08, the subject modified rifles at a back bench outfitted with jigs, thread cutters, and solvent traps. Multiple unserialized receivers were visible. The subject bragged about clients who “pay for silence.”
On 09/09, a phone call arranged delivery of “three crates” to a desert rendezvous, specifying urgency and “militarygrade parts.” On 09/10, the subject tested the agent with a drop of a box labeled scrap to an abandoned rail yard. The weight and rattle suggested mixed metal components. Delivery completed under surveillance without opening to preserve cover.
Cover intact though scrutiny is increasing. Recommend immediate tracing of the railyard contact, controlled intercept of the desert transfer, and NIBIN checks on recovered parts.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,11 @@
Undercover Report Case File 07-14
Agent: Mason (cover identity)
Date: 06/12 06/15
Subject continues to operate a cashheavy nightclub believed to be central to midlevel narcotics distribution in the northwest sector. Cover identity as parttime bartender remains effective and provides nightly access to storeroom traffic and the restricted back hallway behind the stage. On 06/13, the subject supervised delivery of three sealed cartons labeled as beverage syrups. The weight and the handlers posture suggested dense contents inconsistent with that label. Subject instructed all staff to avoid contact and to log the cartons as vendor overstock without serials.
On 06/14, the subject held a closeddoor conversation with a courier known locally as “Rico.” Portions overheard included references to a “Miami truck” and “eastcoast push.” Tone implied urgency and reliance on corrupt support, described as “our friend at permits.” Identity of the alleged official remains unknown. Later that evening, a floor manager tested staff loyalty by asking casual questions about police patrol patterns near 12th Street.
On 06/15, subject gave the agent an envelope for a routine offsite drop. Envelope was briefly photographed under pretext of retrieving car keys; contents included a short ledger with coded initials, tally marks, and four phone numbers written in alternating ink colors. Envelope was delivered intact to avoid suspicion. Subjects postdrop demeanor appeared relaxed, suggesting the transaction cleared immediate obligations.
Cover remains intact, with agent perceived as reliable but peripheral. Recommend discreet financial analysis of the ledger numbers, targeted canvass for the unknown permits contact, and coordination with portofentry teams to watch for southtonorth freight aligning with subjects timetable.
@@ -0,0 +1,12 @@
Undercover Report Case File 92-14
Agent: Langston (cover identity)
Date: 05/10 05/14
Subject continues to expand operations through a network of import/export fronts in the industrial docklands. Cover identity as an independent freight consultant has provided access to routing meetings and latenight inspections. On 05/11, the subject oversaw containers labeled “agricultural machinery” with weights above manifest and brandnew locks. Handlers were armed and avoided eye contact. No safe chance to open containers without exposure.
On 05/12, the subject introduced an associate, “Gallo,” who quizzed the agent on Gulfport customs routines and inspection frequencies. Questions implied an imminent push of highvalue contraband through maritime lanes with compromised timing windows. The crew canceled two runs after learning of a regional seizure, and the subject complained about “partners overseas losing patience.”
On 05/14, a briefcase exchange at a dockside café lasted under two minutes; the subject accepted the case and passed it to Gallo without inspection. Both appeared tense but determined.
Cover remains stable yet fragile. Recommend expanded surveillance at the targeted warehouses, customs liaisons to flag the specific manifest anomalies noted, and a rapid extraction plan if the crew pivots to violent vetting.
Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible. Cover remains intact. Recommend continued surveillance and coordinated warrants when feasible.
@@ -0,0 +1,20 @@
095_07-14.txt 07-14 Mason
007_19-52.txt 19-52 Harper
083_25-39.txt 25-39 Doyle
019_31-11.txt 31-11 Vega
075_46-77.txt 46-77 Ellis
031_53-28.txt 53-28 Navarro
072_61-05.txt 61-05 Carter
064_72-90.txt 72-90 Quinn
091_81-33.txt 81-33 Raines
079_89-47.txt 89-47 Dalton
098_92-14.txt 92-14 Langston
012_94-31.txt 94-31 Donovan
016_98-07.txt 98-07 Fletcher
087_102-45.txt 102-45 Sanders
094_110-19.txt 110-19 Mitchell
063_117-56.txt 117-56 OConnor
017_123-88.txt 123-88 Holloway
011_130-62.txt 130-62 Lennox
093_138-24.txt 138-24 Bennett
001_145-93.txt 145-93 Carver
+3
View File
@@ -0,0 +1,3 @@
body {
background-color: skyblue;
}
+63
View File
@@ -0,0 +1,63 @@
/* Styles specific to Game1 */
/* page-level indicator to confirm CSS is loaded */
/* Custom scrollbar for WebKit browsers */
html::-webkit-scrollbar,
body::-webkit-scrollbar {
width: 1px;
}
html::-webkit-scrollbar-track,
body::-webkit-scrollbar-track {
background: #000;
}
html::-webkit-scrollbar-thumb,
body::-webkit-scrollbar-thumb {
background: #F00;
}
/* Standard properties for Firefox */
body {
background-color: #000;
min-height: 100vh;
font-family: monospace;
margin: 0;
scrollbar-width: thin;
scrollbar-color: #F00 #000;
}
div#game-timer {
position: fixed;
top: 20px;
left: 20px;
color: #F00;
font-size: 28px;
z-index: 100;
}
div#message-container {
padding: 20px;
padding-top: 60px; /* Space for fixed timer */
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: calc(100vh - 100px); /* Fill most of the viewport initially */
box-sizing: border-box;
font-size: 20px;
}
div#input {
padding: 20px;
}
input#input-message {
width: 100%;
padding: 10px;
background: #000;
border: 1px solid #F00;
color: #F00;
font-size: 18px;
box-sizing: border-box;
font-family: monospace;
}
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_dir(dirname(__DIR__).'/vendor')) {
throw new LogicException('Dependencies are missing. Try running "composer install".');
}
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env php
<?php
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
if (PHP_VERSION_ID >= 80000) {
require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit';
} else {
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit\TextUI\Command::main();
}
} else {
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
exit(1);
}
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
}
+7
View File
@@ -0,0 +1,7 @@
services:
###> symfony/mercure-bundle ###
mercure:
ports:
- "80"
###< symfony/mercure-bundle ###
+31
View File
@@ -0,0 +1,31 @@
services:
###> symfony/mercure-bundle ###
mercure:
image: dunglas/mercure
restart: unless-stopped
environment:
# Uncomment the following line to disable HTTPS,
#SERVER_NAME: ':80'
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
# Set the URL of your Symfony project (without trailing slash!) as value of the cors_origins directive
MERCURE_EXTRA_DIRECTIVES: |
cors_origins http://127.0.0.1:8000
# Comment the following line to disable the development mode
command: /usr/bin/caddy run --config /etc/caddy/dev.Caddyfile
healthcheck:
test: ["CMD", "curl", "-f", "https://localhost/healthz"]
timeout: 5s
retries: 5
start_period: 60s
volumes:
- mercure_data:/data
- mercure_config:/config
###< symfony/mercure-bundle ###
volumes:
###> symfony/mercure-bundle ###
mercure_data:
mercure_config:
###< symfony/mercure-bundle ###
+113
View File
@@ -0,0 +1,113 @@
{
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.16",
"doctrine/doctrine-migrations-bundle": "^3.4",
"doctrine/orm": "^3.5",
"phpdocumentor/reflection-docblock": "^5.6",
"phpstan/phpdoc-parser": "^2.3",
"symfony/asset": "7.3.*",
"symfony/asset-mapper": "7.3.*",
"symfony/console": "7.3.*",
"symfony/doctrine-messenger": "7.3.*",
"symfony/dotenv": "7.3.*",
"symfony/expression-language": "7.3.*",
"symfony/flex": "^2",
"symfony/form": "7.3.*",
"symfony/framework-bundle": "7.3.*",
"symfony/http-client": "7.3.*",
"symfony/intl": "7.3.*",
"symfony/mailer": "7.3.*",
"symfony/mercure-bundle": "^0.3",
"symfony/mime": "7.3.*",
"symfony/monolog-bundle": "^3.0",
"symfony/notifier": "7.3.*",
"symfony/process": "7.3.*",
"symfony/property-access": "7.3.*",
"symfony/property-info": "7.3.*",
"symfony/runtime": "7.3.*",
"symfony/security-bundle": "7.3.*",
"symfony/sendgrid-mailer": "7.3.*",
"symfony/serializer": "7.3.*",
"symfony/stimulus-bundle": "^2.30",
"symfony/string": "7.3.*",
"symfony/translation": "7.3.*",
"symfony/twig-bundle": "7.3.*",
"symfony/ux-turbo": "^2.30",
"symfony/validator": "7.3.*",
"symfony/web-link": "7.3.*",
"symfony/webpack-encore-bundle": "^2.1",
"symfony/yaml": "7.3.*",
"symfonycasts/reset-password-bundle": "^1.24",
"symfonycasts/verify-email-bundle": "^1.18",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0"
},
"config": {
"allow-plugins": {
"php-http/discovery": true,
"symfony/flex": true,
"symfony/runtime": true
},
"bump-after-update": true,
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*",
"symfony/polyfill-php82": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd",
"importmap:install": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "7.3.*"
}
},
"require-dev": {
"phpunit/phpunit": "^11.5",
"symfony/browser-kit": "7.3.*",
"symfony/css-selector": "7.3.*",
"symfony/debug-bundle": "7.3.*",
"symfony/maker-bundle": "^1.0",
"symfony/stopwatch": "7.3.*",
"symfony/web-profiler-bundle": "7.3.*"
}
}
Generated
+10603
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
];
+11
View File
@@ -0,0 +1,11 @@
framework:
asset_mapper:
# The paths to make available to the asset mapper.
paths:
- assets/
missing_import_mode: strict
when@prod:
framework:
asset_mapper:
missing_import_mode: warn
+19
View File
@@ -0,0 +1,19 @@
framework:
cache:
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: null
+11
View File
@@ -0,0 +1,11 @@
# Enable stateless CSRF protection for forms and logins/logouts
framework:
form:
csrf_protection:
token_id: submit
csrf_protection:
stateless_token_ids:
- submit
- authenticate
- logout
+5
View File
@@ -0,0 +1,5 @@
when@dev:
debug:
# Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
# See the "server:dump" command to start a new server.
dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
+50
View File
@@ -0,0 +1,50 @@
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
#server_version: '16'
profiling_collect_backtrace: '%kernel.debug%'
use_savepoints: true
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src'
prefix: 'App'
alias: App
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod:
doctrine:
orm:
auto_generate_proxy_classes: false
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system
+6
View File
@@ -0,0 +1,6 @@
doctrine_migrations:
migrations_paths:
# namespace is arbitrary but should be different from App\Migrations
# as migrations classes should NOT be autoloaded
'DoctrineMigrations': '%kernel.project_dir%/migrations'
enable_profiler: false
+20
View File
@@ -0,0 +1,20 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
default_locale: 'en'
translator:
default_path: '%kernel.project_dir%/translations'
fallbacks: ['en', 'nl']
# Note that the session will be started ONLY if you read or write from it.
session: true
#esi: true
#fragments: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
+3
View File
@@ -0,0 +1,3 @@
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
+6
View File
@@ -0,0 +1,6 @@
mercure:
hubs:
default:
url: '%env(MERCURE_URL)%'
public_url: '%env(MERCURE_PUBLIC_URL)%'
jwt: '%env(MERCURE_JWT_SECRET)%'
+29
View File
@@ -0,0 +1,29 @@
framework:
messenger:
failure_transport: failed
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
async:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
use_notify: true
check_delayed_interval: 60000
retry_strategy:
max_retries: 3
multiplier: 2
failed: 'doctrine://default?queue_name=failed'
# sync: 'sync://'
default_bus: messenger.bus.default
buses:
messenger.bus.default: []
routing:
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
Symfony\Component\Notifier\Message\ChatMessage: async
Symfony\Component\Notifier\Message\SmsMessage: async
# Route your messages to the transports
'App\Tech\Message\ProcessTaskMessage': async
+62
View File
@@ -0,0 +1,62 @@
monolog:
channels:
- deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
when@dev:
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
# type: firephp
# level: info
#chromephp:
# type: chromephp
# level: info
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
when@test:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
channels: ["!event"]
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
when@prod:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
nested:
type: stream
path: php://stderr
level: debug
formatter: monolog.formatter.json
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
deprecation:
type: stream
channels: [deprecation]
path: php://stderr
formatter: monolog.formatter.json
+13
View File
@@ -0,0 +1,13 @@
framework:
notifier:
chatter_transports:
texter_transports:
sendgrid: '%env(MAILER_DSN)%'
channel_policy:
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
urgent: ['email']
high: ['email']
medium: ['email']
low: ['email']
admin_recipients:
- { email: admin@example.com }
+3
View File
@@ -0,0 +1,3 @@
framework:
property_info:
with_constructor_extractor: true
+2
View File
@@ -0,0 +1,2 @@
symfonycasts_reset_password:
request_password_repository: App\Tech\Repository\ResetPasswordRequestRepository
+10
View File
@@ -0,0 +1,10 @@
framework:
router:
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null
+47
View File
@@ -0,0 +1,47 @@
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
app_user_provider:
entity:
class: App\Tech\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
user_checker: App\Tech\Service\UserChecker
form_login:
login_path: app_login
check_path: app_login
enable_csrf: true
username_parameter: username
password_parameter: password
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
+5
View File
@@ -0,0 +1,5 @@
framework:
default_locale: en
translator:
default_path: '%kernel.project_dir%/translations'
providers:
+4
View File
@@ -0,0 +1,4 @@
twig:
globals:
mercure_public_url: '%env(MERCURE_PUBLIC_URL)%'
mercure_topic_base: '%env(MERCURE_TOPIC_BASE)%'
+4
View File
@@ -0,0 +1,4 @@
# Enable stateless CSRF protection for forms and logins/logouts
framework:
csrf_protection:
check_header: true
+11
View File
@@ -0,0 +1,11 @@
framework:
validation:
# Enables validator auto-mapping support.
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
#auto_mapping:
# App\Entity\: []
when@test:
framework:
validation:
not_compromised_password: false
+13
View File
@@ -0,0 +1,13 @@
when@dev:
web_profiler:
toolbar: true
framework:
profiler:
collect_serializer_data: true
when@test:
framework:
profiler:
collect: false
collect_serializer_data: true
+45
View File
@@ -0,0 +1,45 @@
webpack_encore:
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
output_path: '%kernel.project_dir%/public/build'
# If multiple builds are defined (as shown below), you can disable the default build:
# output_path: false
# Set attributes that will be rendered on all script and link tags
script_attributes:
defer: true
# Uncomment (also under link_attributes) if using Turbo Drive
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
# 'data-turbo-track': reload
# link_attributes:
# Uncomment if using Turbo Drive
# 'data-turbo-track': reload
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
# crossorigin: 'anonymous'
# Preload all rendered script and link tags automatically via the HTTP/2 Link header
# preload: true
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
# strict_mode: false
# If you have multiple builds:
# builds:
# frontend: '%kernel.project_dir%/public/frontend/build'
# pass the build name as the 3rd argument to the Twig functions
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
framework:
assets:
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
#when@prod:
# webpack_encore:
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
# # Available in version 1.2
# cache: true
#when@test:
# webpack_encore:
# strict_mode: false
+5
View File
@@ -0,0 +1,5 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
}
+29
View File
@@ -0,0 +1,29 @@
# Attribute-based routing imports for controllers in subnamespaces
website_controllers:
resource:
path: ../src/Website/Controller/
namespace: App\Website\Controller
type: attribute
game_controllers:
resource:
path: ../src/Game/Controller/
namespace: App\Game\Controller
type: attribute
prefix: /game
tech_controllers:
resource:
path: ../src/Tech/Controller/
namespace: App\Tech\Controller
type: attribute
# Uncomment when you add base controllers
# base_controllers:
# resource:
# path: ../src/Base/Controller/
# namespace: App\Base\Controller
# type: attribute
# # Set a prefix if desired, e.g., "/base" or leave empty to mount at root
# # prefix: /base
+13
View File
@@ -0,0 +1,13 @@
website:
resource: ../../src/Website/Controller/
type: attribute
prefix:
en: '/'
nl: '/nl'
game:
resource: ../../src/Game/Controller/
type: attribute
prefix:
en: '/game'
nl: '/nl/game'
+4
View File
@@ -0,0 +1,4 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
prefix: /_error
+3
View File
@@ -0,0 +1,3 @@
_security_logout:
resource: security.route_loader.logout
type: service
+8
View File
@@ -0,0 +1,8 @@
when@dev:
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.php'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.php'
prefix: /_profiler
+20
View File
@@ -0,0 +1,20 @@
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
+138
View File
@@ -0,0 +1,138 @@
# Contribution & Code Style Guide
This document is for Junie (and humans) to keep our code style consistent and to quickly find the files well reference during development of the Online Escape Room platform.
Project type: Symfony 7.3, PHP >= 8.5.1, Doctrine ORM 3, Twig, Stimulus (UX), Importmap/Asset Mapper, PHPUnit 11.
## 1. Repository Conventions
- PHP version: 8.5.1+ (composer.json enforces ">=8.5.1").
- Framework: Symfony 7.3.* (see composer.json).
- Architecture: MVC with Controllers in `src/Controller`, Entities in `src/Entity`, Repositories in `src/Repository`, Templates in `templates`.
- Env files: `.env`, `.env.local` (ignored), and environment overrides like `.env.test.local`.
- Routes: annotation/attributes in controllers or YAML/PHP in `config/routes`.
- Documentation location: All documentation must live under the `doc/` directory. New docs requested by the team will be added there.
## 2. Coding Standards
### 2.1 PHP
- Standard: PSR-12 (line length soft cap 120; prefer multi-line for long signatures/arrays).
- Strict types at top of new files: `declare(strict_types=1);`
- Type-hint everything (params, returns, properties). Prefer readonly where applicable.
- Visibility: declare on all properties and methods.
- Exceptions: throw domain-specific exceptions for game logic; do not return null where an exception is appropriate.
- Controllers: keep thin; delegate to services. Use DTOs/Form types to validate input.
- Dependency Injection: constructor injection; avoid container-aware services.
- Naming: Services suffixed with `...Service`, commands with `...Command`, event listeners with `...Listener`/`...Subscriber`.
- Logging: use `Psr\Log\LoggerInterface` where meaningful.
### 2.2 Twig
- Keep templates lean; no heavy logic. Use filters/functions and view models if needed.
- Use `trans` for strings that will be localized.
- Partial templates/components: place in `templates/_partials` or `templates/components`.
### 2.3 JavaScript (Stimulus / vanilla)
- Use ES modules via Importmap/Asset Mapper.
- Controllers in `assets/controllers`. Name as `something_controller.js` following Stimulus conventions.
- Prefer small, focused controllers. Keep DOM queries scoped to controller element.
- Avoid global state; communicate via events or Turbo streams when appropriate.
### 2.4 Styles (CSS/SCSS)
- Keep styles in `assets/styles`. Use BEM naming for classes.
- Prefer CSS variables for theme colors, spacing scale, z-index scale.
### 2.5 YAML / Config
- 2-space indentation, no tabs.
- Use parameters and env vars (`env()`) instead of hardcoding secrets.
### 2.6 Git & Commits
- Branch naming: `feature/<short-name>`, `fix/<short-name>`, `chore/<short-name>`.
- Commit messages:
- Conventional commits style: `feat: ...`, `fix: ...`, `chore: ...`, `docs: ...`, `test: ...`, `refactor: ...`.
- First line ≤ 72 chars; add body when needed with rationale.
## 3. Linting, Tests, and Quality
### 3.1 PHP
- Use PHP-CS-Fixer or PHP_CodeSniffer (PHPCS) with PSR-12. If not yet installed, proposed composer scripts (to add later):
- `composer require --dev friendsofphp/php-cs-fixer`
- Script: `php-cs-fixer fix --allow-risky=yes`
- Static analysis: PHPStan level 68 recommended:
- `composer require --dev phpstan/phpstan`
- Run: `vendor/bin/phpstan analyse src tests` (configure `phpstan.neon` later)
### 3.2 Symfony
- Cache and debug:
- `php bin/console cache:clear`
- `php bin/console debug:router`
- `php bin/console debug:container`
### 3.3 Tests
- PHPUnit (already required):
- Run tests: `vendor/bin/phpunit`
- Tests location: `tests/`
- Config: `phpunit.dist.xml`
### 3.4 Frontend
- Stimulus/UX: controllers auto-registered via `symfony/stimulus-bundle`.
- Asset Mapper/Importmap:
- Install deps: `php bin/console importmap:install`
- Dev server (if using symfony local server): `symfony server:start -d`
## 4. Project File Map (Quick Reference)
- App kernel: `src/Kernel.php`
- Controllers: `src/Controller/`
- Domain entities: `src/Entity/`
- Repositories: `src/Repository/`
- Migrations: `migrations/`
- Templates: `templates/`
- Translations: `translations/`
- Assets entry: `assets/app.js`, styles in `assets/styles/`
- Stimulus controllers: `assets/controllers/`
- Routes: `config/routes/`
- Packages config: `config/packages/`
- Env vars: `.env` (base), `.env.local` (local overrides)
- Public web root: `public/`
- Tests: `tests/`
## 5. How We Build Features (Checklist)
1) Create branch: `feature/<name>`.
2) Describe the task in an issue with acceptance criteria.
3) Implement backend (entities/services/controllers) with tests.
4) Implement templates and Stimulus controller if interactive.
5) Add/adjust routes and translations.
6) Run: linters, phpstan, phpunit; ensure green.
7) Open PR; request review.
## 6. Escape Room Domain Notes (early)
- Core concepts likely: Game, Room, Puzzle, Session, Player, Team, Hint, Timer.
- Consider events (Domain Events) for puzzle solved, hint requested, time warnings.
- Real-time collaboration options: Symfony Mercure, WebSockets, or Turbo Streams.
- Persist immutable audit trail for gameplay.
## 7. Editor Configuration
- Recommend EditorConfig. If we add `.editorconfig` later, set:
- Indent 4 spaces for PHP, 2 for YAML/Twig/JS/CSS.
- LF line endings, UTF-8, insert final newline, trim trailing whitespace.
## 8. Security & Secrets
- Never commit secrets. Use environment variables or Symfony Vault.
- Review `APP_ENV`, `APP_SECRET`, database DSN in `.env` and `.env.local`.
## 9. Release & Environments
- Envs: `dev`, `test`, `prod`.
- Build steps: run migrations, warmup cache, compile assets if using.
## 10. References
- Symfony Best Practices: https://symfony.com/doc/current/best_practices.html
- Doctrine ORM 3 Docs: https://www.doctrine-project.org/projects/doctrine-orm/en/current/
- Stimulus: https://stimulus.hotwired.dev/
+51
View File
@@ -0,0 +1,51 @@
# Project File Index (Quick Reference)
Use this index to quickly locate files and directories during development and in discussions.
## Top-Level
- docker/compose.yaml / docker/compose.override.yaml — Docker services.
- docker/ — Docker build contexts and configs (php Dockerfile, nginx vhost, compose files).
- composer.json / composer.lock — Dependencies and scripts.
- importmap.php — Importmap configuration for JS dependencies.
- phpunit.dist.xml — PHPUnit configuration.
- public/ — Web root (index.php, assets, static files).
- var/ — Cache and logs.
- vendor/ — Composer dependencies.
## Application Source (src/)
- src/Kernel.php — Symfony Kernel bootstrapping.
- src/Website/ — Marketing/public website area (controllers, templates under templates/website/).
- src/Game/ — Game area (controllers, templates under templates/game/).
- src/Entity/ — Doctrine ORM entities.
- src/Repository/ — Doctrine repositories.
## Configuration (config/)
- config/packages/ — Symfony bundles configuration (framework.yaml, cache.yaml, etc.).
- config/routes/ — Routing configuration files.
- config/routes/app.yaml — Imports attribute routes for both sites (Website and Game).
## Data & DB
- migrations/ — Doctrine migrations.
## Presentation
- templates/ — Twig templates.
- templates/website — Views for the public website.
- templates/game — Views for the game area.
- translations/ — i18n message files.
## Frontend Assets
- assets/app.js — Main JS entry (imports Stimulus, styles, etc.).
- assets/controllers/ — Stimulus controllers.
- assets/styles/ — Global styles.
- assets/vendor/ — Vendor frontend assets if any.
## Tests
- tests/ — Test suites for PHPUnit.
## Environment
- .env — Base environment configuration.
- .env.local — Local overrides (ignored).
## Notes
- Follow doc/CONTRIBUTING.md for code style and workflows.
- Email setup: see doc/email.md for dev Mailpit and production SendGrid configuration.
+10
View File
@@ -0,0 +1,10 @@
# Project Documentation
This directory contains all project documentation for EscapePage.
- Code Style & Contribution Guide: CONTRIBUTING.md
- Project File Index: FILES.md
Policy: All new and existing documentation must be placed in this doc/ directory. If you ask Junie to add docs in the future, they will be created under doc/.
Additional docs can be added here as the project grows (architecture decisions, API docs, gameplay design, onboarding, etc.).
+60
View File
@@ -0,0 +1,60 @@
# Docker Setup
This app can run fully in Docker using docker compose with PHP-FPM, Nginx and MySQL.
## Services
- php: PHP 8.5.1 FPM with required extensions and Composer
- nginx: Serves the Symfony app from public/ and proxies PHP to php-fpm
- database: MySQL 8.0 (data persisted in a volume)
- mailer (dev only via compose.override.yaml): Mailpit (SMTP/UI)
## Prerequisites
- Docker and Docker Compose (v2)
## Usage
### 1) Build and start
```
./docker/setup.sh
```
App will be served at http://localhost:8080
Alternatively (manual):
```
docker compose -f docker/compose.yaml -f docker/compose.override.yaml up -d --build
```
### 2) Install dependencies
The setup script already runs composer install. To run manually:
```
docker compose -f docker/compose.yaml -f docker/compose.override.yaml exec php composer install
```
### 3) Prepare DB
The setup script already prepares the DB. To run manually:
```
docker compose -f docker/compose.yaml -f docker/compose.override.yaml exec php php bin/console doctrine:database:create --if-not-exists
docker compose -f docker/compose.yaml -f docker/compose.override.yaml exec php php bin/console doctrine:migrations:migrate -n
```
### 4) Run tests
```
docker compose -f docker/compose.yaml -f docker/compose.override.yaml exec php vendor/bin/phpunit
```
### 5) Logs
```
docker compose -f docker/compose.yaml -f docker/compose.override.yaml logs -f nginx
docker compose -f docker/compose.yaml -f docker/compose.override.yaml logs -f php
```
### 6) Stop
```
docker compose -f docker/compose.yaml -f docker/compose.override.yaml down
```
## Notes
- .env already points DATABASE_URL to the `database` service hostname.
- Nginx listens on port 8080 (mapped from container 80) to avoid conflicts.
- Source is bind-mounted; changes on host reflect inside containers.
- For production images, create a separate Dockerfile with build steps (composer install --no-dev, cache warmup) and avoid bind mounts.
+45
View File
@@ -0,0 +1,45 @@
# Email Delivery: Dev Mailcatcher & Production SendGrid
This application uses Symfony Mailer. We separate development and production delivery:
- Development: Mailpit (mailcatcher) via SMTP in Docker.
- Production: SendGrid via API transport.
## Development (Mailpit)
- Service is defined in `compose.override.yaml` as `mailer` (axllent/mailpit).
- Ports:
- SMTP: 1025 (mapped to host 1025)
- Web UI: 8025 (mapped to host 8025)
- Default DSN for dev is set in `.env`:
```
MAILER_DSN=smtp://mailer:1025
```
- Usage:
1. Start stack: `docker compose up -d`
2. Send an email from the app.
3. Open http://localhost:8025 to view captured emails.
## Production (SendGrid)
Use the SendGrid API transport. Do not commit secrets.
- Example configuration is in `.env.prod`:
```
MAILER_DSN=sendgrid+api://%env(resolve:SENDGRID_API_KEY)%@default
```
- Provide `SENDGRID_API_KEY` via:
- Real environment variable on the server/container, or
- Symfony secrets: `php bin/console secrets:set SENDGRID_API_KEY` (and dump for prod), or
- Orchestration secret stores (e.g., Docker/K8s).
### Notes
- No Mailpit container is defined in the base `compose.yaml`, only in `compose.override.yaml`. This ensures it is used in development only.
- To test email locally without Docker, you can:
- Run Mailpit on your host (ports 1025/8025) and set `MAILER_DSN=smtp://127.0.0.1:1025` in `.env.local`.
- If you need to use SendGrid SMTP instead of API, a DSN example:
`smtp://apikey:YOUR_SENDGRID_API_KEY@smtp.sendgrid.net:587`.
+26
View File
@@ -0,0 +1,26 @@
services:
php:
environment:
XDEBUG_MODE: off
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- mailer
###> doctrine/doctrine-bundle ###
database:
ports:
- "3306"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
mailer:
image: axllent/mailpit
ports:
- "1025:1025"
- "8025:8025"
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
###< symfony/mailer ###
+113
View File
@@ -0,0 +1,113 @@
version: '3.7'
services:
php:
build:
context: ..
dockerfile: docker/php/Dockerfile
container_name: escapepage-php
volumes:
- ../:/var/www/html:delegated
environment:
APP_ENV: dev
depends_on:
- database
- mercure
networks:
- backend
restart: unless-stopped
php-worker:
build:
context: ..
dockerfile: docker/php/Dockerfile
container_name: escapepage-php-worker
volumes:
- ../:/var/www/html:delegated
environment:
APP_ENV: dev
depends_on:
- database
- mercure
command: ["php", "bin/console", "messenger:consume", "async", "-vv"]
networks:
- backend
restart: unless-stopped
nginx:
image: nginx:1.29.4-alpine
container_name: escapepage-nginx
ports:
- "8080:80"
volumes:
- ../:/var/www/html:ro
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- php
networks:
- backend
restart: unless-stopped
mailer:
image: axllent/mailpit:latest
container_name: escapepage-mailer
ports:
- "8025:8025"
networks:
- backend
restart: unless-stopped
mercure:
image: dunglas/mercure:v0.21
container_name: escapepage-mercure
environment:
SERVER_NAME: ":80"
MERCURE_PUBLISHER_JWT_KEY: ${MERCURE_JWT_SECRET:-!ChangeThisMercureJWT!}
MERCURE_SUBSCRIBER_JWT_KEY: ${MERCURE_JWT_SECRET:-!ChangeThisMercureJWT!}
MERCURE_CORS_ALLOWED_ORIGINS: http://localhost:8080
MERCURE_PUBLISH_ALLOWED_ORIGINS: http://localhost:8080
MERCURE_EXTRA_DIRECTIVES: |
cors_origins http://localhost:8080
# Allow anonymous subscribers in dev only
anonymous
ports:
- "8090:80"
networks:
- backend
restart: unless-stopped
###> doctrine/doctrine-bundle ###
database:
image: mysql:8.0
container_name: escapepage-db
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE:-app}
MYSQL_USER: ${MYSQL_USER:-app}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-!ChangeMe!}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root}
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD:-root}"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
command: ["--default-authentication-plugin=mysql_native_password", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
volumes:
- database_data:/var/lib/mysql:rw
# Uncomment the two lines below if you need to access MySQL from your host (workbench, etc.)
# ports:
# - "3306:3306"
networks:
- backend
restart: unless-stopped
###< doctrine/doctrine-bundle ###
volumes:
###> doctrine/doctrine-bundle ###
database_data:
###< doctrine/doctrine-bundle ###
networks:
backend:
driver: bridge
+28
View File
@@ -0,0 +1,28 @@
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.php index.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_pass php:9000;
fastcgi_read_timeout 120;
}
location ~ /\.ht {
deny all;
}
client_max_body_size 32m;
}
+30
View File
@@ -0,0 +1,30 @@
FROM php:8.3-fpm-alpine
# Install system deps
RUN apk add --no-cache \
bash \
git \
icu-dev \
libzip-dev \
oniguruma-dev \
g++ \
make \
nodejs \
npm
# Install PHP extensions
RUN docker-php-ext-configure intl \
&& docker-php-ext-install -j$(nproc) intl pdo pdo_mysql opcache zip
# Install composer
ENV COMPOSER_ALLOW_SUPERUSER=1 \
COMPOSER_HOME=/tmp/composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Configure PHP
COPY docker/php/php.ini $PHP_INI_DIR/conf.d/zz-custom.ini
WORKDIR /var/www/html
# Default command
CMD ["php-fpm"]
+9
View File
@@ -0,0 +1,9 @@
memory_limit=512M
post_max_size=32M
upload_max_filesize=32M
max_execution_time=60
; For Symfony dev
opcache.enable=1
opcache.enable_cli=1
opcache.validate_timestamps=1
opcache.revalidate_freq=0
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env bash
set -euo pipefail
# Simple setup script to bootstrap the Dockerized dev stack for this project.
# - Builds and starts containers (php, nginx, mariadb, mailpit via override)
# - Installs composer dependencies
# - Ensures APP_SECRET is set (generates if empty)
# - Creates and migrates the database
# - Installs/imports JS dependencies
# - Prints helpful info on success
# Usage:
# ./docker/setup.sh # full setup
# ./docker/setup.sh --no-build # skip image rebuild
# ./docker/setup.sh --down # stop and remove containers (down)
# ./docker/setup.sh --recreate # force recreate containers
ROOT_DIR=$(cd "$(dirname "$0")"/.. && pwd)
DOCKER_DIR="$ROOT_DIR/docker"
# Determine the docker compose command (V2 'docker compose' or V1 'docker-compose')
if docker compose version >/dev/null 2>&1; then
DOCKER_COMPOSE="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE="docker-compose"
else
echo "Error: Neither 'docker compose' nor 'docker-compose' was found. Please install Docker Compose." >&2
exit 1
fi
# Helper to run docker compose from the docker/ directory
dc() { (cd "$DOCKER_DIR" && $DOCKER_COMPOSE -f compose.yaml "$@"); }
REBUILD=1
RECREATE=0
DOWN_ONLY=0
for arg in "$@"; do
case "$arg" in
--no-build) REBUILD=0 ;;
--recreate) RECREATE=1 ;;
--down) DOWN_ONLY=1 ;;
*) echo "Unknown option: $arg" >&2; exit 1 ;;
esac
done
need() { command -v "$1" >/dev/null 2>&1 || { echo "Error: '$1' is required but not installed." >&2; exit 1; }; }
need docker
if [ "$DOWN_ONLY" -eq 1 ]; then
dc down
exit 0
fi
BUILD_ARGS=()
if [ "$REBUILD" -eq 1 ]; then
BUILD_ARGS+=("--build")
fi
if [ "$RECREATE" -eq 1 ]; then
BUILD_ARGS+=("--force-recreate")
fi
# Start stack
dc up "${BUILD_ARGS[@]}"
# Helper to run commands in php container
pexec() { dc exec -T php "$@"; }
# Wait for database to be healthy (mariadb/mysql)
printf "Waiting for database to be healthy..."
# Use docker inspect health status
DB_HEALTH=""
for i in {1..60}; do
DB_ID=$(dc ps -q database 2>/dev/null || true)
if [ -n "$DB_ID" ]; then
DB_HEALTH=$(docker inspect -f '{{.State.Health.Status}}' "$DB_ID" 2>/dev/null || true)
fi
if [ "$DB_HEALTH" = "healthy" ]; then
echo " OK"
break
fi
printf "."
sleep 2
if [ "$i" -eq 60 ]; then
echo -e "\nWarning: database health check not healthy yet, continuing anyway."
fi
done
# Ensure composer is available and install dependencies
pexec composer install --no-interaction
# Ensure APP_SECRET is set
if grep -q '^APP_SECRET=$' "$ROOT_DIR/.env" 2>/dev/null; then
echo "Generating APP_SECRET in .env.local..."
mkdir -p "$ROOT_DIR"
SECRET=$(openssl rand -hex 16)
# Write to .env.local so we don't commit it
if [ ! -f "$ROOT_DIR/.env.local" ]; then
printf "APP_SECRET=%s\n" "$SECRET" > "$ROOT_DIR/.env.local"
elif ! grep -q '^APP_SECRET=' "$ROOT_DIR/.env.local"; then
printf "APP_SECRET=%s\n" "$SECRET" >> "$ROOT_DIR/.env.local"
fi
fi
# Prepare DB
echo "Creating database if it doesn't exist..."
pexec php bin/console doctrine:database:create --if-not-exists
echo "Running migrations..."
pexec php bin/console doctrine:migrations:migrate -n
# Import JS deps (Importmap/Asset Mapper)
if [ -f "$ROOT_DIR/importmap.php" ]; then
pexec php bin/console importmap:install || true
fi
# Build assets if using Webpack Encore
if [ -f "$ROOT_DIR/package.json" ]; then
echo "Installing npm dependencies..."
pexec npm install
echo "Building assets..."
pexec npm run build
fi
APP_URL=http://localhost:8080
MAILPIT_URL=http://localhost:8025
cat <<EOT
Setup complete!
Open the app: $APP_URL
Mailpit (dev): $MAILPIT_URL
Common commands:
(cd "$DOCKER_DIR" && $DOCKER_COMPOSE logs -f nginx)
(cd "$DOCKER_DIR" && $DOCKER_COMPOSE logs -f php)
(cd "$DOCKER_DIR" && $DOCKER_COMPOSE logs -f php-worker)
(cd "$DOCKER_DIR" && $DOCKER_COMPOSE exec php bash)
(cd "$DOCKER_DIR" && $DOCKER_COMPOSE exec php npm run watch)
(cd "$DOCKER_DIR" && $DOCKER_COMPOSE down)
You can re-run this script any time. Use --no-build to skip rebuilding images.
EOT
+28
View File
@@ -0,0 +1,28 @@
<?php
/**
* Returns the importmap for this application.
*
* - "path" is a path inside the asset mapper system. Use the
* "debug:asset-map" command to see the full list of paths.
*
* - "entrypoint" (JavaScript only) set to true for any module that will
* be used as an "entrypoint" (and passed to the importmap() Twig function).
*
* The "importmap:require" command can be used to add new entries to this file.
*/
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
'@hotwired/stimulus' => [
'version' => '3.2.2',
],
'@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
],
'@hotwired/turbo' => [
'version' => '7.3.0',
],
];
View File
+33
View File
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260103210448 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE `user` (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, is_verified TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', available_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', delivered_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 (queue_name, available_at, delivered_at, id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE `user`');
$this->addSql('DROP TABLE messenger_messages');
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260103212025 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE email_log (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, email_identifier VARCHAR(255) NOT NULL, sent_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_6FB4883A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE email_log ADD CONSTRAINT FK_6FB4883A76ED395 FOREIGN KEY (user_id) REFERENCES `user` (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE email_log DROP FOREIGN KEY FK_6FB4883A76ED395');
$this->addSql('DROP TABLE email_log');
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260103214856 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user ADD username VARCHAR(180) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME ON user (username)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_IDENTIFIER_USERNAME ON `user`');
$this->addSql('ALTER TABLE `user` DROP username');
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260103215543 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE reset_password_request (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, selector VARCHAR(20) NOT NULL, hashed_token VARCHAR(100) NOT NULL, requested_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', expires_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_7CE748AA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE reset_password_request ADD CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES `user` (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE reset_password_request DROP FOREIGN KEY FK_7CE748AA76ED395');
$this->addSql('DROP TABLE reset_password_request');
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260105113139 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE game (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, number_of_players INT NOT NULL, status VARCHAR(20) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE player (id INT AUTO_INCREMENT NOT NULL, session_id INT NOT NULL, user_id INT NOT NULL, screen INT NOT NULL, INDEX IDX_98197A65613FECDF (session_id), INDEX IDX_98197A65A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE session (id INT AUTO_INCREMENT NOT NULL, game_id INT NOT NULL, status VARCHAR(20) NOT NULL, timer INT NOT NULL, created DATETIME NOT NULL, INDEX IDX_D044D5D4E48FD905 (game_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE player ADD CONSTRAINT FK_98197A65613FECDF FOREIGN KEY (session_id) REFERENCES session (id)');
$this->addSql('ALTER TABLE player ADD CONSTRAINT FK_98197A65A76ED395 FOREIGN KEY (user_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE session ADD CONSTRAINT FK_D044D5D4E48FD905 FOREIGN KEY (game_id) REFERENCES game (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE player DROP FOREIGN KEY FK_98197A65613FECDF');
$this->addSql('ALTER TABLE player DROP FOREIGN KEY FK_98197A65A76ED395');
$this->addSql('ALTER TABLE session DROP FOREIGN KEY FK_D044D5D4E48FD905');
$this->addSql('DROP TABLE game');
$this->addSql('DROP TABLE player');
$this->addSql('DROP TABLE session');
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260105121159 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE player ADD level JSON DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE player DROP level');
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260105155949 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE game_setting (id INT AUTO_INCREMENT NOT NULL, game_id INT NOT NULL, name VARCHAR(255) NOT NULL, value LONGTEXT DEFAULT NULL, INDEX IDX_AB6C7B7E48FD905 (game_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE session_setting (id INT AUTO_INCREMENT NOT NULL, session_id INT NOT NULL, player_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, value LONGTEXT DEFAULT NULL, INDEX IDX_8DAC3AC2613FECDF (session_id), INDEX IDX_8DAC3AC299E6F5DF (player_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE game_setting ADD CONSTRAINT FK_AB6C7B7E48FD905 FOREIGN KEY (game_id) REFERENCES game (id)');
$this->addSql('ALTER TABLE session_setting ADD CONSTRAINT FK_8DAC3AC2613FECDF FOREIGN KEY (session_id) REFERENCES session (id)');
$this->addSql('ALTER TABLE session_setting ADD CONSTRAINT FK_8DAC3AC299E6F5DF FOREIGN KEY (player_id) REFERENCES player (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE game_setting DROP FOREIGN KEY FK_AB6C7B7E48FD905');
$this->addSql('ALTER TABLE session_setting DROP FOREIGN KEY FK_8DAC3AC2613FECDF');
$this->addSql('ALTER TABLE session_setting DROP FOREIGN KEY FK_8DAC3AC299E6F5DF');
$this->addSql('DROP TABLE game_setting');
$this->addSql('DROP TABLE session_setting');
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260105160603 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE player DROP level');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE player ADD level JSON DEFAULT NULL');
}
}
+8205
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
{
"name": "escapepage",
"private": true,
"version": "1.0.0",
"description": "EscapePage Symfony app assets built with Webpack Encore",
"license": "UNLICENSED",
"scripts": {
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production"
},
"devDependencies": {
"@babel/core": "^7.25.0",
"@babel/preset-env": "^7.25.0",
"@symfony/webpack-encore": "^4.6.1",
"babel-loader": "^9.1.3",
"core-js": "^3.37.1",
"css-loader": "^7.1.2",
"mini-css-extract-plugin": "^2.9.2",
"regenerator-runtime": "^0.14.1",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4",
"webpack-notifier": "^1.15.0"
}
}
+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
failOnDeprecation="true"
failOnNotice="true"
failOnWarning="true"
bootstrap="tests/bootstrap.php"
cacheDirectory=".phpunit.cache"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<source ignoreSuppressionOfDeprecations="true"
ignoreIndirectDeprecations="true"
restrictNotices="true"
restrictWarnings="true"
>
<include>
<directory>src</directory>
</include>
<deprecationTrigger>
<method>Doctrine\Deprecations\Deprecation::trigger</method>
<method>Doctrine\Deprecations\Deprecation::delegateTriggerToBackend</method>
<function>trigger_deprecation</function>
</deprecationTrigger>
</source>
<extensions>
</extensions>
</phpunit>

Some files were not shown because too many files have changed in this diff Show More