Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# .github/workflows/ci.yml
# Backend CI pipeline for PHP 8.4 with MySQL service, Composer caching
# Runs on PRs to develop and manual dispatch for main branch AWS deployments

name: Backend CI

on:
# Trigger on pull requests targeting develop branch
pull_request:
branches:
- develop
paths:
- 'backend/**'
- '.github/workflows/ci.yml'

# Manual trigger for main branch (AWS deployment gate)
# All tests must pass before pushing to AWS
workflow_dispatch:
branches:
- main

jobs:
backend-tests:
name: Backend Tests
runs-on: ubuntu-latest

# MySQL service container for integration tests
services:
mysql:
image: mysql:8.0
env:
MYSQL_DATABASE: backend_testing
MYSQL_USER: laravel
MYSQL_PASSWORD: laravel_password
MYSQL_ROOT_PASSWORD: root_password
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3

# Redis service for cache/queue/session
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd="redis-cli ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3

defaults:
run:
working-directory: ./backend

steps:
# Checkout the repository code
- name: Checkout code
uses: actions/checkout@v4

# Setup PHP 8.4 with required extensions
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: mbstring, pdo, pdo_mysql, xml, ctype, json, tokenizer, redis
coverage: xdebug

# Wait for MySQL to be ready
- name: Wait for MySQL
run: |
for i in {1..30}; do
if mysqladmin ping -h 127.0.0.1 -u laravel -plaravel_password --silent; then
break
fi
echo "Waiting for MySQL..."
sleep 1
done

