Repository navigation
Releases: myastroboard/myastroshine
Release list
v0.6.1
What's changed
Fixes
- The backend HTTP client moves from the frozen
httpxto its maintained forkhttpx2(Astrodex
handoff, update check); HTTPS now verifies against the system certificate store. - Security: Pillow moves to 13.0.0, fixing the 15 security advisories
pip-auditreports
against 12.3.0, and every other backend and frontend dependency is brought to its latest release.
Commits since v0.6.0
- chore: file changelog for release v0.6.0 (192530b)
- chore: sync organization standards (a50e604)
- chore: update dependencies in package.json (3b16ca0)
- fix(deps): replace frozen httpx with its maintained fork httpx2 (a246be6)
- chore: sync organization standards (#68) (d6bf4c1)
- Fix/deps pillow 13 (#71) (ec6aeaa)
Docker image
docker pull ghcr.io/myastroboard/myastroshine:0.6.1 # GitHub Container Registry
docker pull myastroboard/myastroshine:0.6.1 # Docker Hub| Platform | Architecture |
|---|---|
linux/amd64 |
x86_64 |
linux/arm64 |
ARM 64-bit (Raspberry Pi 4/5, Apple Silicon) |
v0.6.0
What's changed
Features
- An iPhone ProRAW (
.dng) opens in the linear editor, and a Milky Way shot with a landscape uses
the phone's sky mask, single or stacked: no halos round trees, a dark night sky. See
docs/ALGORITHMS.md "Nightscapes". - Wide-angle shots (35 mm-equivalent focal up to 50 mm) have their lens vignetting and sky colour
shading corrected automatically, and a clean stack no longer crushes darker sky to black.
Phone ProRAW keeps the phone's white balance and stacks with equal weights. - Stacking follows wide-angle lens distortion: stars stay sharp across the whole stack instead of
turning into short streaks toward the corners. - New optional "Style" step before Export: Vivid, Soft glow or Cinematic finishing looks from a
gallery of your own image, one strength slider, nothing invented. See docs/ALGORITHMS.md "Looks".
The Astrodex copy carries the style, and its parameters gain alookkey (myastroboard). - Night landscapes get two more styles that treat the sky and the ground apart: Galactic core and
Blue hour, with no halo round the trees. See docs/ALGORITHMS.md "Looks". - Deep-sky styles, picked with chips above the gallery: Luminous and Structure for nebulae, Deep
field and Warm core for galaxies, Sparkle and Night velvet for star clusters - stars keep their size. - Moon and planet styles (Crisp and Moonlight, Crisp and Rich colour), sized to the disc, with no ring
on the limb; after a built-in preset the Style gallery opens on the matching kind of picture.
Fixes
- Uploading stack frames now shows real progress and a frame counter instead of sitting at 0 % until
the end; requests stay under the per-file size limit from Settings (so a reverse proxy accepts them). - The editor no longer crashes on a phone ProRAW whose capture info has no gain or sensor
temperature (the info panel now skips fields the API sends as null). - Stacking now removes an aircraft or satellite trail from a short stack (3 to 10 frames), and the
default winsorized rejection no longer leaves a faint line where a trail was rejected. - An upload a proxy refuses as too large (Cloudflare caps requests at 100 MB) now says so and
suggests the local address, instead of showing the proxy's raw HTML error page. - Full-resolution renders are about 10% faster (vibrance, denoise and sharpen), with identical
output. The weekly performance benchmark's full-res budget is now 12 s; see CONTRIBUTING.md. - Lib update
- Auto Astro now showcases the picture instead of crushing its sky to black: a darker but never
clipped sky, a lifted object, a neutral background, noise and colour dosed per kind of picture,
and your Stack settings kept. See docs/ALGORITHMS.md "Auto Astro". - Stacked composites no longer render with a green sky, and Denoise now also removes the coarser
grain and colour mottle of real stacks while sparing faint stars. See docs/ALGORITHMS.md. - Phone Milky Way shots (wide-angle ProRAW) no longer come out covered in green and magenta blotches,
and a light-polluted sky no longer gets a dark arch and lavender sides. See docs/ALGORITHMS.md
"Render hints".
Commits since v0.5.1
- chore: file changelog for release v0.5.1 (71d4443)
- fix: improve error handling for uploads exceeding proxy limits (9e23816)
- chore: update checklist for MyAstroShine 0.5.1 with new features and logging improvements (172997c)
- chore: sync organization standards (6ee8212)
- chore: add workflow to require changelog entry for pull requests (0e80d17)
- chore: update contribution guidelines and changelog format to align with organization standards (caf83a0)
- Add sky mask functionality and tests for nightscape processing (69f2b72)
- Enhance star alignment with polynomial warp refinement for wide-angle lens distortion (c7ba45a)
- Refine devignette and normalised_radius functions for improved vignetting correction and clarity in documentation (d87faa1)
- Add affine reference coordinates and enhance drizzle integration (d5b9b99)
- Update source-map-js to version 1.2.2 for improved functionality and security (01029ac)
- chore: update dependencies in package.json and package-lock.json (f08377e)
- refactor: update performance benchmarks and enhance full-resolution rendering speed (8a3a618)
- feat: add style feature for image editing with localization support (10494e9)
- feat: add new night landscape looks and enhance style panel functionality (8479e2d)
- Enhance style gallery with new looks and grouping (3c8ecfa)
- feat: add Moon and Planet looks to the style gallery (9aa341c)
- feat: enhance upload process with progress tracking and size limits (4ef181e)
- Refactor tests and enhance Auto Astro functionality (e034f15)
- refactor: update documentation references to align with new structure (d94fe55)
- feat: improve Milky Way rendering and background extraction for wide-field shots (8415f83)
- chore: update version to 0.6.0 (ca53343)
Docker image
docker pull ghcr.io/myastroboard/myastroshine:0.6.0 # GitHub Container Registry
docker pull myastroboard/myastroshine:0.6.0 # Docker Hub| Platform | Architecture |
|---|---|
linux/amd64 |
x86_64 |
linux/arm64 |
ARM 64-bit (Raspberry Pi 4/5, Apple Silicon) |
v0.5.1
What's changed
Fixed
- Clean stop exit code. Stopping the container now exits with code 0
instead of 143. uvicorn re-raised the SIGTERM after its graceful shutdown, so
Home Assistant reported the app as "did not handle SIGTERM" and showed an
error on the app card.
Commits since v0.5.0
- chore: file changelog for release v0.5.0 (5ab839e)
- chore: restore CODEOWNERS file with maintainers information (86a34d0)
- fix: ensure graceful shutdown exits with code 0 instead of 143 (01d34e4)
- chore: update version to 0.5.1 (53cfa61)
Docker image
docker pull ghcr.io/myastroboard/myastroshine:0.5.1 # GitHub Container Registry
docker pull myastroboard/myastroshine:0.5.1 # Docker Hub| Platform | Architecture |
|---|---|
linux/amd64 |
x86_64 |
linux/arm64 |
ARM 64-bit (Raspberry Pi 4/5, Apple Silicon) |
v0.5.0
What's changed
Changed
-
A friendlier editor for people who are not photographers. The start
screen offers two drop zones side by side (one photo / several shots of the
same target) instead of a mode toggle. The workflow rail groups the steps into
Prepare / Enhance / Finish with an icon and a plain-language subtitle each;
every step opens on one short sentence with the details behind "Learn more",
and ends on a distinct "Next step" button. Auto Astro is the Start step's main
action and confirms when it has set everything; presets are cards with an icon
and a visible description. Sliders fill from their neutral value, white
balance / tint / exposure / colour show a gradient track, and a double-click
puts a slider back to neutral. Before / After are labelled on the image, the
histogram is folded away, and Export ends on a "your image is ready" recap.
Several labels say what they do ("Clean the sky", "3D effect", "Remove
haze"). Own line-icon set, no emoji; footer theme toggle as icons. -
Go-back points (formerly milestones) explain themselves, are named after
the steps that changed ("2 - Light, Colour"), and going back from an unsaved
edit keeps that edit as a new point first - nothing is lost. -
Phone layout: the preview is pinned above the controls and the rail is a
bottom tab bar; the editor no longer overflows horizontally. -
One container, no Redis, no worker. Image and stack processing now run as
background jobs inside the application process, and the app runs its own
maintenance (hourly cleanup, minute-by-minute watch-folder poll)./process
and/stack/{id}/processalways answer at once with the queued job; progress
streams over the same WebSockets. Edits and stacks have separate thread pools,
so a long stack never blocks the editor. A job still running at shutdown stops
at its next step and endsfailed(an external engine it ran is killed, not
orphaned); jobs left over from a crash are failed at the next start. The
star-mask, Auto Astro, depth-shift and upload-decoding routes no longer run on
the event loop. Upgrading from compose: take the newdocker-compose.yml
(or drop theworkerandredisservices) - see docs/DEPLOYMENT.md. -
Runs on older x86-64 CPUs. The amd64 image now starts on CPUs without
x86-64-v2 (Proxmox's defaultkvm64CPU model, used by the Home Assistant OS VM
scripts), where NumPy's PyPI wheels crashed with "Illegal instruction": NumPy
is rebuilt without a CPU baseline. ACPU compatibilityCI check (also a gate
of the release) runs the image under an emulatedkvm64CPU. -
Listens on IPv4 and IPv6. One dual-stack socket instead of IPv4 only, so a
host name resolving to IPv6 (oftenhomeassistant.local) reaches the app. -
Clean, bounded stop. A container stop ends in a few seconds with exit code
0, even with a job running (it endsfailed, "interrupted by a server
shutdown"). -
Uploads never sit in memory whole. Files stay in their spooled temp files
and are read one at a time: a 20-frame batch, a calibration set or a.zip
archive no longer loads entirely into RAM (an archive was read whole before),
which matters on small hosts like a Raspberry Pi. Oversized files are refused
from their declared size before they are read, an over-cap request before its
body is received, and an archive member before it is unpacked. Batch routes
take at most 20 files per request; the web UI now also sends calibration
frames in batches of 20. -
Works under a path prefix. The web UI builds every URL - assets, API calls,
images returned by the API, WebSockets - relative to the page, so it can be
served athttps://example.com/astro/behind a reverse proxy or inside a Home
Assistant ingress. CI checks the source and the built bundle for root-absolute
URLs, and an e2e run walks the app behind a fake ingress proxy. -
Stack step: adaptive, colour-preserving stretch (
stack.stretch_mode,
default"adaptive"). The stretch now works on luminance and carries colour
as a ratio, and its curve is solved per image from the sky level and the
object level (both read on a star-suppressed copy). Galaxy cores are no longer
clipped flat (M31's core was never saturated in the linear data - the old
stretch clipped it), stars keep their colour, and a frame-filling nebula is no
longer mistaken for the sky."classic"keeps the previous stretch. -
Colour calibration uses the star field as the white reference. Aperture
photometry on the unsaturated stars sets the channel gains, replacing the
balance of channel means, which a strongly coloured target (a red emission
nebula, the Pleiades) pulled toward grey. Falls back to the previous method
when fewer than 20 clean stars are measured. The sky is neutralised without
clipping its noise, which removes the purple, mottled background a weak-blue
sensor gave after calibration. -
Denoise, colour noise reduction and sharpness are multiscale (starlet
wavelet) operations instead of a bilateral filter and a 3x3 Laplacian kernel:
grain is removed while stars and filaments keep their amplitude, and
sharpening only boosts structure that rises above the noise. -
Saturation and vibrance run in float and preserve luminance (no 8-bit HSV
round trip). -
StarNet2 and DeepSNR exchange 16-bit or float data, never 8-bit. On a
stacked composite, DeepSNR now runs on the linear data before the stretch (a
float FITS with--linear), which is what the model is trained on. The
engine estimate cache stores lossless.npyfiles.
Added
- Ready for Home Assistant ingress. Running as a Home Assistant app (the
Supervisor injectsSUPERVISOR_TOKEN), requests from the Supervisor get the
browser's own address back fromX-Forwarded-For, so the rate limit, the
login throttle and the concurrent-job cap count each HA user apart instead of
all of them as one; the admin cookie is scoped to the ingress prefix and
Securewhen HA is served over HTTPS. The Supervisor's headers are honoured
only from its address (IPv4-mapped forms included) and removed from anyone
else's requests; nothing changes for a plain Docker install. - Reset the admin password without a shell. An empty
reset-adminfile in
the data directory - for the Home Assistant app, in its folder under
addon_configs- clears the admin password at the next start and is deleted.
The login form says how. - Admin password. Settings - and every
/api/admin/*and/api/tokens
route - now need an admin login; using the app (upload, edit, stack, download,
presets) stays open. On first start the Settings page asks to create the
password; until then the administration surface is locked. Settings ->
Security changes the password, lists the logged-in browsers (and logs them
out), and sets how long a login lasts (admin_session_idle_days, default 7,
30 at most). Failed logins are throttled per IP. A lost password is reset from
the host withpython -m app.cli reset-admin. New routes under/api/auth
(docs/API.md "Admin authentication"); migration0a1b2c3d4e5fadds the
admin_credentialsandadmin_sessionstables. - Settings reorganised by subject: General, Stacking, ML engines, Astrodex
(was Webhooks), Security, Logs, Maintenance (was Operations). The catch-all
Advanced tab is gone: CORS and rate limiting moved to Security, log levels to
Logs, the ML engines to their own tab, configuration backup to Maintenance. - Install StarNet2 / DeepSNR from Settings. Upload the CLI package downloaded
from starnetastro.com (Settings -> ML engines): the server
unpacks and checks it, shows its licence, and installs it once the admin
accepts - no bind mount or path to type. Remove deletes it. A package built for
another architecture (the x86-64 build on a Raspberry Pi) is refused with a
clear message. Mounting a binary and setting its path still works. New admin
routes under/api/admin/engines(docs/API.md "External ML engines"). green_removal(0-100): SCNR average-neutral green removal, in the Sky step.
Removed
PROCESSING_MODE,REDIS_URLandCELERY_BROKER_URL(ignored if still set),
theworkerandrediscompose services,worker.log, and theredisfield
ofGET /api/health.celery,redisandcelery-typesleave the
dependencies.
Fixed
- The Depth Shift viewer opened underneath the inspector column (the modal was
rendered inside the sticky preview column's stacking context). - Ellipses and middle dots in the translations are ASCII now ("...", "-").
Dependencies
- Backend: SQLAlchemy 2.0.54 -> 2.1.1, uvicorn 0.53.0 -> 0.54.0, ruff 0.16.8 ->
0.16.9 (dev). - Frontend (dev): vite 8.3.0 -> 8.3.1, vitest / @vitest/coverage-v8 5.0.1 ->
5.0.2, @types/node 26.6.2 -> 26.6.3. - Backend: fastapi 0.141.1 -> 0.142.2.
- Frontend (dev): vitest / @vitest/coverage-v8 5.0.2 -> 5.0.3, typescript-eslint
8.70.1 -> 8.71.0, globals 17.12.0 -> 17.13.0; brace-expansion 5.0.12 (transitive, via eslint) for
GHSA-q2hr-2g5m-vwhr / GHSA-qhr7-859c-m2p7 / GHSA-6j4f-fj2g-mc7p. - Frontend (dev): vite 8.3.1 -> 8.3.2.
Commits since v0.4.2
- chore: file changelog for release v0.4.2 (ee2d832)
- Add unit tests for hooks and WebSocket client; enhance coverage configuration (26c1f32)
- chore: update dependencies in frontend package.json (9fbc6e5)
- feat: adaptive colour-preserving stretch and multiscale processing (de0e99e)
- Add unit tests for StackView, adminAuth, appUrl, relativeUrls, and useAdminAuth (29e14c5)
- feat: add EngineInstaller component for managing external ML engines (b4f35fe)
- refactor: reorganize settings and update documentation for clarity (8591bfb)
- fix: standardize spelling of "Astrodex" across the application (bb6a10c)
- feat: implement CPU compatibility checks and dual-stack server support (32a2a45)
- fix: clarify socket binding co...
v0.4.2
What's changed
Added
- A capture info panel for a stacked composite session. Below the workflow
rail, a small "Capture" card shows what's read off the source FITS
header(s) - object, telescope, filter, frame count x exposure, total
exposure, date, gain, sensor temperature - for both an in-app multi-frame
stack and a single already-stacked upload (a Seestar / ASIAIR live stack).
An already-stacked source's own frame count / total exposure (STACKCNT/
TOTALEXP) are trusted as-is; the in-app stacker sums each kept sub's own
exposure instead. Every field is best-effort and simply omitted if absent;
the whole card stays hidden for an ordinary photo. New
GET /api/session/{id}/capture-info. - A golden-image regression test suite (
backend/tests/regression/) runs a
synthetic frame through the real enhancement and stacking pipelines on every
pytestrun and diffs the result against a checked-in reference - catches a
silent numeric regression (a gain, a clamp) that runs cleanly with no
exception but changes what the pipeline actually produces, the shape of the
0.4.1 colour-calibration bug. Internal - no user-facing change; see
CONTRIBUTING.md. - Settings gains an Operations tab. Recent processing jobs (status,
session/stack, timestamp, error - filterable, paginated,supersededrows
hidden by default since every debounced slider edit creates one) and a
disk-usage breakdown of the data volume (images / stacks / database / logs)- useful for the folder-watch stacking mode, meant to run unattended for
hours. A newjob_history_retention_hourssetting (default 7 days) bounds
how long a finished job is kept; the hourly cleanup now prunes old rows
instead of letting thejobstable grow forever. New
GET /api/admin/jobs,GET /api/admin/disk-usage.
- useful for the folder-watch stacking mode, meant to run unattended for
GET /api/healthnow actually checks something. It used to always
report"database": "connected"regardless of whether the database was
reachable. It now runs a real query, pings Redis when
PROCESSING_MODE=queue(skipped entirely insyncmode, where nothing uses
Redis), and reports the data volume's disk usage.- Settings -> Advanced gains a Backup & restore block. Exports the runtime
settings and every user preset (never the 5 built-ins - each instance
seeds those itself) as one downloadable JSON file, and restores them from
one - for moving to a new machine or sharing a preset library. Not sessions
or images: those are transient by design (session_expiry_hours) and the
actual deliverable is the downloaded picture, not the working session - the
whole data volume is already the backup unit for everything else. An
imported preset whose name already exists on the target instance is skipped,
never overwritten or renamed. NewGET /api/admin/config-export,
POST /api/admin/config-import.
Changed
- Auto Astro now also measures colour cast and noise. Previously scoped
to tone (contrast/exposure/highlights/shadows) and star density; it now
additionally proposestemperature(from the background sky's own
blue-vs-red balance, damped to half the measured cast so a genuinely
coloured target isn't washed out - the same caveat as the Colour
calibration hint below) anddenoise/chroma_denoise(from the sky
background's own luma and Cr/Cb noise level - colour speckle is usually
more objectionable than luma noise in a stacked frame). Each stays at its
default when the measurement is inconclusive or the frame is already close
to neutral/clean;tint, saturation, sharpness, and colour grading remain
manual - confidence-limited choices a heuristic has no business making.
Agradient_reductionheuristic (a fitted brightness trend) was also built
and checked against a real library of stacked composites and lunar
photos - and reverted, since it couldn't reliably tell a real
light-pollution gradient apart from an ordinary asymmetric bright subject
(an ordinary lunar photo measured in the same range as legitimate-looking
deep-sky corrections);gradient_reductionstays manual-only. The
denoise/chroma-denoise scale was also recalibrated against that same
library - the first cut, tuned only against synthetic noise, capped out
(over-smoothing real DSO detail along with the sky) on nearly every real
capture tested. Seedocs/ALGORITHMS.md"Auto Astro". - The Colour calibration hint now says what it can get wrong. It neutralises
the sky and balances the channels toward a white star field - the right call
for a sensor colour cast, but it can't tell that apart from a target's own
real colour, so it can wash out a genuinely blue reflection nebula (the
Pleiades) or a red emission nebula. The hint now says to turn it off for
those. - The tone/colour/detail sliders step by 0.1, not 0.01. Contrast, exposure,
highlights, shadows, whites, blacks, clarity, sharpness, vibrance and
saturation showed a spurious second decimal (1.23) no one could aim for by
hand - a coarser step (matching the crop tool's straighten slider, already
0.1) lands on the same clean numbers with a fifth as many stops and reads
simpler at a glance. Every default (1.0, 0.0, ...) still falls exactly on
the new grid. The 0-100-range sliders (denoise, star reduction, vignette,
...) were already stepping by 1 and are unchanged - this is purely a slider
granularity change, the stored values are still plain floats.
Commits since v0.4.1
- chore: file changelog for release v0.4.1 (51b5799)
- fix: improve colour calibration handling for single stacked uploads and adjust editor step order (79ae993)
- feat: add capture info panel and API for stacked composite sessions, including metadata extraction from FITS headers (932ba40)
- fix: adjust slider step values for improved user experience and consistency (a0e1531)
- feat: add golden-image regression tests for image enhancement and stacking pipelines, including synthetic frame generation chore: update dependencies for frontend and backend, including React and Vite docs: enhance CONTRIBUTING.md with regression testing guidelines (cd0e46b)
- feat: enhance health check and job management features (574f39a)
- feat: enhance AutoAstroService with gradient reduction, white balance, and noise handling (a6741bf)
- fix: remove gradient reduction heuristic from AutoAstroService and update documentation (c470efb)
- Add Portuguese translations for the application (2b02f4a)
- chore: update version to 0.4.2 (ab1b737)
- refactor: remove client_ip from JobSummary and related components (aa4f12b)
Docker image
docker pull ghcr.io/myastroboard/myastroshine:0.4.2 # GitHub Container Registry
docker pull myastroboard/myastroshine:0.4.2 # Docker Hub| Platform | Architecture |
|---|---|
linux/amd64 |
x86_64 |
linux/arm64 |
ARM 64-bit (Raspberry Pi 4/5, Apple Silicon) |
v0.4.1
What's changed
Changed
- A stacked FITS (or a 16-bit PNG/TIFF) now opens as a composite session, the
same as the multi-frame stacker's own output, instead of a one-shot 8-bit
auto-stretch on upload. The editor's linear Stack step - background
extraction, colour calibration, a tunable deep stretch - runs on the 32-bit
data on every render, and the faint signal is never quantised to 256 levels on
the way in. A Seestar / alt-az live stack's field-rotation + vignette border
(the "red top / marked corners") is detected from the pixels and trimmed on
ingest.POST /api/uploadreturnsis_stack: truefor these. See
docs/ALGORITHMS.md"Upload ingest" andapp/services/linear_upload.py. - Background extraction gains a frame-edge residual correction. After the
degree-2 polynomial it adds back the object-free sky residual, smoothed and
masked to the frame border, so the sharper edge/corner colour cast a
paraboloid can't bend to (a Seestar footprint the crop only partly removes) is
taken too - while a galaxy halo or a frame-filling nebula in the interior is
left exactly as before. - A 3-plane (RGB) FITS that still goes through
decode_image(an AstroDex
handoff, say) is stretched with one shared, colour-preserving transform and a
deep sky target, not three independent per-channel stretches that lifted the
sky to a milky grey and rebalanced the colour. - The white-balance Temperature slider snaps to standard Kelvin stops
(2000 / 3200 / 4500 / 5500 / 6000 / 6500 / 7000 / 7500 / 8000 K) instead of a
free 50 K ramp, and the readout names the tone ("Neutral · 6500 K"). Lower K
warms the image, higher K cools it - the hint said the opposite and is fixed.
The backend still accepts any value in range; an older preset's off-stop value
shows verbatim with the thumb on the nearest stop. - Each editor slider gets a one-step revert. The value a slider held before
your current run of edits is remembered, and a small back-arrow appears next
to that slider (only the one you're adjusting) to put it straight back. Cleared
by a preset, a section reset, or a milestone restore. - Vignette is now signed (-100..100). Positive still brightens the corners
(lens-vignetting correction); negative darkens them - to deepen a vignette for
effect, or tame an over-corrected stack.
Fixed
- A trailing slash on a CORS origin or AstroDex callback allowlist entry
in Settings is now stripped on save (https://host/->https://host). A
pasted slash previously made the entry silently match nothing - the CORS
origin never carries one and the allowlist is checked against a slash-stripped
callback_base. The allowlist match also now enforces a path boundary, so
https://board.exampleno longer also authoriseshttps://board.example.evil. - Editor sliders and tone curves now render on release, not on a timer.
Dragging slowly, or pausing mid-drag, no longer kicks off a render before you
let go - the value tracks live and the pipeline runs on pointer-up / key-up
(with a 1.2 s fallback if a release event never arrives).
Commits since v0.4.0
- feat: implement AstroDex handoff integration (01e7dc8)
- chore: update version to 0.4.0 and reflect in README (19c346f)
- chore: file changelog for release v0.4.0 (61ebc98)
- fix: update image references in docker-compose and deployment documentation (19dcac2)
- feat: implement crop_low_signal_border for single uploaded stacks (3ec95ba)
- feat: add frame-edge residual correction to background extraction (2a1f6c0)
- fix: normalize trailing slashes in CORS origin and AstroDex callback allowlist entries (d003833)
- feat: implement temperature slider snapping to standard Kelvin stops with updated hints (4f297e3)
- feat: update slider rendering to trigger on release, enhancing user interaction (3b784d1)
- feat: implement one-step revert for slider adjustments and update vignette correction range (4007306)
- chore: bump version to 0.4.1 (3b03033)
Docker image
docker pull ghcr.io/myastroboard/myastroshine:0.4.1 # GitHub Container Registry
docker pull myastroboard/myastroshine:0.4.1 # Docker Hub| Platform | Architecture |
|---|---|
linux/amd64 |
x86_64 |
linux/arm64 |
ARM 64-bit (Raspberry Pi 4/5, Apple Silicon) |
v0.4.0
What's changed
Changed
- AstroDex integration rebuilt around a signed handoff. MyAstroBoard now
opens the editor with a single?handoff=token; the backend verifies it,
pulls the source image from the board itself, and drops you straight into the
editor. The Export step gains Send back to AstroDex, which posts the
processed image back as a signedmultipart/form-datarequest - the board
files it as a new picture on the same object, never a replacement. This
instance is never contacted by the board, only ever calls out to it, so
the flow works whether the board is on the LAN or behind a reverse proxy. The
handoff token is HMAC-SHA256 signed with a webhook token'ssigning_secret,
expires after 12 h, and is single-use for the return. Seedocs/API.md
"AstroDex integration" andinitial_plan/PASSATION_MYASTROBOARD_INTEGRATION.md.
Removed
- The never-wired push endpoints
POST /api/astrodex/receiveand
POST /api/send-to-astrodex(and theAstroDexService/AstroDexDispatch
services), replaced by the handoff routes above.astrodex_linksis reshaped
by migrationd4e5f6a7b8c9;astrodex_callback_urls/
astrodex_max_retries/astrodex_retry_delay_secondsare unchanged.
Commits since v0.3.0
- Add Docker Image Size badge to README (f10be9b)
- chore: file changelog for release v0.3.0 (3888d70)
- feat: implement AstroDex handoff integration (237f116)
- chore: update version to 0.4.0 and reflect in README (b50d2e4)
Docker image
docker pull ghcr.io/myastroboard/myastroshine:0.4.0 # GitHub Container Registry
docker pull myastroboard/myastroshine:0.4.0 # Docker Hub| Platform | Architecture |
|---|---|
linux/amd64 |
x86_64 |
linux/arm64 |
ARM 64-bit (Raspberry Pi 4/5, Apple Silicon) |
v0.3.0
What's changed
Added
- Star removal (starless): the editor's Stars step now offers two ways to
handle stars, grouped and explained side by side - Reduce (shrink each
star in place, the existing control) and Remove. Raise Remove stars
and the pipeline splits: the stars are pulled out right after the background
corrections, every creative adjustment (tone, curves, colour, detail) then
works on the nebula alone, and Bring stars back screen-blends them in at
the end (0 keeps the image starless, 100 restores them full strength).
Detection (sensitivity / max size, mask preview) is shared by both. The
reconstruction is classical - a median-blur estimate on a downscaled copy,
sized so galaxy and nebula cores are preserved - with no ML model and no new
dependency (it also letscikit-image, unused since the v0.2 star-detection
rebuild, be dropped). A very dense Milky Way star field is the known limit of
the classical method; the StarNet2 engine below is the way past it. - Optional ML engines for star removal and noise reduction, installed by the
operator, never bundled. Point Settings -> Advanced at a
StarNet2 and/or DeepSNR binary you mount into the
containers and the editor gains an engine toggle: StarNet2 in the Stars
step (per-edit, replaces the classical split for the run) and DeepSNR in
the Detail step's denoise control (runs early, before the tone stretch). Each
is arm's-length - MyAstroShine writes a TIFF, runs the tool, reads the result
back - and any failure (missing binary, timeout, bad output) logs and falls
back to the classical code, so a client can always request them. A pass streams
its progress onto the editor bar; the result is cached per session so a
creative-only tweak doesn't re-run it. Nothing ships in the image and no
Python dependency is added - seedocs/DEPLOYMENT.md"External ML engines" and
THIRD_PARTY.md(the tools are non-commercial; the operator accepts their
terms). - Edit milestones: a timeline under the preview where you can save the current
adjustments (sliders, curves, framing, and the Depth Shift focal point) as a
checkpoint and click back to it if you push an edit too far. The first
milestone is always the original image. Milestones live only in the browser
for the image being edited - loading another photo starts over, and there is
no server-side copy. - Light theme, now the default, matching the MyAstroBoard visual charter (deep
teal primary accent, amber ecosystem accent, frosted panels over a lightly
teal-tinted ground). The dark theme is unchanged. - A Theme control in the footer - System / Light / Dark. "System" follows the
operating system's light/dark setting and updates live when it changes. The
choice is remembered per browser. - The upload screen now shows real progress: a percentage and bar while the file
transfers (overXMLHttpRequest, whichfetchcan't report), then an
indeterminate "Preparing your image…" spinner while the server decodes it -
previously a large FITS / RAW upload just sat with an unchanged button. GET /api/config- a small public endpoint exposing the runtime limits the UI
needs before a session exists (the upload size cap, stacking limits). The
upload screen's size hint and its pre-flight check now follow the operator's
configuredmax_image_size_mbinstead of a hardcoded 100 MB.- Stacking rebuild (in progress): multi-frame stacking is being reworked to run
on linear, full-bit-depth data instead of stretched 8-bit previews - the old
pipeline was never run on real data and produced a near-black result on a real
Seestar set. This release lays the foundation: a unified linear ingest (FITS
Bayer mosaics kept intact and debayered in-pipeline, camera RAW demosaiced
linearly, 8-bit previews sRGB-linearised), a.ziparchive upload so a
thousand-frame session is a handful of requests, per-frame thumbnails, and a
frame-by-frame include/exclude toggle (POST /api/stack/{id}/frame/{i}/exclude)
for dropping a sub with a trail or cloud. Frames now upload in batches
(POST /api/stack/{id}/upload-frames) or as a.zip
(POST /api/stack/{id}/upload-archive) instead of one request per frame, and
the frontend checks the frame count against the instance limit before starting
so you get a clear message, not a raw error. The stacking screen is reworked
into a collect -> upload -> review -> stack flow: a drag-and-drop zone matching
the single-image one (accepted formats, size limit), then frames upload as a
batch and a thumbnail grid lets you click any frame to preview it large and
tick a box to drop a trailed or clouded sub. After stacking you can still tweak
a setting or exclude another frame and hit Re-stack
(POST /api/stack/{id}/processnow takes an optional settings body) with no
re-upload, or inspect a frame and go "Back to composite". Abeforeunload
guard stops a mis-swipe or a mouse "back" from losing an in-progress stack.
The pipeline now registers the frames - it detects stars, picks the
sharpest frame as the reference and asterism-matches the rest onto it (a
vendored triangle matcher, no new dependency), warps them with Lanczos,
normalises each to the reference, and combines with iterative sigma rejection
and noise weighting, all in bounded memory (afloat16memmap + row tiling,
so a thousand-frame stack does not need a thousand frames of RAM). On a real
150-frame Seestar set: sub-pixel alignment, ~8.7x noise reduction. It now also
calibrates each frame: upload master darks, flats, bias and dark-flats
(POST /api/stack/{id}/calibration/{kind}/frames) and the pipeline builds a
median master of each, applies(light - bias - dark) / flaton the Bayer
mosaic before debayer, and repairs hot / dead pixels from the master
dark/flat with a neighbour median (the honest replacement for the removed
"cosmic ray" step; toggle with Repair hot & dead pixels). The Bayer
mosaic is now debayered with an edge-aware interpolating demosaic at full
resolution for the align/combine passes (registration still measures on the
cheap half-res superpixel). Every sub is now scored (star count, FWHM,
roundness, sky background, SNR) and the worst are auto-rejected: the
Auto-reject bad frames setting (off / lenient / moderate / strict, default
moderate) drops a clouded, soft, trailed or dawn sub before it can pollute the
stack, the frame grid shows each sub's score and why it was dropped, and
unchecking a frame rescues it from the filter on the next run.weighting: "quality"now uses that same score. The finished composite is cleaned up
before it opens in the editor (Clean up the composite, on by default): the
field-rotation edges are cropped away, a low-order sky-gradient is subtracted
(a degree-2 fit that cannot carve into a nebula), and the colour is
neutralised and balanced. Combined with a better reference-frame choice (the
middle of the session, not the frame with the most stars) a real 100-sub set
now comes out framed on the target with a flat neutral background instead of
noisy rainbow speckle. Finally, a stacked composite now opens the editor on
its 32-bit linear data, with a new Stack step (composite sessions
only): a Stretch control that sets the auto-stretch strength, a
Background extraction slider, and a Colour calibration toggle - all
non-destructive, recomputed from the linear composite so nothing is lost to an
early 8-bit quantisation. The whole creative pipeline (ImageProcessingService)
now runs in float32 internally and quantises only at the encode boundary, which
also benefits single-image FITS/RAW edits. Only the field-rotation crop is
baked into the saved composite; background extraction and colour calibration
moved out of the one-shot cleanup and into the Stack step. - Stacking scale & UX: the progress bar now shows which frame each step is on
("Aligning 340 / 1066"), not just a percentage. The register / align / combine
passes run on a thread pool (auto-sized to the CPU count, capped at 4,
tunable in Settings) - roughly 2x faster on a real multi-frame stack, and
parallelising the combine step is what moved the needle. An interrupted run now
resumes: the aligned frames and a small plan file survive a crash, so a
retry - or a re-stack that only changes the combination / rejection / weighting- skips straight to the combine step instead of re-registering everything. And
a watch folder: point the worker at a directory (Settings) and frames
dropped there are ingested into a rolling stack that auto-processes once the
folder goes quiet; the stacking screen shows a banner to open it.
- skips straight to the combine step instead of re-registering everything. And
- Drizzle (Fruchter & Hook) as an opt-in stacking option (2x / 3x). Each
input pixel is a shrunken "drop" mapped through its registration transform and
area-distributed onto a finer output grid, so a large, well-dithered stack
(the Seestar's alt-az field rotation supplies the dither) yields real
resolution gain a plain resample cannot. It runs as an extra pass after the
normal stack (which stays the fallback and the outlier reference), is slower
and correlates neighbouring-pixel noise, and is off by default.
Changed
- The language switcher moved from the header to the footer, next to the new
theme control; the header now carries only the brand and Settings. - Denoise and Chroma denoise now use the documented bilateral-filter range
(diameter 5-20, sigma 75-150) so high slider values deliver the intended
stronger noise cleanup on deep-sky frames. - Built-in deep-sky presets were rebalanced to darken shadows instead of
lifting them (Galaxyshadows: -0.25, Deep Fieldshadows: -0.35) for
better object-vs-background separation, matching the Auto Astro strategy. - The pe...
v0.2.0
What's changed
Added
- Star reduction rebuilt on per-star detection (
StarDetectionService, a
thresholded top-hat +cv2.connectedComponentsWithStats, at native
resolution, robust to ordinary sensor/JPEG noise) instead of a single
image-wide top-hat mask, so only genuine stars are shrunk and diffuse
nebulosity is never dimmed. Each star shrinks via erosion floored at its
own local background, so it can't crush to a black dot or bloat into a flat
pale disc at full strength. Newstar_sensitivity/star_max_size
parameters tune what counts as a star. - Star mask preview:
POST /api/star-mask/{session_id}reports detected star
positions for a live "N sources detected" overlay in the editor, toggled from
the Stars panel. - Auto Astro: a one-click "Auto Astro" button (
POST /api/auto-astro/{session_id})
analyses the image's histogram and star density and applies a computed
starting parameter set - crushing the background for depth/separation from
the DSO, and a gentle, log-scaled star reduction that stays a sensible
starting point across both sparse frames and busy deep-stacked fields -
in place of manually dialing in every slider. Auto Astro and preset apply
both keep the session's current framing (crop / rotate / straighten / flip)
rather than resetting it - a look is not a composition. - Editor UX: a workflow-driven three-pane editor. A numbered rail on the
left steps through the retouching order (1 Framing, 2 Background, 3 Light,
4 Curves, 5 Colour, 6 Detail, 7 Stars, 8 Depth), bracketed by a
one-click Start (Auto Astro + presets) and Export - the same order
the backend pipeline applies. Only the selected step's controls show, in an
inspector panel with its own help text, reset, and a "Next" link; the
preview + histogram stay pinned on the right instead of scrolling out of
view under a long list of tools. A step shows a dot on the rail once its
values leave the default. Crop / straighten / rotate / flip is now step 1,
edited directly on the preview (the separate full-screen crop editor is
gone). White balance (temperature / tint) moved from the creative colour
controls into step 2, next to the other background corrections, matching the
pipeline. A focal-point picker on the preview (click to set) drives where
the Depth Shift parallax centers -focus_pointwas accepted by the API
before this but never used. - A "New photo" button on the editor returns to the upload screen -
previously the only way back was a full reload. Leaving with unsaved edits
(the button, or a browser back / reload / mobile edge-swipe) now asks first,
so a mis-swipe on a slider no longer silently loses the work. The mode
switcher is hidden while a photo is open. - i18n: FR + EN. Every frontend-owned UI string now goes through
useTranslation()'st(), backed byfrontend/src/i18n/translations/{en,fr}.json
(en.jsonis the reference language); a compact EN/FR selector sits in the
header. Detects the browser language on first load, then persists the
choice client-side.scripts/validate_i18n.py(new CI job) checks key
parity, leaf types, and{placeholder}names between the two files.
Backend-owned detail strings (log lines, specific error text) stay
English-only, but the five built-in preset names / descriptions and a few
whole classes of API failure (server busy, temporarily unavailable, 5xx)
are now shown in the user's language. - Permanent page footer (name, version, GitHub link - inspired by
MyAstroBoard's own footer bar), replacing the version number that used to
sit in the header. In-app update check folds into it: once a newer GitHub
release is published, a discreet second line appears with a link to it and
a "What's new" that opens the release notes in a modal, rendered from
markdown (headings, bold, lists, links) rather than shown as raw
###/**syntax.GET /api/version/check-updates(VersionCheckService)
queries GitHub's releases API and caches the result in memory for 4 hours,
so the frontend's 4-hourly poll can never translate into hitting GitHub's
rate limit; every failure path (timeout, GitHub's own rate limit, a
malformed response, ...) degrades to no notice rather than an error. The
frontend re-verifies the version comparison itself before showing
anything, so a stale/incorrect cache can never present as a downgrade. - Tone curve editor: an interactive curve graph (drag points to reshape,
double-click to add or remove a point) alongside the adjustment sliders.
Backed by a newcurve_pointsparameter and a monotone cubic Hermite
spline LUT stage in the processing pipeline, so a handful of dragged
points make a smooth curve - not a faceted polyline - and can never
overshoot past a control point's value into crushed shadows or blown
highlights. - Five missing core astro ops, a new Corrections section, and split
tone controls:- Vignette correction - brightens the corners to counteract lens
vignetting (a generic radial model, not a per-lens calibrated profile). - Gradient reduction - flattens smooth background gradients (light
pollution, sky glow) via a large-blur background estimate, subtracted
back out. - Dehaze - dark-channel-prior haze removal, restoring contrast/colour
lost to a veiling glow or light-pollution haze. - Colour noise reduction - denoises only the Cr/Cb colour channels,
leaving luma (and its own separatedenoisecontrol) untouched -
colour speckle tolerates far more smoothing than brightness detail does. - Whites / Blacks - push the white/black clipping points, narrower
and more aggressive than the existing Highlights/Shadows (only the true
near-white/near-black tail moves, not the broader upper/lower-mid
range) - the usual distinction in most photo editors. - Vignette correction, Gradient reduction and Dehaze live in the editor's
step 2 (Background), applied before any creative grading.
- Vignette correction - brightens the corners to counteract lens
- FITS + 16-bit + camera RAW upload support - previously 8-bit JPEG/PNG/
TIFF only (and a 16-bit TIFF/PNG was silently truncated to 8-bit). FITS
(.fits/.fit/.fts) and camera RAW (.cr2/.cr3/.nef/.arw/.dng/
.orf/.rw2/.pef/.raf) now decode viaastropy/rawpyrespectively.
FITS and a genuine 16-bit TIFF/PNG both get a new auto-stretch (the same
"screen transfer function" PixInsight/Siril use) instead of a naive bit-
shift; RAW is demosaiced with the camera's as-shot white balance. See
docs/ALGORITHMS.md"Upload ingest: FITS / RAW / 16-bit". - Colour curves - the Tone Curve panel now has 4 tabs (RGB / Red / Green /
Blue), each an independent curve on the samecurve_points_to_lut
monotone-spline LUT the master RGB curve already used, applied via
cv2.split/cv2.LUTper channel /cv2.mergeinstead of identically to
all three. For a colour cast a single white-balance gain can't reach at one
specific tonal range (e.g. a green background-sky cast only in the
midtones), or deliberate colour grading. Newred_curve_points/
green_curve_points/blue_curve_pointsparameters (same empty-by-default,
first-at-0/last-at-255 validation ascurve_points), applied right after
the master curve. Seedocs/ALGORITHMS.md"Colour curves".
Changed
brightnessrenamed toexposurethroughout the API, Auto Astro, and the
editor UI - no behaviour change, just a name matching the rest of the
"Exposure/Highlights/Shadows/Whites/Blacks" tone-control family this
release completes. A saved preset or automation using the old
brightnesskey needs updating toexposure.- Full-resolution enhance's performance budget raised from 5s to 8s
(tests/benchmarks/test_processing_speed.py) to account for the 5 new
pipeline stages above - measured 5.75s on a 24MP frame with every slider
active at once (an unrealistic worst case; the interactive preview budget,
what a slider drag actually feels like, is unchanged and unaffected).
Removed
- The
denoise_enable_ml/depth_detection_methodSettings fields (and
their "Processing" section) - both were placeholders for ML backends
evaluated this release and not adopted (seedocs/ALGORITHMS.md"Depth
map" and "ML denoising"): no viable pretrained denoising model exists to
point a self-hoster at, and MiDaS/DPT-Hybrid depth estimation produces a
near-featureless result on real astrophotos regardless of model size.
Neither field ever did anything -depth_detection_methodhad no reader in
DepthMapService/DepthShiftServiceeven before this evaluation. An old
app_settings.jsonwith these keys still loads fine; they're just ignored. - The
depth_shift_intensityprocessing parameter and its unused
ProcessRequest.apply_depth_shiftcompanion - dead since they were added
(no pipeline stage ever read them; the Depth Shift viewer has always kept
its own intensity state).ProcessingParametersnow silently drops the
retired key on the way in, so a stored preset from an older version still
loads instead of hittingextra_forbidden. - Dead-code sweep before the release: the unused
useAstroDexIntegration
hook is now wired to the "Send to AstroDex" button (which gains
sending / sent / error feedback); the unusedreact-router-domdependency
(routing is hand-rolled hash-based), the unreachableUpstreamUnavailableError
exception, the never-calledStorageService.count_stack_frames, the unused
API_PORTconstant, and the unusedget_astrodex_serviceDI wrapper are gone.
Fixed
- A processing job that got stuck non-terminal (a worker died mid-run, or a
queued job was never picked up) counted against the per-IP concurrency limit
forever - a few stuck rows would eventually make every enhance / Auto Astro
fail with "Too many concurrent processing jobs". Such a job now stops
counting once it is older tha...
v0.1.0
What's changed
First implementation pass covering the full v1.0 + v1.1 roadmap. Nothing has been
tagged yet.
Added
Core enhancement (Sprint 1-3)
- Image upload with format/size validation, 512 px preview generation, per-channel
histogram, and session tracking (POST /api/upload,GET /api/preview/{id}). ImageProcessingServicepipeline: geometry (rotate / flip / straighten /
crop), white balance (temperature/tint), contrast, brightness,
highlights/shadows recovery, saturation, vibrance, clarity, denoise
(bilateral), star reduction (top-hat star mask + morphological erosion),
sharpness. Validated against documented bounds.POST /api/process/{id}applies parameters and returns a job handle.GET /api/healthsystem health check.- Alembic migration scaffolding;
init_db()creates tables for local/dev use.
Job queue and progress (Sprint 3)
PROCESSING_MODEsetting:sync(run in the request, default) orqueue
(Celery task on Redis).- Celery app and tasks (
task_process_image,task_process_stack,
task_cleanup_sessions);task_always_eagerunderAPP_ENV=test. JobRecordtracking with per-step progress; Redis pub/sub bridge.WS /ws/processing-status/{job_id}andWS /ws/stack-status/{job_id}: DB
catch-up on connect, then live relay until a terminal status.
Presets (Sprint 3)
PresetServicewith five built-ins (Nebula, Galaxy, Deep Field, Lunar,
Cluster); built-ins cannot be deleted.GET/POST /api/presets,DELETE /api/presets/{id},
POST /api/presets/{id}/apply/{session_id}.- Duplicate-name and quota (50 user presets) guards.
Depth Shift (Sprint 4)
DepthMapService: Sobel-gradient depth map, normalization/smoothing, depth
statistics.- Parallax layer generation (2-12 BGRA layers, far to near).
POST /api/depth-shift/{id}, plus metadata, depth-map, and per-layer endpoints.
AstroDex integration (Sprint 4)
AstroDexService: canonical-JSON HMAC-SHA256 signing, payload composition,
retry with exponential backoff on 5xx.POST /api/astrodex/receive(inbound image) andPOST /api/send-to-astrodex
(outbound signed webhook, delivered in the background).- Long-lived bearer webhook tokens with per-token signing secrets, created and
revoked from the Settings UI (GET/POST /api/tokens,DELETE /api/tokens/{id}). - Callback-URL allowlist (
ASTRODEX_CALLBACK_URLS).
Stacking (Sprint 6-7)
RegistrationService: SIFT/ORB keypoints, Lowe ratio test, RANSAC homography,
perspective warp.NormalizationService(background-level equalization) andCosmicRayService
(MAD-based robust sigma rejection with an absolute-deviation floor).CombinationService: NaN-aware median, mean, and iterative sigma-clip;
SNR-improvement estimate (~sqrt(N)).POST /api/stack/initiate,POST /api/stack/{id}/upload-frame,
POST /api/stack/{id}/process,GET /api/stack/{id}. The composite is a normal
session and can be enhanced, previewed, and downloaded.
Frontend
- React 19 + TypeScript + Vite single-page app, Tailwind CSS v4 (CSS-first).
- "Darkroom / neutre pro" design system (
docs/DESIGN.md): semantic token layer
and shared component classes (.panel,.btn,.field,.slider,
.segmented,.chip,.dropzone) insrc/styles/index.css. Dark-only. - Single-image editor: drag-and-drop upload, before/after split preview with zoom
controls, histogram, grouped parameter sliders (500 ms debounce), preset
buttons, "save as preset" dialog, download. - Parameter tooltips: each slider gets a small "i" badge (hover or keyboard
focus, screen-reader linked viaaria-describedby) explaining what it does. - Crop / rotate tool (
CropTool): full-screen mode with a draggable crop
rectangle (corner + edge handles), straighten dial (+/-45 deg), 90 deg rotate,
horizontal / vertical flip, and aspect presets (Free / Original / 1:1 / 16:9 /
3:2 / 4:5 / 5:4). Commits ageometryobject applied first in the pipeline. - Preset chips: apply, plus a two-step delete on user presets (built-ins have no
delete affordance; the backend also rejects it with 403). - Interactive Depth Shift viewer (pointer-driven parallax, intensity slider).
- Multi-frame stacking mode: frame upload list, settings panel (alignment,
combination, cosmic-ray/background toggles), step-by-step progress over the
WebSocket, results panel with statistics, and "enhance composite" handoff. - Webhook token manager (create with one-time secret display, revoke).
- AstroDex context detection from URL parameters and "send to AstroDex" action.
- snake_case <-> camelCase conversion isolated to the API/WS clients.
Tooling and infra
scripts/check_deps_fresh.py: fails when any pin falls behind PyPI/npm; run in
pytestand a weekly CI job.- Docker Compose (
api,worker,web,redis) and a hot-reload
docker-compose.dev.yml. - Playwright end-to-end suite (
npm run test:e2e): upload -> slider -> process
-> download, save-as-preset, and the full three-frame stacking flow with the
"enhance composite" handoff. Boots the real backend and Vite dev server. - GitHub Actions: backend (ruff, mypy, pytest), frontend (lint, typecheck, test,
build), and e2e (Playwright) jobs, plus the dependency-freshness cron. - API listens on port 8002.
- Initial Alembic revision (
606a1e113989_create_core_tables) covering all six
tables;alembic upgrade head/downgrade baseandalembic checkverified
clean against the ORM models.
API rate limiting
- Per-IP request-rate limit (default 120/min, in-memory fixed window) on
/upload,/process/{id},/presets/{id}/apply/{session_id}, and
/stack/*; over the limit returns429 RATE_LIMITED. (Shipped at the API
spec's original 10/min first; raised the same day after it broke e2e and
would have broken real interactive editing - the editor re-processes on
every debounced slider change.) - Per-IP concurrent-job limit (default 5), checked against the shared
jobs
table so it holds under bothsyncandqueueprocessing modes. rate_limit_enabled/rate_limit_per_minute/max_concurrent_jobs_per_ip
in Settings -> Advanced;JobRecord.client_ip(new Alembic revision
623faa14df02_add_job_client_ip).
Session-cleanup scheduler
workerruns Celery beat embedded (-B, both compose files): hourly,
task_cleanup_sessionsdeletes sessions pastsession_expiry_hoursand
their files, regardless ofPROCESSING_MODE. Schedule state persisted at
DATA_DIR/celerybeat-schedule.
Performance benchmark suite
backend/tests/benchmarks/: codifies the Success Metrics acceptance
criteria as runnable checks - full-res (~24MP) enhance (measured 3.0s vs a
5s budget), preview (512px) reprocess (38ms vs 500ms), and an empirical
stacking-SNR check (16 synthetic frames with known noise through
combine(..., "mean"), measured 3.99x vs a theoretical 4.00x). Opt-in
(RUN_BENCHMARKS=1 pytest tests/benchmarks --no-cov) rather than part of
the default suite, since wall-clock budgets are sensitive to the machine and
to coverage instrumentation; runs weekly via
.github/workflows/benchmarks.yml, not on every push/PR.
Release mechanics
- Root
VERSIONfile is now the single source of truth for the app version
(previously hardcoded separately in the backend and frontend); read via a
build-timeAPP_VERSION/VITE_APP_VERSIONDocker build argument, or
straight from the file for local dev. - Single Docker image: the root
Dockerfile(multi-stage: Node builds
the frontend, Python runs the API) replaces the previous two-image split
(backend/Dockerfile+frontend/Dockerfilebehind nginx). FastAPI now
serves the built React SPA directly (StaticFiles, mounted after every
/api//wsroute - the frontend's hash-based routing needs no
SPA-fallback handling), withGZipMiddlewareand the security response
headers nginx used to add (X-Frame-Options,X-Content-Type-Options,
Referrer-Policy) moved intoapp/main.py. Atarget: backendbuild
(skips the frontend stage) servesworkerand the devapiservice, which
never need the built UI. One less container, one URL (:8002) for
everything instead of:8002(API) +:3000(nginx). .github/workflows/release.yml: tag-triggered (v*.*.*) multi-arch build
and push of the one image to bothghcr.io/myastroboard/myastroshine
and Docker Hub'smyastroboard/myastroshine, a Trivy scan, and a GitHub
Release generated from this changelog..github/workflows/post-release-cleanup.yml: opens a PR that files this
section under a dated release heading after a successful publish
(scripts/changelog_release.py).CODE_OF_CONDUCT.md,SECURITY.md.docker-compose.ymlgainedimage:alongsidebuild:onapiso a clean
machine candocker compose upfrom the published image without cloning
the repo; seedocs/DEPLOYMENT.md.
Changed
Configuration moved out of the environment (PASSATION alignment, part 1)
docker compose upnow needs no.envediting. The compose files carry only
structural variables (APP_ENV,DATA_DIR,PROCESSING_MODE, the Redis URLs);
docker-compose.ymldropped from 11 backend variables to 6 and holds no
secrets.- Single persistence root
DATA_DIR(/datain the image). The database,
session images, stacking frames, cache, log file,secret_key.txtand
app_settings.jsonall derive from it; the two data volumes were merged into
one (myastroshine_data). - The session / HMAC-fallback secret is generated once into
DATA_DIR/secret_key.txt(secrets.token_hex(32)) and never regenerated.
ASTRODEX_WEBHOOK_SECRETis gone. - New
app_settings.jsonholds every runtime-tunable value (CORS origins,
AstroDex callback allowlist and retry policy, upload limit, session lifetime,
preview size, ML denoise, depth method, stacking defaults, log levels...