Compare commits

...

8 Commits

13 changed files with 104 additions and 50 deletions

View File

@ -46,9 +46,17 @@ app = FastAPI(
description="API פשוט לבחירת מתכונים לצהריים / ערב / כל ארוחה 😋", 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( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000"], allow_origins=allowed_origins,
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],

View File

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

3
frontend/.gitignore vendored
View File

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

@ -15,18 +15,23 @@ COPY . .
# Build the application # Build the application
RUN npm run build RUN npm run build
# Production stage # Production stage - use nginx to serve static files
FROM node:22-alpine FROM nginx:alpine
WORKDIR /app # Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Install a simple HTTP server to serve the built app
RUN npm install -g serve
# Copy built app from builder stage # 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 # Ensure entrypoint script is executable and has correct line endings
CMD ["serve", "-s", "dist", "-l", "3000"] 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" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>frontend</title> <title>frontend</title>
<!-- Load environment variables before app starts -->
<script src="/env.js"></script>
</head> </head>
<body> <body>
<div id="root"></div> <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() { export async function getRecipes() {
const res = await fetch(`${API_BASE}/recipes`); 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);