Skip to content

Commit dbd9c6e

Browse files
authored
Merge pull request #191 from chvvkumar/dev
Mosaic Filters, Session Improvements, and System Optimizations
2 parents 9765cc2 + 9ebcbd7 commit dbd9c6e

22 files changed

Lines changed: 1571 additions & 143 deletions

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.git
2+
node_modules
3+
frontend/node_modules
4+
backend/.venv
5+
__pycache__
6+
*.pyc
7+
.env
8+
docs/
9+
guides/
10+
images/
11+
*.md
12+
.github/
13+
backend/tests/

.github/workflows/build-deploy.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ permissions:
1919
jobs:
2020
build-and-push:
2121
runs-on: [self-hosted, Linux, X64]
22+
env:
23+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
2224

2325
steps:
2426
- name: Checkout code
@@ -99,8 +101,8 @@ jobs:
99101
build-args: |
100102
GALACTILOG_VERSION=${{ steps.version.outputs.version }}
101103
GALACTILOG_GIT_SHA=${{ github.sha }}
102-
cache-from: type=local,src=/tmp/.buildx-cache
103-
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
104+
cache-from: type=registry,ref=chvvkumar/galactilog:buildcache
105+
cache-to: type=registry,ref=chvvkumar/galactilog:buildcache,mode=max
104106

105107
- name: Report image size
106108
shell: bash

.github/workflows/build-snd.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ on:
1515
jobs:
1616
build-and-push:
1717
runs-on: [self-hosted, Linux, X64]
18+
env:
19+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
1820

1921
steps:
2022
- name: Checkout code
@@ -39,8 +41,8 @@ jobs:
3941
build-args: |
4042
GALACTILOG_VERSION=snd
4143
GALACTILOG_GIT_SHA=${{ github.sha }}
42-
cache-from: type=local,src=/tmp/.buildx-cache
43-
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
44+
cache-from: type=registry,ref=chvvkumar/galactilog:buildcache-snd
45+
cache-to: type=registry,ref=chvvkumar/galactilog:buildcache-snd,mode=max
4446

4547
- name: Report image size
4648
shell: bash

Dockerfile

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22
FROM node:20-alpine AS frontend-builder
33
WORKDIR /app
44
COPY frontend/package.json frontend/package-lock.json ./
5-
RUN npm ci
5+
RUN --mount=type=cache,target=/root/.npm npm ci
66
COPY frontend/ .
77
ENV VITE_API_URL=/api
88
RUN npm run build
99

