Compare commits

...

8 Commits

13 changed files with 104 additions and 50 deletions

View File

@ -46,9 +46,17 @@ app = FastAPI(
description="API פשוט לבחירת מתכונים לצהריים / ערב / כל ארוחה 😋",
)
# Allow CORS from frontend domains
allowed_origins = [
"http://localhost:5173",
"http://localhost:3000",
"https://my-recipes.dvirlabs.com",
"http://my-recipes.dvirlabs.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000"],
allow_origins=allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@ -1,5 +1,5 @@
fastapi==0.103.2
uvicorn[standard]==0.23.2
fastapi==0.115.0
uvicorn[standard]==0.30.1
pydantic==2.7.4
python-dotenv==1.0.1

3
frontend/.gitignore vendored
View File

@ -12,6 +12,9 @@ dist
dist-ssr
*.local
# Local development env.js (production uses runtime injection)
public/env.js
# Editor directories and files
.vscode/*
!.vscode/extensions.json

View File

@ -0,0 +1,31 @@
#!/bin/sh
# Don't use set -e to avoid crashing if chown fails
# Generate env.js from API_BASE environment variable
# This is set in the Helm deployment values
TARGET="/usr/share/nginx/html/env.js"
# API_BASE should be set via deployment env (e.g., from Helm values)
# Default to /api as fallback (relative path)
: ${API_BASE:=/api}
echo "[ENTRYPOINT] Generating env.js with API_BASE=${API_BASE}"
cat > "$TARGET" <<EOF
window.__ENV__ = {
API_BASE: "${API_BASE}"
};
EOF
if [ -f "$TARGET" ]; then
echo "[ENTRYPOINT] ✓ env.js generated successfully at $TARGET"
cat "$TARGET"
else
echo "[ENTRYPOINT] ✗ Failed to generate env.js"
exit 1
fi
# Ensure ownership/permissions for nginx (don't fail if this doesn't work)
chown nginx:nginx /usr/share/nginx/html/env.js 2>/dev/null || echo "[ENTRYPOINT] Note: Could not change ownership (not critical)"
echo "[ENTRYPOINT] env.js setup complete"

View File

@ -1,5 +1,5 @@
# Build stage
FROM node:22-alpine AS builder
FROM node:22-alpine AS builder
WORKDIR /app
@ -15,18 +15,23 @@ COPY . .
# Build the application
RUN npm run build
# Production stage
FROM node:22-alpine
# Production stage - use nginx to serve static files
FROM nginx:alpine
WORKDIR /app
# Install a simple HTTP server to serve the built app
RUN npm install -g serve
# Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy built app from builder stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 3000
# Copy entrypoint script to nginx entrypoint.d directory
# This will run before nginx starts and generate env.js from API_BASE env var
COPY 10-generate-env.sh /docker-entrypoint.d/10-generate-env.sh
# Serve the built app
CMD ["serve", "-s", "dist", "-l", "3000"]
# Ensure entrypoint script is executable and has correct line endings
RUN chmod +x /docker-entrypoint.d/10-generate-env.sh && \
sed -i 's/\r$//' /docker-entrypoint.d/10-generate-env.sh
EXPOSE 80
# nginx will start automatically; our script in /docker-entrypoint.d runs first

View File

@ -5,6 +5,8 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>frontend</title>
<!-- Load environment variables before app starts -->
<script src="/env.js"></script>
</head>
<body>
<div id="root"></div>

28
frontend/nginx.conf Normal file
View File

@ -0,0 +1,28 @@
worker_processes 1;
events { worker_connections 1024; }
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Serve static files and fallback to index.html for SPA
location / {
try_files $uri $uri/ /index.html;
}
# Optional caching for static assets
location ~* \.(?:css|js|svg|png|jpg|jpeg|gif|ico)$ {
try_files $uri =404;
expires 7d;
add_header Cache-Control "public";
}
}
}

View File

@ -0,0 +1,3 @@
window.__ENV__ = {
API_BASE: "${API_BASE:-/api}"
};

View File

@ -1,4 +1,13 @@
const API_BASE = "http://localhost:8000";
// Get API base from injected env.js or fallback to /api relative path
const getApiBase = () => {
if (typeof window !== "undefined" && window.__ENV__ && window.__ENV__.API_BASE) {
return window.__ENV__.API_BASE;
}
// Default to relative /api path for local/containerized deployments
return "/api";
};
const API_BASE = getApiBase();
export async function getRecipes() {
const res = await fetch(`${API_BASE}/recipes`);

View File

@ -1,35 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-db-schema
namespace: {{ .Values.global.namespace }}
data:
schema.sql: |
-- Create recipes table
CREATE TABLE IF NOT EXISTS recipes (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
meal_type TEXT NOT NULL,
time_minutes INTEGER NOT NULL,
made_by TEXT,
tags JSONB NOT NULL DEFAULT '[]',
ingredients JSONB NOT NULL DEFAULT '[]',
steps JSONB NOT NULL DEFAULT '[]',
image TEXT
);
CREATE INDEX IF NOT EXISTS idx_recipes_meal_type
ON recipes (meal_type);
CREATE INDEX IF NOT EXISTS idx_recipes_time_minutes
ON recipes (time_minutes);
CREATE INDEX IF NOT EXISTS idx_recipes_made_by
ON recipes (made_by);
CREATE INDEX IF NOT EXISTS idx_recipes_tags_jsonb
ON recipes USING GIN (tags);
CREATE INDEX IF NOT EXISTS idx_recipes_ingredients_jsonb
ON recipes USING GIN (ingredients);