Refactor Docker configuration and development setup
- Update .dockerignore with comprehensive ignore patterns for API and client - Modify docker-compose files to improve service configurations - Enhance Nginx configuration for development and production environments - Refactor Dockerfile.api with improved build process - Add docker-setup.sh script for simplified Docker deployment - Update update-credentials.vue page with improved UI - Remove hCaptcha dependency from package-lock.json - Update PHP configuration and entrypoint scripts
This commit is contained in:
parent
bf85d8fa76
commit
f7df6bc0d7
|
|
@ -2,3 +2,38 @@
|
||||||
/Dockerfile
|
/Dockerfile
|
||||||
/data
|
/data
|
||||||
\.env
|
\.env
|
||||||
|
|
||||||
|
# API ignores
|
||||||
|
api/vendor/
|
||||||
|
api/storage/framework/
|
||||||
|
api/storage/logs/
|
||||||
|
api/storage/app/
|
||||||
|
api/.env
|
||||||
|
api/.env.*
|
||||||
|
api/.git/
|
||||||
|
api/.idea/
|
||||||
|
api/.vscode/
|
||||||
|
api/node_modules/
|
||||||
|
api/*.log
|
||||||
|
|
||||||
|
# Client ignores
|
||||||
|
client/node_modules/
|
||||||
|
client/.nuxt/
|
||||||
|
client/dist/
|
||||||
|
client/.output/
|
||||||
|
client/coverage/
|
||||||
|
client/.env
|
||||||
|
client/.env.*
|
||||||
|
client/.git/
|
||||||
|
client/.idea/
|
||||||
|
client/.vscode/
|
||||||
|
client/npm-debug.log*
|
||||||
|
client/yarn-debug.log*
|
||||||
|
client/yarn-error.log*
|
||||||
|
|
||||||
|
# Global ignores
|
||||||
|
**/.DS_Store
|
||||||
|
**/*.log
|
||||||
|
**/.git/
|
||||||
|
**/.idea/
|
||||||
|
**/.vscode/
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ on:
|
||||||
- "client/**"
|
- "client/**"
|
||||||
- "docker/**"
|
- "docker/**"
|
||||||
- "docker-compose*.yml"
|
- "docker-compose*.yml"
|
||||||
|
- ".github/workflows/dockerhub.yml"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|
@ -30,8 +31,8 @@ jobs:
|
||||||
echo "UI_TAGS=${{secrets.DOCKER_UI_REPO}}:latest,${{secrets.DOCKER_UI_REPO}}:${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
|
echo "UI_TAGS=${{secrets.DOCKER_UI_REPO}}:latest,${{secrets.DOCKER_UI_REPO}}:${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo "VERSION=dev" >> $GITHUB_ENV
|
echo "VERSION=dev" >> $GITHUB_ENV
|
||||||
echo "API_TAGS=${{secrets.DOCKER_API_REPO}}:dev" >> $GITHUB_ENV
|
echo "API_TAGS=${{secrets.DOCKER_API_REPO}}:dev,${{secrets.DOCKER_API_REPO}}:dev-${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||||
echo "UI_TAGS=${{secrets.DOCKER_UI_REPO}}:dev" >> $GITHUB_ENV
|
echo "UI_TAGS=${{secrets.DOCKER_UI_REPO}}:dev,${{secrets.DOCKER_UI_REPO}}:dev-${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
|
|
@ -59,6 +60,8 @@ jobs:
|
||||||
build-args: |
|
build-args: |
|
||||||
APP_ENV=${{ env.VERSION == 'dev' && 'local' || 'production' }}
|
APP_ENV=${{ env.VERSION == 'dev' && 'local' || 'production' }}
|
||||||
tags: ${{ env.API_TAGS }}
|
tags: ${{ env.API_TAGS }}
|
||||||
|
cache-from: type=registry,ref=${{secrets.DOCKER_API_REPO}}:dev
|
||||||
|
cache-to: type=inline
|
||||||
|
|
||||||
- name: Build and push Client image
|
- name: Build and push Client image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
|
|
@ -68,3 +71,5 @@ jobs:
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ env.UI_TAGS }}
|
tags: ${{ env.UI_TAGS }}
|
||||||
|
cache-from: type=registry,ref=${{secrets.DOCKER_UI_REPO}}:dev
|
||||||
|
cache-to: type=inline
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ namespace App\Http;
|
||||||
use App\Http\Middleware\AcceptsJsonMiddleware;
|
use App\Http\Middleware\AcceptsJsonMiddleware;
|
||||||
use App\Http\Middleware\AuthenticateJWT;
|
use App\Http\Middleware\AuthenticateJWT;
|
||||||
use App\Http\Middleware\CustomDomainRestriction;
|
use App\Http\Middleware\CustomDomainRestriction;
|
||||||
|
use App\Http\Middleware\DevCorsMiddleware;
|
||||||
use App\Http\Middleware\ImpersonationMiddleware;
|
use App\Http\Middleware\ImpersonationMiddleware;
|
||||||
use App\Http\Middleware\IsAdmin;
|
use App\Http\Middleware\IsAdmin;
|
||||||
use App\Http\Middleware\IsModerator;
|
use App\Http\Middleware\IsModerator;
|
||||||
|
|
@ -25,6 +26,7 @@ class Kernel extends HttpKernel
|
||||||
protected $middleware = [
|
protected $middleware = [
|
||||||
// \App\Http\Middleware\TrustHosts::class,
|
// \App\Http\Middleware\TrustHosts::class,
|
||||||
\App\Http\Middleware\TrustProxies::class,
|
\App\Http\Middleware\TrustProxies::class,
|
||||||
|
DevCorsMiddleware::class,
|
||||||
\Illuminate\Http\Middleware\HandleCors::class,
|
\Illuminate\Http\Middleware\HandleCors::class,
|
||||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
|
|
@ -66,7 +68,7 @@ class Kernel extends HttpKernel
|
||||||
],
|
],
|
||||||
|
|
||||||
'api-external' => [
|
'api-external' => [
|
||||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class DevCorsMiddleware
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
// Only apply in development mode
|
||||||
|
if (!config('app.dev_cors')) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $next($request);
|
||||||
|
|
||||||
|
// Handle preflight OPTIONS request
|
||||||
|
if ($request->isMethod('OPTIONS')) {
|
||||||
|
$response = response('', 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CORS headers
|
||||||
|
$response->headers->set('Access-Control-Allow-Origin', 'http://localhost:3000', true);
|
||||||
|
$response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH', true);
|
||||||
|
$response->headers->set('Access-Control-Allow-Headers', 'DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization, X-XSRF-TOKEN, Accept', true);
|
||||||
|
$response->headers->set('Access-Control-Allow-Credentials', 'true', true);
|
||||||
|
$response->headers->set('Access-Control-Expose-Headers', 'Content-Length, Content-Range', true);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,6 +28,8 @@ return [
|
||||||
|
|
||||||
'env' => env('APP_ENV', 'production'),
|
'env' => env('APP_ENV', 'production'),
|
||||||
|
|
||||||
|
'dev_cors' => env('APP_DEV_CORS', false),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Application Debug Mode
|
| Application Debug Mode
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
/Dockerfile
|
|
||||||
/.dockerignore
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Remember Me -->
|
<!-- Remember Me -->
|
||||||
<div class="relative flex items-start mt-5">
|
<div class="relative flex items-center mt-3">
|
||||||
<CheckboxInput
|
<CheckboxInput
|
||||||
v-model="remember"
|
v-model="remember"
|
||||||
class="w-full md:w-1/2"
|
class="w-full md:w-1/2"
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button
|
<v-button
|
||||||
class="w-full flex"
|
class="w-full flex mt-2"
|
||||||
:loading="form.busy || loading"
|
:loading="form.busy || loading"
|
||||||
>
|
>
|
||||||
Log in to continue
|
Log in to continue
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ import { useFeatureFlagsStore } from '~/stores/featureFlags'
|
||||||
export default defineNuxtRouteMiddleware(async () => {
|
export default defineNuxtRouteMiddleware(async () => {
|
||||||
const featureFlagsStore = useFeatureFlagsStore()
|
const featureFlagsStore = useFeatureFlagsStore()
|
||||||
|
|
||||||
if (import.meta.server && Object.keys(featureFlagsStore.flags).length === 0) {
|
// Load flags if they haven't been loaded yet
|
||||||
|
if (!featureFlagsStore.isLoaded) {
|
||||||
await featureFlagsStore.fetchFlags()
|
await featureFlagsStore.fetchFlags()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
export default defineNuxtRouteMiddleware(() => {
|
export default defineNuxtRouteMiddleware(async () => {
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
const featureFlagsStore = useFeatureFlagsStore()
|
||||||
|
|
||||||
|
// Ensure feature flags are loaded
|
||||||
|
if (!featureFlagsStore.isLoaded) {
|
||||||
|
await featureFlagsStore.fetchFlags()
|
||||||
|
}
|
||||||
|
|
||||||
if (useFeatureFlag('self_hosted')) {
|
if (useFeatureFlag('self_hosted')) {
|
||||||
if (authStore.check && authStore.user?.email === 'admin@opnform.com') {
|
if (authStore.check && authStore.user?.email === 'admin@opnform.com') {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
"@codemirror/lang-html": "^6.4.9",
|
||||||
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
|
||||||
"@iconify-json/material-symbols": "^1.2.4",
|
"@iconify-json/material-symbols": "^1.2.4",
|
||||||
"@nuxt/ui": "^2.19.2",
|
"@nuxt/ui": "^2.19.2",
|
||||||
"@pinia/nuxt": "^0.5.5",
|
"@pinia/nuxt": "^0.5.5",
|
||||||
|
|
@ -1338,18 +1337,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@hcaptcha/vue3-hcaptcha": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@hcaptcha/vue3-hcaptcha/-/vue3-hcaptcha-1.3.0.tgz",
|
|
||||||
"integrity": "sha512-IEonS6JiYdU7uy6aeib8cYtMO4nj8utwStbA9bWHyYbOvOvhpkV+AW8vfSKh6SntYxqle/TRwhv+kU9p92CfsA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"vue": "^3.2.19"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"vue": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@headlessui/tailwindcss": {
|
"node_modules/@headlessui/tailwindcss": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-white">
|
<div class="bg-white" v-if="workspace">
|
||||||
<div class="flex bg-gray-50 pb-5 border-b">
|
<div class="flex bg-gray-50 pb-5 border-b">
|
||||||
<div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl p-4">
|
<div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl p-4">
|
||||||
<div class="pt-4 pb-0">
|
<div class="pt-4 pb-0">
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
Your Forms
|
Your Forms
|
||||||
</h2>
|
</h2>
|
||||||
<v-button
|
<v-button
|
||||||
v-if="!workspace.is_readonly"
|
v-if="!workspace?.is_readonly"
|
||||||
v-track.create_form_click
|
v-track.create_form_click
|
||||||
:to="{ name: 'forms-create' }"
|
:to="{ name: 'forms-create' }"
|
||||||
>
|
>
|
||||||
|
|
@ -87,7 +87,7 @@
|
||||||
again.
|
again.
|
||||||
</div>
|
</div>
|
||||||
<v-button
|
<v-button
|
||||||
v-if="!workspace.is_readonly && forms.length === 0"
|
v-if="!workspace?.is_readonly && forms.length === 0"
|
||||||
v-track.create_form_click
|
v-track.create_form_click
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
:to="{ name: 'forms-create' }"
|
:to="{ name: 'forms-create' }"
|
||||||
|
|
@ -182,7 +182,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="!workspace.is_pro"
|
v-if="!workspace?.is_pro"
|
||||||
class="px-4"
|
class="px-4"
|
||||||
>
|
>
|
||||||
<UAlert
|
<UAlert
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,74 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<div class=" bg-gray-50 flex flex-col justify-center sm:px-6 lg:px-8 py-10 flex-grow">
|
||||||
:show="showModal"
|
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
max-width="lg"
|
<h2 class="text-center text-3xl font-bold tracking-tight text-gray-900">
|
||||||
@close="logout"
|
|
||||||
>
|
|
||||||
<div class="">
|
|
||||||
<h2 class="font-medium text-3xl mb-3">
|
|
||||||
Welcome to OpnForm!
|
Welcome to OpnForm!
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-sm text-gray-600">
|
<p class="mt-2 text-center text-sm text-gray-600">
|
||||||
You're using the self-hosted version of OpnForm and need to set up your account.
|
You're using the self-hosted version of OpnForm and need to set up your account.
|
||||||
Please enter your email and create a password to continue.
|
Please enter your email and create a password to continue.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
class="mt-4"
|
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
|
||||||
@submit.prevent="updateCredentials"
|
<form
|
||||||
@keydown="form.onKeydown($event)"
|
@submit.prevent="updateCredentials"
|
||||||
>
|
@keydown="form.onKeydown($event)"
|
||||||
<!-- Email -->
|
>
|
||||||
<text-input
|
<!-- Email -->
|
||||||
name="email"
|
<text-input
|
||||||
:form="form"
|
name="email"
|
||||||
label="Email"
|
:form="form"
|
||||||
:required="true"
|
label="Email"
|
||||||
placeholder="Your email address"
|
:required="true"
|
||||||
/>
|
placeholder="Your email address"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<text-input
|
<text-input
|
||||||
native-type="password"
|
native-type="password"
|
||||||
placeholder="Your password"
|
placeholder="Your password"
|
||||||
name="password"
|
name="password"
|
||||||
:form="form"
|
:form="form"
|
||||||
label="Password"
|
label="Password"
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Password Confirmation-->
|
<!-- Password Confirmation-->
|
||||||
<text-input
|
<text-input
|
||||||
native-type="password"
|
native-type="password"
|
||||||
:form="form"
|
:form="form"
|
||||||
:required="true"
|
:required="true"
|
||||||
placeholder="Enter confirm password"
|
placeholder="Enter confirm password"
|
||||||
name="password_confirmation"
|
name="password_confirmation"
|
||||||
label="Confirm Password"
|
label="Confirm Password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button
|
<div class="mt-6">
|
||||||
class="mx-auto"
|
<v-button
|
||||||
:loading="form.busy || loading"
|
class="w-full justify-center"
|
||||||
>
|
:loading="form.busy || loading"
|
||||||
Update Credentials
|
>
|
||||||
</v-button>
|
Update Credentials
|
||||||
</form>
|
</v-button>
|
||||||
</modal>
|
</div>
|
||||||
|
|
||||||
|
<!-- Cancel Link -->
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="text-sm text-gray-600 hover:text-gray-900"
|
||||||
|
@click="logout"
|
||||||
|
>
|
||||||
|
Cancel and return to login
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
@ -67,7 +79,7 @@ const workspacesStore = useWorkspacesStore()
|
||||||
const formsStore = useFormsStore()
|
const formsStore = useFormsStore()
|
||||||
const user = computed(() => authStore.user)
|
const user = computed(() => authStore.user)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const showModal = ref(true)
|
const loading = ref(false)
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
name: "",
|
name: "",
|
||||||
email: "",
|
email: "",
|
||||||
|
|
@ -82,6 +94,7 @@ onMounted(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const updateCredentials = () => {
|
const updateCredentials = () => {
|
||||||
|
loading.value = true
|
||||||
form
|
form
|
||||||
.post("update-credentials")
|
.post("update-credentials")
|
||||||
.then(async (data) => {
|
.then(async (data) => {
|
||||||
|
|
@ -95,11 +108,13 @@ const updateCredentials = () => {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
useAlert().error(error.response._data.message)
|
useAlert().error(error.response._data.message)
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
authStore.logout()
|
authStore.logout()
|
||||||
showModal.value = false
|
|
||||||
router.push({ name: "login" })
|
router.push({ name: "login" })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -3,11 +3,15 @@ import { ref } from 'vue'
|
||||||
|
|
||||||
export const useFeatureFlagsStore = defineStore('feature_flags', () => {
|
export const useFeatureFlagsStore = defineStore('feature_flags', () => {
|
||||||
const flags = ref({})
|
const flags = ref({})
|
||||||
|
const isLoaded = ref(false)
|
||||||
|
|
||||||
async function fetchFlags() {
|
async function fetchFlags() {
|
||||||
|
if (isLoaded.value) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await useOpnApi('content/feature-flags')
|
const { data } = await useOpnApi('content/feature-flags')
|
||||||
flags.value = data.value
|
flags.value = data.value
|
||||||
|
isLoaded.value = true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch feature flags:', error)
|
console.error('Failed to fetch feature flags:', error)
|
||||||
}
|
}
|
||||||
|
|
@ -20,5 +24,5 @@ export const useFeatureFlagsStore = defineStore('feature_flags', () => {
|
||||||
}, flags.value)
|
}, flags.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { flags, fetchFlags, getFlag }
|
return { flags, isLoaded, fetchFlags, getFlag }
|
||||||
})
|
})
|
||||||
|
|
@ -1,35 +1,70 @@
|
||||||
services:
|
services:
|
||||||
api: &api-base
|
api: &api-base
|
||||||
image: jhumanj/opnform-api:dev
|
image: jhumanj/opnform-api:dev
|
||||||
|
container_name: opnform-api
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/Dockerfile.api
|
dockerfile: docker/Dockerfile.api
|
||||||
args:
|
args:
|
||||||
APP_ENV: local
|
- APP_ENV=local
|
||||||
volumes:
|
volumes: &api-base-volumes
|
||||||
- ./api:/usr/share/nginx/html:delegated
|
- ./api:/usr/share/nginx/html:delegated
|
||||||
- /usr/share/nginx/html/vendor # Exclude vendor directory from the mount
|
- /usr/share/nginx/html/vendor # Exclude vendor directory from the mount
|
||||||
- ./api/storage:/usr/share/nginx/html/storage:delegated # Mount storage directory directly
|
- ./api/storage:/usr/share/nginx/html/storage:delegated
|
||||||
environment:
|
environment: &api-base-env
|
||||||
|
APP_ENV: local
|
||||||
|
APP_DEV_CORS: "true"
|
||||||
|
IS_API_WORKER: "false"
|
||||||
|
# Database settings
|
||||||
DB_HOST: db
|
DB_HOST: db
|
||||||
REDIS_HOST: redis
|
REDIS_HOST: redis
|
||||||
DB_DATABASE: ${DB_DATABASE:-forge}
|
DB_DATABASE: ${DB_DATABASE:-forge}
|
||||||
DB_USERNAME: ${DB_USERNAME:-forge}
|
DB_USERNAME: ${DB_USERNAME:-forge}
|
||||||
DB_PASSWORD: ${DB_PASSWORD:-forge}
|
DB_PASSWORD: ${DB_PASSWORD:-forge}
|
||||||
DB_CONNECTION: ${DB_CONNECTION:-pgsql}
|
DB_CONNECTION: ${DB_CONNECTION:-pgsql}
|
||||||
|
# Storage settings
|
||||||
FILESYSTEM_DISK: local
|
FILESYSTEM_DISK: local
|
||||||
LOCAL_FILESYSTEM_VISIBILITY: public
|
LOCAL_FILESYSTEM_VISIBILITY: public
|
||||||
APP_ENV: local
|
# Development settings
|
||||||
PHP_IDE_CONFIG: "serverName=Docker"
|
PHP_IDE_CONFIG: serverName=Docker
|
||||||
XDEBUG_MODE: "${XDEBUG_MODE:-off}"
|
XDEBUG_MODE: ${XDEBUG_MODE:-off}
|
||||||
XDEBUG_CONFIG: "client_host=host.docker.internal"
|
XDEBUG_CONFIG: client_host=host.docker.internal
|
||||||
APP_URL: "http://localhost"
|
APP_URL: http://localhost
|
||||||
|
FRONT_URL: http://localhost:3000
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
|
api-worker:
|
||||||
|
<<: *api-base
|
||||||
|
container_name: opnform-api-worker
|
||||||
|
command: ["php", "artisan", "queue:work"]
|
||||||
|
volumes: *api-base-volumes
|
||||||
|
environment:
|
||||||
|
<<: *api-base-env
|
||||||
|
APP_ENV: local
|
||||||
|
IS_API_WORKER: "true"
|
||||||
|
|
||||||
|
api-scheduler:
|
||||||
|
<<: *api-base
|
||||||
|
container_name: opnform-api-scheduler
|
||||||
|
command: ["php", "artisan", "schedule:work"]
|
||||||
|
volumes: *api-base-volumes
|
||||||
|
environment:
|
||||||
|
<<: *api-base-env
|
||||||
|
APP_ENV: local
|
||||||
|
IS_API_WORKER: "true"
|
||||||
|
AUTORUN_ENABLED: "false"
|
||||||
|
# Scheduler settings
|
||||||
|
CONTAINER_ROLE: scheduler
|
||||||
|
PHP_MEMORY_LIMIT: 512M
|
||||||
|
PHP_MAX_EXECUTION_TIME: 60
|
||||||
|
|
||||||
ui:
|
ui:
|
||||||
image: jhumanj/opnform-client:dev
|
image: jhumanj/opnform-client:dev
|
||||||
|
container_name: opnform-client
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/Dockerfile.client
|
dockerfile: docker/Dockerfile.client
|
||||||
|
|
@ -57,6 +92,8 @@ services:
|
||||||
- "24678:24678" # Vite HMR port
|
- "24678:24678" # Vite HMR port
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
|
image: nginx:1
|
||||||
|
container_name: opnform-ingress
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/nginx.dev.conf:/etc/nginx/templates/default.conf.template
|
- ./docker/nginx.dev.conf:/etc/nginx/templates/default.conf.template
|
||||||
environment:
|
environment:
|
||||||
|
|
@ -65,13 +102,7 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
depends_on:
|
depends_on:
|
||||||
- api
|
api:
|
||||||
- ui
|
condition: service_started
|
||||||
|
ui:
|
||||||
api-worker:
|
condition: service_started
|
||||||
<<: *api-base
|
|
||||||
environment:
|
|
||||||
IS_API_WORKER: "true"
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
@ -1,55 +1,81 @@
|
||||||
---
|
---
|
||||||
services:
|
services:
|
||||||
api: &api
|
api: &api-environment
|
||||||
image: jhumanj/opnform-api:latest
|
image: jhumanj/opnform-api:latest
|
||||||
|
container_name: opnform-api
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/Dockerfile.api
|
dockerfile: docker/Dockerfile.api
|
||||||
args:
|
args:
|
||||||
APP_ENV: production
|
- APP_ENV=production
|
||||||
environment: &api-environment # Add this anchor
|
volumes: &api-environment-volumes
|
||||||
|
- ./api/storage:/usr/share/nginx/html/storage:rw
|
||||||
|
- ./api/bootstrap/cache:/usr/share/nginx/html/bootstrap/cache:rw
|
||||||
|
environment: &api-env
|
||||||
|
APP_ENV: production
|
||||||
|
IS_API_WORKER: "false"
|
||||||
|
# Database settings
|
||||||
DB_HOST: db
|
DB_HOST: db
|
||||||
REDIS_HOST: redis
|
REDIS_HOST: redis
|
||||||
DB_DATABASE: ${DB_DATABASE:-forge}
|
DB_DATABASE: ${DB_DATABASE:-forge}
|
||||||
DB_USERNAME: ${DB_USERNAME:-forge}
|
DB_USERNAME: ${DB_USERNAME:-forge}
|
||||||
DB_PASSWORD: ${DB_PASSWORD:-forge}
|
DB_PASSWORD: ${DB_PASSWORD:-forge}
|
||||||
DB_CONNECTION: ${DB_CONNECTION:-pgsql}
|
DB_CONNECTION: ${DB_CONNECTION:-pgsql}
|
||||||
|
# Storage settings
|
||||||
FILESYSTEM_DISK: local
|
FILESYSTEM_DISK: local
|
||||||
LOCAL_FILESYSTEM_VISIBILITY: public
|
LOCAL_FILESYSTEM_VISIBILITY: public
|
||||||
env_file:
|
env_file:
|
||||||
- ./api/.env
|
- ./api/.env
|
||||||
volumes:
|
depends_on:
|
||||||
- opnform_storage:/usr/share/nginx/html/storage:rw
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
api-worker:
|
api-worker:
|
||||||
image: jhumanj/opnform-api:latest
|
<<: *api-environment
|
||||||
build:
|
container_name: opnform-api-worker
|
||||||
context: .
|
command: ["php", "artisan", "queue:work"]
|
||||||
dockerfile: docker/Dockerfile.api
|
volumes: *api-environment-volumes
|
||||||
args:
|
|
||||||
APP_ENV: production
|
|
||||||
command: php artisan queue:work
|
|
||||||
environment:
|
environment:
|
||||||
<<: *api-environment
|
<<: *api-env
|
||||||
|
APP_ENV: production
|
||||||
IS_API_WORKER: "true"
|
IS_API_WORKER: "true"
|
||||||
env_file:
|
env_file:
|
||||||
- ./api/.env
|
- ./api/.env
|
||||||
volumes:
|
|
||||||
- opnform_storage:/usr/share/nginx/html/storage:rw
|
api-scheduler:
|
||||||
|
<<: *api-environment
|
||||||
|
container_name: opnform-api-scheduler
|
||||||
|
command: ["php", "artisan", "schedule:work"]
|
||||||
|
volumes: *api-environment-volumes
|
||||||
|
environment:
|
||||||
|
<<: *api-env
|
||||||
|
APP_ENV: production
|
||||||
|
IS_API_WORKER: "true"
|
||||||
|
# Scheduler settings
|
||||||
|
CONTAINER_ROLE: scheduler
|
||||||
|
PHP_MEMORY_LIMIT: 512M
|
||||||
|
PHP_MAX_EXECUTION_TIME: 60
|
||||||
|
env_file:
|
||||||
|
- ./api/.env
|
||||||
|
|
||||||
ui:
|
ui:
|
||||||
image: jhumanj/opnform-client:latest
|
image: jhumanj/opnform-client:latest
|
||||||
|
container_name: opnform-client
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/Dockerfile.client
|
dockerfile: docker/Dockerfile.client
|
||||||
env_file:
|
env_file:
|
||||||
- ./client/.env
|
- ./client/.env
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:7
|
image: redis:7
|
||||||
|
container_name: opnform-redis
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:16
|
image: postgres:16
|
||||||
|
container_name: opnform-db
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: ${DB_DATABASE:-forge}
|
POSTGRES_DB: ${DB_DATABASE:-forge}
|
||||||
POSTGRES_USER: ${DB_USERNAME:-forge}
|
POSTGRES_USER: ${DB_USERNAME:-forge}
|
||||||
|
|
@ -64,10 +90,16 @@ services:
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
image: nginx:1
|
image: nginx:1
|
||||||
|
container_name: opnform-ingress
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/nginx.conf:/etc/nginx/templates/default.conf.template
|
- ./docker/nginx.conf:/etc/nginx/templates/default.conf.template
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
|
depends_on:
|
||||||
|
api:
|
||||||
|
condition: service_started
|
||||||
|
ui:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres-data:
|
postgres-data:
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,58 @@
|
||||||
# Stage 1: Composer dependencies
|
|
||||||
FROM composer:latest as composer
|
|
||||||
WORKDIR /app
|
|
||||||
COPY api/composer.* ./
|
|
||||||
|
|
||||||
ARG APP_ENV=production
|
|
||||||
RUN if [ "$APP_ENV" = "production" ]; then \
|
|
||||||
composer install --ignore-platform-req=php --no-dev --optimize-autoloader; \
|
|
||||||
else \
|
|
||||||
composer install --ignore-platform-req=php --optimize-autoloader; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Stage 2: Final image
|
|
||||||
FROM php:8.3-fpm
|
FROM php:8.3-fpm
|
||||||
|
|
||||||
# Install system dependencies and PHP extensions
|
# Install system dependencies
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
git \
|
libzip-dev \
|
||||||
curl \
|
|
||||||
libpng-dev \
|
libpng-dev \
|
||||||
libonig-dev \
|
postgresql-client \
|
||||||
libxml2-dev \
|
|
||||||
zip \
|
|
||||||
unzip \
|
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
&& docker-php-ext-install pdo_pgsql mbstring exif pcntl bcmath gd \
|
unzip \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install composer
|
||||||
|
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
|
||||||
|
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
RUN docker-php-ext-install pdo pgsql pdo_pgsql gd bcmath zip \
|
||||||
&& pecl install redis \
|
&& pecl install redis \
|
||||||
&& docker-php-ext-enable redis
|
&& docker-php-ext-enable redis
|
||||||
|
|
||||||
# Install xdebug if not in production
|
WORKDIR /usr/share/nginx/html/
|
||||||
ARG APP_ENV=production
|
|
||||||
RUN if [ "$APP_ENV" != "production" ]; then \
|
# Create storage directories
|
||||||
pecl install xdebug && \
|
RUN mkdir -p storage/framework/sessions \
|
||||||
docker-php-ext-enable xdebug; \
|
storage/framework/views \
|
||||||
|
storage/framework/cache \
|
||||||
|
storage/logs \
|
||||||
|
storage/app/public \
|
||||||
|
bootstrap/cache \
|
||||||
|
&& chown -R www-data:www-data storage bootstrap/cache \
|
||||||
|
&& chmod -R 775 storage bootstrap/cache
|
||||||
|
|
||||||
|
# Copy composer files and helpers.php first
|
||||||
|
COPY api/composer.json api/composer.lock ./
|
||||||
|
COPY api/app/helpers.php ./app/helpers.php
|
||||||
|
|
||||||
|
# Install dependencies without running scripts
|
||||||
|
RUN if [ "$APP_ENV" = "production" ] ; then \
|
||||||
|
composer install --no-dev --no-scripts --ignore-platform-req=php --optimize-autoloader ; \
|
||||||
|
else \
|
||||||
|
composer install --no-scripts --ignore-platform-req=php --optimize-autoloader ; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Configure PHP
|
# Copy the rest of the application
|
||||||
COPY docker/php/php.ini /usr/local/etc/php/conf.d/app.ini
|
COPY api/ .
|
||||||
COPY docker/php/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf
|
|
||||||
|
|
||||||
WORKDIR /usr/share/nginx/html
|
# Run composer scripts and clear cache
|
||||||
|
RUN composer dump-autoload -o \
|
||||||
# Copy application files
|
&& php artisan package:discover --ansi \
|
||||||
COPY api/artisan artisan
|
&& composer clear-cache \
|
||||||
COPY api/bootstrap ./bootstrap
|
&& chmod -R 775 storage \
|
||||||
COPY api/config ./config
|
&& chown -R www-data:www-data storage
|
||||||
COPY api/app ./app
|
|
||||||
COPY api/database ./database
|
|
||||||
COPY api/public ./public
|
|
||||||
COPY api/routes ./routes
|
|
||||||
COPY api/tests ./tests
|
|
||||||
COPY api/resources ./resources
|
|
||||||
COPY api/storage ./storage
|
|
||||||
|
|
||||||
# Copy vendor directory from composer stage
|
|
||||||
COPY --from=composer /app/vendor ./vendor
|
|
||||||
|
|
||||||
# Set permissions
|
|
||||||
RUN chmod -R 775 storage \
|
|
||||||
&& chmod -R 775 bootstrap/cache \
|
|
||||||
&& chown -R www-data:www-data /usr/share/nginx/html
|
|
||||||
|
|
||||||
|
# Setup entrypoint
|
||||||
COPY docker/php-fpm-entrypoint /usr/local/bin/opnform-entrypoint
|
COPY docker/php-fpm-entrypoint /usr/local/bin/opnform-entrypoint
|
||||||
RUN chmod a+x /usr/local/bin/*
|
RUN chmod a+x /usr/local/bin/*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,18 @@ map $original_uri $api_uri {
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name opnform;
|
server_name opnform;
|
||||||
root /usr/share/nginx/html/public;
|
root /usr/share/nginx/html/public;
|
||||||
|
|
||||||
access_log /dev/stdout;
|
access_log /dev/stdout;
|
||||||
error_log /dev/stderr error;
|
error_log /dev/stderr error;
|
||||||
|
|
||||||
index index.html index.htm index.php;
|
index index.html index.htm index.php;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_pass http://ui:3000;
|
proxy_pass http://opnform-client:3000;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
proxy_set_header X-Forwarded-Port $server_port;
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
|
@ -24,16 +24,22 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~/(api|open|local\/temp|forms\/assets)/ {
|
location ~/(api|open|local\/temp|forms\/assets)/ {
|
||||||
try_files $uri $uri/ /index.php?$query_string;
|
set $original_uri $uri;
|
||||||
|
try_files $uri $uri/ /index.php$is_args$args;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ \.php$ {
|
location ~ \.php$ {
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
fastcgi_pass api:9000;
|
fastcgi_pass opnform-api:9000;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/public/index.php;
|
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
|
||||||
fastcgi_param REQUEST_URI $api_uri;
|
fastcgi_param REQUEST_URI $api_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Deny access to . files
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,35 +4,16 @@ map $original_uri $api_uri {
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name opnform;
|
server_name localhost;
|
||||||
root /usr/share/nginx/html/public;
|
root /usr/share/nginx/html/public;
|
||||||
|
|
||||||
access_log /dev/stdout;
|
access_log /dev/stdout;
|
||||||
error_log /dev/stderr error;
|
error_log /dev/stderr error;
|
||||||
|
|
||||||
index index.html index.htm index.php;
|
index index.html index.htm index.php;
|
||||||
|
|
||||||
# Development CORS headers
|
# Frontend proxy
|
||||||
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS, PATCH' always;
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-XSRF-TOKEN' always;
|
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
|
||||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
|
||||||
|
|
||||||
# Handle preflight requests
|
|
||||||
if ($request_method = 'OPTIONS') {
|
|
||||||
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS, PATCH' always;
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-XSRF-TOKEN' always;
|
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
|
||||||
add_header 'Access-Control-Max-Age' 1728000;
|
|
||||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
|
||||||
add_header 'Content-Length' 0;
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Development proxy settings
|
|
||||||
location / {
|
location / {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_pass http://ui:3000;
|
proxy_pass http://ui:3000;
|
||||||
|
|
@ -43,23 +24,23 @@ server {
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
proxy_set_header X-Forwarded-Port $server_port;
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "Upgrade";
|
||||||
proxy_read_timeout 86400;
|
|
||||||
proxy_buffering off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# HMR websocket support
|
# HMR websocket support
|
||||||
location /_nuxt {
|
location /_nuxt {
|
||||||
proxy_pass http://ui:3000;
|
proxy_pass http://ui:3000;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_cache_bypass $http_upgrade;
|
proxy_cache_bypass $http_upgrade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# API handling
|
||||||
location ~/(api|open|local\/temp|forms\/assets)/ {
|
location ~/(api|open|local\/temp|forms\/assets)/ {
|
||||||
try_files $uri $uri/ /index.php?$query_string;
|
set $original_uri $uri;
|
||||||
|
try_files $uri $uri/ /index.php$is_args$args;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ \.php$ {
|
location ~ \.php$ {
|
||||||
|
|
@ -67,7 +48,13 @@ server {
|
||||||
fastcgi_pass api:9000;
|
fastcgi_pass api:9000;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/public/index.php;
|
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
|
||||||
fastcgi_param REQUEST_URI $api_uri;
|
fastcgi_param REQUEST_URI $api_uri;
|
||||||
|
fastcgi_read_timeout 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deny access to . files
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ main() {
|
||||||
prep_storage
|
prep_storage
|
||||||
wait_for_db
|
wait_for_db
|
||||||
apply_db_migrations
|
apply_db_migrations
|
||||||
run_init_project
|
run_init_project
|
||||||
run_server "$@"
|
run_server "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ wait_for_db() {
|
||||||
|
|
||||||
apply_db_migrations() {
|
apply_db_migrations() {
|
||||||
echo "Running DB Migrations"
|
echo "Running DB Migrations"
|
||||||
./artisan migrate
|
./artisan migrate --force
|
||||||
}
|
}
|
||||||
|
|
||||||
run_init_project() {
|
run_init_project() {
|
||||||
|
|
@ -59,7 +59,7 @@ run_init_project() {
|
||||||
|
|
||||||
run_server() {
|
run_server() {
|
||||||
echo "Starting server $@"
|
echo "Starting server $@"
|
||||||
exec /usr/local/bin/docker-php-entrypoint "$@"
|
exec "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
[www]
|
||||||
|
user = www-data
|
||||||
|
group = www-data
|
||||||
|
listen = 9000
|
||||||
|
|
||||||
|
pm = dynamic
|
||||||
|
pm.max_children = 20
|
||||||
|
pm.start_servers = 2
|
||||||
|
pm.min_spare_servers = 1
|
||||||
|
pm.max_spare_servers = 3
|
||||||
|
pm.max_requests = 1000
|
||||||
|
|
||||||
|
clear_env = no
|
||||||
|
catch_workers_output = yes
|
||||||
|
decorate_workers_output = no
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
; PHP Configuration
|
||||||
|
memory_limit = 512M
|
||||||
|
max_execution_time = 60
|
||||||
|
upload_max_filesize = 64M
|
||||||
|
post_max_size = 64M
|
||||||
|
max_input_vars = 3000
|
||||||
|
|
||||||
|
; Error reporting
|
||||||
|
error_reporting = E_ALL
|
||||||
|
display_errors = Off
|
||||||
|
display_startup_errors = Off
|
||||||
|
log_errors = On
|
||||||
|
error_log = /dev/stderr
|
||||||
|
|
||||||
|
; Date
|
||||||
|
date.timezone = UTC
|
||||||
|
|
||||||
|
; Session
|
||||||
|
session.save_handler = redis
|
||||||
|
session.save_path = "tcp://redis:6379"
|
||||||
|
|
||||||
|
; OpCache
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.memory_consumption=256
|
||||||
|
opcache.max_accelerated_files=20000
|
||||||
|
opcache.validate_timestamps=1
|
||||||
|
opcache.revalidate_freq=0
|
||||||
|
|
@ -10,13 +10,15 @@ import CloudVersion from "/snippets/cloud-version.mdx";
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
OpnForm provides a Docker-based development environment that offers:
|
OpnForm provides a Docker-based development environment that offers:
|
||||||
- Hot-reload for both frontend and backend
|
- Hot Module Replacement (HMR) for real-time frontend updates
|
||||||
|
- Vue DevTools integration for debugging
|
||||||
|
- PHP hot reload for backend changes
|
||||||
- Xdebug support for PHP debugging
|
- Xdebug support for PHP debugging
|
||||||
- Automatic dependency management
|
- Automatic dependency management
|
||||||
- PostgreSQL database and Redis setup
|
- PostgreSQL database and Redis setup
|
||||||
- Nginx reverse proxy configuration
|
- Nginx reverse proxy configuration
|
||||||
|
|
||||||
This is the recommended way to get started with OpnForm development.
|
For details about the Docker architecture and components, see our [Docker Deployment](/deployment/docker) guide.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
|
@ -32,18 +34,19 @@ This is the recommended way to get started with OpnForm development.
|
||||||
cd OpnForm
|
cd OpnForm
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Create environment files:
|
2. Run the setup script in development mode:
|
||||||
```bash
|
```bash
|
||||||
./scripts/setup-env.sh
|
chmod +x scripts/docker-setup.sh
|
||||||
```
|
./scripts/docker-setup.sh --dev
|
||||||
This will create the necessary `.env` files for both the API and client. See our [Environment Variables](/configuration/environment-variables) guide for configuration details.
|
|
||||||
|
|
||||||
3. Start the development environment:
|
|
||||||
```bash
|
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Access your development environment:
|
This script will:
|
||||||
|
- Create necessary environment files
|
||||||
|
- Pull or build required Docker images
|
||||||
|
- Start all containers in development mode
|
||||||
|
- Display access information
|
||||||
|
|
||||||
|
3. Access your development environment:
|
||||||
- Frontend: http://localhost:3000
|
- Frontend: http://localhost:3000
|
||||||
- API: http://localhost/api
|
- API: http://localhost/api
|
||||||
|
|
||||||
|
|
@ -60,28 +63,54 @@ You will be prompted to change your email and password after your first login.
|
||||||
|
|
||||||
## Development Features
|
## Development Features
|
||||||
|
|
||||||
### Hot Reload
|
### Frontend Development
|
||||||
|
|
||||||
The development setup includes hot reload capabilities:
|
The development setup includes advanced frontend features:
|
||||||
- Frontend (Nuxt.js): Changes to files in the `client` directory trigger automatic rebuilds
|
- **Hot Module Replacement (HMR)**: Changes to Vue components and styles are instantly reflected without page reload
|
||||||
- Backend (Laravel): Changes to files in the `api` directory are immediately reflected, except for queued jobs which require restarting the api-worker container (`docker compose -f docker-compose.yml -f docker-compose.dev.yml restart api-worker`)
|
- **Vue DevTools**: Full integration for component inspection and state management debugging ([learn more](https://devtools.vuejs.org/))
|
||||||
|
- **Source Maps**: Enabled for easier debugging
|
||||||
|
- **Fast Refresh**: Preserves component state during updates
|
||||||
|
- **Error Overlay**: Displays errors directly in the browser
|
||||||
|
|
||||||
### File Structure
|
### Backend Development
|
||||||
|
|
||||||
|
The Laravel API service provides:
|
||||||
|
- **PHP Hot Reload**: Changes to PHP files are immediately available
|
||||||
|
- **Xdebug Integration**: Ready for step-by-step debugging
|
||||||
|
- **Laravel Telescope**: Available for request and queue monitoring
|
||||||
|
- **Artisan Commands**: Direct access to Laravel's CLI tools
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
Queue workers require restart after code changes:
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml restart api-worker
|
||||||
|
```
|
||||||
|
</Note>
|
||||||
|
|
||||||
|
### Development URLs
|
||||||
|
|
||||||
|
- **Frontend**: http://localhost:3000
|
||||||
|
- Direct access to Nuxt dev server
|
||||||
|
- Includes HMR websocket connection
|
||||||
|
- Vue DevTools available
|
||||||
|
|
||||||
|
- **API**: http://localhost/api
|
||||||
|
- Handled by Nginx reverse proxy
|
||||||
|
- Automatic routing to PHP-FPM
|
||||||
|
- Supports file uploads and long requests
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
The development setup mounts your local directories into the containers:
|
The development setup mounts your local directories into the containers:
|
||||||
- `./api`: Mounted to the API container with vendor directory preserved
|
```
|
||||||
- `./client`: Mounted to the UI container with node_modules preserved
|
OpnForm/
|
||||||
- Database and Redis data are persisted through Docker volumes
|
├── api/ # Laravel API (mounted to api container)
|
||||||
|
│ ├── vendor/ # Preserved in container
|
||||||
### Container Services
|
│ └── storage/ # Mounted for logs and uploads
|
||||||
|
├── client/ # Nuxt frontend (mounted to ui container)
|
||||||
The development environment includes:
|
│ └── node_modules/ # Preserved in container
|
||||||
- `api`: Laravel API service with hot reload
|
└── docker/ # Docker configuration files
|
||||||
- `ui`: Nuxt.js frontend with HMR
|
```
|
||||||
- `api-worker`: Laravel queue worker
|
|
||||||
- `db`: PostgreSQL database
|
|
||||||
- `redis`: Redis server
|
|
||||||
- `ingress`: Nginx reverse proxy
|
|
||||||
|
|
||||||
## Common Tasks
|
## Common Tasks
|
||||||
|
|
||||||
|
|
@ -95,6 +124,9 @@ docker compose -f docker-compose.yml -f docker-compose.dev.yml exec api php arti
|
||||||
|
|
||||||
# NPM commands
|
# NPM commands
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec ui npm [command]
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec ui npm [command]
|
||||||
|
|
||||||
|
# Database commands
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec db psql -U forge
|
||||||
```
|
```
|
||||||
|
|
||||||
### Accessing Logs
|
### Accessing Logs
|
||||||
|
|
@ -105,35 +137,48 @@ View container logs:
|
||||||
# All containers
|
# All containers
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f
|
||||||
|
|
||||||
# Specific container
|
# Specific container (e.g., frontend)
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f [service]
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f ui
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database Management
|
### Database Access
|
||||||
|
|
||||||
The PostgreSQL database is accessible:
|
The PostgreSQL database is accessible:
|
||||||
- From containers: `host=db`
|
- From containers: `host=db`
|
||||||
- From your machine: `localhost:5432`
|
- From your machine: `localhost:5432`
|
||||||
- Default credentials: username=forge, password=forge, database=forge
|
- Default credentials:
|
||||||
|
```
|
||||||
|
Host: localhost
|
||||||
|
Port: 5432
|
||||||
|
Database: forge
|
||||||
|
Username: forge
|
||||||
|
Password: forge
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Container Issues
|
### Container Issues
|
||||||
If containers aren't starting properly:
|
If containers aren't starting properly:
|
||||||
```bash
|
```bash
|
||||||
# Remove all containers and volumes
|
# Clean everything and restart
|
||||||
docker compose down -v
|
./scripts/docker-setup.sh --dev
|
||||||
|
|
||||||
# Rebuild and start
|
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Permission Issues
|
### Permission Issues
|
||||||
If you encounter permission issues with storage or vendor directories:
|
If you encounter permission issues:
|
||||||
```bash
|
```bash
|
||||||
# Fix storage permissions
|
# Fix storage permissions
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec api chmod -R 775 storage
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec api chmod -R 775 storage
|
||||||
|
|
||||||
# Fix vendor permissions
|
# Fix vendor permissions
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec api chmod -R 775 vendor
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec api chmod -R 775 vendor
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### HMR Issues
|
||||||
|
If hot reload isn't working:
|
||||||
|
1. Check browser console for WebSocket errors
|
||||||
|
2. Ensure ports 3000 and 24678 are available
|
||||||
|
3. Try restarting the UI container:
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml restart ui
|
||||||
|
```
|
||||||
|
|
@ -8,49 +8,34 @@ import CloudVersion from "/snippets/cloud-version.mdx";
|
||||||
<CloudVersion/>
|
<CloudVersion/>
|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
This guide is for deploying OpnForm on a production server. If you're looking to **develop OpnForm locally**, check out our [Docker Development Setup](/deployment/docker-development) guide which provides **hot-reload and other development features**.
|
Looking to develop OpnForm locally? Check out our [Docker Development Setup](/deployment/docker-development) guide which provides hot-reload and other development features.
|
||||||
</Tip>
|
</Tip>
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Docker
|
|
||||||
- Docker Compose
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
1. Clone the repository:
|
1. Clone the repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/JhumanJ/OpnForm.git
|
git clone https://github.com/JhumanJ/OpnForm.git
|
||||||
cd OpnForm
|
cd OpnForm
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Set up environment files:
|
2. Run the setup script:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/setup-env.sh --docker
|
chmod +x scripts/docker-setup.sh
|
||||||
|
./scripts/docker-setup.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
3. (Optional) Customize the environment variables:
|
The script will:
|
||||||
|
- Create necessary environment files
|
||||||
You can modify two environment files to customize your OpnForm installation:
|
- Pull required Docker images
|
||||||
- The `.env` file in the `api` directory for backend configuration
|
- Start all containers in production mode
|
||||||
- The `.env` file in the `client` directory for frontend configuration
|
- Display access information
|
||||||
|
|
||||||
For more information on available environment variables, please refer to our [Environment Variables](/configuration/environment-variables) page.
|
|
||||||
|
|
||||||
4. Start the application:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Access OpnForm at http://localhost
|
|
||||||
|
|
||||||
|
3. Access your OpnForm instance at `http://localhost`
|
||||||
|
|
||||||
### Initial Login
|
### Initial Login
|
||||||
|
|
||||||
After installation, use these credentials to access the app:
|
After deployment, use these credentials to access the app:
|
||||||
|
|
||||||
- Email: `admin@opnform.com`
|
- Email: `admin@opnform.com`
|
||||||
- Password: `password`
|
- Password: `password`
|
||||||
|
|
@ -59,71 +44,171 @@ You will be prompted to change your email and password after your first login.
|
||||||
|
|
||||||
<Note>Public registration is disabled in the self-hosted version. Use the admin account to invite additional users.</Note>
|
<Note>Public registration is disabled in the self-hosted version. Use the admin account to invite additional users.</Note>
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Nginx Proxy] --> B[Frontend - Nuxt SSR]
|
||||||
|
A --> C[Backend - Laravel API]
|
||||||
|
C --> D[PostgreSQL]
|
||||||
|
C --> E[Redis]
|
||||||
|
C --> F[Queue Worker]
|
||||||
|
C --> G[Scheduler]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab title="Frontend">
|
||||||
|
The Nuxt frontend service:
|
||||||
|
- Server-Side Rendered application
|
||||||
|
- Built with Vue 3 and Tailwind CSS
|
||||||
|
- Handles dynamic rendering and client-side interactivity
|
||||||
|
- Optimized for production performance
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Backend">
|
||||||
|
The Laravel API service:
|
||||||
|
- Handles business logic and data persistence
|
||||||
|
- Provides REST API endpoints
|
||||||
|
- Manages file uploads and processing
|
||||||
|
- Includes required PHP extensions (pgsql, redis, etc.)
|
||||||
|
- Configured for PostgreSQL and Redis connections
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Workers">
|
||||||
|
Background processing services:
|
||||||
|
- **API Worker**: Processes queued jobs (emails, exports, etc.)
|
||||||
|
- **API Scheduler**: Handles scheduled tasks and periodic cleanups
|
||||||
|
- Both share the same codebase as the main API
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Databases">
|
||||||
|
Data storage services:
|
||||||
|
- **PostgreSQL**: Primary database for all application data
|
||||||
|
- **Redis**: Used for:
|
||||||
|
- Session storage
|
||||||
|
- Cache
|
||||||
|
- Queue management
|
||||||
|
- Real-time features
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Proxy">
|
||||||
|
The Nginx proxy service:
|
||||||
|
- Routes requests between frontend and backend
|
||||||
|
- Handles SSL termination
|
||||||
|
- Manages file upload limits
|
||||||
|
- Serves static assets
|
||||||
|
- Configured for optimal performance
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
## Docker Images
|
## Docker Images
|
||||||
|
|
||||||
OpnForm provides pre-built Docker images for easy deployment. You can find our official Docker images on Docker Hub:
|
OpnForm provides pre-built Docker images for easy deployment:
|
||||||
|
|
||||||
- [OpnForm API Image](https://hub.docker.com/r/jhumanj/opnform-api)
|
- [OpnForm API Image](https://hub.docker.com/r/jhumanj/opnform-api)
|
||||||
- [OpnForm Client Image](https://hub.docker.com/r/jhumanj/opnform-client)
|
- [OpnForm Client Image](https://hub.docker.com/r/jhumanj/opnform-client)
|
||||||
|
|
||||||
We recommend using these official images for your OpnForm deployment.
|
### Building Custom Images
|
||||||
|
|
||||||
|
While we recommend using the official images, you can build custom images if needed:
|
||||||
## Building Your Own Docker Images
|
|
||||||
|
|
||||||
By default, OpnForm uses pre-built images from Docker Hub. However, if you want to build the images yourself (for development or customization), you have two options:
|
|
||||||
|
|
||||||
### Option 1: Using Docker Compose (Recommended)
|
|
||||||
|
|
||||||
The simplest way to build the images is using Docker Compose:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Build all images
|
||||||
docker compose build
|
docker compose build
|
||||||
|
|
||||||
|
# Or build specific images
|
||||||
|
docker build -t opnform-api:local -f docker/Dockerfile.api .
|
||||||
|
docker build -t opnform-ui:local -f docker/Dockerfile.client .
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build all the necessary images. You can then start the application as usual:
|
### Custom Configuration
|
||||||
|
Create a `docker-compose.override.yml` to customize your deployment:
|
||||||
```bash
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 2: Building Images Manually
|
|
||||||
|
|
||||||
You can also build the images manually using the provided Dockerfiles:
|
|
||||||
|
|
||||||
1. Build the API image:
|
|
||||||
```bash
|
|
||||||
docker build -t opnform-api:local -f docker/Dockerfile.api .
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Build the UI image:
|
|
||||||
```bash
|
|
||||||
docker build -t opnform-ui:local -f docker/Dockerfile.client .
|
|
||||||
```
|
|
||||||
|
|
||||||
If you build the images manually, make sure to update your docker-compose.override.yml to use these local images (see below).
|
|
||||||
|
|
||||||
### Overriding Docker Compose Configuration
|
|
||||||
|
|
||||||
You can override the default Docker Compose configuration by creating a `docker-compose.override.yml` file. This allows you to customize various aspects of the deployment without modifying the main `docker-compose.yml` file.
|
|
||||||
|
|
||||||
Example `docker-compose.override.yml`:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
api:
|
api:
|
||||||
image: opnform-api:local
|
image: opnform-api:local
|
||||||
|
environment:
|
||||||
|
PHP_MEMORY_LIMIT: 1G
|
||||||
ui:
|
ui:
|
||||||
image: opnform-ui:local
|
image: opnform-ui:local
|
||||||
api-worker:
|
ingress:
|
||||||
image: opnform-api:local
|
volumes:
|
||||||
|
- ./custom-nginx.conf:/etc/nginx/conf.d/default.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
### Clearing all resources
|
### Updates
|
||||||
|
|
||||||
To completely remove all Docker containers, networks, and volumes created by Docker Compose and also remove all images used by these services, you can use the following command:
|
1. Pull latest changes:
|
||||||
|
```bash
|
||||||
|
git pull origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Update containers:
|
||||||
|
```bash
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitoring
|
||||||
|
|
||||||
|
View container logs:
|
||||||
|
```bash
|
||||||
|
# All containers
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Specific container
|
||||||
|
docker compose logs -f api
|
||||||
```
|
```
|
||||||
docker compose down -v --rmi all
|
|
||||||
|
Monitor container health:
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container Issues
|
||||||
|
|
||||||
|
If containers aren't starting:
|
||||||
|
```bash
|
||||||
|
# View detailed logs
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Recreate containers
|
||||||
|
docker compose down
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Issues
|
||||||
|
|
||||||
|
If database connections fail:
|
||||||
|
```bash
|
||||||
|
# Check database status
|
||||||
|
docker compose exec db pg_isready
|
||||||
|
|
||||||
|
# View database logs
|
||||||
|
docker compose logs db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache Issues
|
||||||
|
|
||||||
|
Clear various caches:
|
||||||
|
```bash
|
||||||
|
# Clear application cache
|
||||||
|
docker compose exec api php artisan cache:clear
|
||||||
|
|
||||||
|
# Clear config cache
|
||||||
|
docker compose exec api php artisan config:clear
|
||||||
|
|
||||||
|
# Clear route cache
|
||||||
|
docker compose exec api php artisan route:clear
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission Issues
|
||||||
|
|
||||||
|
Fix storage permissions:
|
||||||
|
```bash
|
||||||
|
docker compose exec api chown -R www-data:www-data storage
|
||||||
|
docker compose exec api chmod -R 775 storage
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# ASCII Art
|
||||||
|
echo -e "${BLUE}"
|
||||||
|
cat << "EOF"
|
||||||
|
____ ______
|
||||||
|
/ __ \____ ____ / ____/___ _________ ___
|
||||||
|
/ / / / __ \/ __ \/ /_ / __ \/ ___/ __ `__ \
|
||||||
|
/ /_/ / /_/ / / / / __/ / /_/ / / / / / / / /
|
||||||
|
\____/ .___/_/ /_/_/ \____/_/ /_/ /_/ /_/
|
||||||
|
/_/
|
||||||
|
EOF
|
||||||
|
echo -e "${NC}"
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
DEV_MODE=false
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--dev) DEV_MODE=true ;;
|
||||||
|
*) echo "Unknown parameter: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
echo -e "${BLUE}Starting OpnForm Docker setup...${NC}"
|
||||||
|
|
||||||
|
# Run the environment setup script with --docker flag
|
||||||
|
echo -e "${GREEN}Setting up environment files...${NC}"
|
||||||
|
bash "$SCRIPT_DIR/setup-env.sh" --docker
|
||||||
|
|
||||||
|
# Determine which compose files to use
|
||||||
|
COMPOSE_FILES="-f docker-compose.yml"
|
||||||
|
if [ "$DEV_MODE" = true ]; then
|
||||||
|
echo -e "${YELLOW}Development mode enabled - using docker-compose.dev.yml${NC}"
|
||||||
|
COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.dev.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start Docker containers
|
||||||
|
echo -e "${GREEN}Starting Docker containers...${NC}"
|
||||||
|
docker compose $COMPOSE_FILES up -d
|
||||||
|
|
||||||
|
# Display access instructions
|
||||||
|
if [ "$DEV_MODE" = true ]; then
|
||||||
|
echo -e "${BLUE}Development environment setup complete!${NC}"
|
||||||
|
echo -e "${YELLOW}Please wait for the frontend to finish building (this may take a few minutes)${NC}"
|
||||||
|
echo -e "${GREEN}Then visit: http://localhost:3000${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${BLUE}Production environment setup complete!${NC}"
|
||||||
|
echo -e "${YELLOW}Please wait a moment for all services to start${NC}"
|
||||||
|
echo -e "${GREEN}Then visit: http://localhost${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}Default admin credentials:${NC}"
|
||||||
|
echo -e "${GREEN}Email: admin@opnform.com${NC}"
|
||||||
|
echo -e "${GREEN}Password: password${NC}"
|
||||||
Loading…
Reference in New Issue