7 files changed
+312
-23
No files matched your search
+20
-15
@@ -1,21 +1,26 @@
|
||||
node_modules
|
||||
.next
|
||||
generated
|
||||
.git
|
||||
.gitea
|
||||
.github
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# The previous Next.js application is intentionally outside this build.
|
||||
legacy-nextjs
|
||||
|
||||
node_modules
|
||||
vendor
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.local.example
|
||||
test-results
|
||||
playwright-report
|
||||
blob-report
|
||||
playwright/.cache
|
||||
coverage
|
||||
storage/logs/*
|
||||
storage/framework/cache/data/*
|
||||
storage/framework/sessions/*
|
||||
storage/framework/views/*
|
||||
bootstrap/cache/*.php
|
||||
public/build
|
||||
docker-compose*.yml
|
||||
docker-compose*.yaml
|
||||
*.log
|
||||
tests
|
||||
e2e
|
||||
docs
|
||||
*.md
|
||||
.vscode
|
||||
.idea
|
||||
.DS_Store
|
||||
npm-debug.log*
|
||||
templates
|
||||
+9
-4
@@ -2,7 +2,7 @@ APP_NAME=NextChair
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost:8000
|
||||
APP_URL=http://localhost:8085
|
||||
APP_DEFAULT_BUSINESS_SLUG=
|
||||
|
||||
APP_LOCALE=en
|
||||
@@ -22,11 +22,16 @@ LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_HOST=db
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=nextchair
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
DB_USERNAME=nextchair
|
||||
DB_PASSWORD=change-me
|
||||
DB_ROOT_PASSWORD=change-me-root
|
||||
|
||||
# Docker publishes Nginx on this local bind address by default.
|
||||
NEXTCHAIR_HTTP_BIND=127.0.0.1
|
||||
NEXTCHAIR_HTTP_PORT=8085
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:22-bookworm-slim AS frontend
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY resources ./resources
|
||||
COPY public ./public
|
||||
COPY vite.config.js .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
|
||||
FROM composer:2 AS composer
|
||||
|
||||
|
||||
FROM php:8.4-fpm-bookworm AS app
|
||||
|
||||
ENV COMPOSER_ALLOW_SUPERUSER=1 \
|
||||
PHP_OPCACHE_VALIDATE_TIMESTAMPS=0
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gosu \
|
||||
libfreetype6-dev \
|
||||
libicu-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libonig-dev \
|
||||
libpng-dev \
|
||||
libxml2-dev \
|
||||
libzip-dev \
|
||||
unzip \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install -j"$(nproc)" \
|
||||
bcmath \
|
||||
exif \
|
||||
gd \
|
||||
intl \
|
||||
mbstring \
|
||||
opcache \
|
||||
pcntl \
|
||||
pdo_mysql \
|
||||
xml \
|
||||
zip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
|
||||
COPY . .
|
||||
COPY --from=frontend /var/www/html/public/build ./public/build
|
||||
|
||||
RUN composer install --no-dev --optimize-autoloader --no-interaction --prefer-dist \
|
||||
&& mkdir -p \
|
||||
storage/framework/cache/data \
|
||||
storage/framework/sessions \
|
||||
storage/framework/views \
|
||||
storage/logs \
|
||||
bootstrap/cache \
|
||||
&& chown -R www-data:www-data storage bootstrap/cache \
|
||||
&& chmod -R ug+rwX storage bootstrap/cache
|
||||
|
||||
COPY docker/entrypoint.sh /usr/local/bin/nextchair-entrypoint
|
||||
RUN chmod +x /usr/local/bin/nextchair-entrypoint
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/nextchair-entrypoint"]
|
||||
CMD ["php-fpm", "-F"]
|
||||
|
||||
|
||||
FROM nginx:1.27-alpine AS nginx
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
COPY public ./public
|
||||
COPY --from=frontend /var/www/html/public/build ./public/build
|
||||
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
RUN mkdir -p /var/www/html/storage/app/public \
|
||||
&& ln -s /var/www/html/storage/app/public /var/www/html/public/storage
|
||||
@@ -5,10 +5,9 @@ The application is being rebuilt as a conventional Laravel web application
|
||||
using PHP, MySQL, Blade, Tailwind CSS, Alpine.js, and Vite.
|
||||
|
||||
The audited Next.js implementation is preserved in [`legacy-nextjs`](legacy-nextjs)
|
||||
as the functional and visual migration reference. Deployment-specific files
|
||||
from the previous implementation are retained there for reference only; the
|
||||
Laravel application does not manage Docker, Caddy, Nginx, or server
|
||||
provisioning.
|
||||
as the functional and visual migration reference. The Laravel application has
|
||||
its own deployment-neutral Docker option at the repository root; files inside
|
||||
`legacy-nextjs` are not used by it.
|
||||
|
||||
## Local development
|
||||
|
||||
@@ -26,6 +25,51 @@ application resolves a business from the request hostname through the
|
||||
`business_domains` table. Local development can use a configured local domain
|
||||
or the `APP_DEFAULT_BUSINESS_SLUG` fallback.
|
||||
|
||||
## Docker deployment
|
||||
|
||||
The root `compose.yaml` runs Laravel with PHP 8.4 FPM, Nginx, MySQL 8,
|
||||
the database-backed queue worker, and the scheduler. It does not include or
|
||||
configure Caddy; an existing reverse proxy can forward traffic to Nginx on
|
||||
`127.0.0.1:8085`.
|
||||
|
||||
First run:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Set private values in `.env`, including:
|
||||
|
||||
```dotenv
|
||||
APP_URL=http://localhost:8085
|
||||
APP_KEY=
|
||||
DB_HOST=db
|
||||
DB_DATABASE=nextchair
|
||||
DB_USERNAME=nextchair
|
||||
DB_PASSWORD=replace-with-a-private-password
|
||||
DB_ROOT_PASSWORD=replace-with-a-private-root-password
|
||||
```
|
||||
|
||||
Then build and start the stack:
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
docker compose exec app php artisan key:generate
|
||||
docker compose exec app php artisan migrate
|
||||
```
|
||||
|
||||
Migrations are intentionally not run by container startup. To inspect the
|
||||
application logs:
|
||||
|
||||
```bash
|
||||
docker compose logs -f app nginx queue scheduler db
|
||||
```
|
||||
|
||||
The default host binding is `127.0.0.1:8085:80`. Override it with
|
||||
`NEXTCHAIR_HTTP_BIND` and `NEXTCHAIR_HTTP_PORT` in `.env` when needed. MySQL
|
||||
has no published host port and is reachable only as `db:3306` inside Compose.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: app
|
||||
image: nextchair-laravel:latest
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
APP_ENV: ${APP_ENV:-production}
|
||||
APP_DEBUG: ${APP_DEBUG:-false}
|
||||
APP_URL: ${APP_URL:-http://localhost:8085}
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: db
|
||||
DB_PORT: 3306
|
||||
DB_DATABASE: ${DB_DATABASE:-nextchair}
|
||||
DB_USERNAME: ${DB_USERNAME:-nextchair}
|
||||
DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD in .env}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- nextchair_storage:/var/www/html/storage
|
||||
|
||||
nginx:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: nginx
|
||||
image: nextchair-nginx:latest
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- app
|
||||
ports:
|
||||
- "${NEXTCHAIR_HTTP_BIND:-127.0.0.1}:${NEXTCHAIR_HTTP_PORT:-8085}:80"
|
||||
volumes:
|
||||
- nextchair_storage:/var/www/html/storage:ro
|
||||
|
||||
db:
|
||||
image: mysql:8.4
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_DATABASE: ${DB_DATABASE:-nextchair}
|
||||
MYSQL_USER: ${DB_USERNAME:-nextchair}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD in .env}
|
||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:?Set DB_ROOT_PASSWORD in .env}
|
||||
volumes:
|
||||
- nextchair_mysql_data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD --silent"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 20s
|
||||
|
||||
queue:
|
||||
image: nextchair-laravel:latest
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
APP_ENV: ${APP_ENV:-production}
|
||||
APP_DEBUG: ${APP_DEBUG:-false}
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: db
|
||||
DB_PORT: 3306
|
||||
DB_DATABASE: ${DB_DATABASE:-nextchair}
|
||||
DB_USERNAME: ${DB_USERNAME:-nextchair}
|
||||
DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD in .env}
|
||||
command: ["php", "artisan", "queue:work", "--sleep=3", "--tries=3", "--timeout=90"]
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- nextchair_storage:/var/www/html/storage
|
||||
|
||||
scheduler:
|
||||
image: nextchair-laravel:latest
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
APP_ENV: ${APP_ENV:-production}
|
||||
APP_DEBUG: ${APP_DEBUG:-false}
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: db
|
||||
DB_PORT: 3306
|
||||
DB_DATABASE: ${DB_DATABASE:-nextchair}
|
||||
DB_USERNAME: ${DB_USERNAME:-nextchair}
|
||||
DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD in .env}
|
||||
command: ["php", "artisan", "schedule:work"]
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- nextchair_storage:/var/www/html/storage
|
||||
|
||||
volumes:
|
||||
nextchair_mysql_data:
|
||||
nextchair_storage:
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
mkdir -p \
|
||||
storage/framework/cache/data \
|
||||
storage/framework/sessions \
|
||||
storage/framework/views \
|
||||
storage/logs \
|
||||
bootstrap/cache
|
||||
|
||||
chown -R www-data:www-data storage bootstrap/cache
|
||||
chmod -R ug+rwX storage bootstrap/cache
|
||||
|
||||
# This is safe to run on every start and does not perform migrations.
|
||||
php artisan storage:link --force >/dev/null 2>&1 || true
|
||||
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
exec gosu www-data "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -0,0 +1,26 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/html/public$fastcgi_script_name;
|
||||
fastcgi_param DOCUMENT_ROOT /var/www/html/public;
|
||||
fastcgi_pass app:9000;
|
||||
fastcgi_read_timeout 90s;
|
||||
}
|
||||
|
||||
location ~ /\. { deny all; }
|
||||
}
|
||||
Reference in new issue
Block a user