# Cache Composer dependencies for faster builds
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: |
~/.composer/cache/files
~/.composer/cache/repo
key: ${{ runner.os }}-composer-${{ hashFiles('backend/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-

# Install Composer dependencies
- name: Install Composer dependencies
run: composer install --no-interaction --prefer-dist --optimize-autoloader

# Generate application key
- name: Generate passport keys
run: php artisan passport:keys

# Run database migrations for testing
- name: Run migrations
env:
DB_HOST: 127.0.0.1
DB_DATABASE: backend_testing
DB_USERNAME: laravel
DB_PASSWORD: laravel_password
REDIS_HOST: 127.0.0.1
run: php artisan migrate --force --env=testing

# Run PHP CS Fixer in dry-run mode to check code style
- name: Check code style
run: |
if [ -f vendor/bin/php-cs-fixer ]; then
vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.dist.php || true
fi

# Run PHPUnit tests
# All tests must pass - failure blocks merge / deployment
- name: Run PHPUnit tests
env:
DB_HOST: 127.0.0.1
DB_DATABASE: backend_testing
DB_USERNAME: laravel
DB_PASSWORD: laravel_password
REDIS_HOST: 127.0.0.1
run: |
if [ -f vendor/bin/phpunit ]; then
vendor/bin/phpunit --testdox --colors=never
else
echo "phpunit not found - skipping tests"
exit 1
fi


# Job-level status check
# Explicitly fail the job if any previous step failed
# This ensures merge / deployment is blocked on test failures
outputs:
tests-passed: ${{ job.status == 'success' }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ vendor/
# Environment
.env.local
.env.*.local
.env

# Logs
storage/logs/
Expand All @@ -38,3 +39,4 @@ Thumbs.db
bootstrap/cache/
storage/framework/cache/

/.php-cs-fixer.cache
2 changes: 1 addition & 1 deletion backend/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ trim_trailing_whitespace = false
indent_size = 2

[{compose,docker-compose}.{yml,yaml}]
indent_size = 4
indent_size = 4
4 changes: 3 additions & 1 deletion backend/.env.docker
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ APP_NAME="Bank Online System"
APP_ENV=local
APP_KEY=base64:GApRAIeV6cXRlYg61WKVW9sz/WemoGBppXgyhgUt4DA=
APP_DEBUG=true
APP_URL=http://localhost:8000
APP_URL=http://127.0.0.1:8000

APP_FRONTEND_URL=http://localhost:5173

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
Expand Down
6 changes: 4 additions & 2 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
APP_NAME="Bank Online System"
APP_ENV=local
APP_KEY=base64:GApRAIeV6cXRlYg61WKVW9sz/WemoGBppXgyhgUt4DA=
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_URL=http://127.0.0.1:8000

APP_FRONTEND_URL=http://localhost:5173

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
Expand Down
73 changes: 73 additions & 0 deletions backend/.env.testing
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
APP_NAME="Bank Online System"
APP_ENV=local
APP_KEY=base64:8l4We7vCbeN9iLHUXIQ4UjZhUtAYTCeyN37gjCqoQsc=
APP_DEBUG=true
APP_URL=http://localhost:8000

PASSPORT_CLIENT_ID=bank-client-id
PASSPORT_CLIENT_SECRET=bank-client-secret
PASSPORT_REDIRECT_URI=http://localhost:5173/auth/callback
PASSPORT_AUTHORIZE_URL=http://localhost:5173/oauth/authorize
PASSPORT_TOKEN_URL=http://localhost:8000/oauth/token
PASSPORT_USER_ENDPOINT=http://localhost:8000/api/user

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US

APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database

# PHP_CLI_SERVER_WORKERS=4

BCRYPT_ROUNDS=12

LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=backend_testing
DB_USERNAME=laravel
DB_PASSWORD=laravel_password

SESSION_DRIVER=cookie
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:5174

BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database

CACHE_DRIVER=redis
CACHE_STORE=redis

MEMCACHED_HOST=127.0.0.1

REDIS_CLIENT=predis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

VITE_APP_NAME="${APP_NAME}"
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.env.production
.phpactor.json
.phpunit.result.cache
.php-cs-fixer.cache
/.codex
/.cursor/
/.idea
Expand Down
62 changes: 62 additions & 0 deletions backend/.php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in([
__DIR__ . '/app',
__DIR__ . '/config',
__DIR__ . '/database',
__DIR__ . '/routes',
__DIR__ . '/tests',
])
->exclude([
'bootstrap',
'storage',
'vendor',
])
->name('*.php')
->notName('*.blade.php')
->ignoreDotFiles(true)
->ignoreVCS(true);

return (new PhpCsFixer\Config())
->setRules([
'@PSR12' => true,
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'no_unused_imports' => true,
'not_operator_with_successor_space' => true,
'trailing_comma_in_multiline' => [
'elements' => ['arrays', 'arguments', 'parameters'],
],
'phpdoc_scalar' => true,
'unary_operator_spaces' => true,
'binary_operator_spaces' => [
'default' => 'align_single_space_minimal',
],
'blank_line_before_statement' => [
'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_var_without_name' => true,
'class_attributes_separation' => [
'elements' => [
'method' => 'one',
],
],
'method_argument_space' => [
'on_multiline' => 'ensure_fully_multiline',
'keep_multiple_spaces_after_comma' => true,
],
'single_trait_insert_per_statement' => true,
'declare_strict_types' => false,
'blank_line_after_opening_tag' => false,
'strict_comparison' => true,
'cast_spaces' => true,
'concat_space' => ['spacing' => 'one'],
'types_spaces' => true,
'modernize_strpos' => true,
])
->setFinder($finder)
->setRiskyAllowed(true)
->setUsingCache(true);
11 changes: 0 additions & 11 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,9 @@ RUN docker-php-ext-install pdo pdo_mysql

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

COPY ./docker/nginx.conf /etc/nginx/http.d/default.conf
COPY ./docker/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf
COPY ./docker/supervisord.conf /etc/supervisord.conf

RUN mkdir -p storage/logs bootstrap/cache && chmod -R 775 storage bootstrap/cache

#COPY ./docker/entrypoint.sh /entrypoint.sh
#RUN chmod +x /entrypoint.sh

COPY docker/entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh

EXPOSE 80

#ENTRYPOINT ["/entrypoint.sh"]

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
6 changes: 3 additions & 3 deletions backend/app/Console/Commands/Generator/ServiceCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ protected function makeDirectory(string $path): void
{
$directory = dirname($path);

if (!$this->filesystem->isDirectory($directory)) {
if (! $this->filesystem->isDirectory($directory)) {
$this->filesystem->makeDirectory($directory, 0755, true, true);
}
}

protected function buildClass(string $name): string
{
$namespace = 'App\\Services';
$extends = 'Service';
$extends = 'Service';

$className = class_basename($name);

Expand All @@ -71,7 +71,7 @@ protected function buildClass(string $name): string
"<?php\n\nnamespace %s;\n\nuse App\\Services\\Service;\n\nclass %s extends %s\n{\n \n}\n",
$namespace,
$className,
$extends
$extends,
);
}
}
Loading
Loading