Initial commit: Complete NodeJS-native setup

- Migrated from Python pre-commit to NodeJS-native solution
- Reorganized documentation structure
- Set up Husky + lint-staged for efficient pre-commit hooks
- Fixed Dockerfile healthcheck issue
- Added comprehensive documentation index
This commit is contained in:
William Valentin
2025-09-06 01:42:48 -07:00
commit e48adbcb00
159 changed files with 24405 additions and 0 deletions

78
docker/.dockerignore Normal file
View File

@@ -0,0 +1,78 @@
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Build output
dist
build
# Environment files (security)
.env
.env.*
!.env.example
# Development files
.vscode
.idea
*.swp
*.swo
*~
# Version control
.git
.gitignore
.gitattributes
# Documentation
README.md
README_*.md
CHANGELOG.md
CONTRIBUTING.md
LICENSE
docs/
# Docker files (avoid recursion)
Dockerfile
docker-compose.yaml
.dockerignore
# Scripts and testing (not needed in container)
scripts/
tests/
coverage/
**/__tests__
**/*.test.*
**/*.spec.*
# Logs
logs
*.log
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Temporary files
tmp/
temp/
.tmp
# CouchDB data
couchdb-data/
# Scripts (not needed in container)
setup.sh
deploy.sh
deploy-k8s.sh
validate-env.sh
validate-deployment.sh
# Kubernetes manifests
k8s/

81
docker/Dockerfile Normal file
View File

@@ -0,0 +1,81 @@
# check=skip=SecretsUsedInArgOrEnv
# Build stage
FROM oven/bun:alpine AS builder
# Install system dependencies for native modules
RUN apk add --no-cache python3 make g++
# Create non-root user for security
RUN addgroup -g 1001 -S nodeuser && adduser -S nodeuser -u 1001 -G nodeuser
# Create and set permissions for the working directory
RUN mkdir -p /app && chown -R nodeuser:nodeuser /app
WORKDIR /app
USER nodeuser
# Copy package files first for better Docker layer caching
COPY --chown=nodeuser:nodeuser package.json ./
COPY --chown=nodeuser:nodeuser bun.lock ./
# Install dependencies
RUN bun install --frozen-lockfile
# Copy source code
COPY --chown=nodeuser:nodeuser . ./
# Build arguments for environment configuration
# CouchDB Configuration
ARG VITE_COUCHDB_URL=http://localhost:5984
ARG VITE_COUCHDB_USER=admin
ARG VITE_COUCHDB_PASSWORD=change-this-secure-password
# Application Configuration
ARG APP_BASE_URL=http://localhost:5173
# OAuth Configuration (Optional)
ARG VITE_GOOGLE_CLIENT_ID=""
ARG VITE_GITHUB_CLIENT_ID=""
# Build Environment
ARG NODE_ENV=production
# Set environment variables for build process
# These are embedded into the static build at compile time
ENV VITE_COUCHDB_URL=$VITE_COUCHDB_URL
ENV VITE_COUCHDB_USER=$VITE_COUCHDB_USER
ENV VITE_COUCHDB_PASSWORD=$VITE_COUCHDB_PASSWORD
ENV APP_BASE_URL=$APP_BASE_URL
ENV VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID
ENV VITE_GITHUB_CLIENT_ID=$VITE_GITHUB_CLIENT_ID
ENV NODE_ENV=$NODE_ENV
# Build the application
RUN bun run build
# Production stage - serve with nginx
FROM nginx:alpine
# Install curl for health checks
RUN apk add --no-cache curl
# Copy built files from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy nginx configuration
COPY --from=builder /app/docker/nginx.conf /etc/nginx/conf.d/default.conf
# Set proper permissions for nginx
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /etc/nginx/conf.d
# Add health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# Expose port 80
EXPOSE 80
# Start nginx (runs as nginx user by default in alpine)
CMD ["nginx", "-g", "daemon off;"]

76
docker/README.md Normal file
View File

@@ -0,0 +1,76 @@
# 🐳 Docker Configuration
This directory contains all Docker and containerization-related files for RxMinder.
## Files
- **`Dockerfile`** - Multi-stage Docker build configuration with buildx support
- **`docker-compose.yaml`** - Service orchestration with multi-platform support
- **`docker-bake.hcl`** - Advanced buildx configuration for multi-platform builds
- **`nginx.conf`** - Production web server configuration
- **`.dockerignore`** - Files and directories to exclude from Docker build context
## Docker Buildx Support
This project now supports Docker Buildx for multi-platform builds (AMD64 and ARM64).
### Quick Start with Buildx
```bash
# Setup buildx builder (run once)
../scripts/buildx-helper.sh setup
# Build for local platform only (faster for development)
../scripts/buildx-helper.sh build-local
# Build for multiple platforms
../scripts/buildx-helper.sh build-multi
# Build and push to registry
../scripts/buildx-helper.sh push docker.io/username latest
# Build using Docker Bake (advanced)
../scripts/buildx-helper.sh bake
```
### Manual Buildx Commands
```bash
# Create and use buildx builder
docker buildx create --name rxminder-builder --driver docker-container --bootstrap --use
# Build for multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 -t rxminder:latest --load .
# Build with bake file
docker buildx bake -f docker-bake.hcl
```
## Traditional Usage
From the project root directory:
```bash
# Build and start services
docker compose -f docker/docker-compose.yaml up -d
# View logs
docker compose -f docker/docker-compose.yaml logs
# Stop services
docker compose -f docker/docker-compose.yaml down
```
## Build Process
The Dockerfile uses a multi-stage build:
1. **Builder stage**: Installs dependencies and builds the React app
2. **Production stage**: Serves the built app with nginx
## Services
- **frontend**: React application served by nginx
- **couchdb**: Database for medication and user data
Both services include health checks and proper security configurations.

