initial commit

This commit is contained in:
Murat Özkorkmaz
2025-10-08 15:57:29 +02:00
commit abb3cbc1bd
89 changed files with 12322 additions and 0 deletions

17
.editorconfig Normal file
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

41
.env Normal file
View File

@@ -0,0 +1,41 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=V8W3EMNAXJSPWP2PC92PKX7VEAWCUJWASSNXNDD2DE2JXEB99B6ZVT5D
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
###< doctrine/doctrine-bundle ###
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###
###> symfony/mailer ###
MAILER_DSN=smtp://webmaster@shibuihouse.de:wxjHbsBrm1GCzj@smtp.strato.de:465
###< symfony/mailer ###

8
.env.dev Normal file
View File

@@ -0,0 +1,8 @@
###> symfony/framework-bundle ###
APP_SECRET=751e3602cb3a998c754b074d3cbcad63
###< symfony/framework-bundle ###
###> symfony/mailer ###
MAILER_DSN=smtp://localhost:1025
###< symfony/mailer ###

3
.env.test Normal file
View File

@@ -0,0 +1,3 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'

20
.gitignore vendored Normal file
View File

@@ -0,0 +1,20 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
###> phpunit/phpunit ###
/phpunit.xml
/.phpunit.cache/
###< phpunit/phpunit ###
###> symfony/asset-mapper ###
/public/assets/
/assets/vendor/
###< symfony/asset-mapper ###

8
.idea/.gitignore generated vendored Normal file
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

8
.idea/laravel-idea.xml generated Normal file
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>

6
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
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/web-app.iml" filepath="$PROJECT_DIR$/.idea/web-app.iml" />
</modules>
</component>
</project>

169
.idea/php.xml generated Normal file
View File

@@ -0,0 +1,169 @@
<?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>
<PhpCSConfiguration asDefaultInterpreter="true" />
</phpcs_settings>
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/vendor/egulias/email-validator" />
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
<path value="$PROJECT_DIR$/vendor/symfony/asset-mapper" />
<path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/symfony/stimulus-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/vendor/symfony/intl" />
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
<path value="$PROJECT_DIR$/vendor/psr/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
<path value="$PROJECT_DIR$/vendor/psr/link" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
<path value="$PROJECT_DIR$/vendor/psr/clock" />
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bridge" />
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
<path value="$PROJECT_DIR$/vendor/symfony/mailer" />
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
<path value="$PROJECT_DIR$/vendor/psr/log" />
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
<path value="$PROJECT_DIR$/vendor/psr/container" />
<path value="$PROJECT_DIR$/vendor/symfony/config" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
<path value="$PROJECT_DIR$/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/vendor/symfony/debug-bundle" />
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
<path value="$PROJECT_DIR$/vendor/symfony/web-profiler-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-messenger" />
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-turbo" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-icu" />
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
<path value="$PROJECT_DIR$/vendor/symfony/notifier" />
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
<path value="$PROJECT_DIR$/vendor/symfony/string" />
<path value="$PROJECT_DIR$/vendor/symfony/messenger" />
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
<path value="$PROJECT_DIR$/vendor/symfony/process" />
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/twig/extra-bundle" />
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
<path value="$PROJECT_DIR$/vendor/symfonycasts/tailwind-bundle" />
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
<component name="PhpStan">
<PhpStan_settings>
<PhpStanConfiguration asDefaultInterpreter="true" />
</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="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

10
.idea/sshConfigs.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SshConfigs">
<configs>
<sshConfig authType="PASSWORD" connectionConfig="{&quot;serverAliveInterval&quot;:300}" id="47f002aa-5a72-4ab4-b99a-0fdc7dc1b0e2" customName="carmen reiki" nameFormat="CUSTOM" useOpenSSHConfig="true">
<option name="customName" value="carmen reiki" />
</sshConfig>
</configs>
</component>
</project>

140
.idea/web-app.iml generated Normal file
View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<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/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/symfonycasts/tailwind-bundle" />
<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" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

28
assets/app.js Normal file
View File

@@ -0,0 +1,28 @@
import './bootstrap.js';
/*
* Welcome to your app's main JavaScript file!
*
* This file will be included onto the page via the importmap() Twig function,
* which should already be in your base.html.twig.
*/
import './styles/app.css';
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');
document.addEventListener('click', (e) => {
if (e.target.closest('#menu-btn')) {
const menu = document.getElementById('mobile-menu');
if (menu.style.maxHeight && menu.style.maxHeight !== '0px') {
menu.style.maxHeight = '0px';
} else {
menu.style.maxHeight = menu.scrollHeight + 'px';
}
}
});

5
assets/bootstrap.js vendored Normal file
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
assets/controllers.json Normal file
View File

@@ -0,0 +1,15 @@
{
"controllers": {
"@symfony/ux-turbo": {
"turbo-core": {
"enabled": true,
"fetch": "eager"
},
"mercure-turbo-stream": {
"enabled": false,
"fetch": "eager"
}
}
},
"entrypoints": []
}

View File

@@ -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';

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';
}
}

BIN
assets/images/frankfurt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/images/on-chair.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
assets/images/proj1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
assets/images/proj2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

12
assets/styles/app.css Normal file
View File

