Changelog
All notable changes to GetDecant are documented here. This file is the source of truth for the public getdecant.com/changelog page.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Workflow note: every PR with the
changeloglabel MUST update the[Unreleased]section below before merging. CI enforces this. When a release is cut (gh release create vX.Y.Z), the[Unreleased]block becomes the new version block.
Unreleased
Changed
- Workflow now requires every PR to follow the GetDecant workflow: PRD-issue first, branch named
<type>/<issue#>-<slug>, conventional commits, mandatory Copilot review loop until no unresolved threads, then squash-merge. Documented inCLAUDE.md. (#19, #20)
Fixed
- SaaS admin impersonation now starts through a server action that sets the tenant cookie as
HttpOnly, records an audited impersonation event, and redirects into the tenant dashboard without anydocument.cookiewrite in the admin client. (#24) - Receipt headers now include the branch address and phone with tenant-level fallback, and the POS ticket preview mirrors the same contact lines when branch data is missing. (#96)
- Movement audit logs now show actor display names, keep the raw UUID in a tooltip when available, and let operators filter/export by actor without reading raw IDs. (#97)
Added
- Public
/roadmappage (SSR from GitHub Project, filtered byPublic=true) with milestone grouping, status sub-buckets, and area / priority / search filters. Cached every 10 minutes; renders an empty/error fallback when the GitHub API or token are unavailable. (#30) - 35+ GitHub labels for triage: type/* (8), priority/p0-p3, area/* (15), status/* (6), effort/xs-xl (5), changelog, incident, breaking-change, good-first-issue. (#19, #20)
- 4 milestones aligned to roadmap buckets: M1 GA Blockers (P0), M2 UX Hardening (P1), M3 Reports + Audit + Compliance (P2), M4 Tech Debt + Polish (P3). (#19, #20)
- Issue templates: PRD (full spec format), bug (with severity matrix), incident (production outage workflow). (#19, #20)
- PR template with Copilot loop reminder + changelog gate. (#19, #20)
- SaaS admin tenant creation now provisions a default
Principalbranch (MAIN) in the same transaction, and backfills any existing tenants that were still missing a usable default branch. (#22)
0.2.0 — 2026-04-16
Security
- Critical: UPDATE RLS policy added to
branch_transfer_items. Previously theaddTransferUnitItemActionserver action's "accumulate quantity" branch silently failed because no UPDATE policy existed; adding the same variant twice to a draft transfer kept the original quantity instead of summing. (#18) - Critical:
/api/identifynow requires authentication before invoking the Gemini Vision AI Gateway. Previously unauthenticated requests could trigger billable AI calls. (#18) - High (IDOR):
/api/sync-errors/resolvenow scopes the update to the user'sactive_tenant_id. Previously any authenticated user could resolve sync errors belonging to other tenants by guessing IDs. (#18) - High:
receive_branch_transferRPC now requires explicit branch-level authorization viahas_branch_access(to_branch_id). Previously any tenantstaffcould receive transfers into branches they were not assigned to. (#18) - High:
receive_branch_transferRPC validates the bottle is currently located infrom_branch_idbefore reassigning. Previously a bottle moved manually or already transferred could be silently relocated to the destination. (#18) - High:
/api/prices/competitivereturns 403 when looking up products by ID without an active tenant. Previously the admin client (which bypasses RLS) leaked product brand/name across tenants whenactive_tenant_idwas null. (#18) - High:
has_branch_access()no longer permissively grants access to all branches when a user has zerobranch_memberships. Now requires explicit branch membership OR owner/admin role OR saas_admin. Aligns DB-layer authorization with application-layercanAccessAllBranches. (#18)
Fixed
- Critical bug:
receive_branch_transfercolumn typo (remaining_ml→remaining_volume_ml). Bottle transfer movements were recordingremaining_volume_ml: 0in metadata regardless of actual fill level. (#18) - Critical bug:
getPOSProducts()was aggregating stock across all branches of the tenant. POS at one branch showed inflated stock counts that included other branches' inventory. Now scoped to active branch via PostgREST nested filter + defense-in-depth re-filter in code. (#18) getRecentOrders()throwsMissingBranchErrorwhen no active branch is set, instead of silently returning cross-branch data. POS is always branch-scoped. (#18)- POS home CTA test (
Iniciar sesión→Entrar al sistema) updated to match the renamed link from the trial-signup release. (#18)
Added
- New RPC
ship_branch_transfer(p_tenant_id, p_transfer_id, p_shipped_by)reserves source branch stock atomically when a transfer is shipped. Closes the double-spend race where a sale could drain source stock between ship and receive. (#18) - New RPC
cancel_branch_transfer(p_tenant_id, p_transfer_id, p_cancelled_by)restores reserved source stock when anin_transittransfer is cancelled. (#18) branch_transfers.shipped_byaudit column to track who initiated the ship. (#18)- PowerSync now syncs the multi-branch tables (
branches,branch_memberships,branch_transfers,branch_transfer_items). The newbranch_databucket parameterizes by user-accessible branches so staff offline only receives operational data for branches they can actually access. (#18)
Changed
cancelTransferActionandshipTransferActionserver actions now call the new RPCs (cancel_branch_transfer,ship_branch_transfer) instead of doing the status flip directly. Stock reservation/restoration is atomic with the status change. (#18)- Branch upserts in
supabase/seed.sqldocumented inline — theid = excluded.idis required because the multi-branch migration auto-creates a random-UUID branch for the demo tenant; without updating the PK on conflict, downstream seed inserts fail with FK violations onnpx supabase db reset. (#18)
Removed
apps/web/app/dashboard/inventory/transferencias/client.tsx— main's old client component was incompatible with the action exports we kept; our flow uses page.tsx with form actions directly. (#18)supabase/.temp/cli-latestremoved from version control (path is gitignored; was an old tracked artifact producing noisy diffs on Supabase CLI updates). (#18).playwright-cli/— 22 generated Playwright DOM snapshots and console logs untracked. Path is gitignored. (#18)
DB Migrations
20260416120000_fix_branch_transfer_items_update_rls.sql— UPDATE policy for transfer items.20260416120100_fix_receive_transfer_column_and_auth.sql— fixes column typo + branch-level auth + bottle source-branch validation.20260416120200_ship_time_stock_reservation.sql— addsship_branch_transfer,cancel_branch_transfer, redefinesreceive_branch_transfer, addsshipped_bycolumn.20260416130000_tighten_has_branch_access.sql— removes permissive default from branch access helper.