101
docker/docker-bake.hcl Normal file
View File

@@ -0,0 +1,101 @@
# Docker Bake file for advanced multi-platform builds
# Usage: docker buildx bake -f docker-bake.hcl
variable "TAG" {
default = "latest"
}
variable "REGISTRY" {
default = ""
}
variable "VITE_COUCHDB_URL" {
default = "http://localhost:5984"
}
variable "VITE_COUCHDB_USER" {
default = "admin"
}
variable "VITE_COUCHDB_PASSWORD" {
default = "change-this-secure-password"
}
variable "APP_BASE_URL" {
default = "http://localhost:8080"
}
variable "VITE_GOOGLE_CLIENT_ID" {
default = ""
}
variable "VITE_GITHUB_CLIENT_ID" {
default = ""
}
group "default" {
targets = ["app"]
}
target "app" {
dockerfile = "Dockerfile"
context = "."
platforms = [
"linux/amd64",
"linux/arm64"
]
tags = [
"${REGISTRY}rxminder:${TAG}",
"${REGISTRY}rxminder:latest"
]
args = {
# CouchDB Configuration
VITE_COUCHDB_URL = "${VITE_COUCHDB_URL}"
VITE_COUCHDB_USER = "${VITE_COUCHDB_USER}"
VITE_COUCHDB_PASSWORD = "${VITE_COUCHDB_PASSWORD}"
# Application Configuration
APP_BASE_URL = "${APP_BASE_URL}"
# OAuth Configuration (Optional)
VITE_GOOGLE_CLIENT_ID = "${VITE_GOOGLE_CLIENT_ID}"
VITE_GITHUB_CLIENT_ID = "${VITE_GITHUB_CLIENT_ID}"
# Build environment
NODE_ENV = "production"
}
# Advanced buildx features
cache-from = [
"type=gha",
"type=registry,ref=${REGISTRY}rxminder:buildcache"
]
cache-to = [
"type=gha,mode=max",
"type=registry,ref=${REGISTRY}rxminder:buildcache,mode=max"
]
# Attestations for supply chain security
attest = [
"type=provenance,mode=max",
"type=sbom"
]
}
# Development target for faster local builds
target "dev" {
inherits = ["app"]
platforms = ["linux/amd64"]
tags = ["rxminder:dev"]
cache-from = ["type=gha"]
cache-to = ["type=gha,mode=max"]
}
# Production target with registry push
target "prod" {
inherits = ["app"]
output = ["type=registry"]
}

View File

@@ -0,0 +1,65 @@
services:
# Frontend service
frontend:
build:
context: .
args:
# CouchDB Configuration
- VITE_COUCHDB_URL=${VITE_COUCHDB_URL:-http://couchdb:5984}
- VITE_COUCHDB_USER=${VITE_COUCHDB_USER:-admin}
- VITE_COUCHDB_PASSWORD=${VITE_COUCHDB_PASSWORD:-change-this-secure-password}
# Application Configuration
- APP_BASE_URL=${APP_BASE_URL:-http://localhost:8080}
# OAuth Configuration (Optional)
- VITE_GOOGLE_CLIENT_ID=${VITE_GOOGLE_CLIENT_ID:-}
- VITE_GITHUB_CLIENT_ID=${VITE_GITHUB_CLIENT_ID:-}
# Build Environment
- NODE_ENV=${NODE_ENV:-production}
# Enable buildx for multi-platform builds
platforms:
- linux/amd64
- linux/arm64
ports:
- '8080:80'
depends_on:
couchdb:
condition: service_healthy
restart: unless-stopped
# Health check for the frontend container
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost/']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
labels:
- 'monitoring=true'
- 'service=frontend'
# CouchDB service
couchdb:
image: couchdb:3.3.2
volumes:
- ./couchdb-data:/opt/couchdb/data
environment:
- COUCHDB_USER=${COUCHDB_USER:-admin}
- COUCHDB_PASSWORD=${COUCHDB_PASSWORD:-change-this-secure-password}
ports:
- '5984:5984'
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:5984/_up']
interval: 30s
timeout: 10s
retries: 3
labels:
- 'monitoring=true'
- 'service=couchdb'
# Redis service (commented out as per requirements)
# redis:
# image: redis:alpine
# restart: unless-stopped
# labels:
# - "monitoring=true"
# - "service=redis"

36
docker/nginx.conf Normal file
View File

@@ -0,0 +1,36 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Enable gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# Handle client-side 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";
}
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}