mirror of
https://github.com/opelly27/WinStudentGoalTracker.git
synced 2026-05-20 12:17:35 +00:00
Merge branch 'main' of https://github.com/opelly27/WinStudentGoalTracker
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
design/
|
||||||
|
*.user
|
||||||
|
.vs/
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY api.csproj ./
|
||||||
|
RUN dotnet restore api.csproj
|
||||||
|
|
||||||
|
COPY . ./
|
||||||
|
RUN dotnet publish api.csproj -c Release -o /app/publish --no-restore
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/publish .
|
||||||
|
|
||||||
|
ENV ASPNETCORE_URLS=http://+:8005
|
||||||
|
EXPOSE 8005
|
||||||
|
|
||||||
|
ENTRYPOINT ["dotnet", "api.dll"]
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=localhost;Port=3306;Database=win_student_goal_tracker;Uid=root;Pwd=change_me;"
|
"DefaultConnection": "Server=localhost;Port=3306;Database=winstudentgoaltracker;Uid=root;Pwd=change_me;"
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=localhost;Port=3306;Database=win_student_goal_tracker;Uid=root;Pwd=change_me;"
|
"DefaultConnection": "Server=localhost;Port=3306;Database=winstudentgoaltracker;Uid=root;Pwd=change_me;"
|
||||||
},
|
},
|
||||||
"Jwt": {
|
"Jwt": {
|
||||||
"Key": "super_secret_key_change_me_in_production_123!",
|
"Key": "super_secret_key_change_me_in_production_123!",
|
||||||
|
|||||||
Executable
+60
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Initializes the database schema from db/Objects SQL files.
|
||||||
|
# Runs in order: tables (FK checks off) → functions → views → procedures.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
DB="${MYSQL_DATABASE}"
|
||||||
|
OBJECTS_DIR="/db-objects"
|
||||||
|
|
||||||
|
mysql_exec() {
|
||||||
|
mysql -u root -p"${MYSQL_ROOT_PASSWORD}" "$DB" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Initializing database schema ==="
|
||||||
|
|
||||||
|
# ── Tables (all in one session with FK checks disabled) ──────────────────────
|
||||||
|
if [ -d "$OBJECTS_DIR/tables" ] && ls "$OBJECTS_DIR/tables"/*.sql &>/dev/null; then
|
||||||
|
echo "Loading tables..."
|
||||||
|
{
|
||||||
|
echo "SET FOREIGN_KEY_CHECKS=0;"
|
||||||
|
for f in "$OBJECTS_DIR/tables"/*.sql; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
cat "$f"
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
echo "SET FOREIGN_KEY_CHECKS=1;"
|
||||||
|
} | mysql_exec
|
||||||
|
echo " Tables done."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Functions ─────────────────────────────────────────────────────────────────
|
||||||
|
if [ -d "$OBJECTS_DIR/functions" ] && ls "$OBJECTS_DIR/functions"/*.sql &>/dev/null; then
|
||||||
|
echo "Loading functions..."
|
||||||
|
for f in "$OBJECTS_DIR/functions"/*.sql; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
mysql_exec < "$f"
|
||||||
|
done
|
||||||
|
echo " Functions done."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Views ─────────────────────────────────────────────────────────────────────
|
||||||
|
if [ -d "$OBJECTS_DIR/views" ] && ls "$OBJECTS_DIR/views"/*.sql &>/dev/null; then
|
||||||
|
echo "Loading views..."
|
||||||
|
for f in "$OBJECTS_DIR/views"/*.sql; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
mysql_exec < "$f"
|
||||||
|
done
|
||||||
|
echo " Views done."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Stored Procedures ─────────────────────────────────────────────────────────
|
||||||
|
if [ -d "$OBJECTS_DIR/procedures" ] && ls "$OBJECTS_DIR/procedures"/*.sql &>/dev/null; then
|
||||||
|
echo "Loading procedures..."
|
||||||
|
for f in "$OBJECTS_DIR/procedures"/*.sql; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
mysql_exec < "$f"
|
||||||
|
done
|
||||||
|
echo " Procedures done."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Schema initialization complete ==="
|
||||||
@@ -9,6 +9,66 @@ services:
|
|||||||
- "3309:3306"
|
- "3309:3306"
|
||||||
volumes:
|
volumes:
|
||||||
- win_mysql_data:/var/lib/mysql
|
- win_mysql_data:/var/lib/mysql
|
||||||
|
- ./db/docker-init:/docker-entrypoint-initdb.d:ro
|
||||||
|
- ./db/Objects:/db-objects:ro
|
||||||
|
healthcheck:
|
||||||
|
# Uses TCP (-h 127.0.0.1) so it only passes after init scripts complete
|
||||||
|
# and MySQL starts listening on the network.
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 15
|
||||||
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: ./api
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: winstudent-api
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_URLS=http://+:8005
|
||||||
|
- ConnectionStrings__DefaultConnection=Server=mysql;Port=3306;Database=${MYSQL_DATABASE};Uid=${MYSQL_USER};Pwd=${MYSQL_PASSWORD};
|
||||||
|
- Jwt__Key=${JWT_KEY}
|
||||||
|
- Jwt__Issuer=WinStudentGoalTrackerAPI
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.winstudent-api.rule=Host(`winapi.opelly.me`)"
|
||||||
|
- "traefik.http.routers.winstudent-api.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.winstudent-api.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.winstudent-api.loadbalancer.server.port=8005"
|
||||||
|
- "traefik.http.routers.winstudent-api.middlewares=gzip@file,security-headers@file"
|
||||||
|
|
||||||
|
ui:
|
||||||
|
build:
|
||||||
|
context: ./ui/winstudentgoaltracker
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: winstudent-ui
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.winstudent-ui.rule=Host(`win.opelly.me`)"
|
||||||
|
- "traefik.http.routers.winstudent-ui.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.winstudent-ui.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.winstudent-ui.loadbalancer.server.port=8006"
|
||||||
|
- "traefik.http.routers.winstudent-ui.middlewares=gzip@file,security-headers@file"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
backend:
|
||||||
|
web:
|
||||||
|
external: true
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
win_mysql_data:
|
win_mysql_data:
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.angular/
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FROM node:22-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM nginx:alpine AS runtime
|
||||||
|
COPY --from=build /app/dist/winstudentgoaltracker/browser /usr/share/nginx/html
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
EXPOSE 8006
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
server {
|
||||||
|
listen 8006;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Angular SPA fallback routing
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user