34 changed files with 3331 additions and 552 deletions
@ -0,0 +1,171 @@ |
|||||
|
# TimeSafari Docker Ignore File |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Excludes unnecessary files from Docker build context |
||||
|
# |
||||
|
# Benefits: |
||||
|
# - Faster build times |
||||
|
# - Smaller build context |
||||
|
# - Reduced image size |
||||
|
# - Better security (excludes sensitive files) |
||||
|
|
||||
|
# Dependencies |
||||
|
node_modules |
||||
|
npm-debug.log* |
||||
|
yarn-debug.log* |
||||
|
yarn-error.log* |
||||
|
|
||||
|
# Build outputs |
||||
|
dist |
||||
|
dist-* |
||||
|
build |
||||
|
*.tsbuildinfo |
||||
|
|
||||
|
# Development files |
||||
|
.git |
||||
|
.gitignore |
||||
|
README.md |
||||
|
CHANGELOG.md |
||||
|
CONTRIBUTING.md |
||||
|
BUILDING.md |
||||
|
LICENSE |
||||
|
|
||||
|
# IDE and editor files |
||||
|
.vscode |
||||
|
.idea |
||||
|
*.swp |
||||
|
*.swo |
||||
|
*~ |
||||
|
|
||||
|
# OS generated files |
||||
|
.DS_Store |
||||
|
.DS_Store? |
||||
|
._* |
||||
|
.Spotlight-V100 |
||||
|
.Trashes |
||||
|
ehthumbs.db |
||||
|
Thumbs.db |
||||
|
|
||||
|
# Logs |
||||
|
logs |
||||
|
*.log |
||||
|
|
||||
|
# Runtime data |
||||
|
pids |
||||
|
*.pid |
||||
|
*.seed |
||||
|
*.pid.lock |
||||
|
|
||||
|
# Coverage directory used by tools like istanbul |
||||
|
coverage |
||||
|
*.lcov |
||||
|
|
||||
|
# nyc test coverage |
||||
|
.nyc_output |
||||
|
|
||||
|
# Dependency directories |
||||
|
jspm_packages/ |
||||
|
|
||||
|
# Optional npm cache directory |
||||
|
.npm |
||||
|
|
||||
|
# Optional eslint cache |
||||
|
.eslintcache |
||||
|
|
||||
|
# Optional REPL history |
||||
|
.node_repl_history |
||||
|
|
||||
|
# Output of 'npm pack' |
||||
|
*.tgz |
||||
|
|
||||
|
# Yarn Integrity file |
||||
|
.yarn-integrity |
||||
|
|
||||
|
# dotenv environment variables file |
||||
|
.env |
||||
|
.env.local |
||||
|
.env.development.local |
||||
|
.env.test.local |
||||
|
.env.production.local |
||||
|
|
||||
|
# parcel-bundler cache (https://parceljs.org/) |
||||
|
.cache |
||||
|
.parcel-cache |
||||
|
|
||||
|
# next.js build output |
||||
|
.next |
||||
|
|
||||
|
# nuxt.js build output |
||||
|
.nuxt |
||||
|
|
||||
|
# vuepress build output |
||||
|
.vuepress/dist |
||||
|
|
||||
|
# Serverless directories |
||||
|
.serverless |
||||
|
|
||||
|
# FuseBox cache |
||||
|
.fusebox/ |
||||
|
|
||||
|
# DynamoDB Local files |
||||
|
.dynamodb/ |
||||
|
|
||||
|
# TernJS port file |
||||
|
.tern-port |
||||
|
|
||||
|
# Stores VSCode versions used for testing VSCode extensions |
||||
|
.vscode-test |
||||
|
|
||||
|
# Test files |
||||
|
test-playwright |
||||
|
test-playwright-results |
||||
|
test-results |
||||
|
test-scripts |
||||
|
|
||||
|
# Documentation |
||||
|
doc |
||||
|
|
||||
|
# Scripts (keep only what's needed for build) |
||||
|
scripts/test-*.sh |
||||
|
scripts/*.js |
||||
|
scripts/README.md |
||||
|
|
||||
|
# Platform-specific files |
||||
|
android |
||||
|
ios |
||||
|
electron |
||||
|
|
||||
|
# Docker files (avoid recursive copying) |
||||
|
Dockerfile* |
||||
|
docker-compose* |
||||
|
.dockerignore |
||||
|
|
||||
|
# CI/CD files |
||||
|
.github |
||||
|
.gitlab-ci.yml |
||||
|
.travis.yml |
||||
|
.circleci |
||||
|
|
||||
|
# Temporary files |
||||
|
tmp |
||||
|
temp |
||||
|
|
||||
|
# Backup files |
||||
|
*.bak |
||||
|
*.backup |
||||
|
|
||||
|
# Archive files |
||||
|
*.tar |
||||
|
*.tar.gz |
||||
|
*.zip |
||||
|
*.rar |
||||
|
|
||||
|
# Certificate files |
||||
|
*.pem |
||||
|
*.key |
||||
|
*.crt |
||||
|
*.p12 |
||||
|
|
||||
|
# Configuration files that might contain secrets |
||||
|
*.secrets |
||||
|
secrets.json |
||||
|
config.local.json |
@ -1,36 +1,209 @@ |
|||||
# Build stage |
# TimeSafari Docker Build |
||||
FROM node:22-alpine3.20 AS builder |
# Author: Matthew Raymer |
||||
|
# Description: Multi-stage Docker build for TimeSafari web application |
||||
|
# |
||||
|
# Build Process: |
||||
|
# 1. Base stage: Node.js with build dependencies |
||||
|
# 2. Builder stage: Compile web assets with Vite |
||||
|
# 3. Production stage: Nginx server with optimized assets |
||||
|
# |
||||
|
# Security Features: |
||||
|
# - Non-root user execution |
||||
|
# - Minimal attack surface with Alpine Linux |
||||
|
# - Multi-stage build to reduce image size |
||||
|
# - No build dependencies in final image |
||||
|
# |
||||
|
# Usage: |
||||
|
# Production: docker build -t timesafari:latest . |
||||
|
# Staging: docker build --build-arg BUILD_MODE=staging -t timesafari:staging . |
||||
|
# Development: docker build --build-arg BUILD_MODE=development -t timesafari:dev . |
||||
|
# |
||||
|
# Build Arguments: |
||||
|
# BUILD_MODE: development, staging, or production (default: production) |
||||
|
# NODE_ENV: node environment (default: production) |
||||
|
# VITE_PLATFORM: vite platform (default: web) |
||||
|
# VITE_PWA_ENABLED: enable PWA (default: true) |
||||
|
# VITE_DISABLE_PWA: disable PWA (default: false) |
||||
|
# |
||||
|
# Environment Variables: |
||||
|
# NODE_ENV: Build environment (development/production) |
||||
|
# VITE_APP_SERVER: Application server URL |
||||
|
# VITE_DEFAULT_ENDORSER_API_SERVER: Endorser API server URL |
||||
|
# VITE_DEFAULT_IMAGE_API_SERVER: Image API server URL |
||||
|
# VITE_DEFAULT_PARTNER_API_SERVER: Partner API server URL |
||||
|
# VITE_DEFAULT_PUSH_SERVER: Push notification server URL |
||||
|
# VITE_PASSKEYS_ENABLED: Enable passkeys feature |
||||
|
|
||||
# Install build dependencies |
# ============================================================================= |
||||
|
# BASE STAGE - Common dependencies and setup |
||||
|
# ============================================================================= |
||||
|
FROM node:22-alpine3.20 AS base |
||||
|
|
||||
RUN apk add --no-cache bash git python3 py3-pip py3-setuptools make g++ gcc |
# Install system dependencies for build process |
||||
|
RUN apk add --no-cache \ |
||||
|
bash \ |
||||
|
git \ |
||||
|
python3 \ |
||||
|
py3-pip \ |
||||
|
py3-setuptools \ |
||||
|
make \ |
||||
|
g++ \ |
||||
|
gcc \ |
||||
|
&& rm -rf /var/cache/apk/* |
||||
|
|
||||
|
# Create non-root user for security |
||||
|
RUN addgroup -g 1001 -S nodejs && \ |
||||
|
adduser -S nextjs -u 1001 |
||||
|
|
||||
# Set working directory |
# Set working directory |
||||
WORKDIR /app |
WORKDIR /app |
||||
|
|
||||
# Copy package files |
# Copy package files for dependency installation |
||||
COPY package*.json ./ |
COPY package*.json ./ |
||||
|
|
||||
# Install dependencies |
# Install dependencies with security audit |
||||
RUN npm ci |
RUN npm ci --only=production --audit --fund=false && \ |
||||
|
npm audit fix --audit-level=moderate || true |
||||
|
|
||||
|
# ============================================================================= |
||||
|
# BUILDER STAGE - Compile web assets |
||||
|
# ============================================================================= |
||||
|
FROM base AS builder |
||||
|
|
||||
|
# Define build arguments with defaults |
||||
|
ARG BUILD_MODE=production |
||||
|
ARG NODE_ENV=production |
||||
|
ARG VITE_PLATFORM=web |
||||
|
ARG VITE_PWA_ENABLED=true |
||||
|
ARG VITE_DISABLE_PWA=false |
||||
|
|
||||
|
# Set environment variables from build arguments |
||||
|
ENV BUILD_MODE=${BUILD_MODE} |
||||
|
ENV NODE_ENV=${NODE_ENV} |
||||
|
ENV VITE_PLATFORM=${VITE_PLATFORM} |
||||
|
ENV VITE_PWA_ENABLED=${VITE_PWA_ENABLED} |
||||
|
ENV VITE_DISABLE_PWA=${VITE_DISABLE_PWA} |
||||
|
|
||||
|
# Install all dependencies (including dev dependencies) |
||||
|
RUN npm ci --audit --fund=false && \ |
||||
|
npm audit fix --audit-level=moderate || true |
||||
|
|
||||
# Copy source code |
# Copy source code |
||||
COPY . . |
COPY . . |
||||
|
|
||||
# Build the application |
# Build the application with proper error handling |
||||
RUN npm run build:web |
RUN echo "Building TimeSafari in ${BUILD_MODE} mode..." && \ |
||||
|
npm run build:web || (echo "Build failed. Check the logs above." && exit 1) |
||||
|
|
||||
|
# Verify build output exists |
||||
|
RUN ls -la dist/ || (echo "Build output not found in dist/ directory" && exit 1) |
||||
|
|
||||
|
# ============================================================================= |
||||
|
# PRODUCTION STAGE - Nginx server |
||||
|
# ============================================================================= |
||||
|
FROM nginx:alpine AS production |
||||
|
|
||||
|
# Define build arguments for production stage |
||||
|
ARG BUILD_MODE=production |
||||
|
ARG NODE_ENV=production |
||||
|
|
||||
|
# Set environment variables |
||||
|
ENV BUILD_MODE=${BUILD_MODE} |
||||
|
ENV NODE_ENV=${NODE_ENV} |
||||
|
|
||||
# Production stage |
# Install security updates and clean cache |
||||
FROM nginx:alpine |
RUN apk update && \ |
||||
|
apk upgrade && \ |
||||
|
apk add --no-cache \ |
||||
|
curl \ |
||||
|
&& rm -rf /var/cache/apk/* |
||||
|
|
||||
|
# Create non-root user for nginx |
||||
|
RUN addgroup -g 1001 -S nginx && \ |
||||
|
adduser -S nginx -u 1001 -G nginx |
||||
|
|
||||
|
# Copy appropriate nginx configuration based on build mode |
||||
|
COPY docker/nginx.conf /etc/nginx/nginx.conf |
||||
|
COPY docker/default.conf /etc/nginx/conf.d/default.conf |
||||
|
|
||||
|
# Copy staging configuration if needed |
||||
|
COPY docker/staging.conf /etc/nginx/conf.d/staging.conf |
||||
|
|
||||
# Copy built assets from builder stage |
# Copy built assets from builder stage |
||||
COPY --from=builder /app/dist /usr/share/nginx/html |
COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html |
||||
|
|
||||
|
# Create necessary directories with proper permissions |
||||
|
RUN mkdir -p /var/cache/nginx /var/log/nginx /var/run && \ |
||||
|
chown -R nginx:nginx /var/cache/nginx /var/log/nginx /var/run && \ |
||||
|
chown -R nginx:nginx /usr/share/nginx/html |
||||
|
|
||||
# Copy nginx configuration if needed |
# Switch to non-root user |
||||
# COPY nginx.conf /etc/nginx/conf.d/default.conf |
USER nginx |
||||
|
|
||||
# Expose port 80 |
# Expose port 80 |
||||
EXPOSE 80 |
EXPOSE 80 |
||||
|
|
||||
|
# Health check |
||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ |
||||
|
CMD curl -f http://localhost/ || exit 1 |
||||
|
|
||||
|
# Start nginx with proper signal handling |
||||
|
CMD ["nginx", "-g", "daemon off;"] |
||||
|
|
||||
|
# ============================================================================= |
||||
|
# DEVELOPMENT STAGE - For development with hot reloading |
||||
|
# ============================================================================= |
||||
|
FROM base AS development |
||||
|
|
||||
|
# Define build arguments for development stage |
||||
|
ARG BUILD_MODE=development |
||||
|
ARG NODE_ENV=development |
||||
|
ARG VITE_PLATFORM=web |
||||
|
ARG VITE_PWA_ENABLED=true |
||||
|
ARG VITE_DISABLE_PWA=false |
||||
|
|
||||
|
# Set environment variables |
||||
|
ENV BUILD_MODE=${BUILD_MODE} |
||||
|
ENV NODE_ENV=${NODE_ENV} |
||||
|
ENV VITE_PLATFORM=${VITE_PLATFORM} |
||||
|
ENV VITE_PWA_ENABLED=${VITE_PWA_ENABLED} |
||||
|
ENV VITE_DISABLE_PWA=${VITE_DISABLE_PWA} |
||||
|
|
||||
|
# Install all dependencies including dev dependencies |
||||
|
RUN npm ci --audit --fund=false && \ |
||||
|
npm audit fix --audit-level=moderate || true |
||||
|
|
||||
|
# Copy source code |
||||
|
COPY . . |
||||
|
|
||||
|
# Expose development port |
||||
|
EXPOSE 5173 |
||||
|
|
||||
|
# Start development server |
||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] |
||||
|
|
||||
|
# ============================================================================= |
||||
|
# STAGING STAGE - For staging environment testing |
||||
|
# ============================================================================= |
||||
|
FROM production AS staging |
||||
|
|
||||
|
# Define build arguments for staging stage |
||||
|
ARG BUILD_MODE=staging |
||||
|
ARG NODE_ENV=staging |
||||
|
|
||||
|
# Set environment variables |
||||
|
ENV BUILD_MODE=${BUILD_MODE} |
||||
|
ENV NODE_ENV=${NODE_ENV} |
||||
|
|
||||
|
# Copy staging-specific nginx configuration |
||||
|
COPY docker/staging.conf /etc/nginx/conf.d/default.conf |
||||
|
|
||||
|
# Expose port 80 |
||||
|
EXPOSE 80 |
||||
|
|
||||
|
# Health check for staging |
||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ |
||||
|
CMD curl -f http://localhost/health || exit 1 |
||||
|
|
||||
# Start nginx |
# Start nginx |
||||
CMD ["nginx", "-g", "daemon off;"] |
CMD ["nginx", "-g", "daemon off;"] |
@ -0,0 +1,210 @@ |
|||||
|
# TimeSafari Docker Compose Configuration |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Multi-environment Docker Compose setup for TimeSafari |
||||
|
# |
||||
|
# Usage: |
||||
|
# Development: docker-compose up dev |
||||
|
# Staging: docker-compose up staging |
||||
|
# Production: docker-compose up production |
||||
|
# Custom: BUILD_MODE=staging docker-compose up custom |
||||
|
# |
||||
|
# Environment Variables: |
||||
|
# BUILD_MODE: development, staging, or production (default: production) |
||||
|
# NODE_ENV: node environment (default: production) |
||||
|
# VITE_PLATFORM: vite platform (default: web) |
||||
|
# VITE_PWA_ENABLED: enable PWA (default: true) |
||||
|
# VITE_DISABLE_PWA: disable PWA (default: false) |
||||
|
# PORT: port to expose (default: 80 for production, 5173 for dev) |
||||
|
# ENV_FILE: environment file to use (default: .env.production) |
||||
|
# |
||||
|
# See .env files for application-specific configuration |
||||
|
# VITE_APP_SERVER: Application server URL |
||||
|
# VITE_DEFAULT_ENDORSER_API_SERVER: Endorser API server URL |
||||
|
|
||||
|
version: '3.8' |
||||
|
|
||||
|
# Default values that can be overridden |
||||
|
x-defaults: &defaults |
||||
|
build: |
||||
|
context: . |
||||
|
dockerfile: Dockerfile |
||||
|
args: |
||||
|
BUILD_MODE: ${BUILD_MODE:-production} |
||||
|
NODE_ENV: ${NODE_ENV:-production} |
||||
|
VITE_PLATFORM: ${VITE_PLATFORM:-web} |
||||
|
VITE_PWA_ENABLED: ${VITE_PWA_ENABLED:-true} |
||||
|
VITE_DISABLE_PWA: ${VITE_DISABLE_PWA:-false} |
||||
|
restart: unless-stopped |
||||
|
healthcheck: |
||||
|
test: ["CMD", "curl", "-f", "http://localhost/health"] |
||||
|
interval: 30s |
||||
|
timeout: 10s |
||||
|
retries: 3 |
||||
|
start_period: 40s |
||||
|
|
||||
|
services: |
||||
|
# Development service with hot reloading |
||||
|
dev: |
||||
|
<<: *defaults |
||||
|
build: |
||||
|
context: . |
||||
|
dockerfile: Dockerfile |
||||
|
target: development |
||||
|
args: |
||||
|
BUILD_MODE: development |
||||
|
NODE_ENV: development |
||||
|
VITE_PLATFORM: web |
||||
|
VITE_PWA_ENABLED: true |
||||
|
VITE_DISABLE_PWA: false |
||||
|
ports: |
||||
|
- "${DEV_PORT:-5173}:5173" |
||||
|
volumes: |
||||
|
- .:/app |
||||
|
- /app/node_modules |
||||
|
environment: |
||||
|
- NODE_ENV=development |
||||
|
- VITE_PLATFORM=web |
||||
|
- VITE_PWA_ENABLED=true |
||||
|
- VITE_DISABLE_PWA=false |
||||
|
env_file: |
||||
|
- ${DEV_ENV_FILE:-.env.development} |
||||
|
healthcheck: |
||||
|
test: ["CMD", "curl", "-f", "http://localhost:5173"] |
||||
|
interval: 30s |
||||
|
timeout: 10s |
||||
|
retries: 3 |
||||
|
start_period: 40s |
||||
|
|
||||
|
# Staging service for testing |
||||
|
staging: |
||||
|
<<: *defaults |
||||
|
build: |
||||
|
context: . |
||||
|
dockerfile: Dockerfile |
||||
|
target: staging |
||||
|
args: |
||||
|
BUILD_MODE: staging |
||||
|
NODE_ENV: staging |
||||
|
VITE_PLATFORM: web |
||||
|
VITE_PWA_ENABLED: true |
||||
|
VITE_DISABLE_PWA: false |
||||
|
ports: |
||||
|
- "${STAGING_PORT:-8080}:80" |
||||
|
environment: |
||||
|
- NODE_ENV=staging |
||||
|
- VITE_PLATFORM=web |
||||
|
- VITE_PWA_ENABLED=true |
||||
|
- VITE_DISABLE_PWA=false |
||||
|
env_file: |
||||
|
- ${STAGING_ENV_FILE:-.env.staging} |
||||
|
|
||||
|
# Production service |
||||
|
production: |
||||
|
<<: *defaults |
||||
|
build: |
||||
|
context: . |
||||
|
dockerfile: Dockerfile |
||||
|
target: production |
||||
|
args: |
||||
|
BUILD_MODE: production |
||||
|
NODE_ENV: production |
||||
|
VITE_PLATFORM: web |
||||
|
VITE_PWA_ENABLED: true |
||||
|
VITE_DISABLE_PWA: false |
||||
|
ports: |
||||
|
- "${PROD_PORT:-80}:80" |
||||
|
environment: |
||||
|
- NODE_ENV=production |
||||
|
- VITE_PLATFORM=web |
||||
|
- VITE_PWA_ENABLED=true |
||||
|
- VITE_DISABLE_PWA=false |
||||
|
env_file: |
||||
|
- ${PROD_ENV_FILE:-.env.production} |
||||
|
|
||||
|
# Production service with SSL (requires certificates) |
||||
|
production-ssl: |
||||
|
<<: *defaults |
||||
|
build: |
||||
|
context: . |
||||
|
dockerfile: Dockerfile |
||||
|
target: production |
||||
|
args: |
||||
|
BUILD_MODE: production |
||||
|
NODE_ENV: production |
||||
|
VITE_PLATFORM: web |
||||
|
VITE_PWA_ENABLED: true |
||||
|
VITE_DISABLE_PWA: false |
||||
|
ports: |
||||
|
- "${SSL_PORT:-443}:443" |
||||
|
- "${HTTP_PORT:-80}:80" |
||||
|
environment: |
||||
|
- NODE_ENV=production |
||||
|
- VITE_PLATFORM=web |
||||
|
- VITE_PWA_ENABLED=true |
||||
|
- VITE_DISABLE_PWA=false |
||||
|
env_file: |
||||
|
- ${PROD_ENV_FILE:-.env.production} |
||||
|
volumes: |
||||
|
- ./ssl:/etc/nginx/ssl:ro |
||||
|
- ./docker/nginx-ssl.conf:/etc/nginx/conf.d/default.conf:ro |
||||
|
healthcheck: |
||||
|
test: ["CMD", "curl", "-f", "https://localhost/health"] |
||||
|
interval: 30s |
||||
|
timeout: 10s |
||||
|
retries: 3 |
||||
|
start_period: 40s |
||||
|
|
||||
|
# Custom service - configurable via environment variables |
||||
|
custom: |
||||
|
<<: *defaults |
||||
|
build: |
||||
|
context: . |
||||
|
dockerfile: Dockerfile |
||||
|
target: ${BUILD_TARGET:-production} |
||||
|
args: |
||||
|
BUILD_MODE: ${BUILD_MODE:-production} |
||||
|
NODE_ENV: ${NODE_ENV:-production} |
||||
|
VITE_PLATFORM: ${VITE_PLATFORM:-web} |
||||
|
VITE_PWA_ENABLED: ${VITE_PWA_ENABLED:-true} |
||||
|
VITE_DISABLE_PWA: ${VITE_DISABLE_PWA:-false} |
||||
|
ports: |
||||
|
- "${CUSTOM_PORT:-8080}:${CUSTOM_INTERNAL_PORT:-80}" |
||||
|
environment: |
||||
|
- NODE_ENV=${NODE_ENV:-production} |
||||
|
- VITE_PLATFORM=${VITE_PLATFORM:-web} |
||||
|
- VITE_PWA_ENABLED=${VITE_PWA_ENABLED:-true} |
||||
|
- VITE_DISABLE_PWA=${VITE_DISABLE_PWA:-false} |
||||
|
env_file: |
||||
|
- ${CUSTOM_ENV_FILE:-.env.production} |
||||
|
healthcheck: |
||||
|
test: ["CMD", "curl", "-f", "http://localhost:${CUSTOM_INTERNAL_PORT:-80}/health"] |
||||
|
interval: 30s |
||||
|
timeout: 10s |
||||
|
retries: 3 |
||||
|
start_period: 40s |
||||
|
|
||||
|
# Load balancer for production (optional) |
||||
|
nginx-lb: |
||||
|
image: nginx:alpine |
||||
|
ports: |
||||
|
- "${LB_PORT:-80}:80" |
||||
|
- "${LB_SSL_PORT:-443}:443" |
||||
|
volumes: |
||||
|
- ./docker/nginx-lb.conf:/etc/nginx/nginx.conf:ro |
||||
|
- ./ssl:/etc/nginx/ssl:ro |
||||
|
depends_on: |
||||
|
- production |
||||
|
restart: unless-stopped |
||||
|
healthcheck: |
||||
|
test: ["CMD", "curl", "-f", "http://localhost/health"] |
||||
|
interval: 30s |
||||
|
timeout: 10s |
||||
|
retries: 3 |
||||
|
start_period: 40s |
||||
|
|
||||
|
networks: |
||||
|
default: |
||||
|
driver: bridge |
||||
|
ipam: |
||||
|
config: |
||||
|
- subnet: 172.20.0.0/16 |
@ -0,0 +1,509 @@ |
|||||
|
# TimeSafari Docker Setup |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
This directory contains Docker configuration files for building and deploying TimeSafari across different environments with full configurability. |
||||
|
|
||||
|
## Files |
||||
|
|
||||
|
- `Dockerfile` - Multi-stage Docker build for TimeSafari |
||||
|
- `nginx.conf` - Main nginx configuration with security headers |
||||
|
- `default.conf` - Production server configuration |
||||
|
- `staging.conf` - Staging server configuration with relaxed caching |
||||
|
- `docker-compose.yml` - Multi-environment Docker Compose setup |
||||
|
- `.dockerignore` - Optimizes build context |
||||
|
- `run.sh` - Convenient script to run different configurations |
||||
|
|
||||
|
## Quick Start |
||||
|
|
||||
|
### Using the Run Script (Recommended) |
||||
|
|
||||
|
```bash |
||||
|
# Development mode with hot reloading |
||||
|
./docker/run.sh dev |
||||
|
|
||||
|
# Staging mode for testing |
||||
|
./docker/run.sh staging |
||||
|
|
||||
|
# Production mode |
||||
|
./docker/run.sh production |
||||
|
|
||||
|
# Custom mode with environment variables |
||||
|
BUILD_MODE=staging ./docker/run.sh custom |
||||
|
|
||||
|
# Show build arguments for a mode |
||||
|
./docker/run.sh dev --build-args |
||||
|
|
||||
|
# Custom port and environment file |
||||
|
./docker/run.sh staging --port 9000 --env .env.test |
||||
|
``` |
||||
|
|
||||
|
### Using Docker Compose |
||||
|
|
||||
|
```bash |
||||
|
# Development environment with hot reloading |
||||
|
docker-compose up dev |
||||
|
|
||||
|
# Staging environment |
||||
|
docker-compose up staging |
||||
|
|
||||
|
# Production environment |
||||
|
docker-compose up production |
||||
|
|
||||
|
# Custom environment with variables |
||||
|
BUILD_MODE=staging docker-compose up custom |
||||
|
``` |
||||
|
|
||||
|
## Build Commands |
||||
|
|
||||
|
### Manual Docker Build |
||||
|
|
||||
|
```bash |
||||
|
# Build production image (default) |
||||
|
docker build -t timesafari:latest . |
||||
|
|
||||
|
# Build staging image |
||||
|
docker build --build-arg BUILD_MODE=staging -t timesafari:staging . |
||||
|
|
||||
|
# Build development image |
||||
|
docker build --build-arg BUILD_MODE=development -t timesafari:dev . |
||||
|
|
||||
|
# Build with custom arguments |
||||
|
docker build \ |
||||
|
--build-arg BUILD_MODE=staging \ |
||||
|
--build-arg NODE_ENV=staging \ |
||||
|
--build-arg VITE_PWA_ENABLED=true \ |
||||
|
-t timesafari:custom . |
||||
|
``` |
||||
|
|
||||
|
### Run Container |
||||
|
|
||||
|
```bash |
||||
|
# Run production container |
||||
|
docker run -d -p 80:80 timesafari:latest |
||||
|
|
||||
|
# Run with environment file |
||||
|
docker run -d -p 80:80 --env-file .env.production timesafari:latest |
||||
|
|
||||
|
# Run with custom environment variables |
||||
|
docker run -d -p 80:80 \ |
||||
|
-e VITE_APP_SERVER=https://myapp.com \ |
||||
|
-e VITE_DEFAULT_ENDORSER_API_SERVER=https://api.myapp.com \ |
||||
|
timesafari:latest |
||||
|
``` |
||||
|
|
||||
|
## Configuration Options |
||||
|
|
||||
|
### Build Arguments |
||||
|
|
||||
|
The Dockerfile supports these build arguments: |
||||
|
|
||||
|
| Argument | Default | Description | |
||||
|
|----------|---------|-------------| |
||||
|
| `BUILD_MODE` | `production` | Build mode: development, staging, or production | |
||||
|
| `NODE_ENV` | `production` | Node.js environment | |
||||
|
| `VITE_PLATFORM` | `web` | Vite platform type | |
||||
|
| `VITE_PWA_ENABLED` | `true` | Enable PWA features | |
||||
|
| `VITE_DISABLE_PWA` | `false` | Disable PWA features | |
||||
|
|
||||
|
### Environment Variables |
||||
|
|
||||
|
Docker Compose supports these environment variables: |
||||
|
|
||||
|
| Variable | Default | Description | |
||||
|
|----------|---------|-------------| |
||||
|
| `BUILD_MODE` | `production` | Build mode | |
||||
|
| `NODE_ENV` | `production` | Node environment | |
||||
|
| `VITE_PLATFORM` | `web` | Vite platform | |
||||
|
| `VITE_PWA_ENABLED` | `true` | Enable PWA | |
||||
|
| `VITE_DISABLE_PWA` | `false` | Disable PWA | |
||||
|
| `DEV_PORT` | `5173` | Development port | |
||||
|
| `STAGING_PORT` | `8080` | Staging port | |
||||
|
| `PROD_PORT` | `80` | Production port | |
||||
|
| `DEV_ENV_FILE` | `.env.development` | Development env file | |
||||
|
| `STAGING_ENV_FILE` | `.env.staging` | Staging env file | |
||||
|
| `PROD_ENV_FILE` | `.env.production` | Production env file | |
||||
|
|
||||
|
### Environment Files |
||||
|
|
||||
|
Create environment files for different deployments: |
||||
|
|
||||
|
```bash |
||||
|
# .env.development |
||||
|
VITE_APP_SERVER=https://dev.timesafari.app |
||||
|
VITE_DEFAULT_ENDORSER_API_SERVER=https://dev-api.endorser.ch |
||||
|
VITE_DEFAULT_IMAGE_API_SERVER=https://dev-image-api.timesafari.app |
||||
|
VITE_DEFAULT_PARTNER_API_SERVER=https://dev-partner-api.endorser.ch |
||||
|
VITE_DEFAULT_PUSH_SERVER=https://dev.timesafari.app |
||||
|
VITE_PASSKEYS_ENABLED=true |
||||
|
|
||||
|
# .env.staging |
||||
|
VITE_APP_SERVER=https://staging.timesafari.app |
||||
|
VITE_DEFAULT_ENDORSER_API_SERVER=https://staging-api.endorser.ch |
||||
|
VITE_DEFAULT_IMAGE_API_SERVER=https://staging-image-api.timesafari.app |
||||
|
VITE_DEFAULT_PARTNER_API_SERVER=https://staging-partner-api.endorser.ch |
||||
|
VITE_DEFAULT_PUSH_SERVER=https://staging.timesafari.app |
||||
|
VITE_PASSKEYS_ENABLED=true |
||||
|
|
||||
|
# .env.production |
||||
|
VITE_APP_SERVER=https://timesafari.app |
||||
|
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch |
||||
|
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app |
||||
|
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch |
||||
|
VITE_DEFAULT_PUSH_SERVER=https://timesafari.app |
||||
|
VITE_PASSKEYS_ENABLED=true |
||||
|
``` |
||||
|
|
||||
|
## Build Modes |
||||
|
|
||||
|
### Development Mode |
||||
|
- **Target**: `development` |
||||
|
- **Features**: Hot reloading, development server |
||||
|
- **Port**: 5173 |
||||
|
- **Caching**: Disabled |
||||
|
- **Use Case**: Local development |
||||
|
|
||||
|
```bash |
||||
|
./docker/run.sh dev |
||||
|
# or |
||||
|
docker build --target development -t timesafari:dev . |
||||
|
``` |
||||
|
|
||||
|
### Staging Mode |
||||
|
- **Target**: `staging` |
||||
|
- **Features**: Production build with relaxed caching |
||||
|
- **Port**: 8080 (mapped from 80) |
||||
|
- **Caching**: Short-term (1 hour) |
||||
|
- **Use Case**: Testing and QA |
||||
|
|
||||
|
```bash |
||||
|
./docker/run.sh staging |
||||
|
# or |
||||
|
docker build --build-arg BUILD_MODE=staging -t timesafari:staging . |
||||
|
``` |
||||
|
|
||||
|
### Production Mode |
||||
|
- **Target**: `production` |
||||
|
- **Features**: Optimized production build |
||||
|
- **Port**: 80 |
||||
|
- **Caching**: Long-term (1 year for assets) |
||||
|
- **Use Case**: Live deployment |
||||
|
|
||||
|
```bash |
||||
|
./docker/run.sh production |
||||
|
# or |
||||
|
docker build -t timesafari:latest . |
||||
|
``` |
||||
|
|
||||
|
### Custom Mode |
||||
|
- **Target**: Configurable via `BUILD_TARGET` |
||||
|
- **Features**: Fully configurable |
||||
|
- **Port**: Configurable via `CUSTOM_PORT` |
||||
|
- **Use Case**: Special deployments |
||||
|
|
||||
|
```bash |
||||
|
BUILD_MODE=staging NODE_ENV=staging ./docker/run.sh custom |
||||
|
``` |
||||
|
|
||||
|
## Advanced Usage |
||||
|
|
||||
|
### Custom Build Configuration |
||||
|
|
||||
|
```bash |
||||
|
# Build with specific environment |
||||
|
docker build \ |
||||
|
--build-arg BUILD_MODE=staging \ |
||||
|
--build-arg NODE_ENV=staging \ |
||||
|
--build-arg VITE_PWA_ENABLED=false \ |
||||
|
-t timesafari:staging-no-pwa . |
||||
|
|
||||
|
# Run with custom configuration |
||||
|
docker run -d -p 9000:80 \ |
||||
|
-e VITE_APP_SERVER=https://test.example.com \ |
||||
|
timesafari:staging-no-pwa |
||||
|
``` |
||||
|
|
||||
|
### Docker Compose with Custom Variables |
||||
|
|
||||
|
```bash |
||||
|
# Set environment variables |
||||
|
export BUILD_MODE=staging |
||||
|
export NODE_ENV=staging |
||||
|
export STAGING_PORT=9000 |
||||
|
export STAGING_ENV_FILE=.env.test |
||||
|
|
||||
|
# Run staging with custom config |
||||
|
docker-compose up staging |
||||
|
``` |
||||
|
|
||||
|
### Multi-Environment Deployment |
||||
|
|
||||
|
```bash |
||||
|
# Development |
||||
|
./docker/run.sh dev |
||||
|
|
||||
|
# Staging in another terminal |
||||
|
./docker/run.sh staging --port 8081 |
||||
|
|
||||
|
# Production in another terminal |
||||
|
./docker/run.sh production --port 8082 |
||||
|
``` |
||||
|
|
||||
|
## Security Features |
||||
|
|
||||
|
### Built-in Security |
||||
|
- **Non-root user execution**: All containers run as non-root users |
||||
|
- **Security headers**: XSS protection, content type options, frame options |
||||
|
- **Rate limiting**: API request rate limiting |
||||
|
- **File access restrictions**: Hidden files and backup files blocked |
||||
|
- **Minimal attack surface**: Alpine Linux base images |
||||
|
|
||||
|
### Security Headers |
||||
|
- `X-Frame-Options: SAMEORIGIN` |
||||
|
- `X-Content-Type-Options: nosniff` |
||||
|
- `X-XSS-Protection: 1; mode=block` |
||||
|
- `Referrer-Policy: strict-origin-when-cross-origin` |
||||
|
- `Content-Security-Policy`: Comprehensive CSP policy |
||||
|
|
||||
|
## Performance Optimizations |
||||
|
|
||||
|
### Caching Strategy |
||||
|
- **Static assets**: 1 year cache with immutable flag (production) |
||||
|
- **HTML files**: 1 hour cache (production) / no cache (staging) |
||||
|
- **Service worker**: No cache |
||||
|
- **Manifest**: 1 day cache (production) / 1 hour cache (staging) |
||||
|
|
||||
|
### Compression |
||||
|
- **Gzip compression**: Enabled for text-based files |
||||
|
- **Compression level**: 6 (balanced) |
||||
|
- **Minimum size**: 1024 bytes |
||||
|
|
||||
|
### Nginx Optimizations |
||||
|
- **Sendfile**: Enabled for efficient file serving |
||||
|
- **TCP optimizations**: nopush and nodelay enabled |
||||
|
- **Keepalive**: 65 second timeout |
||||
|
- **Worker processes**: Auto-detected based on CPU cores |
||||
|
|
||||
|
## Health Checks |
||||
|
|
||||
|
### Built-in Health Checks |
||||
|
All services include health checks that: |
||||
|
- Check every 30 seconds |
||||
|
- Timeout after 10 seconds |
||||
|
- Retry 3 times before marking unhealthy |
||||
|
- Start checking after 40 seconds |
||||
|
|
||||
|
### Health Check Endpoints |
||||
|
- **Production/Staging**: `http://localhost/health` |
||||
|
- **Development**: `http://localhost:5173` |
||||
|
|
||||
|
## SSL/HTTPS Setup |
||||
|
|
||||
|
### SSL Certificates |
||||
|
For SSL deployment, create an `ssl` directory with certificates: |
||||
|
|
||||
|
```bash |
||||
|
mkdir ssl |
||||
|
# Copy your certificates to ssl/ directory |
||||
|
cp your-cert.pem ssl/ |
||||
|
cp your-key.pem ssl/ |
||||
|
``` |
||||
|
|
||||
|
### SSL Configuration |
||||
|
Use the `production-ssl` service in docker-compose: |
||||
|
|
||||
|
```bash |
||||
|
docker-compose up production-ssl |
||||
|
``` |
||||
|
|
||||
|
## Monitoring and Logging |
||||
|
|
||||
|
### Log Locations |
||||
|
- **Access logs**: `/var/log/nginx/access.log` |
||||
|
- **Error logs**: `/var/log/nginx/error.log` |
||||
|
|
||||
|
### Log Format |
||||
|
``` |
||||
|
$remote_addr - $remote_user [$time_local] "$request" |
||||
|
$status $body_bytes_sent "$http_referer" |
||||
|
"$http_user_agent" "$http_x_forwarded_for" |
||||
|
``` |
||||
|
|
||||
|
### Log Levels |
||||
|
- **Production**: `warn` level |
||||
|
- **Staging**: `debug` level |
||||
|
- **Development**: Full logging |
||||
|
|
||||
|
## Troubleshooting |
||||
|
|
||||
|
### Common Issues |
||||
|
|
||||
|
#### Build Failures |
||||
|
```bash |
||||
|
# Check build logs |
||||
|
docker build -t timesafari:latest . 2>&1 | tee build.log |
||||
|
|
||||
|
# Verify dependencies |
||||
|
docker run --rm timesafari:latest npm list --depth=0 |
||||
|
|
||||
|
# Check build arguments |
||||
|
./docker/run.sh dev --build-args |
||||
|
``` |
||||
|
|
||||
|
#### Container Won't Start |
||||
|
```bash |
||||
|
# Check container logs |
||||
|
docker logs <container_id> |
||||
|
|
||||
|
# Check health status |
||||
|
docker inspect <container_id> | grep -A 10 "Health" |
||||
|
|
||||
|
# Verify port availability |
||||
|
netstat -tulpn | grep :80 |
||||
|
``` |
||||
|
|
||||
|
#### Environment Variables Not Set |
||||
|
```bash |
||||
|
# Check environment in container |
||||
|
docker exec <container_id> env | grep VITE_ |
||||
|
|
||||
|
# Verify .env file |
||||
|
cat .env.production |
||||
|
|
||||
|
# Check build arguments |
||||
|
./docker/run.sh production --build-args |
||||
|
``` |
||||
|
|
||||
|
#### Performance Issues |
||||
|
```bash |
||||
|
# Check container resources |
||||
|
docker stats <container_id> |
||||
|
|
||||
|
# Check nginx configuration |
||||
|
docker exec <container_id> nginx -t |
||||
|
|
||||
|
# Monitor access logs |
||||
|
docker exec <container_id> tail -f /var/log/nginx/access.log |
||||
|
``` |
||||
|
|
||||
|
### Debug Commands |
||||
|
|
||||
|
#### Container Debugging |
||||
|
```bash |
||||
|
# Enter running container |
||||
|
docker exec -it <container_id> /bin/sh |
||||
|
|
||||
|
# Check nginx status |
||||
|
docker exec <container_id> nginx -t |
||||
|
|
||||
|
# Check file permissions |
||||
|
docker exec <container_id> ls -la /usr/share/nginx/html |
||||
|
``` |
||||
|
|
||||
|
#### Network Debugging |
||||
|
```bash |
||||
|
# Check container network |
||||
|
docker network inspect bridge |
||||
|
|
||||
|
# Test connectivity |
||||
|
docker exec <container_id> curl -I http://localhost |
||||
|
|
||||
|
# Check DNS resolution |
||||
|
docker exec <container_id> nslookup google.com |
||||
|
``` |
||||
|
|
||||
|
## Production Deployment |
||||
|
|
||||
|
### Recommended Production Setup |
||||
|
1. **Use specific version tags**: `timesafari:1.0.0` |
||||
|
2. **Implement health checks**: Already included |
||||
|
3. **Configure proper logging**: Use external log aggregation |
||||
|
4. **Set up reverse proxy**: Use nginx-lb service |
||||
|
5. **Use Docker secrets**: For sensitive data |
||||
|
|
||||
|
### Production Commands |
||||
|
```bash |
||||
|
# Build with specific version |
||||
|
docker build -t timesafari:1.0.0 . |
||||
|
|
||||
|
# Run with production settings |
||||
|
docker run -d \ |
||||
|
--name timesafari \ |
||||
|
-p 80:80 \ |
||||
|
--restart unless-stopped \ |
||||
|
--env-file .env.production \ |
||||
|
timesafari:1.0.0 |
||||
|
|
||||
|
# Update production deployment |
||||
|
docker stop timesafari |
||||
|
docker rm timesafari |
||||
|
docker build -t timesafari:1.0.1 . |
||||
|
docker run -d --name timesafari -p 80:80 --restart unless-stopped --env-file .env.production timesafari:1.0.1 |
||||
|
``` |
||||
|
|
||||
|
## Development Workflow |
||||
|
|
||||
|
### Local Development |
||||
|
```bash |
||||
|
# Start development environment |
||||
|
./docker/run.sh dev |
||||
|
|
||||
|
# Make changes to code (hot reloading enabled) |
||||
|
# Access at http://localhost:5173 |
||||
|
|
||||
|
# Stop development environment |
||||
|
docker-compose down dev |
||||
|
``` |
||||
|
|
||||
|
### Testing Changes |
||||
|
```bash |
||||
|
# Build and test staging |
||||
|
./docker/run.sh staging |
||||
|
|
||||
|
# Test production build locally |
||||
|
./docker/run.sh production |
||||
|
``` |
||||
|
|
||||
|
### Continuous Integration |
||||
|
```bash |
||||
|
# Build and test in CI |
||||
|
docker build -t timesafari:test . |
||||
|
docker run -d --name timesafari-test -p 8080:80 timesafari:test |
||||
|
|
||||
|
# Run tests against container |
||||
|
curl -f http://localhost:8080/health |
||||
|
|
||||
|
# Cleanup |
||||
|
docker stop timesafari-test |
||||
|
docker rm timesafari-test |
||||
|
``` |
||||
|
|
||||
|
## Best Practices |
||||
|
|
||||
|
### Security |
||||
|
- Always use non-root users |
||||
|
- Keep base images updated |
||||
|
- Scan images for vulnerabilities |
||||
|
- Use secrets for sensitive data |
||||
|
- Implement proper access controls |
||||
|
|
||||
|
### Performance |
||||
|
- Use multi-stage builds |
||||
|
- Optimize layer caching |
||||
|
- Minimize image size |
||||
|
- Use appropriate base images |
||||
|
- Implement proper caching |
||||
|
|
||||
|
### Monitoring |
||||
|
- Use health checks |
||||
|
- Monitor resource usage |
||||
|
- Set up log aggregation |
||||
|
- Implement metrics collection |
||||
|
- Use proper error handling |
||||
|
|
||||
|
### Maintenance |
||||
|
- Regular security updates |
||||
|
- Monitor for vulnerabilities |
||||
|
- Keep dependencies updated |
||||
|
- Document configuration changes |
||||
|
- Test deployment procedures |
@ -0,0 +1,110 @@ |
|||||
|
# TimeSafari Default Server Configuration |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Production server configuration for TimeSafari web application |
||||
|
# |
||||
|
# Features: |
||||
|
# - Vue.js SPA routing support |
||||
|
# - Static file caching optimization |
||||
|
# - Security hardening |
||||
|
# - Performance optimization |
||||
|
# - Proper error handling |
||||
|
|
||||
|
server { |
||||
|
listen 80; |
||||
|
server_name _; |
||||
|
root /usr/share/nginx/html; |
||||
|
index index.html; |
||||
|
|
||||
|
# Security headers |
||||
|
add_header X-Frame-Options "SAMEORIGIN" always; |
||||
|
add_header X-Content-Type-Options "nosniff" always; |
||||
|
add_header X-XSS-Protection "1; mode=block" always; |
||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always; |
||||
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; |
||||
|
|
||||
|
# Handle Vue.js SPA routing |
||||
|
location / { |
||||
|
try_files $uri $uri/ /index.html; |
||||
|
|
||||
|
# Cache static assets |
||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { |
||||
|
expires 1y; |
||||
|
add_header Cache-Control "public, immutable"; |
||||
|
add_header Vary "Accept-Encoding"; |
||||
|
} |
||||
|
|
||||
|
# Cache HTML files for a shorter time |
||||
|
location ~* \.html$ { |
||||
|
expires 1h; |
||||
|
add_header Cache-Control "public, must-revalidate"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Handle service worker |
||||
|
location /sw.js { |
||||
|
expires 0; |
||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate"; |
||||
|
add_header Pragma "no-cache"; |
||||
|
} |
||||
|
|
||||
|
# Handle manifest file |
||||
|
location /manifest.json { |
||||
|
expires 1d; |
||||
|
add_header Cache-Control "public"; |
||||
|
} |
||||
|
|
||||
|
# Handle API requests (if needed) |
||||
|
location /api/ { |
||||
|
limit_req zone=api burst=20 nodelay; |
||||
|
proxy_pass http://backend:3000; |
||||
|
proxy_set_header Host $host; |
||||
|
proxy_set_header X-Real-IP $remote_addr; |
||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
||||
|
proxy_set_header X-Forwarded-Proto $scheme; |
||||
|
} |
||||
|
|
||||
|
# Handle health check |
||||
|
location /health { |
||||
|
access_log off; |
||||
|
return 200 "healthy\n"; |
||||
|
add_header Content-Type text/plain; |
||||
|
} |
||||
|
|
||||
|
# Handle robots.txt |
||||
|
location /robots.txt { |
||||
|
expires 1d; |
||||
|
add_header Cache-Control "public"; |
||||
|
} |
||||
|
|
||||
|
# Handle favicon |
||||
|
location /favicon.ico { |
||||
|
expires 1y; |
||||
|
add_header Cache-Control "public, immutable"; |
||||
|
} |
||||
|
|
||||
|
# Security: Deny access to hidden files |
||||
|
location ~ /\. { |
||||
|
deny all; |
||||
|
access_log off; |
||||
|
log_not_found off; |
||||
|
} |
||||
|
|
||||
|
# Security: Deny access to backup files |
||||
|
location ~ ~$ { |
||||
|
deny all; |
||||
|
access_log off; |
||||
|
log_not_found off; |
||||
|
} |
||||
|
|
||||
|
# Error pages |
||||
|
error_page 404 /index.html; |
||||
|
error_page 500 502 503 504 /50x.html; |
||||
|
|
||||
|
location = /50x.html { |
||||
|
root /usr/share/nginx/html; |
||||
|
} |
||||
|
|
||||
|
# Logging |
||||
|
access_log /var/log/nginx/access.log main; |
||||
|
error_log /var/log/nginx/error.log warn; |
||||
|
} |
@ -0,0 +1,72 @@ |
|||||
|
# TimeSafari Nginx Configuration |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Main nginx configuration for TimeSafari web application |
||||
|
# |
||||
|
# Features: |
||||
|
# - Security headers for web application |
||||
|
# - Gzip compression for better performance |
||||
|
# - Proper handling of Vue.js SPA routing |
||||
|
# - Static file caching optimization |
||||
|
# - Security hardening |
||||
|
|
||||
|
user nginx; |
||||
|
worker_processes auto; |
||||
|
error_log /var/log/nginx/error.log warn; |
||||
|
pid /var/run/nginx.pid; |
||||
|
|
||||
|
events { |
||||
|
worker_connections 1024; |
||||
|
use epoll; |
||||
|
multi_accept on; |
||||
|
} |
||||
|
|
||||
|
http { |
||||
|
include /etc/nginx/mime.types; |
||||
|
default_type application/octet-stream; |
||||
|
|
||||
|
# Logging format |
||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' |
||||
|
'$status $body_bytes_sent "$http_referer" ' |
||||
|
'"$http_user_agent" "$http_x_forwarded_for"'; |
||||
|
|
||||
|
access_log /var/log/nginx/access.log main; |
||||
|
|
||||
|
# Performance optimizations |
||||
|
sendfile on; |
||||
|
tcp_nopush on; |
||||
|
tcp_nodelay on; |
||||
|
keepalive_timeout 65; |
||||
|
types_hash_max_size 2048; |
||||
|
client_max_body_size 16M; |
||||
|
|
||||
|
# Gzip compression |
||||
|
gzip on; |
||||
|
gzip_vary on; |
||||
|
gzip_min_length 1024; |
||||
|
gzip_proxied any; |
||||
|
gzip_comp_level 6; |
||||
|
gzip_types |
||||
|
text/plain |
||||
|
text/css |
||||
|
text/xml |
||||
|
text/javascript |
||||
|
application/json |
||||
|
application/javascript |
||||
|
application/xml+rss |
||||
|
application/atom+xml |
||||
|
image/svg+xml; |
||||
|
|
||||
|
# Security headers |
||||
|
add_header X-Frame-Options "SAMEORIGIN" always; |
||||
|
add_header X-Content-Type-Options "nosniff" always; |
||||
|
add_header X-XSS-Protection "1; mode=block" always; |
||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always; |
||||
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'self';" always; |
||||
|
|
||||
|
# Rate limiting |
||||
|
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; |
||||
|
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s; |
||||
|
|
||||
|
# Include server configurations |
||||
|
include /etc/nginx/conf.d/*.conf; |
||||
|
} |
@ -0,0 +1,272 @@ |
|||||
|
#!/bin/bash |
||||
|
# TimeSafari Docker Run Script |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Convenient script to run TimeSafari in different Docker configurations |
||||
|
# |
||||
|
# Usage: |
||||
|
# ./docker/run.sh dev # Run development mode |
||||
|
# ./docker/run.sh staging # Run staging mode |
||||
|
# ./docker/run.sh production # Run production mode |
||||
|
# ./docker/run.sh custom # Run custom mode with environment variables |
||||
|
# |
||||
|
# Environment Variables: |
||||
|
# BUILD_MODE: development, staging, or production |
||||
|
# NODE_ENV: node environment |
||||
|
# VITE_PLATFORM: vite platform |
||||
|
# VITE_PWA_ENABLED: enable PWA |
||||
|
# VITE_DISABLE_PWA: disable PWA |
||||
|
# PORT: port to expose |
||||
|
# ENV_FILE: environment file to use |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
# Colors for output |
||||
|
readonly RED='\033[0;31m' |
||||
|
readonly GREEN='\033[0;32m' |
||||
|
readonly YELLOW='\033[1;33m' |
||||
|
readonly BLUE='\033[0;34m' |
||||
|
readonly NC='\033[0m' # No Color |
||||
|
|
||||
|
# Logging functions |
||||
|
log_info() { |
||||
|
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] [INFO]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_success() { |
||||
|
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_warn() { |
||||
|
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] [WARN]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_error() { |
||||
|
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
# Function to show usage |
||||
|
show_usage() { |
||||
|
echo "TimeSafari Docker Run Script" |
||||
|
echo "" |
||||
|
echo "Usage: $0 <mode> [options]" |
||||
|
echo "" |
||||
|
echo "Modes:" |
||||
|
echo " dev - Development mode with hot reloading" |
||||
|
echo " staging - Staging mode for testing" |
||||
|
echo " production - Production mode" |
||||
|
echo " custom - Custom mode with environment variables" |
||||
|
echo "" |
||||
|
echo "Options:" |
||||
|
echo " --port <port> - Custom port (default: 5173 for dev, 8080 for staging, 80 for production)" |
||||
|
echo " --env <file> - Environment file (default: .env.<mode>)" |
||||
|
echo " --build-args - Show build arguments for the mode" |
||||
|
echo " --help - Show this help message" |
||||
|
echo "" |
||||
|
echo "Examples:" |
||||
|
echo " $0 dev" |
||||
|
echo " $0 staging --port 9000" |
||||
|
echo " $0 production --env .env.prod" |
||||
|
echo " BUILD_MODE=staging $0 custom" |
||||
|
echo "" |
||||
|
echo "Environment Variables:" |
||||
|
echo " BUILD_MODE: development, staging, or production" |
||||
|
echo " NODE_ENV: node environment" |
||||
|
echo " VITE_PLATFORM: vite platform" |
||||
|
echo " VITE_PWA_ENABLED: enable PWA" |
||||
|
echo " VITE_DISABLE_PWA: disable PWA" |
||||
|
echo " PORT: port to expose" |
||||
|
echo " ENV_FILE: environment file to use" |
||||
|
} |
||||
|
|
||||
|
# Function to show build arguments for a mode |
||||
|
show_build_args() { |
||||
|
local mode=$1 |
||||
|
echo "Build arguments for $mode mode:" |
||||
|
echo "" |
||||
|
case $mode in |
||||
|
dev) |
||||
|
echo " BUILD_MODE: development" |
||||
|
echo " NODE_ENV: development" |
||||
|
echo " VITE_PLATFORM: web" |
||||
|
echo " VITE_PWA_ENABLED: true" |
||||
|
echo " VITE_DISABLE_PWA: false" |
||||
|
echo " Target: development" |
||||
|
echo " Port: 5173" |
||||
|
;; |
||||
|
staging) |
||||
|
echo " BUILD_MODE: staging" |
||||
|
echo " NODE_ENV: staging" |
||||
|
echo " VITE_PLATFORM: web" |
||||
|
echo " VITE_PWA_ENABLED: true" |
||||
|
echo " VITE_DISABLE_PWA: false" |
||||
|
echo " Target: staging" |
||||
|
echo " Port: 80 (mapped to 8080)" |
||||
|
;; |
||||
|
production) |
||||
|
echo " BUILD_MODE: production" |
||||
|
echo " NODE_ENV: production" |
||||
|
echo " VITE_PLATFORM: web" |
||||
|
echo " VITE_PWA_ENABLED: true" |
||||
|
echo " VITE_DISABLE_PWA: false" |
||||
|
echo " Target: production" |
||||
|
echo " Port: 80" |
||||
|
;; |
||||
|
custom) |
||||
|
echo " BUILD_MODE: \${BUILD_MODE:-production}" |
||||
|
echo " NODE_ENV: \${NODE_ENV:-production}" |
||||
|
echo " VITE_PLATFORM: \${VITE_PLATFORM:-web}" |
||||
|
echo " VITE_PWA_ENABLED: \${VITE_PWA_ENABLED:-true}" |
||||
|
echo " VITE_DISABLE_PWA: \${VITE_DISABLE_PWA:-false}" |
||||
|
echo " Target: \${BUILD_TARGET:-production}" |
||||
|
echo " Port: \${CUSTOM_PORT:-8080}:\${CUSTOM_INTERNAL_PORT:-80}" |
||||
|
;; |
||||
|
*) |
||||
|
log_error "Unknown mode: $mode" |
||||
|
exit 1 |
||||
|
;; |
||||
|
esac |
||||
|
} |
||||
|
|
||||
|
# Function to check if Docker is running |
||||
|
check_docker() { |
||||
|
if ! docker info > /dev/null 2>&1; then |
||||
|
log_error "Docker is not running. Please start Docker and try again." |
||||
|
exit 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to check if docker-compose is available |
||||
|
check_docker_compose() { |
||||
|
if ! command -v docker-compose > /dev/null 2>&1; then |
||||
|
log_error "docker-compose is not installed. Please install docker-compose and try again." |
||||
|
exit 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to check if required files exist |
||||
|
check_files() { |
||||
|
local mode=$1 |
||||
|
local env_file=$2 |
||||
|
|
||||
|
if [ ! -f "Dockerfile" ]; then |
||||
|
log_error "Dockerfile not found. Please run this script from the project root." |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
if [ ! -f "docker-compose.yml" ]; then |
||||
|
log_error "docker-compose.yml not found. Please run this script from the project root." |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -n "$env_file" ] && [ ! -f "$env_file" ]; then |
||||
|
log_warn "Environment file $env_file not found. Using defaults." |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to run the container |
||||
|
run_container() { |
||||
|
local mode=$1 |
||||
|
local port=$2 |
||||
|
local env_file=$3 |
||||
|
|
||||
|
log_info "Starting TimeSafari in $mode mode..." |
||||
|
|
||||
|
# Set environment variables based on mode |
||||
|
case $mode in |
||||
|
dev) |
||||
|
export DEV_PORT=${port:-5173} |
||||
|
if [ -n "$env_file" ]; then |
||||
|
export DEV_ENV_FILE="$env_file" |
||||
|
fi |
||||
|
docker-compose up dev |
||||
|
;; |
||||
|
staging) |
||||
|
export STAGING_PORT=${port:-8080} |
||||
|
if [ -n "$env_file" ]; then |
||||
|
export STAGING_ENV_FILE="$env_file" |
||||
|
fi |
||||
|
docker-compose up staging |
||||
|
;; |
||||
|
production) |
||||
|
export PROD_PORT=${port:-80} |
||||
|
if [ -n "$env_file" ]; then |
||||
|
export PROD_ENV_FILE="$env_file" |
||||
|
fi |
||||
|
docker-compose up production |
||||
|
;; |
||||
|
custom) |
||||
|
export CUSTOM_PORT=${port:-8080} |
||||
|
if [ -n "$env_file" ]; then |
||||
|
export CUSTOM_ENV_FILE="$env_file" |
||||
|
fi |
||||
|
docker-compose up custom |
||||
|
;; |
||||
|
*) |
||||
|
log_error "Unknown mode: $mode" |
||||
|
exit 1 |
||||
|
;; |
||||
|
esac |
||||
|
} |
||||
|
|
||||
|
# Main script |
||||
|
main() { |
||||
|
local mode="" |
||||
|
local port="" |
||||
|
local env_file="" |
||||
|
local show_args=false |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
while [[ $# -gt 0 ]]; do |
||||
|
case $1 in |
||||
|
dev|staging|production|custom) |
||||
|
mode="$1" |
||||
|
shift |
||||
|
;; |
||||
|
--port) |
||||
|
port="$2" |
||||
|
shift 2 |
||||
|
;; |
||||
|
--env) |
||||
|
env_file="$2" |
||||
|
shift 2 |
||||
|
;; |
||||
|
--build-args) |
||||
|
show_args=true |
||||
|
shift |
||||
|
;; |
||||
|
--help|-h) |
||||
|
show_usage |
||||
|
exit 0 |
||||
|
;; |
||||
|
*) |
||||
|
log_error "Unknown option: $1" |
||||
|
show_usage |
||||
|
exit 1 |
||||
|
;; |
||||
|
esac |
||||
|
done |
||||
|
|
||||
|
# Check if mode is provided |
||||
|
if [ -z "$mode" ]; then |
||||
|
log_error "No mode specified." |
||||
|
show_usage |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
# Show build arguments if requested |
||||
|
if [ "$show_args" = true ]; then |
||||
|
show_build_args "$mode" |
||||
|
exit 0 |
||||
|
fi |
||||
|
|
||||
|
# Check prerequisites |
||||
|
check_docker |
||||
|
check_docker_compose |
||||
|
check_files "$mode" "$env_file" |
||||
|
|
||||
|
# Run the container |
||||
|
run_container "$mode" "$port" "$env_file" |
||||
|
} |
||||
|
|
||||
|
# Run main function with all arguments |
||||
|
main "$@" |
@ -0,0 +1,110 @@ |
|||||
|
# TimeSafari Staging Server Configuration |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Staging server configuration for TimeSafari web application |
||||
|
# |
||||
|
# Features: |
||||
|
# - Relaxed caching for testing |
||||
|
# - Debug-friendly settings |
||||
|
# - Same security as production |
||||
|
# - Development-friendly error handling |
||||
|
|
||||
|
server { |
||||
|
listen 80; |
||||
|
server_name _; |
||||
|
root /usr/share/nginx/html; |
||||
|
index index.html; |
||||
|
|
||||
|
# Security headers (same as production) |
||||
|
add_header X-Frame-Options "SAMEORIGIN" always; |
||||
|
add_header X-Content-Type-Options "nosniff" always; |
||||
|
add_header X-XSS-Protection "1; mode=block" always; |
||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always; |
||||
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; |
||||
|
|
||||
|
# Handle Vue.js SPA routing |
||||
|
location / { |
||||
|
try_files $uri $uri/ /index.html; |
||||
|
|
||||
|
# Relaxed caching for staging |
||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { |
||||
|
expires 1h; |
||||
|
add_header Cache-Control "public, must-revalidate"; |
||||
|
add_header Vary "Accept-Encoding"; |
||||
|
} |
||||
|
|
||||
|
# No caching for HTML files in staging |
||||
|
location ~* \.html$ { |
||||
|
expires 0; |
||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate"; |
||||
|
add_header Pragma "no-cache"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Handle service worker (no caching) |
||||
|
location /sw.js { |
||||
|
expires 0; |
||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate"; |
||||
|
add_header Pragma "no-cache"; |
||||
|
} |
||||
|
|
||||
|
# Handle manifest file (short cache) |
||||
|
location /manifest.json { |
||||
|
expires 1h; |
||||
|
add_header Cache-Control "public, must-revalidate"; |
||||
|
} |
||||
|
|
||||
|
# Handle API requests (if needed) |
||||
|
location /api/ { |
||||
|
limit_req zone=api burst=20 nodelay; |
||||
|
proxy_pass http://backend:3000; |
||||
|
proxy_set_header Host $host; |
||||
|
proxy_set_header X-Real-IP $remote_addr; |
||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
||||
|
proxy_set_header X-Forwarded-Proto $scheme; |
||||
|
} |
||||
|
|
||||
|
# Handle health check |
||||
|
location /health { |
||||
|
access_log off; |
||||
|
return 200 "healthy-staging\n"; |
||||
|
add_header Content-Type text/plain; |
||||
|
} |
||||
|
|
||||
|
# Handle robots.txt (no caching in staging) |
||||
|
location /robots.txt { |
||||
|
expires 0; |
||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate"; |
||||
|
} |
||||
|
|
||||
|
# Handle favicon (short cache) |
||||
|
location /favicon.ico { |
||||
|
expires 1h; |
||||
|
add_header Cache-Control "public, must-revalidate"; |
||||
|
} |
||||
|
|
||||
|
# Security: Deny access to hidden files |
||||
|
location ~ /\. { |
||||
|
deny all; |
||||
|
access_log off; |
||||
|
log_not_found off; |
||||
|
} |
||||
|
|
||||
|
# Security: Deny access to backup files |
||||
|
location ~ ~$ { |
||||
|
deny all; |
||||
|
access_log off; |
||||
|
log_not_found off; |
||||
|
} |
||||
|
|
||||
|
# Error pages (more verbose for staging) |
||||
|
error_page 404 /index.html; |
||||
|
error_page 500 502 503 504 /50x.html; |
||||
|
|
||||
|
location = /50x.html { |
||||
|
root /usr/share/nginx/html; |
||||
|
} |
||||
|
|
||||
|
# Enhanced logging for staging |
||||
|
access_log /var/log/nginx/access.log main; |
||||
|
error_log /var/log/nginx/error.log debug; |
||||
|
} |
@ -0,0 +1,155 @@ |
|||||
|
#!/bin/bash |
||||
|
# experiment.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Build script for TimeSafari Electron application |
||||
|
# This script handles the complete build process for the TimeSafari Electron app, |
||||
|
# including web asset compilation and Capacitor sync. |
||||
|
# |
||||
|
# Build Process: |
||||
|
# 1. Environment setup and dependency checks |
||||
|
# 2. Web asset compilation (Vite) |
||||
|
# 3. Capacitor sync |
||||
|
# 4. Electron start |
||||
|
# |
||||
|
# Dependencies: |
||||
|
# - Node.js and npm |
||||
|
# - TypeScript |
||||
|
# - Vite |
||||
|
# - @capacitor-community/electron |
||||
|
# |
||||
|
# Usage: ./experiment.sh |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Required command not found |
||||
|
# 2 - TypeScript installation failed |
||||
|
# 3 - Build process failed |
||||
|
# 4 - Capacitor sync failed |
||||
|
# 5 - Electron start failed |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# ANSI color codes for better output formatting |
||||
|
readonly RED='\033[0;31m' |
||||
|
readonly GREEN='\033[0;32m' |
||||
|
readonly YELLOW='\033[1;33m' |
||||
|
readonly BLUE='\033[0;34m' |
||||
|
readonly NC='\033[0m' # No Color |
||||
|
|
||||
|
# Logging functions |
||||
|
log_info() { |
||||
|
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] [INFO]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_success() { |
||||
|
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_warn() { |
||||
|
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] [WARN]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_error() { |
||||
|
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
# Function to check if a command exists |
||||
|
check_command() { |
||||
|
if ! command -v "$1" &> /dev/null; then |
||||
|
log_error "$1 is required but not installed." |
||||
|
exit 1 |
||||
|
fi |
||||
|
log_info "Found $1: $(command -v "$1")" |
||||
|
} |
||||
|
|
||||
|
# Function to measure and log execution time |
||||
|
measure_time() { |
||||
|
local start_time=$(date +%s) |
||||
|
"$@" |
||||
|
local end_time=$(date +%s) |
||||
|
local duration=$((end_time - start_time)) |
||||
|
log_success "Completed in ${duration} seconds" |
||||
|
} |
||||
|
|
||||
|
# Print build header |
||||
|
echo -e "\n${BLUE}=== TimeSafari Electron Build Process ===${NC}\n" |
||||
|
log_info "Starting build process at $(date)" |
||||
|
|
||||
|
# Check required commands |
||||
|
log_info "Checking required dependencies..." |
||||
|
check_command node |
||||
|
check_command npm |
||||
|
check_command git |
||||
|
|
||||
|
# Create application data directory |
||||
|
log_info "Setting up application directories..." |
||||
|
mkdir -p ~/.local/share/TimeSafari/timesafari |
||||
|
|
||||
|
# Clean up previous builds |
||||
|
log_info "Cleaning previous builds..." |
||||
|
rm -rf dist* || log_warn "No previous builds to clean" |
||||
|
|
||||
|
# Set environment variables for the build |
||||
|
log_info "Configuring build environment..." |
||||
|
export VITE_PLATFORM=electron |
||||
|
export VITE_PWA_ENABLED=false |
||||
|
export VITE_DISABLE_PWA=true |
||||
|
export DEBUG_MIGRATIONS=0 |
||||
|
|
||||
|
# Ensure TypeScript is installed |
||||
|
log_info "Verifying TypeScript installation..." |
||||
|
if [ ! -f "./node_modules/.bin/tsc" ]; then |
||||
|
log_info "Installing TypeScript..." |
||||
|
if ! npm install --save-dev typescript@~5.2.2; then |
||||
|
log_error "TypeScript installation failed!" |
||||
|
exit 2 |
||||
|
fi |
||||
|
# Verify installation |
||||
|
if [ ! -f "./node_modules/.bin/tsc" ]; then |
||||
|
log_error "TypeScript installation verification failed!" |
||||
|
exit 2 |
||||
|
fi |
||||
|
log_success "TypeScript installed successfully" |
||||
|
else |
||||
|
log_info "TypeScript already installed" |
||||
|
fi |
||||
|
|
||||
|
# Get git hash for versioning |
||||
|
GIT_HASH=$(git log -1 --pretty=format:%h) |
||||
|
log_info "Using git hash: ${GIT_HASH}" |
||||
|
|
||||
|
# Build web assets |
||||
|
log_info "Building web assets with Vite..." |
||||
|
if ! measure_time env VITE_GIT_HASH="$GIT_HASH" npx vite build --config vite.config.app.electron.mts --mode electron; then |
||||
|
log_error "Web asset build failed!" |
||||
|
exit 3 |
||||
|
fi |
||||
|
|
||||
|
# Sync with Capacitor |
||||
|
log_info "Syncing with Capacitor..." |
||||
|
if ! measure_time npx cap sync electron; then |
||||
|
log_error "Capacitor sync failed!" |
||||
|
exit 4 |
||||
|
fi |
||||
|
|
||||
|
# Restore capacitor config |
||||
|
log_info "Restoring capacitor config..." |
||||
|
if ! git checkout electron/capacitor.config.json; then |
||||
|
log_error "Failed to restore capacitor config!" |
||||
|
exit 4 |
||||
|
fi |
||||
|
|
||||
|
# Start Electron |
||||
|
log_info "Starting Electron..." |
||||
|
cd electron/ |
||||
|
if ! measure_time npm run electron:start; then |
||||
|
log_error "Electron start failed!" |
||||
|
exit 5 |
||||
|
fi |
||||
|
|
||||
|
# Print build summary |
||||
|
log_success "Build and start completed successfully!" |
||||
|
echo -e "\n${GREEN}=== End of Build Process ===${NC}\n" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -1,6 +0,0 @@ |
|||||
eth_keys |
|
||||
pywebview |
|
||||
pyinstaller>=6.12.0 |
|
||||
setuptools>=69.0.0 # Required for distutils for electron-builder on macOS |
|
||||
# For development |
|
||||
watchdog>=3.0.0 # For file watching support |
|
@ -0,0 +1,285 @@ |
|||||
|
# TimeSafari Build Scripts |
||||
|
|
||||
|
This directory contains unified build and test scripts for the TimeSafari application. All scripts use a common utilities library to eliminate redundancy and provide consistent logging, error handling, timing, and environment variable management. |
||||
|
|
||||
|
## Architecture |
||||
|
|
||||
|
### Common Utilities (`common.sh`) |
||||
|
|
||||
|
The `common.sh` script provides shared functionality used by all build scripts: |
||||
|
|
||||
|
- **Logging Functions**: `log_info`, `log_success`, `log_warn`, `log_error`, `log_debug`, `log_step` |
||||
|
- **Timing**: `measure_time` for execution time tracking |
||||
|
- **Headers/Footers**: `print_header`, `print_footer` for consistent output formatting |
||||
|
- **Validation**: `check_command`, `check_directory`, `check_file`, `check_venv` |
||||
|
- **Execution**: `safe_execute` for error-handled command execution |
||||
|
- **Utilities**: `get_git_hash`, `clean_build_artifacts`, `validate_env_vars` |
||||
|
- **Environment Management**: `setup_build_env`, `setup_app_directories`, `load_env_file`, `print_env_vars` |
||||
|
- **CLI**: `parse_args`, `print_usage` for command-line argument handling |
||||
|
|
||||
|
### Environment Variable Management |
||||
|
|
||||
|
All scripts automatically handle environment variables for different build types: |
||||
|
|
||||
|
#### Build Types and Environment Variables |
||||
|
|
||||
|
| Platform | Mode | PWA Enabled | Native Features | Build Script | |
||||
|
|----------|------|-------------|-----------------|--------------| |
||||
|
| `web` | web | true | false | `build-web.sh` | |
||||
|
| `capacitor` | capacitor | false | true | `build-capacitor.sh` | |
||||
|
| `electron` | electron | false | true | `build-electron.sh` | |
||||
|
|
||||
|
#### Automatic Environment Setup |
||||
|
|
||||
|
Each script automatically: |
||||
|
1. **Sets platform-specific variables** based on build type |
||||
|
2. **Gets git hash** for versioning (`VITE_GIT_HASH`) |
||||
|
3. **Creates application directories** (`~/.local/share/TimeSafari/timesafari`) |
||||
|
4. **Loads .env file** if it exists |
||||
|
5. **Validates required variables** when needed |
||||
|
|
||||
|
#### Environment Functions |
||||
|
|
||||
|
- `setup_build_env(build_type, production)` - Sets environment for specific build type |
||||
|
- `setup_app_directories()` - Creates necessary application directories |
||||
|
- `load_env_file(filename)` - Loads variables from .env file |
||||
|
- `print_env_vars(prefix)` - Displays current environment variables |
||||
|
- `validate_env_vars(var1, var2, ...)` - Validates required variables exist |
||||
|
|
||||
|
### Script Structure |
||||
|
|
||||
|
All scripts follow this unified pattern: |
||||
|
|
||||
|
```bash |
||||
|
#!/bin/bash |
||||
|
# script-name.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Brief description of what the script does |
||||
|
# |
||||
|
# Exit Codes: List of exit codes and their meanings |
||||
|
# Usage: ./scripts/script-name.sh [options] |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print header |
||||
|
print_header "Script Title" |
||||
|
log_info "Starting process at $(date)" |
||||
|
|
||||
|
# Setup environment (automatic) |
||||
|
setup_build_env "build_type" |
||||
|
setup_app_directories |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Execute steps with safe_execute |
||||
|
safe_execute "Step description" "command to execute" || exit 1 |
||||
|
|
||||
|
# Print footer |
||||
|
print_footer "Script Title" |
||||
|
exit 0 |
||||
|
``` |
||||
|
|
||||
|
## Available Scripts |
||||
|
|
||||
|
### Test Scripts |
||||
|
|
||||
|
- **`test-all.sh`**: Comprehensive test suite (prerequisites, build, web tests, mobile tests) |
||||
|
- **`test-mobile.sh`**: Mobile test suite (Capacitor build, Android tests, iOS tests) |
||||
|
- **`test-common.sh`**: Test script to verify common utilities work correctly |
||||
|
- **`test-env.sh`**: Test script to verify environment variable handling |
||||
|
|
||||
|
### Build Scripts |
||||
|
|
||||
|
- **`build-electron.sh`**: Complete Electron build process |
||||
|
- **`build-android.sh`**: Complete Android build process |
||||
|
- **`build-electron-linux.sh`**: Linux Electron packaging (AppImage, .deb) |
||||
|
- **`build-electron-mac.sh`**: macOS Electron packaging (standard, universal) |
||||
|
|
||||
|
### Development Scripts |
||||
|
|
||||
|
- **`electron-dev.sh`**: Electron development workflow |
||||
|
|
||||
|
## Benefits of Unification |
||||
|
|
||||
|
### Before (Redundant) |
||||
|
```bash |
||||
|
# Each script had 50+ lines of duplicate code: |
||||
|
readonly RED='\033[0;31m' |
||||
|
readonly GREEN='\033[0;32m' |
||||
|
# ... 40+ more lines of duplicate logging functions |
||||
|
log_info "Step 1/4: Doing something..." |
||||
|
if ! measure_time some_command; then |
||||
|
log_error "Step failed!" |
||||
|
exit 1 |
||||
|
fi |
||||
|
# Manual environment variable setup |
||||
|
export VITE_PLATFORM=electron |
||||
|
export VITE_PWA_ENABLED=false |
||||
|
# ... more manual exports |
||||
|
``` |
||||
|
|
||||
|
### After (Unified) |
||||
|
```bash |
||||
|
# Each script is now ~20 lines of focused logic: |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
print_header "Script Title" |
||||
|
setup_build_env "electron" # Automatic environment setup |
||||
|
safe_execute "Step description" "some_command" || exit 1 |
||||
|
print_footer "Script Title" |
||||
|
``` |
||||
|
|
||||
|
## Usage Examples |
||||
|
|
||||
|
### Running Tests |
||||
|
```bash |
||||
|
# Run all tests |
||||
|
./scripts/test-all.sh |
||||
|
|
||||
|
# Run mobile tests only |
||||
|
./scripts/test-mobile.sh |
||||
|
|
||||
|
# Run with verbose logging |
||||
|
./scripts/test-all.sh --verbose |
||||
|
|
||||
|
# Show environment variables |
||||
|
./scripts/test-env.sh --env |
||||
|
``` |
||||
|
|
||||
|
### Building Applications |
||||
|
```bash |
||||
|
# Build Electron |
||||
|
./scripts/build-electron.sh |
||||
|
|
||||
|
# Build Android |
||||
|
./scripts/build-android.sh |
||||
|
|
||||
|
# Build Linux package |
||||
|
./scripts/build-electron-linux.sh deb |
||||
|
|
||||
|
# Build universal Mac package |
||||
|
./scripts/build-electron-mac.sh universal |
||||
|
|
||||
|
# Show environment variables for build |
||||
|
./scripts/build-electron.sh --env |
||||
|
``` |
||||
|
|
||||
|
### Development Workflows |
||||
|
```bash |
||||
|
# Start Electron development |
||||
|
./scripts/electron-dev.sh |
||||
|
``` |
||||
|
|
||||
|
## Environment Variable Features |
||||
|
|
||||
|
### Automatic Setup |
||||
|
All scripts automatically configure the correct environment variables for their build type: |
||||
|
|
||||
|
```bash |
||||
|
# Electron builds automatically get: |
||||
|
export VITE_PLATFORM=electron |
||||
|
export VITE_PWA_ENABLED=false |
||||
|
export VITE_DISABLE_PWA=true |
||||
|
export DEBUG_MIGRATIONS=0 |
||||
|
export VITE_GIT_HASH=<git-hash> |
||||
|
|
||||
|
# Production builds also get: |
||||
|
export NODE_ENV=production |
||||
|
``` |
||||
|
|
||||
|
### .env File Support |
||||
|
Scripts automatically load variables from `.env` files if they exist: |
||||
|
|
||||
|
```bash |
||||
|
# .env file example: |
||||
|
VITE_API_URL=https://api.example.com |
||||
|
VITE_DEBUG=true |
||||
|
CUSTOM_VAR=value |
||||
|
``` |
||||
|
|
||||
|
### Environment Validation |
||||
|
Required environment variables can be validated: |
||||
|
|
||||
|
```bash |
||||
|
# In your script |
||||
|
validate_env_vars "VITE_API_URL" "VITE_DEBUG" || exit 1 |
||||
|
``` |
||||
|
|
||||
|
### Environment Inspection |
||||
|
View current environment variables with the `--env` flag: |
||||
|
|
||||
|
```bash |
||||
|
./scripts/build-electron.sh --env |
||||
|
./scripts/test-env.sh --env |
||||
|
``` |
||||
|
|
||||
|
## Error Handling |
||||
|
|
||||
|
All scripts use consistent error handling: |
||||
|
|
||||
|
- **Exit Codes**: Each script documents specific exit codes |
||||
|
- **Safe Execution**: `safe_execute` provides timing and error handling |
||||
|
- **Graceful Failure**: Scripts stop on first error with clear messages |
||||
|
- **Logging**: All operations are logged with timestamps and colors |
||||
|
- **Environment Validation**: Required variables are checked before execution |
||||
|
|
||||
|
## Testing |
||||
|
|
||||
|
To verify the common utilities work correctly: |
||||
|
|
||||
|
```bash |
||||
|
# Test all common functions |
||||
|
./scripts/test-common.sh |
||||
|
|
||||
|
# Test environment variable handling |
||||
|
./scripts/test-env.sh |
||||
|
|
||||
|
# Test with verbose logging |
||||
|
./scripts/test-env.sh --verbose |
||||
|
``` |
||||
|
|
||||
|
## Maintenance |
||||
|
|
||||
|
### Adding New Scripts |
||||
|
|
||||
|
1. Create new script following the unified pattern |
||||
|
2. Source `common.sh` at the top |
||||
|
3. Use `setup_build_env()` for environment setup |
||||
|
4. Use `safe_execute` for command execution |
||||
|
5. Document exit codes and usage |
||||
|
6. Make executable: `chmod +x scripts/new-script.sh` |
||||
|
|
||||
|
### Modifying Common Utilities |
||||
|
|
||||
|
1. Update `common.sh` with new functions |
||||
|
2. Export new functions with `export -f function_name` |
||||
|
3. Update this README if adding new categories |
||||
|
4. Test with `test-common.sh` and `test-env.sh` |
||||
|
|
||||
|
### Adding New Build Types |
||||
|
|
||||
|
1. Add new case to `setup_build_env()` function |
||||
|
2. Define appropriate environment variables |
||||
|
3. Update this README with new build type |
||||
|
4. Test with `test-env.sh` |
||||
|
|
||||
|
## Security Considerations |
||||
|
|
||||
|
- All scripts use `set -e` for immediate failure on errors |
||||
|
- Commands are executed through `safe_execute` for consistent error handling |
||||
|
- No direct execution of user input without validation |
||||
|
- Environment variables are validated when required |
||||
|
- .env files are loaded safely with proper parsing |
||||
|
|
||||
|
## Performance |
||||
|
|
||||
|
- Common utilities are sourced once per script execution |
||||
|
- Timing information is automatically collected for all operations |
||||
|
- Build artifacts are cleaned up automatically |
||||
|
- No redundant command execution or file operations |
||||
|
- Environment variables are set efficiently with minimal overhead |
@ -0,0 +1,71 @@ |
|||||
|
#!/bin/bash |
||||
|
# build-android.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Android build script for TimeSafari application |
||||
|
# This script handles the complete Android build process including cleanup, |
||||
|
# web build, Capacitor build, Gradle build, and Android Studio launch. |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Android cleanup failed |
||||
|
# 2 - Web build failed |
||||
|
# 3 - Capacitor build failed |
||||
|
# 4 - Gradle clean failed |
||||
|
# 5 - Gradle assemble failed |
||||
|
# 6 - Capacitor sync failed |
||||
|
# 7 - Asset generation failed |
||||
|
# 8 - Android Studio launch failed |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print build header |
||||
|
print_header "TimeSafari Android Build Process" |
||||
|
log_info "Starting Android build process at $(date)" |
||||
|
|
||||
|
# Setup environment for Capacitor build |
||||
|
setup_build_env "capacitor" |
||||
|
|
||||
|
# Setup application directories |
||||
|
setup_app_directories |
||||
|
|
||||
|
# Load environment from .env file if it exists |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Step 1: Clean Android app |
||||
|
safe_execute "Cleaning Android app" "npm run clean:android" || exit 1 |
||||
|
|
||||
|
# Step 2: Clean dist directory |
||||
|
log_info "Cleaning dist directory..." |
||||
|
clean_build_artifacts "dist" |
||||
|
|
||||
|
# Step 3: Build web assets |
||||
|
safe_execute "Building web assets" "npm run build:web" || exit 2 |
||||
|
|
||||
|
# Step 4: Build Capacitor version |
||||
|
safe_execute "Building Capacitor version" "npm run build:capacitor" || exit 3 |
||||
|
|
||||
|
# Step 5: Clean Gradle build |
||||
|
safe_execute "Cleaning Gradle build" "cd android && ./gradlew clean && cd .." || exit 4 |
||||
|
|
||||
|
# Step 6: Assemble debug build |
||||
|
safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5 |
||||
|
|
||||
|
# Step 7: Sync with Capacitor |
||||
|
safe_execute "Syncing with Capacitor" "npx cap sync android" || exit 6 |
||||
|
|
||||
|
# Step 8: Generate assets and open Android Studio |
||||
|
safe_execute "Generating assets" "npx capacitor-assets generate --android" || exit 7 |
||||
|
safe_execute "Opening Android Studio" "npx cap open android" || exit 8 |
||||
|
|
||||
|
# Print build summary |
||||
|
log_success "Android build completed successfully!" |
||||
|
print_footer "Android Build" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,82 @@ |
|||||
|
#!/bin/bash |
||||
|
# build-electron-linux.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Electron Linux build script for TimeSafari application |
||||
|
# This script builds Electron packages for Linux with support for different formats. |
||||
|
# |
||||
|
# Usage: ./scripts/build-electron-linux.sh [deb|prod] |
||||
|
# - No argument: Builds AppImage |
||||
|
# - deb: Builds .deb package |
||||
|
# - prod: Builds production AppImage |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Build failed |
||||
|
# 2 - Invalid argument |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Parse build type argument |
||||
|
BUILD_TYPE=${1:-"appimage"} |
||||
|
PRODUCTION=false |
||||
|
|
||||
|
case $BUILD_TYPE in |
||||
|
"deb") |
||||
|
BUILD_TARGET="deb" |
||||
|
log_info "Building .deb package" |
||||
|
;; |
||||
|
"prod") |
||||
|
BUILD_TARGET="AppImage" |
||||
|
PRODUCTION=true |
||||
|
log_info "Building production AppImage" |
||||
|
;; |
||||
|
"appimage"|"") |
||||
|
BUILD_TARGET="AppImage" |
||||
|
log_info "Building AppImage" |
||||
|
;; |
||||
|
*) |
||||
|
log_error "Invalid build type: $BUILD_TYPE" |
||||
|
log_error "Usage: $0 [deb|prod]" |
||||
|
exit 2 |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
# Print build header |
||||
|
print_header "TimeSafari Electron Linux Build" |
||||
|
log_info "Starting Linux build process at $(date)" |
||||
|
log_info "Build type: $BUILD_TYPE" |
||||
|
log_info "Build target: $BUILD_TARGET" |
||||
|
log_info "Production mode: $PRODUCTION" |
||||
|
|
||||
|
# Setup environment for Electron build |
||||
|
setup_build_env "electron" "$PRODUCTION" |
||||
|
|
||||
|
# Setup application directories |
||||
|
setup_app_directories |
||||
|
|
||||
|
# Load environment from .env file if it exists |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Step 1: Build Electron application |
||||
|
if [ "$PRODUCTION" = true ]; then |
||||
|
safe_execute "Building production Electron application" "npm run build:electron-prod" || exit 1 |
||||
|
else |
||||
|
safe_execute "Building Electron application" "npm run build:electron" || exit 1 |
||||
|
fi |
||||
|
|
||||
|
# Step 2: Build package |
||||
|
safe_execute "Building Linux package" "npx electron-builder --linux $BUILD_TARGET" || exit 1 |
||||
|
|
||||
|
# Print build summary |
||||
|
log_success "Linux build completed successfully!" |
||||
|
log_info "Package type: $BUILD_TARGET" |
||||
|
print_footer "Linux Build" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,74 @@ |
|||||
|
#!/bin/bash |
||||
|
# build-electron-mac.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Electron Mac build script for TimeSafari application |
||||
|
# This script builds Electron packages for macOS with support for universal builds. |
||||
|
# |
||||
|
# Usage: ./scripts/build-electron-mac.sh [universal] |
||||
|
# - No argument: Builds standard Mac package |
||||
|
# - universal: Builds universal Mac package (Intel + Apple Silicon) |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Build failed |
||||
|
# 2 - Invalid argument |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Parse build type argument |
||||
|
BUILD_TYPE=${1:-"standard"} |
||||
|
UNIVERSAL=false |
||||
|
|
||||
|
case $BUILD_TYPE in |
||||
|
"universal") |
||||
|
UNIVERSAL=true |
||||
|
log_info "Building universal Mac package (Intel + Apple Silicon)" |
||||
|
;; |
||||
|
"standard"|"") |
||||
|
log_info "Building standard Mac package" |
||||
|
;; |
||||
|
*) |
||||
|
log_error "Invalid build type: $BUILD_TYPE" |
||||
|
log_error "Usage: $0 [universal]" |
||||
|
exit 2 |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
# Print build header |
||||
|
print_header "TimeSafari Electron Mac Build" |
||||
|
log_info "Starting Mac build process at $(date)" |
||||
|
log_info "Build type: $BUILD_TYPE" |
||||
|
log_info "Universal build: $UNIVERSAL" |
||||
|
|
||||
|
# Setup environment for Electron build (production mode for packaging) |
||||
|
setup_build_env "electron" "true" |
||||
|
|
||||
|
# Setup application directories |
||||
|
setup_app_directories |
||||
|
|
||||
|
# Load environment from .env file if it exists |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Step 1: Build Electron application |
||||
|
safe_execute "Building Electron application" "npm run build:electron-prod" || exit 1 |
||||
|
|
||||
|
# Step 2: Build package |
||||
|
if [ "$UNIVERSAL" = true ]; then |
||||
|
safe_execute "Building universal Mac package" "npx electron-builder --mac --universal" || exit 1 |
||||
|
else |
||||
|
safe_execute "Building Mac package" "npx electron-builder --mac" || exit 1 |
||||
|
fi |
||||
|
|
||||
|
# Print build summary |
||||
|
log_success "Mac build completed successfully!" |
||||
|
log_info "Package type: $([ "$UNIVERSAL" = true ] && echo "Universal" || echo "Standard")" |
||||
|
print_footer "Mac Build" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,53 @@ |
|||||
|
#!/bin/bash |
||||
|
# build-electron.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Electron build script for TimeSafari application |
||||
|
# This script handles the complete Electron build process including cleanup, |
||||
|
# TypeScript compilation, Vite build, and Electron-specific setup. |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Cleanup failed |
||||
|
# 2 - TypeScript compilation failed |
||||
|
# 3 - Vite build failed |
||||
|
# 4 - Electron build script failed |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print build header |
||||
|
print_header "TimeSafari Electron Build Process" |
||||
|
log_info "Starting Electron build process at $(date)" |
||||
|
|
||||
|
# Setup environment for Electron build |
||||
|
setup_build_env "electron" |
||||
|
|
||||
|
# Setup application directories |
||||
|
setup_app_directories |
||||
|
|
||||
|
# Load environment from .env file if it exists |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Step 1: Clean previous builds |
||||
|
safe_execute "Cleaning previous builds" "npm run clean:electron" || exit 1 |
||||
|
|
||||
|
# Step 2: Compile TypeScript for Electron |
||||
|
safe_execute "Compiling TypeScript for Electron" "npx tsc -p tsconfig.electron.json" || exit 2 |
||||
|
|
||||
|
# Step 3: Build with Vite |
||||
|
safe_execute "Building with Vite" "npx vite build --config vite.config.electron.mts" || exit 3 |
||||
|
|
||||
|
# Step 4: Run Electron build script |
||||
|
safe_execute "Running Electron build script" "node scripts/build-electron.js" || exit 4 |
||||
|
|
||||
|
# Print build summary |
||||
|
log_success "Electron build completed successfully!" |
||||
|
print_footer "Electron Build" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,331 @@ |
|||||
|
#!/bin/bash |
||||
|
# common.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Common utilities and functions for TimeSafari build scripts |
||||
|
# This script provides shared logging, timing, and utility functions |
||||
|
# that can be sourced by other build scripts to eliminate redundancy. |
||||
|
# |
||||
|
# Usage: source ./scripts/common.sh |
||||
|
# |
||||
|
# Provides: |
||||
|
# - Color constants |
||||
|
# - Logging functions (log_info, log_success, log_warn, log_error) |
||||
|
# - Timing function (measure_time) |
||||
|
# - Common utility functions |
||||
|
# - Environment variable management |
||||
|
|
||||
|
# ANSI color codes for better output formatting |
||||
|
readonly RED='\033[0;31m' |
||||
|
readonly GREEN='\033[0;32m' |
||||
|
readonly YELLOW='\033[1;33m' |
||||
|
readonly BLUE='\033[0;34m' |
||||
|
readonly PURPLE='\033[0;35m' |
||||
|
readonly CYAN='\033[0;36m' |
||||
|
readonly NC='\033[0m' # No Color |
||||
|
|
||||
|
# Logging functions |
||||
|
log_info() { |
||||
|
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] [INFO]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_success() { |
||||
|
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_warn() { |
||||
|
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] [WARN]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_error() { |
||||
|
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_debug() { |
||||
|
echo -e "${PURPLE}[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_step() { |
||||
|
echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')] [STEP]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
# Function to measure and log execution time |
||||
|
measure_time() { |
||||
|
local start_time=$(date +%s) |
||||
|
"$@" |
||||
|
local end_time=$(date +%s) |
||||
|
local duration=$((end_time - start_time)) |
||||
|
log_success "Completed in ${duration} seconds" |
||||
|
} |
||||
|
|
||||
|
# Function to print section headers |
||||
|
print_header() { |
||||
|
local title="$1" |
||||
|
echo -e "\n${BLUE}=== $title ===${NC}\n" |
||||
|
} |
||||
|
|
||||
|
print_footer() { |
||||
|
local title="$1" |
||||
|
echo -e "\n${GREEN}=== $title Complete ===${NC}\n" |
||||
|
} |
||||
|
|
||||
|
# Function to check if a command exists |
||||
|
check_command() { |
||||
|
if ! command -v "$1" &> /dev/null; then |
||||
|
log_error "$1 is required but not installed." |
||||
|
return 1 |
||||
|
fi |
||||
|
log_debug "Found $1: $(command -v "$1")" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
# Function to check if a directory exists |
||||
|
check_directory() { |
||||
|
if [ ! -d "$1" ]; then |
||||
|
log_error "Directory not found: $1" |
||||
|
return 1 |
||||
|
fi |
||||
|
log_debug "Directory exists: $1" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
# Function to check if a file exists |
||||
|
check_file() { |
||||
|
if [ ! -f "$1" ]; then |
||||
|
log_error "File not found: $1" |
||||
|
return 1 |
||||
|
fi |
||||
|
log_debug "File exists: $1" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
# Function to safely execute a command with error handling |
||||
|
safe_execute() { |
||||
|
local step_name="$1" |
||||
|
local command="$2" |
||||
|
|
||||
|
log_step "$step_name" |
||||
|
if ! measure_time eval "$command"; then |
||||
|
log_error "$step_name failed!" |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
# Function to check virtual environment for Python scripts |
||||
|
check_venv() { |
||||
|
if [ ! -d ".venv" ]; then |
||||
|
log_error "Virtual environment not found. Please create it first:" |
||||
|
log_error "python -m venv .venv" |
||||
|
log_error "source .venv/bin/activate" |
||||
|
log_error "pip install -r requirements.txt" |
||||
|
return 1 |
||||
|
fi |
||||
|
log_debug "Virtual environment found: .venv" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
# Function to get git hash for versioning |
||||
|
get_git_hash() { |
||||
|
if command -v git &> /dev/null; then |
||||
|
git log -1 --pretty=format:%h 2>/dev/null || echo "unknown" |
||||
|
else |
||||
|
echo "unknown" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to clean build artifacts |
||||
|
clean_build_artifacts() { |
||||
|
local artifacts=("$@") |
||||
|
for artifact in "${artifacts[@]}"; do |
||||
|
if [ -e "$artifact" ]; then |
||||
|
log_info "Cleaning $artifact" |
||||
|
rm -rf "$artifact" |
||||
|
fi |
||||
|
done |
||||
|
} |
||||
|
|
||||
|
# Function to validate environment variables |
||||
|
validate_env_vars() { |
||||
|
local required_vars=("$@") |
||||
|
local missing_vars=() |
||||
|
|
||||
|
for var in "${required_vars[@]}"; do |
||||
|
if [ -z "${!var}" ]; then |
||||
|
missing_vars+=("$var") |
||||
|
fi |
||||
|
done |
||||
|
|
||||
|
if [ ${#missing_vars[@]} -gt 0 ]; then |
||||
|
log_error "Missing required environment variables: ${missing_vars[*]}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
# Function to set environment variables for different build types |
||||
|
setup_build_env() { |
||||
|
local build_type="$1" |
||||
|
local production="${2:-false}" |
||||
|
|
||||
|
log_info "Setting up environment for $build_type build" |
||||
|
|
||||
|
# Get git hash for versioning |
||||
|
local git_hash=$(get_git_hash) |
||||
|
export VITE_GIT_HASH="$git_hash" |
||||
|
log_debug "Set VITE_GIT_HASH=$git_hash" |
||||
|
|
||||
|
case $build_type in |
||||
|
"electron") |
||||
|
export VITE_PLATFORM=electron |
||||
|
export VITE_PWA_ENABLED=false |
||||
|
export VITE_DISABLE_PWA=true |
||||
|
export DEBUG_MIGRATIONS=0 |
||||
|
if [ "$production" = true ]; then |
||||
|
export NODE_ENV=production |
||||
|
log_debug "Set production mode for Electron" |
||||
|
fi |
||||
|
;; |
||||
|
"capacitor") |
||||
|
export VITE_PLATFORM=capacitor |
||||
|
export VITE_PWA_ENABLED=false |
||||
|
export VITE_DISABLE_PWA=true |
||||
|
export DEBUG_MIGRATIONS=0 |
||||
|
;; |
||||
|
"web") |
||||
|
export VITE_PLATFORM=web |
||||
|
export VITE_PWA_ENABLED=true |
||||
|
export VITE_DISABLE_PWA=false |
||||
|
export DEBUG_MIGRATIONS=0 |
||||
|
;; |
||||
|
*) |
||||
|
log_warn "Unknown build type: $build_type, using default environment" |
||||
|
export VITE_PLATFORM=web |
||||
|
export VITE_PWA_ENABLED=true |
||||
|
export VITE_DISABLE_PWA=false |
||||
|
export DEBUG_MIGRATIONS=0 |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
# Log environment setup |
||||
|
log_debug "Environment variables set:" |
||||
|
log_debug " VITE_PLATFORM=$VITE_PLATFORM" |
||||
|
log_debug " VITE_PWA_ENABLED=$VITE_PWA_ENABLED" |
||||
|
log_debug " VITE_DISABLE_PWA=$VITE_DISABLE_PWA" |
||||
|
log_debug " DEBUG_MIGRATIONS=$DEBUG_MIGRATIONS" |
||||
|
if [ -n "$NODE_ENV" ]; then |
||||
|
log_debug " NODE_ENV=$NODE_ENV" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to create application directories |
||||
|
setup_app_directories() { |
||||
|
log_info "Setting up application directories..." |
||||
|
|
||||
|
# Create TimeSafari data directory |
||||
|
mkdir -p ~/.local/share/TimeSafari/timesafari |
||||
|
|
||||
|
# Create build directories if they don't exist |
||||
|
mkdir -p dist |
||||
|
mkdir -p dist-electron |
||||
|
|
||||
|
log_debug "Application directories created" |
||||
|
} |
||||
|
|
||||
|
# Function to load environment from .env file if it exists |
||||
|
load_env_file() { |
||||
|
local env_file="$1" |
||||
|
|
||||
|
if [ -f "$env_file" ]; then |
||||
|
log_info "Loading environment from $env_file" |
||||
|
# Export variables from .env file (simple key=value format) |
||||
|
while IFS='=' read -r key value; do |
||||
|
# Skip comments and empty lines |
||||
|
[[ $key =~ ^#.*$ ]] && continue |
||||
|
[[ -z $key ]] && continue |
||||
|
|
||||
|
# Remove quotes from value if present |
||||
|
value=$(echo "$value" | sed 's/^["'\'']//;s/["'\'']$//') |
||||
|
|
||||
|
export "$key=$value" |
||||
|
log_debug "Loaded: $key=$value" |
||||
|
done < "$env_file" |
||||
|
else |
||||
|
log_debug "No $env_file file found" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to print current environment variables |
||||
|
print_env_vars() { |
||||
|
local prefix="$1" |
||||
|
|
||||
|
if [ -n "$prefix" ]; then |
||||
|
log_info "Environment variables with prefix '$prefix':" |
||||
|
env | grep "^$prefix" | sort | while read -r line; do |
||||
|
log_debug " $line" |
||||
|
done |
||||
|
else |
||||
|
log_info "Current environment variables:" |
||||
|
env | sort | while read -r line; do |
||||
|
log_debug " $line" |
||||
|
done |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Function to print script usage |
||||
|
print_usage() { |
||||
|
local script_name="$1" |
||||
|
local usage_text="$2" |
||||
|
|
||||
|
echo "Usage: $script_name $usage_text" |
||||
|
echo "" |
||||
|
echo "Options:" |
||||
|
echo " -h, --help Show this help message" |
||||
|
echo " -v, --verbose Enable verbose logging" |
||||
|
echo " -e, --env Show environment variables" |
||||
|
echo "" |
||||
|
} |
||||
|
|
||||
|
# Function to parse command line arguments |
||||
|
parse_args() { |
||||
|
local args=("$@") |
||||
|
local verbose=false |
||||
|
local show_env=false |
||||
|
|
||||
|
for arg in "${args[@]}"; do |
||||
|
case $arg in |
||||
|
-h|--help) |
||||
|
print_usage "$0" "[options]" |
||||
|
exit 0 |
||||
|
;; |
||||
|
-v|--verbose) |
||||
|
verbose=true |
||||
|
;; |
||||
|
-e|--env) |
||||
|
show_env=true |
||||
|
;; |
||||
|
*) |
||||
|
# Handle other arguments in child scripts |
||||
|
;; |
||||
|
esac |
||||
|
done |
||||
|
|
||||
|
if [ "$verbose" = true ]; then |
||||
|
# Enable debug logging |
||||
|
set -x |
||||
|
fi |
||||
|
|
||||
|
if [ "$show_env" = true ]; then |
||||
|
print_env_vars "VITE_" |
||||
|
exit 0 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Export functions for use in child scripts |
||||
|
export -f log_info log_success log_warn log_error log_debug log_step |
||||
|
export -f measure_time print_header print_footer |
||||
|
export -f check_command check_directory check_file |
||||
|
export -f safe_execute check_venv get_git_hash |
||||
|
export -f clean_build_artifacts validate_env_vars |
||||
|
export -f setup_build_env setup_app_directories load_env_file print_env_vars |
||||
|
export -f print_usage parse_args |
@ -0,0 +1,44 @@ |
|||||
|
#!/bin/bash |
||||
|
# electron-dev.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Electron development script for TimeSafari application |
||||
|
# This script builds the application and starts Electron for development. |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Build failed |
||||
|
# 2 - Electron start failed |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print dev header |
||||
|
print_header "TimeSafari Electron Development" |
||||
|
log_info "Starting Electron development at $(date)" |
||||
|
|
||||
|
# Setup environment for Electron development |
||||
|
setup_build_env "electron" |
||||
|
|
||||
|
# Setup application directories |
||||
|
setup_app_directories |
||||
|
|
||||
|
# Load environment from .env file if it exists |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Step 1: Build the application |
||||
|
safe_execute "Building application" "npm run build" || exit 1 |
||||
|
|
||||
|
# Step 2: Start Electron |
||||
|
safe_execute "Starting Electron" "electron ." || exit 2 |
||||
|
|
||||
|
# Print dev summary |
||||
|
log_success "Electron development session ended" |
||||
|
print_footer "Electron Development" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,44 @@ |
|||||
|
#!/bin/bash |
||||
|
# test-all.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Comprehensive test suite for TimeSafari application |
||||
|
# This script runs all tests including prerequisites, web tests, and mobile tests |
||||
|
# with proper error handling and logging. |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Prerequisites check failed |
||||
|
# 2 - Build failed |
||||
|
# 3 - Web tests failed |
||||
|
# 4 - Mobile tests failed |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print test header |
||||
|
print_header "TimeSafari Test Suite" |
||||
|
log_info "Starting comprehensive test suite at $(date)" |
||||
|
|
||||
|
# Step 1: Check prerequisites |
||||
|
safe_execute "Checking prerequisites" "npm run test:prerequisites" || exit 1 |
||||
|
|
||||
|
# Step 2: Build the application |
||||
|
safe_execute "Building application" "npm run build" || exit 2 |
||||
|
|
||||
|
# Step 3: Run web tests |
||||
|
safe_execute "Running web tests" "npm run test:web" || exit 3 |
||||
|
|
||||
|
# Step 4: Run mobile tests |
||||
|
safe_execute "Running mobile tests" "npm run test:mobile" || exit 4 |
||||
|
|
||||
|
# Print test summary |
||||
|
log_success "All tests completed successfully!" |
||||
|
print_footer "Test Suite" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,74 @@ |
|||||
|
#!/bin/bash |
||||
|
# test-common.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Test script to verify common utilities work correctly |
||||
|
# This script tests the common.sh utilities to ensure they function properly. |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print test header |
||||
|
print_header "Common Utilities Test" |
||||
|
log_info "Testing common utilities at $(date)" |
||||
|
|
||||
|
# Test logging functions |
||||
|
log_info "Testing info logging" |
||||
|
log_success "Testing success logging" |
||||
|
log_warn "Testing warning logging" |
||||
|
log_error "Testing error logging (this is expected)" |
||||
|
log_debug "Testing debug logging" |
||||
|
log_step "Testing step logging" |
||||
|
|
||||
|
# Test timing function |
||||
|
log_info "Testing timing function..." |
||||
|
measure_time sleep 1 |
||||
|
|
||||
|
# Test command checking |
||||
|
log_info "Testing command checking..." |
||||
|
if check_command "echo"; then |
||||
|
log_success "echo command found" |
||||
|
else |
||||
|
log_error "echo command not found" |
||||
|
fi |
||||
|
|
||||
|
# Test directory checking |
||||
|
log_info "Testing directory checking..." |
||||
|
if check_directory "scripts"; then |
||||
|
log_success "scripts directory found" |
||||
|
else |
||||
|
log_error "scripts directory not found" |
||||
|
fi |
||||
|
|
||||
|
# Test file checking |
||||
|
log_info "Testing file checking..." |
||||
|
if check_file "scripts/common.sh"; then |
||||
|
log_success "common.sh file found" |
||||
|
else |
||||
|
log_error "common.sh file not found" |
||||
|
fi |
||||
|
|
||||
|
# Test git hash function |
||||
|
log_info "Testing git hash function..." |
||||
|
GIT_HASH=$(get_git_hash) |
||||
|
log_info "Git hash: $GIT_HASH" |
||||
|
|
||||
|
# Test safe execute |
||||
|
log_info "Testing safe execute..." |
||||
|
safe_execute "Testing safe execute" "echo 'Hello from safe_execute'" |
||||
|
|
||||
|
# Test build artifact cleaning |
||||
|
log_info "Testing build artifact cleaning..." |
||||
|
clean_build_artifacts "test-file-1" "test-file-2" |
||||
|
|
||||
|
# Print test summary |
||||
|
log_success "All common utilities tests completed successfully!" |
||||
|
print_footer "Common Utilities Test" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,59 @@ |
|||||
|
#!/bin/bash |
||||
|
# test-env.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Test script to verify environment variable handling |
||||
|
# This script tests the environment variable setup functions. |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print test header |
||||
|
print_header "Environment Variable Test" |
||||
|
log_info "Testing environment variable handling at $(date)" |
||||
|
|
||||
|
# Test 1: Electron environment |
||||
|
log_info "Test 1: Setting up Electron environment..." |
||||
|
setup_build_env "electron" |
||||
|
print_env_vars "VITE_" |
||||
|
|
||||
|
# Test 2: Capacitor environment |
||||
|
log_info "Test 2: Setting up Capacitor environment..." |
||||
|
setup_build_env "capacitor" |
||||
|
print_env_vars "VITE_" |
||||
|
|
||||
|
# Test 3: Web environment |
||||
|
log_info "Test 3: Setting up Web environment..." |
||||
|
setup_build_env "web" |
||||
|
print_env_vars "VITE_" |
||||
|
|
||||
|
# Test 4: Production Electron environment |
||||
|
log_info "Test 4: Setting up Production Electron environment..." |
||||
|
setup_build_env "electron" "true" |
||||
|
print_env_vars "VITE_" |
||||
|
print_env_vars "NODE_ENV" |
||||
|
|
||||
|
# Test 5: Application directories |
||||
|
log_info "Test 5: Setting up application directories..." |
||||
|
setup_app_directories |
||||
|
|
||||
|
# Test 6: Load .env file (if it exists) |
||||
|
log_info "Test 6: Loading .env file..." |
||||
|
load_env_file ".env" |
||||
|
|
||||
|
# Test 7: Git hash |
||||
|
log_info "Test 7: Getting git hash..." |
||||
|
GIT_HASH=$(get_git_hash) |
||||
|
log_info "Git hash: $GIT_HASH" |
||||
|
|
||||
|
# Print test summary |
||||
|
log_success "All environment variable tests completed successfully!" |
||||
|
print_footer "Environment Variable Test" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -0,0 +1,40 @@ |
|||||
|
#!/bin/bash |
||||
|
# test-mobile.sh |
||||
|
# Author: Matthew Raymer |
||||
|
# Description: Mobile test suite for TimeSafari application |
||||
|
# This script builds the Capacitor version and runs Android and iOS tests |
||||
|
# with proper error handling and logging. |
||||
|
# |
||||
|
# Exit Codes: |
||||
|
# 1 - Capacitor build failed |
||||
|
# 2 - Android tests failed |
||||
|
# 3 - iOS tests failed |
||||
|
|
||||
|
# Exit on any error |
||||
|
set -e |
||||
|
|
||||
|
# Source common utilities |
||||
|
source "$(dirname "$0")/common.sh" |
||||
|
|
||||
|
# Parse command line arguments |
||||
|
parse_args "$@" |
||||
|
|
||||
|
# Print test header |
||||
|
print_header "TimeSafari Mobile Test Suite" |
||||
|
log_info "Starting mobile test suite at $(date)" |
||||
|
|
||||
|
# Step 1: Build Capacitor version |
||||
|
safe_execute "Building Capacitor version" "npm run build:capacitor" || exit 1 |
||||
|
|
||||
|
# Step 2: Run Android tests |
||||
|
safe_execute "Running Android tests" "npm run test:android" || exit 2 |
||||
|
|
||||
|
# Step 3: Run iOS tests |
||||
|
safe_execute "Running iOS tests" "npm run test:ios" || exit 3 |
||||
|
|
||||
|
# Print test summary |
||||
|
log_success "Mobile test suite completed successfully!" |
||||
|
print_footer "Mobile Test Suite" |
||||
|
|
||||
|
# Exit with success |
||||
|
exit 0 |
@ -1,4 +0,0 @@ |
|||||
import { initializeApp } from "./main.common"; |
|
||||
|
|
||||
const app = initializeApp(); |
|
||||
app.mount("#app"); |
|
@ -1,59 +0,0 @@ |
|||||
import webview |
|
||||
import os |
|
||||
import sys |
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler |
|
||||
import threading |
|
||||
|
|
||||
def get_dist_path(): |
|
||||
if getattr(sys, 'frozen', False): |
|
||||
base_path = sys._MEIPASS |
|
||||
else: |
|
||||
base_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
||||
|
|
||||
dist_path = os.path.join(base_path, 'dist') |
|
||||
print(f"Dist path: {dist_path}") |
|
||||
return dist_path |
|
||||
|
|
||||
class CustomHandler(SimpleHTTPRequestHandler): |
|
||||
def __init__(self, *args, **kwargs): |
|
||||
dist_dir = get_dist_path() |
|
||||
print(f"Serving from directory: {dist_dir}") |
|
||||
super().__init__(*args, directory=dist_dir, **kwargs) |
|
||||
|
|
||||
def log_message(self, format, *args): |
|
||||
# Override to show more detailed logging |
|
||||
print(f"Request: {format%args}") |
|
||||
if hasattr(self, 'path'): |
|
||||
print(f"Requested path: {self.path}") |
|
||||
full_path = os.path.join(self.directory, self.path.lstrip('/')) |
|
||||
print(f"Full path: {full_path}") |
|
||||
print(f"File exists: {os.path.exists(full_path)}") |
|
||||
if self.path.endswith('.html'): |
|
||||
print(f"HTML content: {open(full_path).read()[:200]}...") |
|
||||
|
|
||||
def run_server(port=8000): |
|
||||
server_address = ('localhost', port) |
|
||||
httpd = HTTPServer(server_address, CustomHandler) |
|
||||
print(f"Serving files from {get_dist_path()} at http://localhost:{port}") |
|
||||
httpd.serve_forever() |
|
||||
|
|
||||
def main(): |
|
||||
dist_path = get_dist_path() |
|
||||
|
|
||||
# Start local server |
|
||||
server_thread = threading.Thread(target=run_server) |
|
||||
server_thread.daemon = True |
|
||||
server_thread.start() |
|
||||
|
|
||||
# Create window using local server |
|
||||
window = webview.create_window( |
|
||||
'TimeSafari', |
|
||||
url='http://localhost:8000', |
|
||||
width=1200, |
|
||||
height=800 |
|
||||
) |
|
||||
|
|
||||
webview.start(debug=True) |
|
||||
|
|
||||
if __name__ == '__main__': |
|
||||
main() |
|
@ -1,135 +0,0 @@ |
|||||
import { |
|
||||
ImageResult, |
|
||||
PlatformService, |
|
||||
PlatformCapabilities, |
|
||||
} from "../PlatformService"; |
|
||||
import { logger } from "../../utils/logger"; |
|
||||
import { QueryExecResult } from "@/interfaces/database"; |
|
||||
|
|
||||
/** |
|
||||
* Platform service implementation for PyWebView platform. |
|
||||
* Note: This is a placeholder implementation with most methods currently unimplemented. |
|
||||
* Implements the PlatformService interface but throws "Not implemented" errors for most operations. |
|
||||
* |
|
||||
* @remarks |
|
||||
* This service is intended for Python-based desktop applications using pywebview. |
|
||||
* Future implementations should provide: |
|
||||
* - Integration with Python backend file operations |
|
||||
* - System camera access through Python |
|
||||
* - Native system dialogs via pywebview |
|
||||
* - Python-JavaScript bridge functionality |
|
||||
*/ |
|
||||
export class PyWebViewPlatformService implements PlatformService { |
|
||||
/** |
|
||||
* Gets the capabilities of the PyWebView platform |
|
||||
* @returns Platform capabilities object |
|
||||
*/ |
|
||||
getCapabilities(): PlatformCapabilities { |
|
||||
return { |
|
||||
hasFileSystem: false, // Not implemented yet
|
|
||||
hasCamera: false, // Not implemented yet
|
|
||||
isMobile: false, |
|
||||
isIOS: false, |
|
||||
hasFileDownload: false, // Not implemented yet
|
|
||||
needsFileHandlingInstructions: false, |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Reads a file using the Python backend. |
|
||||
* @param _path - Path to the file to read |
|
||||
* @returns Promise that should resolve to file contents |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement file reading through pywebview's Python-JavaScript bridge |
|
||||
*/ |
|
||||
async readFile(_path: string): Promise<string> { |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Writes content to a file using the Python backend. |
|
||||
* @param _path - Path where to write the file |
|
||||
* @param _content - Content to write to the file |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement file writing through pywebview's Python-JavaScript bridge |
|
||||
*/ |
|
||||
async writeFile(_path: string, _content: string): Promise<void> { |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Deletes a file using the Python backend. |
|
||||
* @param _path - Path to the file to delete |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement file deletion through pywebview's Python-JavaScript bridge |
|
||||
*/ |
|
||||
async deleteFile(_path: string): Promise<void> { |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Lists files in the specified directory using the Python backend. |
|
||||
* @param _directory - Path to the directory to list |
|
||||
* @returns Promise that should resolve to array of filenames |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement directory listing through pywebview's Python-JavaScript bridge |
|
||||
*/ |
|
||||
async listFiles(_directory: string): Promise<string[]> { |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Should open system camera through Python backend. |
|
||||
* @returns Promise that should resolve to captured image data |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement camera access using Python's camera libraries |
|
||||
*/ |
|
||||
async takePicture(): Promise<ImageResult> { |
|
||||
logger.error("takePicture not implemented in PyWebView platform"); |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Should open system file picker through pywebview. |
|
||||
* @returns Promise that should resolve to selected image data |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement file picker using pywebview's file dialog API |
|
||||
*/ |
|
||||
async pickImage(): Promise<ImageResult> { |
|
||||
logger.error("pickImage not implemented in PyWebView platform"); |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Should handle deep link URLs through the Python backend. |
|
||||
* @param _url - The deep link URL to handle |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement deep link handling using Python's URL handling capabilities |
|
||||
*/ |
|
||||
async handleDeepLink(_url: string): Promise<void> { |
|
||||
logger.error("handleDeepLink not implemented in PyWebView platform"); |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
|
|
||||
dbQuery(sql: string, params?: unknown[]): Promise<QueryExecResult> { |
|
||||
throw new Error("Not implemented for " + sql + " with params " + params); |
|
||||
} |
|
||||
dbExec( |
|
||||
sql: string, |
|
||||
params?: unknown[], |
|
||||
): Promise<{ changes: number; lastId?: number }> { |
|
||||
throw new Error("Not implemented for " + sql + " with params " + params); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Should write and share a file using the Python backend. |
|
||||
* @param _fileName - Name of the file to write and share |
|
||||
* @param _content - Content to write to the file |
|
||||
* @throws Error with "Not implemented" message |
|
||||
* @todo Implement file writing and sharing through pywebview's Python-JavaScript bridge |
|
||||
*/ |
|
||||
async writeAndShareFile(_fileName: string, _content: string): Promise<void> { |
|
||||
logger.error("writeAndShareFile not implemented in PyWebView platform"); |
|
||||
throw new Error("Not implemented"); |
|
||||
} |
|
||||
} |
|
@ -1,4 +0,0 @@ |
|||||
import { defineConfig } from "vite"; |
|
||||
import { createBuildConfig } from "./vite.config.common.mts"; |
|
||||
|
|
||||
export default defineConfig(async () => createBuildConfig('pywebview')); |
|
Loading…
Reference in new issue