.sun-doc-grid (client/phone/date/address) fell back to whatever the
last matching max-width media query set, and print rendering commonly
evaluates those against the page's content width - narrow enough to
trip the existing max-width:700px breakpoint and stack every field
onto its own line instead of the intended 2-column grid. Combined with
generous screen-sized padding/font-sizes carried into print, a normal
order routinely spilled onto a second page.
Adds an explicit @media print block that puts client/phone/date/address
in a single row regardless of viewport width (grid-auto-flow:column),
sets an explicit @page size/margin instead of relying on the browser
default, and shrinks fonts/padding throughout (header, field grid,
table rows, summary, footer) for both the order blank (.sun-doc) and
the receipt (.sun-receipt, which reuses the same grid). Verified with a
standalone reproduction of the markup/CSS - a 2-line order now renders
as one compact page instead of stacking every field before ever
reaching the table.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
performance.js paints a full-screen boot placeholder immediately on
page load (before app-runtime.js and the real auth gate exist), so it
never got updated when login-signature-v1776.js was redesigned from a
dark two-column layout with an offer-gallery/002.jpg table photo to
the light single-column "cream login" with the Caterium SVG mark.
Result: every signed-out visitor saw the old dark/photo screen flash
for a moment, then get replaced by the new light screen once the real
gate rendered - the flicker was two genuinely different, undeployed-
in-sync designs, not a caching artifact. Rebuilt the boot placeholder's
markup and inline critical CSS to mirror login-signature-v1776.js's
current design (same background, mark, type, and copy) so the first
paint already matches what replaces it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The just-merged production-only commits were never run through QA
(they were pushed directly to the production branch), so several
version markers and hardcoded test strings had drifted out of sync
with each other:
- package.json was bumped to 17.8.0 but package-lock.json,
release-manifest.json and app-runtime.js's own VERSION constant were
never updated to match - reverted to 17.7.3 since no other release
artifact actually changed.
- service-worker.js's cache name legitimately moved to
v81-20260912-account-center-loader (real new modules need the cache
bust), but release-manifest.json's pwaCache field and two
release-check.mjs assertions still expected the old v78 name.
- edge-security-v1774.mjs and static-security.mjs asserted the old
employee role list (with "admin") and old PWA cache name that
production's own commits had already changed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
production had diverged from main with 20 unreviewed direct-push
commits never merged back (account center feature, owner-only employee
roles, and a login-screen redesign - the exact "cream login" work that
replaced the old dark table-photo screen). Neither QA nor the
audit fixes on main had ever seen this code.
Conflict resolution:
- service-worker.js: kept production's newer cache-refresh mechanism
(CRITICAL_FRESH, forceFresh, withAccountCenter, v81 cache name) and
combined both sides' CORE asset lists (account-center-v1780.js +
login-signature-v1776.js from production, auth-security-v1774.js +
order-enhancements-v1775.js from main).
- deploy-timeweb.yml: kept main's version, which already independently
verifies service-worker.js's sha256 alongside the login/logo files -
strictly more thorough than production's version of the same check.
Also fixes fallout from production's commits never having been
QA-tested before landing: package.json was bumped to 17.8.0 with
nothing else in the codebase updated to match (reverted to 17.7.3,
matching package-lock.json/release-manifest.json/app-runtime.js, since
no other release artifact actually changed), and three tests
(static-security.mjs, edge-security-v1774.mjs, release-check.mjs) had
hardcoded strings (old PWA cache name, old employee role list) that no
longer matched the code they were checking.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sun_employee_prepare_v28 and sun_employee_finalize_v28 - the RPCs
caterium-create-employee's whole authorization model rests on - were
applied directly to the production database and were never committed,
so the actual authorization logic wasn't auditable from the repo.
Recorded verbatim via pg_get_functiondef() against the live database
on 2026-09-12 (read-only; nothing was re-applied). Confirmed both
match what the security audit inferred from the Edge Function's
error-message handling: caller identity + workspace-owner/platform-admin
check + plan/feature gates + member limits, all enforced here rather
than in the Edge Function itself.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This Edge Function grants platform-admin power (list every user across
every workspace, ban/unban accounts, trigger password resets for any
user_id) but answered with Access-Control-Allow-Origin: '*', unlike the
sibling caterium-create-employee function which already uses an origin
allowlist. Authorization itself was never bypassable this way (the
function still requires the caller's own Bearer token and re-checks
sun_is_platform_admin() server-side), but a wildcard CORS response
removes a real layer of defense-in-depth if a platform-admin token were
ever exposed to another origin.
Applies the same allowedOrigin()/corsHeaders() pattern already proven in
caterium-create-employee, and extends edge-security-v1774.mjs (which
already asserted the wildcard was gone from create-employee, but never
checked this function) to cover both.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
setupOldButton() polled the DOM every 4s forever after the menu editor
first opened, with no way to ever stop - the interval id was not even
kept in a variable. It now returns whether the button was found, the
interval only starts when the first attempt fails, and clears itself
on the first successful attempt (also wired into the existing
disconnect() cleanup alongside the other timers).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pushAllClients() already has every client profile from its own
listClients() call, but looped through pushClient(key) -> getClient(key)
-> listClients() again for each one - N clients meant N+1 full
order-history recomputations instead of one. pushClient now accepts an
optional already-known profile so the bulk path skips the redundant
lookup; single-key callers (scheduleServerPush's debounce) are
unaffected.
compareClientSources() had the same shape of duplicate work: it called
buildClients()/serverListClients() directly and then again inside
mergeClientSources(). mergeClientSources() now accepts already-computed
local/server arrays instead of always recomputing both.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
release-manifest.json still pointed "dataLayer" at the removed
data-layer-v1771.js instead of the actually-loaded v1773.
service-worker.js's offline cache list never included
auth-security-v1774.js, order-enhancements-v1775.js or
login-signature-v1776.js despite performance.js loading all three at
runtime - PWA/offline mode could serve a stale or missing module.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
promote-production.yml triggered on push to main independently of
qa.yml, with no branch protection configured on the repo - a failing
QA run (npm audit, static security tests, e2e) never blocked
production. Switch it to the same workflow_run pattern deploy-timeweb.yml
already uses: only promote the exact commit QA just passed.
Also removes public/core/data-layer-v1770/1771/1772.js: only v1773 is
ever loaded (index.html, performance.js's loadDataLayer, service-worker
cache all reference v1773 only) - the older three were dead weight
shipped to every visitor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Full production-ready docker-compose stack (db, kong, auth, rest,
realtime, storage, imgproxy, meta, functions, studio) targeting
api.caterium.ru, plus bootstrap script for a fresh Cloud Server,
Caddy reverse-proxy config (HTTPS, WebSocket, upload limits), and
dump/restore/verify/storage-sync scripts for moving off the managed
Supabase project (cksuehzcimitsxmeloes). Does not touch public/ or
any live runtime behavior — frontend cutover is documented separately
in frontend-cutover.md and only applied after Etap 8 verification.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>