@@ -0,0 +1,12 @@
@import "tailwindcss";
ul {
list-style: disc;
padding-left: 2em;
padding-top: 1em;
padding-bottom: 2em;
}
li {
padding-bottom: 0.7em;
}

21
bin/console Executable file
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
bin/phpunit Executable file
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';
}

18
compose.override.yaml Normal file
View File

@@ -0,0 +1,18 @@
services:
###> doctrine/doctrine-bundle ###
database:
ports:
- "5432"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
mailer:
image: axllent/mailpit
ports:
- "1025"
- "8025"
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
###< symfony/mailer ###

25
compose.yaml Normal file
View File

@@ -0,0 +1,25 @@
services:
###> doctrine/doctrine-bundle ###
database:
image: postgres:${POSTGRES_VERSION:-16}-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-app}
# You should definitely change the password in production
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
POSTGRES_USER: ${POSTGRES_USER:-app}
healthcheck:
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"]
timeout: 5s
retries: 5
start_period: 60s
volumes:
- database_data:/var/lib/postgresql/data:rw
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
# - ./docker/db/data:/var/lib/postgresql/data:rw
###< doctrine/doctrine-bundle ###
volumes:
###> doctrine/doctrine-bundle ###
database_data:
###< doctrine/doctrine-bundle ###

109
composer.json Normal file
View File

@@ -0,0 +1,109 @@
{
"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/mime": "7.3.*",
"symfony/monolog-bundle": "^3.10",
"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/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/yaml": "7.3.*",
"symfonycasts/tailwind-bundle": "^0.11.1",
"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": "^12.3",
"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.*"
}
}

10033
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

17
config/bundles.php Normal file
View File

@@ -0,0 +1,17 @@
<?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],
Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle::class => ['all' => true],
];

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

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
config/packages/csrf.yaml Normal file
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

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)%"

View File

@@ -0,0 +1,54 @@
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
identity_generation_preferences:
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
auto_mapping: true
mappings:
App:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
controller_resolver:
auto_mapping: false
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

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

View File

@@ -0,0 +1,15 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
# 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

View File

@@ -0,0 +1,3 @@
framework:
mailer:
dsn: '%env(MAILER_DSN)%'

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\Message\YourMessage': async

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

View File

@@ -0,0 +1,12 @@
framework:
notifier:
chatter_transports:
texter_transports:
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 }

View File

@@ -0,0 +1,3 @@
framework:
property_info:
with_constructor_extractor: true

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

View File

@@ -0,0 +1,39 @@
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:
users_in_memory: { memory: null }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: users_in_memory
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# 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

View File

@@ -0,0 +1,6 @@
symfonycasts_tailwind:
# Specify the EXACT version of Tailwind CSS you want to use
binary_version: 'v4.1.11'
# Alternatively, you can specify the path to the binary that you manage yourself
#binary: 'node_modules/.bin/tailwindcss'

View File

@@ -0,0 +1,5 @@
framework:
default_locale: en
translator:
default_path: '%kernel.project_dir%/translations'
providers:

View File

@@ -0,0 +1,6 @@
twig:
file_name_pattern: '*.twig'
when@test:
twig:
strict_variables: true

View File

@@ -0,0 +1,5 @@
# Enable stateless CSRF protection for forms and logins/logouts
framework:
csrf_protection:
check_header: true

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

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

5
config/preload.php Normal file
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';
}

5
config/routes.yaml Normal file
View File

@@ -0,0 +1,5 @@
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute

View File

@@ -0,0 +1,4 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
prefix: /_error

View File

@@ -0,0 +1,3 @@
_security_logout:
resource: security.route_loader.logout
type: service

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
config/services.yaml Normal file
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

23
deploy-assets-dev.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
ENV_FILE=".env"
if grep -q '^APP_ENV=' "$ENV_FILE"; then
# Unterschiedliche sed-Varianten behandeln
if sed --version >/dev/null 2>&1; then
# GNU sed
sed -i 's/^APP_ENV=.*/APP_ENV=dev/' "$ENV_FILE"
else
# BSD sed (macOS)
sed -i '' 's/^APP_ENV=.*/APP_ENV=dev/' "$ENV_FILE"
fi
else
echo "APP_ENV=dev" >> "$ENV_FILE"
fi
rm -rf ./public/assets/
php bin/console cache:clear
php bin/console asset-map:compile
php bin/console tailwind:build

