feat: Add APP_NAME env support for branding and deployment
- Make app name configurable via APP_NAME env variable - Update UI, HTML, Docker, scripts, and k8s to use APP_NAME - Add process-html.sh for template substitution - Document APP_NAME usage in docs/APP_NAME_CONFIGURATION.md - Update Dockerfile, compose, and scripts for dynamic naming - Add index.html.template for environment-based branding
This commit is contained in:
2
App.tsx
2
App.tsx
@@ -116,7 +116,7 @@ const Header: React.FC<{
|
|||||||
className='hidden sm:flex items-center space-x-2 px-4 py-2 text-sm font-medium text-slate-700 bg-slate-100 rounded-lg hover:bg-slate-200 transition-colors dark:bg-slate-700 dark:text-slate-200 dark:hover:bg-slate-600'
|
className='hidden sm:flex items-center space-x-2 px-4 py-2 text-sm font-medium text-slate-700 bg-slate-100 rounded-lg hover:bg-slate-200 transition-colors dark:bg-slate-700 dark:text-slate-200 dark:hover:bg-slate-600'
|
||||||
>
|
>
|
||||||
<MenuIcon className='w-4 h-4' aria-hidden='true' />
|
<MenuIcon className='w-4 h-4' aria-hidden='true' />
|
||||||
<span>Meds</span>
|
<span>{import.meta.env.VITE_APP_NAME || 'Meds'}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={onManageReminders}
|
onClick={onManageReminders}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
FROM oven/bun:alpine AS builder
|
FROM oven/bun:alpine AS builder
|
||||||
|
|
||||||
# Install system dependencies for native modules
|
# Install system dependencies for native modules
|
||||||
RUN apk add --no-cache python3 make g++
|
RUN apk add --no-cache python3 make g++ gettext
|
||||||
|
|
||||||
# Create non-root user for security
|
# Create non-root user for security
|
||||||
RUN addgroup -g 1001 -S nodeuser && adduser -S nodeuser -u 1001 -G nodeuser
|
RUN addgroup -g 1001 -S nodeuser && adduser -S nodeuser -u 1001 -G nodeuser
|
||||||
@@ -24,6 +24,9 @@ RUN bun install --frozen-lockfile
|
|||||||
COPY --chown=nodeuser:nodeuser . ./
|
COPY --chown=nodeuser:nodeuser . ./
|
||||||
|
|
||||||
# Build arguments for environment configuration
|
# Build arguments for environment configuration
|
||||||
|
# Application Name
|
||||||
|
ARG APP_NAME=RxMinder
|
||||||
|
|
||||||
# CouchDB Configuration
|
# CouchDB Configuration
|
||||||
ARG VITE_COUCHDB_URL=http://localhost:5984
|
ARG VITE_COUCHDB_URL=http://localhost:5984
|
||||||
ARG VITE_COUCHDB_USER=admin
|
ARG VITE_COUCHDB_USER=admin
|
||||||
@@ -41,6 +44,7 @@ ARG NODE_ENV=production
|
|||||||
|
|
||||||
# Set environment variables for build process
|
# Set environment variables for build process
|
||||||
# These are embedded into the static build at compile time
|
# These are embedded into the static build at compile time
|
||||||
|
ENV VITE_APP_NAME=$APP_NAME
|
||||||
ENV VITE_COUCHDB_URL=$VITE_COUCHDB_URL
|
ENV VITE_COUCHDB_URL=$VITE_COUCHDB_URL
|
||||||
ENV VITE_COUCHDB_USER=$VITE_COUCHDB_USER
|
ENV VITE_COUCHDB_USER=$VITE_COUCHDB_USER
|
||||||
ENV VITE_COUCHDB_PASSWORD=$VITE_COUCHDB_PASSWORD
|
ENV VITE_COUCHDB_PASSWORD=$VITE_COUCHDB_PASSWORD
|
||||||
@@ -49,6 +53,9 @@ ENV VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID
|
|||||||
ENV VITE_GITHUB_CLIENT_ID=$VITE_GITHUB_CLIENT_ID
|
ENV VITE_GITHUB_CLIENT_ID=$VITE_GITHUB_CLIENT_ID
|
||||||
ENV NODE_ENV=$NODE_ENV
|
ENV NODE_ENV=$NODE_ENV
|
||||||
|
|
||||||
|
# Process HTML template with APP_NAME
|
||||||
|
RUN envsubst '$APP_NAME' < index.html.template > index.html || cp index.html.template index.html
|
||||||
|
|
||||||
# Build the application
|
# Build the application
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
@@ -66,13 +73,13 @@ COPY --from=builder /app/docker/nginx.conf /etc/nginx/conf.d/default.conf
|
|||||||
|
|
||||||
# Set proper permissions for nginx
|
# Set proper permissions for nginx
|
||||||
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
||||||
chown -R nginx:nginx /var/cache/nginx && \
|
chown -R nginx:nginx /var/cache/nginx && \
|
||||||
chown -R nginx:nginx /var/log/nginx && \
|
chown -R nginx:nginx /var/log/nginx && \
|
||||||
chown -R nginx:nginx /etc/nginx/conf.d
|
chown -R nginx:nginx /etc/nginx/conf.d
|
||||||
|
|
||||||
# Add health check
|
# Add health check
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
CMD curl -f http://localhost/ || exit 1
|
CMD curl -f http://localhost/ || exit 1
|
||||||
|
|
||||||
# Expose port 80
|
# Expose port 80
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ services:
|
|||||||
context: ..
|
context: ..
|
||||||
dockerfile: docker/Dockerfile
|
dockerfile: docker/Dockerfile
|
||||||
args:
|
args:
|
||||||
|
# Application Configuration
|
||||||
|
- APP_NAME=${APP_NAME:-RxMinder}
|
||||||
# CouchDB Configuration
|
# CouchDB Configuration
|
||||||
- VITE_COUCHDB_URL=${VITE_COUCHDB_URL:-http://couchdb:5984}
|
- VITE_COUCHDB_URL=${VITE_COUCHDB_URL:-http://couchdb:5984}
|
||||||
- VITE_COUCHDB_USER=${VITE_COUCHDB_USER:-admin}
|
- VITE_COUCHDB_USER=${VITE_COUCHDB_USER:-admin}
|
||||||
@@ -36,6 +38,7 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
- 'monitoring=true'
|
- 'monitoring=true'
|
||||||
- 'service=frontend'
|
- 'service=frontend'
|
||||||
|
- 'app=${APP_NAME:-meds}'
|
||||||
|
|
||||||
# CouchDB service
|
# CouchDB service
|
||||||
couchdb:
|
couchdb:
|
||||||
@@ -56,6 +59,7 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
- 'monitoring=true'
|
- 'monitoring=true'
|
||||||
- 'service=couchdb'
|
- 'service=couchdb'
|
||||||
|
- 'app=${APP_NAME:-meds}'
|
||||||
|
|
||||||
# Redis service (commented out as per requirements)
|
# Redis service (commented out as per requirements)
|
||||||
# redis:
|
# redis:
|
||||||
|
|||||||
198
docs/APP_NAME_CONFIGURATION.md
Normal file
198
docs/APP_NAME_CONFIGURATION.md
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
# APP_NAME Configuration Guide
|
||||||
|
|
||||||
|
This document explains how the `APP_NAME` environment variable is used throughout the application to customize branding and naming.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `APP_NAME` environment variable allows you to customize the application name across all components, from the frontend UI to Docker containers and Kubernetes deployments.
|
||||||
|
|
||||||
|
## Default Values
|
||||||
|
|
||||||
|
- **Default APP_NAME**: `RxMinder`
|
||||||
|
- **Package name fallback**: `rxminder` (lowercase)
|
||||||
|
- **Docker tag fallback**: `meds` (for backward compatibility)
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Setting APP_NAME
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For deployment
|
||||||
|
export APP_NAME="MyMedsApp"
|
||||||
|
make deploy
|
||||||
|
|
||||||
|
# For development
|
||||||
|
export APP_NAME="DevMeds"
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# For Docker build
|
||||||
|
APP_NAME="CustomApp" docker build -t myapp .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env
|
||||||
|
APP_NAME=MyCustomApp
|
||||||
|
|
||||||
|
# .env.production
|
||||||
|
APP_NAME=ProductionApp
|
||||||
|
|
||||||
|
# .env.staging
|
||||||
|
APP_NAME=StagingApp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Where APP_NAME is Used
|
||||||
|
|
||||||
|
### 1. Frontend Application
|
||||||
|
|
||||||
|
- **HTML Title**: `<title>$APP_NAME</title>`
|
||||||
|
- **UI Header**: Button text shows `APP_NAME` value
|
||||||
|
- **Environment Variable**: Available as `import.meta.env.VITE_APP_NAME`
|
||||||
|
|
||||||
|
### 2. Docker Configuration
|
||||||
|
|
||||||
|
- **Build Argument**: Passed to Dockerfile as `--build-arg APP_NAME=...`
|
||||||
|
- **Container Names**: `${app_name_lower}-validation-test`
|
||||||
|
- **Image Tags**: `${app_name_lower}-validation:latest`
|
||||||
|
- **Docker Compose**: Labels include `app=${APP_NAME}`
|
||||||
|
|
||||||
|
### 3. Kubernetes Deployment
|
||||||
|
|
||||||
|
- **Resource Names**: `${APP_NAME}-frontend`, `${APP_NAME}-config`
|
||||||
|
- **Labels**: `app: ${APP_NAME}`
|
||||||
|
- **Container Image**: `${DOCKER_IMAGE:-registry/user/${APP_NAME}:latest}`
|
||||||
|
|
||||||
|
### 4. Package Configuration
|
||||||
|
|
||||||
|
- **Package Name**: `"name": "${APP_NAME:-rxminder}"`
|
||||||
|
|
||||||
|
## File Locations
|
||||||
|
|
||||||
|
### Files That Use APP_NAME
|
||||||
|
|
||||||
|
1. **Frontend Files**:
|
||||||
|
- `index.html.template` - Page title
|
||||||
|
- `App.tsx` - UI header text
|
||||||
|
- `vite.config.ts` - Environment variable mapping
|
||||||
|
|
||||||
|
2. **Docker Files**:
|
||||||
|
- `docker/Dockerfile` - Build argument and environment variable
|
||||||
|
- `docker/docker-compose.yaml` - Build args and labels
|
||||||
|
|
||||||
|
3. **Kubernetes Templates**:
|
||||||
|
- `k8s/frontend-deployment.yaml.template` - Resource names and labels
|
||||||
|
- `k8s/configmap.yaml.template` - Resource names and labels
|
||||||
|
- All other `k8s/*.yaml.template` files
|
||||||
|
|
||||||
|
4. **Scripts**:
|
||||||
|
- `scripts/deploy.sh` - Container and image naming
|
||||||
|
- `scripts/buildx-helper.sh` - Container and image naming
|
||||||
|
- `scripts/validate-deployment.sh` - Container and image naming
|
||||||
|
- `scripts/process-html.sh` - HTML template processing
|
||||||
|
|
||||||
|
## Build Process
|
||||||
|
|
||||||
|
### Development Mode
|
||||||
|
|
||||||
|
1. `npm run predev` → Processes `index.html.template` → `index.html`
|
||||||
|
2. `npm run dev` → Starts development server
|
||||||
|
|
||||||
|
### Production Build
|
||||||
|
|
||||||
|
1. Dockerfile processes `index.html.template` using `envsubst`
|
||||||
|
2. Vite build uses processed `index.html`
|
||||||
|
3. Final image contains customized HTML with correct title
|
||||||
|
|
||||||
|
## Examples by Environment
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env
|
||||||
|
APP_NAME=MedsApp-Dev
|
||||||
|
VITE_APP_NAME=MedsApp-Dev
|
||||||
|
|
||||||
|
# Results in:
|
||||||
|
# - HTML title: "MedsApp-Dev"
|
||||||
|
# - UI header: "MedsApp-Dev"
|
||||||
|
# - Docker containers: "medsapp-dev-validation-test"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staging Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env.staging
|
||||||
|
APP_NAME=MedsApp-Staging
|
||||||
|
|
||||||
|
# Results in:
|
||||||
|
# - Kubernetes resources: "MedsApp-Staging-frontend"
|
||||||
|
# - Docker images: "medsapp-staging-validation:latest"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env.production
|
||||||
|
APP_NAME=MedicationTracker
|
||||||
|
|
||||||
|
# Results in:
|
||||||
|
# - All resources branded as "MedicationTracker"
|
||||||
|
# - Clean production naming
|
||||||
|
```
|
||||||
|
|
||||||
|
## Case Handling
|
||||||
|
|
||||||
|
- **Frontend**: Uses original case (`MyApp`)
|
||||||
|
- **Docker**: Converts to lowercase (`myapp`)
|
||||||
|
- **Kubernetes**: Uses original case in labels, lowercase in DNS names
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **HTML title not updating**: Ensure `index.html.template` exists and `process-html.sh` runs
|
||||||
|
2. **Docker build fails**: Check that `APP_NAME` doesn't contain invalid characters for Docker tags
|
||||||
|
3. **Kubernetes deployment fails**: Verify `APP_NAME` follows Kubernetes naming conventions
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test HTML processing
|
||||||
|
APP_NAME=TestApp ./scripts/process-html.sh
|
||||||
|
|
||||||
|
# Test Docker build
|
||||||
|
APP_NAME=TestApp make deploy
|
||||||
|
|
||||||
|
# Check generated files
|
||||||
|
grep -r "TestApp" dist/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use consistent naming**: Keep `APP_NAME` consistent across all environments
|
||||||
|
2. **Follow naming conventions**: Use alphanumeric characters and hyphens
|
||||||
|
3. **Avoid special characters**: Docker and Kubernetes have naming restrictions
|
||||||
|
4. **Document custom names**: Include `APP_NAME` in your deployment documentation
|
||||||
|
|
||||||
|
## Migration from Hardcoded Values
|
||||||
|
|
||||||
|
If you're migrating from hardcoded "meds" or "rxminder" references:
|
||||||
|
|
||||||
|
1. Set `APP_NAME=meds` to maintain backward compatibility
|
||||||
|
2. Test all deployment scripts with the new variable
|
||||||
|
3. Gradually update to your preferred application name
|
||||||
|
4. Update documentation and deployment guides
|
||||||
|
|
||||||
|
## Environment Variable Precedence
|
||||||
|
|
||||||
|
1. Command-line environment variable (`APP_NAME=...`)
|
||||||
|
2. `.env` file in project root
|
||||||
|
3. Default value (`RxMinder`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Priority order:
|
||||||
|
APP_NAME=CmdLineApp make deploy # Highest priority
|
||||||
|
# vs .env file: APP_NAME=EnvFileApp
|
||||||
|
# vs default: RxMinder # Lowest priority
|
||||||
|
```
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>RxMinder</title>
|
<title>MyCustomMeds</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
|||||||
51
index.html.template
Normal file
51
index.html.template
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>$APP_NAME</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: 'class',
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'sans-serif'],
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
float: {
|
||||||
|
'0%, 100%': { transform: 'translateY(0px)' },
|
||||||
|
'50%': { transform: 'translateY(-10px)' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
float: 'float 3s ease-in-out infinite',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"react": "https://aistudiocdn.com/react@^19.1.1",
|
||||||
|
"react/": "https://aistudiocdn.com/react@^19.1.1/",
|
||||||
|
"react-dom/": "https://aistudiocdn.com/react-dom@^19.1.1/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" href="/index.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="bg-slate-50 dark:bg-slate-900 antialiased">
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/index.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -19,7 +19,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: frontend
|
- name: frontend
|
||||||
image: gitea-http.taildb3494.ts.net/will/meds:latest
|
image: ${DOCKER_IMAGE:-gitea-http.taildb3494.ts.net/will/${APP_NAME}:latest}
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
envFrom:
|
envFrom:
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "rxminder",
|
"name": "${APP_NAME:-rxminder}",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"predev": "./scripts/process-html.sh",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ print_error() {
|
|||||||
# Cleanup function
|
# Cleanup function
|
||||||
cleanup() {
|
cleanup() {
|
||||||
print_status "Cleaning up test containers..."
|
print_status "Cleaning up test containers..."
|
||||||
docker stop meds-validation-test 2>/dev/null || true
|
APP_NAME_LOWER=$(echo "${APP_NAME:-meds}" | tr '[:upper:]' '[:lower:]')
|
||||||
docker rm meds-validation-test 2>/dev/null || true
|
docker stop ${APP_NAME_LOWER}-validation-test 2>/dev/null || true
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation down 2>/dev/null || true
|
docker rm ${APP_NAME_LOWER}-validation-test 2>/dev/null || true
|
||||||
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation down 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set trap for cleanup
|
# Set trap for cleanup
|
||||||
@@ -81,8 +82,12 @@ docker buildx use meds-builder
|
|||||||
print_status "4. Building multi-platform Docker image with buildx..."
|
print_status "4. Building multi-platform Docker image with buildx..."
|
||||||
|
|
||||||
# Build the image with buildx for multiple platforms
|
# Build the image with buildx for multiple platforms
|
||||||
|
# Build single-platform image for testing
|
||||||
|
print_status "Building single-platform Docker image for testing..."
|
||||||
|
APP_NAME_LOWER=$(echo "${APP_NAME:-meds}" | tr '[:upper:]' '[:lower:]')
|
||||||
docker buildx build --no-cache \
|
docker buildx build --no-cache \
|
||||||
--platform linux/amd64,linux/arm64 \
|
--platform "$HOST_PLATFORM" \
|
||||||
|
--build-arg APP_NAME="${APP_NAME:-RxMinder}" \
|
||||||
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
||||||
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
||||||
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
||||||
@@ -95,7 +100,7 @@ docker buildx build --no-cache \
|
|||||||
--build-arg MAILGUN_DOMAIN="${MAILGUN_DOMAIN:-}" \
|
--build-arg MAILGUN_DOMAIN="${MAILGUN_DOMAIN:-}" \
|
||||||
--build-arg MAILGUN_FROM_EMAIL="${MAILGUN_FROM_EMAIL:-}" \
|
--build-arg MAILGUN_FROM_EMAIL="${MAILGUN_FROM_EMAIL:-}" \
|
||||||
--build-arg NODE_ENV="${NODE_ENV:-production}" \
|
--build-arg NODE_ENV="${NODE_ENV:-production}" \
|
||||||
-t meds-validation \
|
-t ${APP_NAME_LOWER}-validation \
|
||||||
--load \
|
--load \
|
||||||
.
|
.
|
||||||
|
|
||||||
@@ -106,16 +111,16 @@ print_status "5. Testing container startup and health..."
|
|||||||
# Run container in background
|
# Run container in background
|
||||||
docker run --rm -d \
|
docker run --rm -d \
|
||||||
-p 8083:80 \
|
-p 8083:80 \
|
||||||
--name meds-validation-test \
|
--name ${APP_NAME_LOWER}-validation-test \
|
||||||
meds-validation
|
${APP_NAME_LOWER}-validation
|
||||||
|
|
||||||
# Wait for container to start
|
# Wait for container to start
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# Check if container is running
|
# Check if container is running
|
||||||
if ! docker ps | grep -q meds-validation-test; then
|
if ! docker ps | grep -q ${APP_NAME_LOWER}-validation-test; then
|
||||||
print_error "Container failed to start"
|
print_error "Container failed to start"
|
||||||
docker logs meds-validation-test
|
docker logs ${APP_NAME_LOWER}-validation-test
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -154,17 +159,17 @@ print_success "Docker Compose build successful"
|
|||||||
|
|
||||||
# Test docker-compose with validation project name
|
# Test docker-compose with validation project name
|
||||||
print_status "8. Testing Docker Compose deployment..."
|
print_status "8. Testing Docker Compose deployment..."
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation up -d --build
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation up -d --build
|
||||||
|
|
||||||
# Wait for services to start
|
# Wait for services to start
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Check service health
|
# Check service health
|
||||||
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
if docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation ps | grep -q "Up"; then
|
||||||
print_success "Docker Compose services started successfully"
|
print_success "Docker Compose services started successfully"
|
||||||
else
|
else
|
||||||
print_error "Docker Compose services failed to start"
|
print_error "Docker Compose services failed to start"
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation logs
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -176,13 +181,13 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "9. Checking image size..."
|
print_status "9. Checking image size..."
|
||||||
IMAGE_SIZE=$(docker image inspect meds-validation --format='{{.Size}}' | numfmt --to=iec)
|
IMAGE_SIZE=$(docker image inspect ${APP_NAME_LOWER}-validation --format='{{.Size}}' | numfmt --to=iec)
|
||||||
print_success "Image size: $IMAGE_SIZE"
|
print_success "Image size: $IMAGE_SIZE"
|
||||||
|
|
||||||
print_status "10. Validating security configuration..."
|
print_status "10. Validating security configuration..."
|
||||||
|
|
||||||
# Check if image runs as non-root
|
# Check if image runs as non-root
|
||||||
USER_INFO=$(docker run --rm meds-validation whoami)
|
USER_INFO=$(docker run --rm ${APP_NAME_LOWER}-validation whoami)
|
||||||
if [[ "$USER_INFO" != "root" ]]; then
|
if [[ "$USER_INFO" != "root" ]]; then
|
||||||
print_success "Container runs as non-root user: $USER_INFO"
|
print_success "Container runs as non-root user: $USER_INFO"
|
||||||
else
|
else
|
||||||
@@ -190,7 +195,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check nginx configuration
|
# Check nginx configuration
|
||||||
if docker run --rm meds-validation nginx -t 2>/dev/null; then
|
if docker run --rm ${APP_NAME_LOWER}-validation nginx -t 2>/dev/null; then
|
||||||
print_success "Nginx configuration is valid"
|
print_success "Nginx configuration is valid"
|
||||||
else
|
else
|
||||||
print_error "Nginx configuration has issues"
|
print_error "Nginx configuration has issues"
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ print_error() {
|
|||||||
# Cleanup function
|
# Cleanup function
|
||||||
cleanup() {
|
cleanup() {
|
||||||
print_status "Cleaning up test containers..."
|
print_status "Cleaning up test containers..."
|
||||||
docker stop meds-validation-test 2>/dev/null || true
|
APP_NAME_LOWER=$(echo "${APP_NAME:-meds}" | tr '[:upper:]' '[:lower:]')
|
||||||
docker rm meds-validation-test 2>/dev/null || true
|
docker stop ${APP_NAME_LOWER}-validation-test 2>/dev/null || true
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation down 2>/dev/null || true
|
docker rm ${APP_NAME_LOWER}-validation-test 2>/dev/null || true
|
||||||
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation down 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set trap for cleanup
|
# Set trap for cleanup
|
||||||
@@ -80,6 +81,9 @@ docker buildx use meds-builder
|
|||||||
|
|
||||||
print_status "4. Building multi-platform Docker image with buildx..."
|
print_status "4. Building multi-platform Docker image with buildx..."
|
||||||
|
|
||||||
|
# Convert APP_NAME to lowercase for Docker compatibility
|
||||||
|
APP_NAME_LOWER=$(echo "${APP_NAME:-meds}" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
# Determine host platform
|
# Determine host platform
|
||||||
HOST_ARCH="$(uname -m)"
|
HOST_ARCH="$(uname -m)"
|
||||||
case "$HOST_ARCH" in
|
case "$HOST_ARCH" in
|
||||||
@@ -97,18 +101,19 @@ if [[ "${MULTI_PLATFORM:-0}" == "1" || -n "${CONTAINER_REGISTRY:-}" ]]; then
|
|||||||
if [[ -n "${CONTAINER_REGISTRY:-}" && "${CONTAINER_REGISTRY}" != */ ]]; then
|
if [[ -n "${CONTAINER_REGISTRY:-}" && "${CONTAINER_REGISTRY}" != */ ]]; then
|
||||||
CONTAINER_REGISTRY="${CONTAINER_REGISTRY}/"
|
CONTAINER_REGISTRY="${CONTAINER_REGISTRY}/"
|
||||||
fi
|
fi
|
||||||
IMAGE_TAG="${IMAGE_TAG:-${CONTAINER_REGISTRY:-}meds-validation:latest}"
|
IMAGE_TAG="${IMAGE_TAG:-${CONTAINER_REGISTRY:-}${APP_NAME_LOWER}-validation:latest}"
|
||||||
print_status "Multi-platform build enabled (platforms: $BUILD_PLATFORMS) -> push $IMAGE_TAG"
|
print_status "Multi-platform build enabled (platforms: $BUILD_PLATFORMS) -> push $IMAGE_TAG"
|
||||||
else
|
else
|
||||||
BUILD_PLATFORMS="$HOST_PLATFORM"
|
BUILD_PLATFORMS="$HOST_PLATFORM"
|
||||||
EXPORT_MODE="--load"
|
EXPORT_MODE="--load"
|
||||||
IMAGE_TAG="${IMAGE_TAG:-meds-validation}"
|
IMAGE_TAG="${IMAGE_TAG:-${APP_NAME_LOWER}-validation}"
|
||||||
print_status "Single-platform build ($BUILD_PLATFORMS) -> load locally as $IMAGE_TAG"
|
print_status "Single-platform build ($BUILD_PLATFORMS) -> load locally as $IMAGE_TAG"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Perform build
|
# Perform build
|
||||||
docker buildx build --no-cache \
|
docker buildx build --no-cache \
|
||||||
--platform "$BUILD_PLATFORMS" \
|
--platform "$BUILD_PLATFORMS" \
|
||||||
|
--build-arg APP_NAME="${APP_NAME:-RxMinder}" \
|
||||||
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
||||||
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
||||||
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
||||||
@@ -138,16 +143,16 @@ print_status "5. Testing container startup and health..."
|
|||||||
# Run container in background
|
# Run container in background
|
||||||
docker run --rm -d \
|
docker run --rm -d \
|
||||||
-p 8083:80 \
|
-p 8083:80 \
|
||||||
--name meds-validation-test \
|
--name ${APP_NAME_LOWER}-validation-test \
|
||||||
"$IMAGE_TAG"
|
"$IMAGE_TAG"
|
||||||
|
|
||||||
# Wait for container to start
|
# Wait for container to start
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# Check if container is running
|
# Check if container is running
|
||||||
if ! docker ps | grep -q meds-validation-test; then
|
if ! docker ps | grep -q ${APP_NAME_LOWER}-validation-test; then
|
||||||
print_error "Container failed to start"
|
print_error "Container failed to start"
|
||||||
docker logs meds-validation-test
|
docker logs ${APP_NAME_LOWER}-validation-test
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -186,17 +191,17 @@ print_success "Docker Compose build successful"
|
|||||||
|
|
||||||
# Test docker-compose with validation project name
|
# Test docker-compose with validation project name
|
||||||
print_status "8. Testing Docker Compose deployment..."
|
print_status "8. Testing Docker Compose deployment..."
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation up -d --build
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation up -d --build
|
||||||
|
|
||||||
# Wait for services to start
|
# Wait for services to start
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Check service health
|
# Check service health
|
||||||
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
if docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation ps | grep -q "Up"; then
|
||||||
print_success "Docker Compose services started successfully"
|
print_success "Docker Compose services started successfully"
|
||||||
else
|
else
|
||||||
print_error "Docker Compose services failed to start"
|
print_error "Docker Compose services failed to start"
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation logs
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
24
scripts/process-html.sh
Executable file
24
scripts/process-html.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Process HTML template with environment variables
|
||||||
|
# This script substitutes environment variables in index.html.template
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
APP_NAME="${APP_NAME:-RxMinder}"
|
||||||
|
|
||||||
|
# Input and output files
|
||||||
|
TEMPLATE_FILE="index.html.template"
|
||||||
|
OUTPUT_FILE="index.html"
|
||||||
|
|
||||||
|
# Check if template exists
|
||||||
|
if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
||||||
|
echo "Error: Template file $TEMPLATE_FILE not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process template with environment variable substitution
|
||||||
|
envsubst '$APP_NAME' < "$TEMPLATE_FILE" > "$OUTPUT_FILE"
|
||||||
|
|
||||||
|
echo "✅ Processed $TEMPLATE_FILE -> $OUTPUT_FILE with APP_NAME=$APP_NAME"
|
||||||
@@ -34,9 +34,10 @@ print_error() {
|
|||||||
# Cleanup function
|
# Cleanup function
|
||||||
cleanup() {
|
cleanup() {
|
||||||
print_status "Cleaning up test containers..."
|
print_status "Cleaning up test containers..."
|
||||||
docker stop meds-validation-test 2>/dev/null || true
|
APP_NAME_LOWER=$(echo "${APP_NAME:-meds}" | tr '[:upper:]' '[:lower:]')
|
||||||
docker rm meds-validation-test 2>/dev/null || true
|
docker stop ${APP_NAME_LOWER}-validation-test 2>/dev/null || true
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation down 2>/dev/null || true
|
docker rm ${APP_NAME_LOWER}-validation-test 2>/dev/null || true
|
||||||
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation down 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set trap for cleanup
|
# Set trap for cleanup
|
||||||
@@ -80,9 +81,11 @@ docker buildx use meds-builder
|
|||||||
|
|
||||||
print_status "4. Building multi-platform Docker image with buildx..."
|
print_status "4. Building multi-platform Docker image with buildx..."
|
||||||
|
|
||||||
# Build the image with buildx for multiple platforms
|
# Build single-platform image for testing
|
||||||
|
APP_NAME_LOWER=$(echo "${APP_NAME:-meds}" | tr '[:upper:]' '[:lower:]')
|
||||||
docker buildx build --no-cache \
|
docker buildx build --no-cache \
|
||||||
--platform linux/amd64,linux/arm64 \
|
--platform linux/amd64 \
|
||||||
|
--build-arg APP_NAME="${APP_NAME:-RxMinder}" \
|
||||||
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
--build-arg COUCHDB_USER="${COUCHDB_USER:-admin}" \
|
||||||
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
--build-arg COUCHDB_PASSWORD="${COUCHDB_PASSWORD:-change-this-secure-password}" \
|
||||||
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
--build-arg VITE_COUCHDB_URL="${VITE_COUCHDB_URL:-http://localhost:5984}" \
|
||||||
@@ -95,7 +98,7 @@ docker buildx build --no-cache \
|
|||||||
--build-arg MAILGUN_DOMAIN="${MAILGUN_DOMAIN:-}" \
|
--build-arg MAILGUN_DOMAIN="${MAILGUN_DOMAIN:-}" \
|
||||||
--build-arg MAILGUN_FROM_EMAIL="${MAILGUN_FROM_EMAIL:-}" \
|
--build-arg MAILGUN_FROM_EMAIL="${MAILGUN_FROM_EMAIL:-}" \
|
||||||
--build-arg NODE_ENV="${NODE_ENV:-production}" \
|
--build-arg NODE_ENV="${NODE_ENV:-production}" \
|
||||||
-t meds-validation \
|
-t ${APP_NAME_LOWER}-validation \
|
||||||
--load \
|
--load \
|
||||||
.
|
.
|
||||||
|
|
||||||
@@ -106,16 +109,16 @@ print_status "5. Testing container startup and health..."
|
|||||||
# Run container in background
|
# Run container in background
|
||||||
docker run --rm -d \
|
docker run --rm -d \
|
||||||
-p 8083:80 \
|
-p 8083:80 \
|
||||||
--name meds-validation-test \
|
--name ${APP_NAME_LOWER}-validation-test \
|
||||||
meds-validation
|
${APP_NAME_LOWER}-validation
|
||||||
|
|
||||||
# Wait for container to start
|
# Wait for container to start
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# Check if container is running
|
# Check if container is running
|
||||||
if ! docker ps | grep -q meds-validation-test; then
|
if ! docker ps | grep -q ${APP_NAME_LOWER}-validation-test; then
|
||||||
print_error "Container failed to start"
|
print_error "Container failed to start"
|
||||||
docker logs meds-validation-test
|
docker logs ${APP_NAME_LOWER}-validation-test
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -154,17 +157,17 @@ print_success "Docker Compose build successful"
|
|||||||
|
|
||||||
# Test docker-compose with validation project name
|
# Test docker-compose with validation project name
|
||||||
print_status "8. Testing Docker Compose deployment..."
|
print_status "8. Testing Docker Compose deployment..."
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation up -d --build
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation up -d --build
|
||||||
|
|
||||||
# Wait for services to start
|
# Wait for services to start
|
||||||
sleep 10
|
sleep 10
|
||||||
|
|
||||||
# Check service health
|
# Check service health
|
||||||
if docker compose -f docker/docker-compose.yaml -p meds-validation ps | grep -q "Up"; then
|
if docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation ps | grep -q "Up"; then
|
||||||
print_success "Docker Compose services started successfully"
|
print_success "Docker Compose services started successfully"
|
||||||
else
|
else
|
||||||
print_error "Docker Compose services failed to start"
|
print_error "Docker Compose services failed to start"
|
||||||
docker compose -f docker/docker-compose.yaml -p meds-validation logs
|
docker compose -f docker/docker-compose.yaml -p ${APP_NAME_LOWER}-validation logs
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -176,13 +179,13 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
print_status "9. Checking image size..."
|
print_status "9. Checking image size..."
|
||||||
IMAGE_SIZE=$(docker image inspect meds-validation --format='{{.Size}}' | numfmt --to=iec)
|
IMAGE_SIZE=$(docker image inspect ${APP_NAME_LOWER}-validation --format='{{.Size}}' | numfmt --to=iec)
|
||||||
print_success "Image size: $IMAGE_SIZE"
|
print_success "Image size: $IMAGE_SIZE"
|
||||||
|
|
||||||
print_status "10. Validating security configuration..."
|
print_status "10. Validating security configuration..."
|
||||||
|
|
||||||
# Check if image runs as non-root
|
# Check if image runs as non-root
|
||||||
USER_INFO=$(docker run --rm meds-validation whoami)
|
USER_INFO=$(docker run --rm ${APP_NAME_LOWER}-validation whoami)
|
||||||
if [[ "$USER_INFO" != "root" ]]; then
|
if [[ "$USER_INFO" != "root" ]]; then
|
||||||
print_success "Container runs as non-root user: $USER_INFO"
|
print_success "Container runs as non-root user: $USER_INFO"
|
||||||
else
|
else
|
||||||
@@ -190,7 +193,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check nginx configuration
|
# Check nginx configuration
|
||||||
if docker run --rm meds-validation nginx -t 2>/dev/null; then
|
if docker run --rm ${APP_NAME_LOWER}-validation nginx -t 2>/dev/null; then
|
||||||
print_success "Nginx configuration is valid"
|
print_success "Nginx configuration is valid"
|
||||||
else
|
else
|
||||||
print_error "Nginx configuration has issues"
|
print_error "Nginx configuration has issues"
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ export default defineConfig(({ mode }) => {
|
|||||||
define: {
|
define: {
|
||||||
'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
|
'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
|
||||||
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),
|
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),
|
||||||
|
'import.meta.env.VITE_APP_NAME': JSON.stringify(
|
||||||
|
env.APP_NAME || 'RxMinder'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|||||||
Reference in New Issue
Block a user