10-
# Stage 2: Install Python dependencies
10+
# Stage 2: Install Python dependencies (only reruns when pyproject.toml changes)
1111
FROM python:3.12-slim AS backend-deps
1212
RUN apt-get update && apt-get install -y --no-install-recommends \
1313
gcc libpq-dev libjpeg62-turbo-dev zlib1g-dev \
1414
&& rm -rf /var/lib/apt/lists/*
1515
WORKDIR /app
1616
COPY backend/pyproject.toml .
17-
COPY backend/app/ app/
17+
RUN mkdir -p app && touch app/__init__.py
1818
RUN pip install --no-cache-dir .
1919

2020
# Stage 3: Runtime
@@ -23,6 +23,8 @@ ARG GALACTILOG_VERSION=dev
2323
ARG GALACTILOG_GIT_SHA=unknown
2424
ENV GALACTILOG_VERSION=${GALACTILOG_VERSION} \
2525
GALACTILOG_GIT_SHA=${GALACTILOG_GIT_SHA}
26+
27+
# Install runtime packages first (cacheable independent of app code)
2628
RUN apt-get update && apt-get install -y --no-install-recommends \
2729
nginx supervisor curl gosu libcap2-bin \
2830
&& rm -rf /var/lib/apt/lists/* \
@@ -34,29 +36,32 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
3436
&& ln -sf /dev/stderr /var/log/nginx/error.log \
3537
&& chown -R galactilog:galactilog /var/log/nginx
3638

39+
# Configure nginx paths and permissions (cacheable, depends only on base nginx config)
40+
RUN mkdir -p /app/data/fits /app/data/thumbnails /app/data/thumbnails/previews \
41+
/app/run /app/run/nginx \
42+
/app/run/nginx/client_body /app/run/nginx/proxy \
43+
/app/run/nginx/fastcgi /app/run/nginx/uwsgi /app/run/nginx/scgi \
44+
&& sed -i 's|^pid .*|pid /app/run/nginx/nginx.pid;|' /etc/nginx/nginx.conf \
45+
&& sed -i 's|^user .*|user galactilog galactilog;|' /etc/nginx/nginx.conf \
46+
&& sed -i 's|^error_log .*|error_log /var/log/nginx/error.log warn;|' /etc/nginx/nginx.conf \
47+
&& sed -i '/^http {/a\ client_body_temp_path /app/run/nginx/client_body;\n proxy_temp_path /app/run/nginx/proxy;\n fastcgi_temp_path /app/run/nginx/fastcgi;\n uwsgi_temp_path /app/run/nginx/uwsgi;\n scgi_temp_path /app/run/nginx/scgi;' /etc/nginx/nginx.conf \
48+
&& setcap cap_net_bind_service=+ep /usr/sbin/nginx
49+
50+
# Copy built artifacts from other stages
3751
COPY --from=backend-deps /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
3852
COPY --from=backend-deps /usr/local/bin /usr/local/bin
3953
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
54+
55+
# Copy application code (changes frequently, placed last)
4056
COPY backend/app/ /app/app/
4157
COPY backend/data/ /app/data/
4258
COPY backend/alembic.ini /app/alembic.ini
4359
COPY backend/alembic/ /app/alembic/
44-
# nginx.conf is mounted at conf.d/default.conf (inside http{} context). Directives
45-
# that must live in the main config (pid, error_log) are redirected via sed below.
4660
COPY nginx.conf /etc/nginx/conf.d/default.conf
4761
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
4862
COPY backend/entrypoint.sh /app/entrypoint.sh
4963
RUN chmod +x /app/entrypoint.sh \
50-
&& mkdir -p /app/data/fits /app/data/thumbnails /app/data/thumbnails/previews \
51-
/app/run /app/run/nginx \
52-
/app/run/nginx/client_body /app/run/nginx/proxy \
53-
/app/run/nginx/fastcgi /app/run/nginx/uwsgi /app/run/nginx/scgi \
54-
&& sed -i 's|^pid .*|pid /app/run/nginx/nginx.pid;|' /etc/nginx/nginx.conf \
55-
&& sed -i 's|^user .*|user galactilog galactilog;|' /etc/nginx/nginx.conf \
56-
&& sed -i 's|^error_log .*|error_log /var/log/nginx/error.log warn;|' /etc/nginx/nginx.conf \
57-
&& sed -i '/^http {/a\ client_body_temp_path /app/run/nginx/client_body;\n proxy_temp_path /app/run/nginx/proxy;\n fastcgi_temp_path /app/run/nginx/fastcgi;\n uwsgi_temp_path /app/run/nginx/uwsgi;\n scgi_temp_path /app/run/nginx/scgi;' /etc/nginx/nginx.conf \
58-
&& chown -R galactilog:galactilog /app/data /app/run \
59-
&& setcap cap_net_bind_service=+ep /usr/sbin/nginx
64+
&& chown -R galactilog:galactilog /app/data /app/run
6065

6166
WORKDIR /app
6267
ENV GALACTILOG_CELERY_CONCURRENCY=4
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""Add mosaic session membership table and related columns.
2+
3+
Revision ID: 0013
4+
Revises: 0012
5+
"""
6+
7+
from alembic import op
8+
import sqlalchemy as sa
9+
from sqlalchemy.dialects.postgresql import UUID, JSONB
10+
11+
12+
revision = "0013"
13+
down_revision = "0012"
14+
branch_labels = None
15+
depends_on = None
16+
17+
18+
def _column_exists(table_name: str, column_name: str) -> bool:
19+
bind = op.get_bind()
20+
insp = sa.inspect(bind)
21+
columns = [c["name"] for c in insp.get_columns(table_name)]
22+
return column_name in columns
23+
24+
25+
def _table_exists(table_name: str) -> bool:
26+
bind = op.get_bind()
27+
insp = sa.inspect(bind)
28+
return table_name in insp.get_table_names()
29+
30+
31+
def upgrade() -> None:
32+
# 1. Create mosaic_panel_sessions table
33+
if not _table_exists("mosaic_panel_sessions"):
34+
op.create_table(
35+
"mosaic_panel_sessions",
36+
sa.Column("id", UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()")),
37+
sa.Column("panel_id", UUID(as_uuid=True), sa.ForeignKey("mosaic_panels.id", ondelete="CASCADE"), nullable=False),
38+
sa.Column("session_date", sa.Date, nullable=False),
39+
sa.Column("status", sa.String(20), nullable=False, server_default="available"),
40+
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
41+
sa.UniqueConstraint("panel_id", "session_date", name="uq_mosaic_panel_sessions_panel_date"),
42+
)
43+
op.create_index("ix_mosaic_panel_sessions_panel_id", "mosaic_panel_sessions", ["panel_id"])
44+
op.create_index("ix_mosaic_panel_sessions_status", "mosaic_panel_sessions", ["status"])
45+
46+
# 2. Add needs_review to mosaics
47+
if not _column_exists("mosaics", "needs_review"):
48+
op.add_column("mosaics", sa.Column("needs_review", sa.Boolean, nullable=False, server_default="false"))
49+
50+
# 3. Add session_dates to mosaic_suggestions
51+
if not _column_exists("mosaic_suggestions", "session_dates"):
52+
op.add_column("mosaic_suggestions", sa.Column("session_dates", JSONB, nullable=True))
53+
54+
# 4. Data migration: seed session records for existing mosaic panels
55+
conn = op.get_bind()
56+
panels = conn.execute(sa.text(
57+
"SELECT mp.id AS panel_id, mp.target_id, mp.object_pattern, m.id AS mosaic_id "
58+
"FROM mosaic_panels mp JOIN mosaics m ON mp.mosaic_id = m.id"
59+
)).fetchall()
60+
61+
for panel in panels:
62+
panel_id = panel.panel_id
63+
target_id = panel.target_id
64+
pattern = panel.object_pattern
65+
66+
if pattern:
67+
dates = conn.execute(sa.text(
68+
"SELECT DISTINCT session_date FROM images "
69+
"WHERE resolved_target_id = :tid AND image_type = 'LIGHT' "
70+
"AND raw_headers->>'OBJECT' ILIKE :pat AND session_date IS NOT NULL"
71+
), {"tid": target_id, "pat": pattern}).fetchall()
72+
else:
73+
dates = conn.execute(sa.text(
74+
"SELECT DISTINCT session_date FROM images "
75+
"WHERE resolved_target_id = :tid AND image_type = 'LIGHT' "
76+
"AND session_date IS NOT NULL"
77+
), {"tid": target_id}).fetchall()
78+
79+
for row in dates:
80+
conn.execute(sa.text(
81+
"INSERT INTO mosaic_panel_sessions (id, panel_id, session_date, status) "
82+
"VALUES (gen_random_uuid(), :panel_id, :session_date, 'available') "
83+
"ON CONFLICT (panel_id, session_date) DO NOTHING"
84+
), {"panel_id": panel_id, "session_date": row.session_date})
85+
86+
# Mark all existing mosaics as needs_review
87+
conn.execute(sa.text("UPDATE mosaics SET needs_review = true"))
88+
89+
90+
def downgrade() -> None:
91+
op.drop_table("mosaic_panel_sessions")
92+
if _column_exists("mosaics", "needs_review"):
93+
op.drop_column("mosaics", "needs_review")
94+
if _column_exists("mosaic_suggestions", "session_dates"):
95+
op.drop_column("mosaic_suggestions", "session_dates")

0 commit comments

Comments
 (0)