24
deploy-assets-prod.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail
ENV_FILE=".env"
if grep -q '^APP_ENV=' "$ENV_FILE"; then
# Unterschiedliche sed-Varianten behandeln
if sed --version >/dev/null 2>&1; then
# GNU sed
sed -i 's/^APP_ENV=.*/APP_ENV=prod/' "$ENV_FILE"
else
# BSD sed (macOS)
sed -i '' 's/^APP_ENV=.*/APP_ENV=prod/' "$ENV_FILE"
fi
else
echo "APP_ENV=prod" >> "$ENV_FILE"
fi
rm -rf ./var/cache/dev
rm -rf ./var/cache/prod
rm -rf ./var/log/*.log
php bin/console tailwind:build --minify
php bin/console asset-map:compile

28
importmap.php Normal file
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',
],
];

0
migrations/.gitignore vendored Normal file
View File

44
phpunit.dist.xml Normal file
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>

5
public/.htaccess Normal file
View File

@@ -0,0 +1,5 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
public/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

BIN
public/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

9
public/index.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

1
public/site.webmanifest Normal file
View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

0
src/Controller/.gitignore vendored Normal file
View File

View File

@@ -0,0 +1,71 @@
<?php
namespace App\Controller;
use App\DTO\ContactDTO;
use App\DTO\EventRegistrationDTO;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Attribute\Route;
final class HomeController extends AbstractController
{
#[Route('/fonts', 'fonts')]
public function fonts(): Response {
return $this->render('home_controller/fonts.html.twig');
}
#[Route('/impressum', 'imprint')]
public function imprint(): Response {
return $this->render('home_controller/imprint.html.twig');
}
#[Route('/datenschutzerklaerung', 'data_privacy')]
public function data_privacy(): Response {
return $this->render('home_controller/data-privacy.html.twig');
}
#[Route('/architektur', 'architecture')]
public function architecture(): Response {
return $this->render('home_controller/architecture.html.twig');
}
#[Route('/kontakt', 'contact')]
public function contact(): Response {
return $this->render('home_controller/contact.html.twig');
}
#[Route('/gutachten', 'building_report')]
public function buildingReport(): Response {
return $this->render('home_controller/building-report.html.twig');
}
#[Route('/ueber-mich', name: 'about_me')]
public function aboutMe(Request $request, MailerInterface $mailer): Response
{
return $this->render('home_controller/about-me.html.twig');
}
#[Route('/', name: 'home')]
public function index(Request $request, MailerInterface $mailer): Response
{
return $this->render('home_controller/index.html.twig');
}
}

22
src/DTO/ContactDTO.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
namespace App\DTO;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
class ContactDTO
{
#[NotBlank(message: 'Bitte geben Sie Ihren Namen ein.')]
public string $firstName;
#[NotBlank(message: 'Bitte geben Sie Ihren Nachnamen ein.')]
public string $lastName;
#[NotBlank(message: 'Bitte geben Sie Ihre E-Mail-Adresse ein.')]
#[Email(message: 'Bitte geben Sie eine gültige E-Mail-Adresse ein.')]
public string $email;
#[NotBlank(message: 'Bitte geben Sie eine Nachricht ein.')]
public string $message;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\DTO;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
class EventRegistrationDTO
{
#[NotBlank(message: 'Bitte geben Sie Ihren Namen ein.')]
public string $eventFirstName;
#[NotBlank(message: 'Bitte geben Sie Ihren Nachnamen ein.')]
public string $eventLastName;
#[NotBlank(message: 'Bitte geben Sie Ihre E-Mail-Adresse ein.')]
#[Email(message: 'Bitte geben Sie eine gültige E-Mail-Adresse ein.')]
public string $eventEmail;
#[NotBlank(message: 'Bitte akzeptieren Sie die Geschäftsbedingungen.')]
public bool $eventAck;
}

0
src/Entity/.gitignore vendored Normal file
View File

11
src/Kernel.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
}

0
src/Repository/.gitignore vendored Normal file
View File

337
symfony.lock Normal file
View File

@@ -0,0 +1,337 @@
{
"doctrine/deprecations": {
"version": "1.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "87424683adc81d7dc305eefec1fced883084aab9"
}
},
"doctrine/doctrine-bundle": {
"version": "2.16",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.13",
"ref": "620b57f496f2e599a6015a9fa222c2ee0a32adcb"
},
"files": [
"config/packages/doctrine.yaml",
"src/Entity/.gitignore",
"src/Repository/.gitignore"
]
},
"doctrine/doctrine-migrations-bundle": {
"version": "3.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.1",
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
},
"files": [
"config/packages/doctrine_migrations.yaml",
"migrations/.gitignore"
]
},
"phpunit/phpunit": {
"version": "12.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "11.1",
"ref": "c6658a60fc9d594805370eacdf542c3d6b5c0869"
},
"files": [
".env.test",
"phpunit.dist.xml",
"tests/bootstrap.php",
"bin/phpunit"
]
},
"symfony/asset-mapper": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a"
},
"files": [
"assets/app.js",
"assets/styles/app.css",
"config/packages/asset_mapper.yaml",
"importmap.php"
]
},
"symfony/console": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461"
},
"files": [
"bin/console"
]
},
"symfony/debug-bundle": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b"
},
"files": [
"config/packages/debug.yaml"
]
},
"symfony/flex": {
"version": "2.8",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.4",
"ref": "52e9754527a15e2b79d9a610f98185a1fe46622a"
},
"files": [
".env",
".env.dev"
]
},
"symfony/form": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.2",
"ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b"
},
"files": [
"config/packages/csrf.yaml"
]
},
"symfony/framework-bundle": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.3",
"ref": "5a1497d539f691b96afd45ae397ce5fe30beb4b9"
},
"files": [
"config/packages/cache.yaml",
"config/packages/framework.yaml",
"config/preload.php",
"config/routes/framework.yaml",
"config/services.yaml",
"public/index.php",
"src/Controller/.gitignore",
"src/Kernel.php",
".editorconfig"
]
},
"symfony/mailer": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "4.3",
"ref": "09051cfde49476e3c12cd3a0e44289ace1c75a4f"
},
"files": [
"config/packages/mailer.yaml"
]
},
"symfony/maker-bundle": {
"version": "1.64",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/messenger": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.0",
"ref": "ba1ac4e919baba5644d31b57a3284d6ba12d52ee"
},
"files": [
"config/packages/messenger.yaml"
]
},
"symfony/monolog-bundle": {
"version": "3.10",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.7",
"ref": "aff23899c4440dd995907613c1dd709b6f59503f"
},
"files": [
"config/packages/monolog.yaml"
]
},
"symfony/notifier": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.0",
"ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc"
},
"files": [
"config/packages/notifier.yaml"
]
},
"symfony/property-info": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.3",
"ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7"
},
"files": [
"config/packages/property_info.yaml"
]
},
"symfony/routing": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "21b72649d5622d8f7da329ffb5afb232a023619d"
},
"files": [
"config/packages/routing.yaml",
"config/routes.yaml"
]
},
"symfony/security-bundle": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "2ae08430db28c8eb4476605894296c82a642028f"
},
"files": [
"config/packages/security.yaml",
"config/routes/security.yaml"
]
},
"symfony/stimulus-bundle": {
"version": "2.30",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.20",
"ref": "c30f782a8910ae9f12e7a1399db607d172d23da6"
},
"files": [
"assets/bootstrap.js",
"assets/controllers.json",
"assets/controllers/csrf_protection_controller.js",
"assets/controllers/hello_controller.js"
]
},
"symfony/translation": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.3",
"ref": "620a1b84865ceb2ba304c8f8bf2a185fbf32a843"
},
"files": [
"config/packages/translation.yaml",
"translations/.gitignore"
]
},
"symfony/twig-bundle": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877"
},
"files": [
"config/packages/twig.yaml",
"templates/base.html.twig"
]
},
"symfony/ux-turbo": {
"version": "2.30",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.20",
"ref": "287f7c6eb6e9b65e422d34c00795b360a787380b"
},
"files": [
"config/packages/ux_turbo.yaml"
]
},
"symfony/validator": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd"
},
"files": [
"config/packages/validator.yaml"
]
},
"symfony/web-profiler-bundle": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.3",
"ref": "a363460c1b0b4a4d0242f2ce1a843ca0f6ac9026"
},
"files": [
"config/packages/web_profiler.yaml",
"config/routes/web_profiler.yaml"
]
},
"symfony/webapp-pack": {
"version": "1.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "7d5c5e282f7e2c36a2c3bbb1504f78456c352407"
},
"files": [
"config/packages/messenger.yaml"
]
},
"symfonycasts/tailwind-bundle": {
"version": "0.11",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "0.8",
"ref": "d0bd0276f74de90adfaa4c6cd74cc0caacd77e0a"
},
"files": [
"config/packages/symfonycasts_tailwind.yaml"
]
},
"twig/extra-bundle": {
"version": "v3.21.0"
}
}

136
templates/base.html.twig Normal file
View File

@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html class="scroll-smooth">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}EC Architektur{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('styles/app.css') }}">
{% endblock %}
</head>
<body class="min-h-screen flex flex-col">
<div>
<span class="">default</span>
<span class="invisible sm:visible">sm</span>
<span class="invisible md:visible">md</span>
<span class="invisible lg:visible">lg</span>
<span class="invisible xl:visible">xl</span>
<span class="invisible 2xl:visible">2xl</span>
</div>
{% set current_path = app.request.get('_route') %}
<nav class="bg-white pt-16 pb-24">
<div class="px-4 sm:px-8 md:px-16 lg:px-32 flex justify-between items-center h-16">
<div class="flex-shrink-0">
<a href="{{ path('home') }}"><img class="max-w-25 md:max-w-50" src="{{ asset('images/logo.png') }}" alt="EC Logo"></a>
</div>
<!-- Desktop Links -->
<div class="hidden md:flex space-x-1">
<span class="px-4 py-4 bg-white text-black">
<span class="py-1 {% if current_path == 'about_me'%}border-b-1 border-black{% endif %}">
<a href="{{ path('about_me') }}" class="font-thin">Über mich</a>
</span>
</span>
<span class="px-4 py-4 bg-white text-black">
<span class="py-1 {% if current_path == 'architecture'%}border-b-1 border-black{% endif %}">
<a href="{{ path('architecture') }}" class="font-thin">Architektur</a>
</span>
</span>
<span class="px-4 py-4 bg-white text-black">
<span class="py-1 {% if current_path == 'building_report'%}border-b-1 border-black{% endif %}">
<a href="{{ path('building_report') }}" class="font-thin">Gutachten</a>
</span>
</span>
<span class="px-4 py-4 bg-black text-white">
<span class="py-1 {% if current_path == 'contact'%}border-b-1 border-white{% endif %}">
<a href="{{ path('contact') }}" class="font-thin">Kontakt</a>
</span>
</span>
</div>
<!-- Hamburger -->
<div class="md:hidden">
<button id="menu-btn" class="focus:outline-none">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
</div>
</div>
<!-- Mobile Drawer -->
<div id="mobile-menu" class="max-h-0 overflow-hidden md:hidden transition-all duration-300 ease-in-out">
<span class="px-3 py-4 bg-white text-black">
<span class="py-1 {% if current_path == 'about_me'%}border-b-1 border-black{% endif %}">
<a href="{{ path('about_me') }}" class="font-thin">Über mich</a>
</span>
</span>
<span class="px-3 py-4 bg-white text-black">
<span class="py-1 {% if current_path == 'architecture'%}border-b-1 border-black{% endif %}">
<a href="{{ path('architecture') }}" class="font-thin">Architektur</a>
</span>
</span>
<span class="px-3 py-4 bg-white text-black">
<span class="py-1 {% if current_path == 'building_report'%}border-b-1 border-black{% endif %}">
<a href="{{ path('building_report') }}" class="font-thin">Gutachten</a>
</span>
</span>
<span class="px-3 py-4 bg-black text-white">
<span class="py-1 {% if current_path == 'contact'%}border-b-1 border-white{% endif %}">
<a href="{{ path('contact') }}" class="font-thin">Kontakt</a>
</span>
</span>
</div>
</nav>
<main class="flex-grow">
{% block body %}{% endblock %}
</main>
<footer class="bg-black text-white">
<div class="px-4 sm:px-8 md:px-16 lg:px-32 pb-16">
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 mt-16 mb-8">
<div>
<p class="text-3xl"><span class="font-semibold">EC</span> <span class="font-thin text-base">ARCHITEKTUR</span></p>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<p class="font-thin mb-4">Hebbelstraße 30</p>
<p class="font-thin mb-4">55127 Mainz, Deutschland</p>
</div>
<div>
<p class="font-thin mb-4">+49 178 8358358</p>
<p class="font-thin mb-4">info@ec-architektur.de</p>
</div>
<div>
<p class="font-thin mb-4"><a href="{{ path('imprint') }}" class="underline">Impressum</a></p>
<p class="font-thin mb-4"><a href="{{ path('data_privacy') }}" class="underline">Datenschutz</a></p>
</div>
</div>
</div>
<!-- Neue Zeile: zentriert -->
<div class="my-8 text-center">
<p class="font-thin text-sm">
© {{ "now"|date("Y") }} Elvan Canalp-Özkorkmaz Alle Rechte vorbehalten.
</p>
</div>
</footer>
</body>
{% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %}
</html>

View File

@@ -0,0 +1,32 @@
{% extends 'base.html.twig' %}
{% block title %}Über mich{% endblock %}
{% block body %}
<div class="grid grid-cols-1 mb-16 md:grid-cols-2 md:gap-8 lg:gap-16">
<!-- Linke Spalte: Bild -->
<div class="h-full md:h-auto md:pl-16 lg:pl-32">
<img
src="{{ asset('/images/on-chair.png') }}"
alt="Elvan Canalp"
class="
w-full h-full object-cover
object-center
md:object-[74%_30%] <!-- Ausschnitt: etwas höher bei kleinen Screens -->
lg:object-[75%_30%] <!-- Standard: Mitte -->
xl:object-[60%_70%] <!-- Ausschnitt: nach unten verschoben bei großen Screens -->
"
>
</div>
<!-- Rechte Spalte: Text -->
<div class="flex flex-col justify-center pl-4 pr-4 md:pr-16 lg:pr-32 pt-8">
<p class="text-5xl mb-8 noto-serif-display-100">Elvan Canalp</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Elvan Canalp-Özkorkmaz (Hannover, 1979) startete 2025 ihre freiberufliche Tätigkeit als Architektin und Sachverständige unter dem Büronamen EC Architektur. Sie absolvierte ihr Studium an der HAWK Hildesheim und Hafencity Universität Hamburg. Schon während des Studiums konnte Sie national & international Erfahrungen sammeln, die sehr realitätsnah waren und teilweise umgesetzt werden konnten.</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Nach dem Studium konnte Sie nahtlos für renommierte Architekturbüros und Projektentwickler Projekte in unterschiedlichen Maßstäben erfolgreich abgewickelt. Dazu zählen u.a. Hochhäuser, Wohnquartiere, Architektur für Mega-Events wie EXPO und Olympische Spiele. Außerdem hat sie vernachlässigte denkmalgeschützte Gebäude mit Achtsamkeit und Präzision den Übergang in die digitale Neuzeit verholfen.</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Zudem bewertete sie diverse Immobilien und brachte die potenziale für nachhaltige Investitionen hervor.</p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,66 @@
{% extends 'base.html.twig' %}
{% block title %}Startseite{% endblock %}
{% block body %}
<div class="grid grid-cols-1 gap-6 mb-32 px-4 sm:px-8 md:px-16 lg:px-32">
<p class="text-5xl noto-serif-display-100">Architektur-</p>
<p class="text-5xl noto-serif-display-100">Leistungen</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-16 mb-16 px-4 sm:px-8 md:px-16 lg:px-32">
<div>
<p class="text-2xl noto-serif-display-100 mb-4">Neubau</p>
<ul>
<li class="font-light text-gray-700 text-base/7">Entwurf & Planung von Neubauten nach HOAI</li>
<li class="font-light text-gray-700 text-base/7">Projektsteuerung für Ihre Vorhaben nach AHO</li>
</ul>
</div>
<div>
<p class="text-2xl noto-serif-display-100 mb-8">Energetische Sanierung</p>
<p class="font-light text-gray-700">Entwurf, Planung & Leitung von Sanierungen</p>
<ul>
<li class="font-light text-gray-700 text-base/7">Einfamilienhäuser</li>
<li class="font-light text-gray-700 text-base/7">Mehrfamilienhäuser</li>
<li class="font-light text-gray-700 text-base/7">Bürogebäude</li>
</ul>
</div>
<div>
<p class="text-2xl noto-serif-display-100 mb-4">Masterpläne, Studien, Wettbewerbe</p>
<ul>
<li class="font-light text-gray-700 text-base/7">Steuerung von Wettbewerben</li>
<li class="font-light text-gray-700 text-base/7">Entwicklung & Erstellung von Gestaltungshandbüchern</li>
<li class="font-light text-gray-700 text-base/7">Mitwirkung an Projektentwicklungsverfahren</li>
<li class="font-light text-gray-700 text-base/7">Erstellung von Machbarkeits- & Vorplanungsstudien</li>
<li class="font-light text-gray-700 text-base/7">Erstellung von Masterplänen</li>
</ul>
</div>
</div>
<hr class="mb-24"/>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6mt-16 mb-32 px-0 sm:px-8 md:px-16 lg:px-32">
<div class="mb-4">
<img src="{{ asset('images/proj1.png') }}" alt="Veranstaltungsgebäude"/>
</div>
<div class="px-4 sm:px-0 md:ml-16">
<p class="text-2xl noto-serif-display-100 mb-8">Veranstaltungsgebäude mit Büroräumen und Café</p>
<p class="font-light text-gray-700 mb-6 text-base/7">In Planung</p>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-16 mb-32 px-0 sm:px-8 md:px-16 lg:px-32">
<div>
<img src="{{ asset('images/proj2.png') }}" alt="Bungalow"/>
</div>
<div class="px-4 sm:px-0 md:ml-16">
<p class="text-2xl noto-serif-display-100 mb-8">Energetische Sanierung Bungalow</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Baujahr 1968</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Sanierung zum KfW 55 - derzeit in Bauphase</p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends 'base.html.twig' %}
{% block title %}Startseite{% endblock %}
{% block body %}
<div class="grid grid-cols-1 mb-32 px-4 sm:px-8 md:px-16 lg:px-32">
<p class="text-5xl mb-8 noto-serif-display-100">Gutachten</p>
<p class="text-2xl mb-8 noto-serif-display-100">Immobilienbewertungen</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Als unabhängige Sachverständige stehe ich Ihnen in allen Fragen rund um die Themen Verkehrswert- bzw. Marktwertgutachten und berate Sie beim Immobilienerwerb oder prüfen bereits vorhandene Wertgutachten.</p>
<p class="font-light text-gray-700 mb-6 text-base/7">Durch meine langjährige Erfahrung als Architektin und Sachverständige biete ich Dienstleistungen auf höchstem Niveau, bin Ansprechpartnerin sowohl für private als auch gewerbliche und öffentliche Kunden für Projekte in unterschiedlichen Maßstäben.</p>
</div>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends 'base.html.twig' %}
{% block title %}Startseite{% endblock %}
{% block body %}
KONTAKTFORMULAR
{% endblock %}

View File

@@ -0,0 +1,96 @@
{% extends 'base.html.twig' %}
{% block title %}Datenschutz{% endblock%}
{% block body %}
<div class="grid grid-cols-1 mb-32 px-4 sm:px-8 md:px-16 lg:px-32">
<p class="text-5xl mb-8">Datenschutz</p>
<p class="text-base font-light mb-8">Wir freuen uns über Ihr Interesse an unserer Website. Der Schutz Ihrer persönlichen Daten ist uns ein wichtiges Anliegen. Nachfolgend informieren wir Sie über die Verarbeitung personenbezogener Daten gemäß Art. 13 Datenschutz-Grundverordnung (DSGVO).</p>
<p class="text-2xl mb-2">1. Verantwortliche Stelle</p>
<p class="text-base font-light mb-8">
Elvan Canalp-Özkorkmaz<br/>
Hebbelstraße 30<br/>
55127 Mainz
</p>
<p class="text-2xl mb-2">2. Erhebung und Speicherung personenbezogener Daten sowie Art und Zweck der Verwendung</p>
<p class="text-base font-bold mb-2">a) Beim Besuch der Website</p>
<p class="text-base font-light">Beim Aufrufen unserer Website werden durch den Browser auf Ihrem Endgerät automatisch Informationen an den Server unserer Website gesendet. Diese Informationen werden temporär in sogenannten Logfiles gespeichert. Folgende Informationen werden dabei erfasst:</p>
<ul>
<li>IP-Adresse des anfragenden Rechners</li>
<li>Datum und Uhrzeit des Zugriffs</li>
<li>Name und URL der abgerufenen Datei</li>
<li>Website, von der aus der Zugriff erfolgt (Referrer-URL)</li>
<li>verwendeter Browser und ggf. das Betriebssystem Ihres Rechners</li>
</ul>
<p class="text-base font-light mb-2">Die genannten Daten werden verarbeitet zu Zwecken:</p>
<ul>
<li>Gewährleistung eines reibungslosen Verbindungsaufbaus der Website</li>
<li>Gewährleistung einer komfortablen Nutzung</li>
<li>Auswertung der Systemsicherheit und -stabilität</li>
</ul>
<p class="text-base font-light mb-4">Rechtsgrundlage: Art. 6 Abs. 1 lit. f DSGVO (berechtigtes Interesse).</p>
<p class="text-base font-bold mb-2">b) Bei Nutzung des Kontaktformulars / E-Mail-Kontakts</p>
<p class="text-base font-light mb-2">Wenn Sie uns per Kontaktformular oder E-Mail Anfragen zukommen lassen, werden Ihre Angaben inklusive der von Ihnen angegebenen Kontaktdaten zur Bearbeitung der Anfrage und für den Fall von Anschlussfragen gespeichert.</p>
<p class="text-base font-light mb-8">Rechtsgrundlage: Art. 6 Abs. 1 lit. b DSGVO (Vertragserfüllung bzw. vorvertragliche Maßnahmen).</p>
<p class="text-2xl mb-2">3. Weitergabe von Daten</p>
<p class="text-base font-light">Eine Übermittlung Ihrer persönlichen Daten an Dritte findet nur statt, wenn:</p>
<ul>
<li>Sie Ihre ausdrückliche Einwilligung gegeben haben (Art. 6 Abs. 1 lit. a DSGVO),</li>
<li>die Weitergabe zur Erfüllung eines Vertrags erforderlich ist (Art. 6 Abs. 1 lit. b DSGVO),</li>
<li>eine rechtliche Verpflichtung besteht (Art. 6 Abs. 1 lit. c DSGVO), oder</li>
<li>die Weitergabe zur Wahrung berechtigter Interessen erforderlich ist (Art. 6 Abs. 1 lit. f DSGVO).</li>
</ul>
<p class="text-2xl mb-2">4. Cookies / Analyse-Tools</p>
<p class="text-base font-light mb-8">Unsere Website verwendet keine Cookies oder Analysetools.</p>
<p class="text-2xl mb-2">5. Betroffenenrechte</p>
<p class="text-base font-light">Sie haben das Recht:</p>
<ul>
<li>gemäß Art. 15 DSGVO Auskunft über Ihre gespeicherten Daten zu verlangen,</li>
<li>gemäß Art. 16 DSGVO Berichtigung unrichtiger oder Vervollständigung unvollständiger Daten zu verlangen,</li>
<li>gemäß Art. 17 DSGVO Löschung der gespeicherten Daten zu verlangen,</li>
<li>gemäß Art. 18 DSGVO Einschränkung der Verarbeitung zu verlangen,</li>
<li>gemäß Art. 20 DSGVO Datenübertragbarkeit zu verlangen,</li>
<li>gemäß Art. 21 DSGVO Widerspruch gegen die Verarbeitung einzulegen.</li>
</ul>
<p class="text-base font-light mb-8">Zur Ausübung Ihrer Rechte genügt eine E-Mail an uns.</p>
<p class="text-2xl mb-2">6. Beschwerderecht</p>
<p class="text-base font-light">Sie haben das Recht, sich bei einer Datenschutz-Aufsichtsbehörde über die Verarbeitung Ihrer personenbezogenen Daten durch uns zu beschweren.</p>
<p class="text-base font-light mb-8">Zuständig ist z. B. der/die Landesdatenschutzbeauftragte Rheinland-Pfalz.</p>
<p class="text-2xl mb-2">7. Datensicherheit</p>
<p class="text-base font-light mb-8">Wir verwenden geeignete technische und organisatorische Sicherheitsmaßnahmen, um Ihre Daten gegen Manipulation, Verlust oder unbefugten Zugriff zu schützen.</p>
<p class="text-2xl mb-2">8. Aktualität und Änderung dieser Datenschutzerklärung</p>
<p class="text-base font-light mb-2">Diese Datenschutzerklärung ist aktuell gültig (Stand: {{ "now"|date("F") }} {{ "now"|date("Y") }}).</p>
<p class="text-base font-light mb-8">Wir behalten uns vor, sie bei Bedarf anzupassen.</p>
</div>
{% endblock %}

View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Font-Vergleich</title>
<!-- Google Fonts: nur die dünnsten Varianten -->
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;1,400&family=EB+Garamond:wght@400&family=PT+Serif:wght@400&family=Noto+Serif:wght@200&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
.font-libre { font-family: 'Libre Baskerville', serif; }
.font-ebgaramond { font-family: 'EB Garamond', serif; }
.font-ptserif { font-family: 'PT Serif', serif; }
.font-notoserif { font-family: 'Noto Serif', serif; }
</style>
</head>
<body class="bg-gray-100 p-8">
<h1 class="text-2xl font-bold mb-6">Vergleich Times New Roman ähnliche Schriften (dünnste Varianten)</h1>
<div class="space-y-6">
<div>
<p class="font-libre text-4xl">Architektur</p>
<span class="text-sm text-gray-600">Libre Baskerville (Regular 400 dünnste Variante verfügbar)</span>
</div>
<div>
<p class="font-ebgaramond text-4xl">Architektur</p>
<span class="text-sm text-gray-600">EB Garamond (Regular 400 wirkt sehr filigran)</span>
</div>
<div>
<p class="font-ptserif text-4xl">Architektur</p>
<span class="text-sm text-gray-600">PT Serif (Regular 400 etwas kräftiger)</span>
</div>
<div>
<p class="font-notoserif text-4xl font-thin">Architektur</p>
<span class="text-sm text-gray-600">Noto Serif (ExtraLight 200 deutlich dünner)</span>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,44 @@
{% extends 'base.html.twig' %}
{% block title %}Impressum{% endblock%}
{% block body %}
<div class="grid grid-cols-1 mb-32 px-4 sm:px-8 md:px-16 lg:px-32">
<p class="text-5xl mb-8">Impressum</p>
<p class="text-2xl mb-2">Angaben gemäß § 5 TMG und § 2 DL-InfoV</p>
<p class="text-base font-light">Elvan Canalp-Özkorkmaz</p>
<p class="text-base font-light">Hebbelstraße 30</p>
<p class="text-base font-light mb-8">55127 Mainz</p>
<p class="text-2xl mb-2">Kontakt</p>
<p class="text-base font-light">Telefon: +49 178 8358358</p>
<p class="text-base font-light mb-8">E-Mail: info@ec-architektur.de</p>
<p class="text-2xl mb-2">Berufsbezeichnung</p>
<p class="text-base font-light mb-8">Architektin, verliehen in der Bundesrepublik Deutschland</p>
<p class="text-2xl mb-2">Zuständige Kammer / Aufsichtsbehörde</p>
<p class="text-base font-light">Architektenkammer [Bundesland]</p>
<p class="text-base font-light mb-8">[Adresse der Kammer]</p>
<p class="text-2xl mb-2">Berufsrechtliche Regelungen</p>
<p class="text-base font-light">Es gelten die berufsrechtlichen Bestimmungen, insbesondere das Architektengesetz [Bundesland] und die Berufsordnung der Architektenkammer [Bundesland].</p>
<p class="text-base font-light mb-8">Diese Regelungen sind einsehbar unter: [URL der Kammer mit Rechtsvorschriften]</p>
<p class="text-2xl mb-2">Umsatzsteuer-ID</p>
<p class="text-base font-light mb-8">Umsatzsteuer-Identifikationsnummer gemäß § 27 a Umsatzsteuergesetz: [falls vorhanden eintragen, sonst „nicht vorhanden“]</p>
<p class="text-2xl mb-2">Berufshaftpflichtversicherung</p>
<p class="text-base font-light">[Name und Anschrift der Versicherungsgesellschaft]</p>
<p class="text-base font-light mb-8">Räumlicher Geltungsbereich: [z. B. Deutschland oder EU-Mitgliedsstaaten]</p>
<p class="text-2xl mb-2">Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</p>
<p class="text-base font-light">Elvan Canalp-Özkorkmaz</p>
<p class="text-base font-light">Hebbelstraße 30</p>
<p class="text-base font-light mb-8">55127 Mainz</p>
</div>
{% endblock %}

View File

@@ -0,0 +1,61 @@
{% extends 'base.html.twig' %}
{% block title %}Startseite{% endblock %}
{% block body %}
<div class="grid grid-cols-1 gap-6 mt-16 mb-8 px-4 sm:px-16">
<div>
<p class="text-7xl noto-sans-display-100 mb-4">Architektur gestalten.</p>
<p class="text-7xl noto-sans-display-100 mb-4">Werte sichern.</p>
</div>
<div class="text-right">
&nbsp;
</div>
</div>
<div class="w-full h-[30vh] sm:h-[40vh] md:h-[50vh] lg:h-[60vh] overflow-hidden">
<img
src="{{ asset('images/frankfurt.png') }}"
alt="Frankfurt Panorama"
class="w-full h-full object-cover object-center"
/>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-16 mb-8 px-4 sm:px-16">
<div>
<p class="text-5xl noto-sans-display-100 mb-16">Mission</p>
<p class="font-thin mb-16">Meine Tätigkeit erstrecken sich von der nachhaltigen Sanierung bestehender Gebäude bis hin zur kompletten Planung und Gestaltung neuer Gebäuden. Während meine Projekttypen vielfältig sind, zieht sich ein roter Faden durch den Projekten: der Fokus auf der Verbesserung der Beziehungen zwischen Mensch und Architektur.</p>
</div>
<div class="text-right">
&nbsp;
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8 py-64 px-4 sm:px-16 bg-neutral-800 text-white">
<div>
<p class="text-5xl noto-sans-display-100 mb-16">Deine Projekte real werden lassen.</p>
<p class="font-thin mb-16">Ich bin immer auf der Suche nach neuen Möglichkeiten und arbeiten gerne auch auf internationaler Ebene. Bitte kontaktiere mich um deine Ideen und Projekte tatsächlich umzusetzen. Ich begleite dich bis zum Ende. </p>
</div>
<div class="text-right">
&nbsp;
</div>
<div>
<a href="#" class="px-8 py-4 bg-white text-black">Kontakt</a>
</div>
</div>
{% endblock %}

13
tests/bootstrap.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
use Symfony\Component\Dotenv\Dotenv;
require dirname(__DIR__).'/vendor/autoload.php';
if (method_exists(Dotenv::class, 'bootEnv')) {
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
}
if ($_SERVER['APP_DEBUG']) {
umask(0000);
}

0
translations/.gitignore vendored Normal file
View File