# Changelog All notable changes to the WeGrocery app are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project loosely follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html): - **Major**: breaking changes that require user re-onboarding - **Minor**: new features, no breaking changes - **Patch**: bug fixes, UI polish, documentation Writing entries: one italic tagline under the version heading, then one bullet per coherent change: a topical emoji, a **bold headline**, and at most two lines saying what the user now sees. Implementation detail belongs in the PR. A bullet that only matters to whoever hosts, runs or develops the app (variables, database, CI, dependencies, monitoring) starts with `[tech]` (`[tecnico]` in Italian, on the same bullet): the in-app page hides it behind "Show technical details", the GitHub release keeps it. > ๐Ÿ‡ฎ๐Ÿ‡น La versione italiana di questo file รจ [CHANGELOG.it.md](./CHANGELOG.it.md). > Le due versioni devono restare sincronizzate. --- ## [Unreleased] ## [1.45.2] - 2026-11-11 *Product icons stay put.* ### Fixed - ๐Ÿง€ **Product icons survive a new listing**: an import keeps the icon the group already uses for a product with that name, in the catalogue and in the cycle, instead of putting back the cart or the guess from the name. The preview shows that icon. ### Changed - ๐ŸŽจ **One icon per product, everywhere**: an icon picked in the import preview, in the catalogue or in a cycle's product (now with its own icon field) goes to every product with the same name, and picking it on one preview row picks it for the rows with the same name. - ๐Ÿ”Ž **More cheeses recognised**: gorgonzola, stracchino, taleggio, fontina, asiago, provola, scamorza, caciotta, robiola, grana and others get ๐Ÿง€ by themselves. ## [1.45.1] - 2026-11-09 *Preparing the repository move to FlyLabs.* ### Changed - [tech] ๐Ÿ”— **Repository transfer preparation**: release and UI checks accept the future FlyLabs owner while retaining the current repository; Console defaults and setup links point to `flylabs-ai/wegrocery`. The transfer is still pending. ## [1.45.0] - 2026-11-09 *Ready to open the group to new people: terms to accept, sign-up, a public page, member import and limited quantities, all off until an admin turns them on.* ### Added - ๐Ÿ“œ **Terms and privacy to accept**: in Settings > Group an admin can ask whoever signs in to accept the group's privacy notice and terms of service (links to the group's own pages) before using the app, and ask everyone again when the texts change. Until then members cannot order or pay. Off by default. - ๐Ÿ”— **Link to the terms of service** next to the privacy notice, on the sign-in page and at the foot of every page. - [tech] ๐Ÿ—„๏ธ **Migration 0051** (`terms_acceptance`): `app_settings.terms_required`, `app_settings.terms_version`, `members.terms_accepted_at`, `members.terms_accepted_version`. Additive, apply before deploying. New optional brand field `termsUrl`. - ๐Ÿšช **New members can join on their own**: in Settings > Members & guide, "Who can join" offers "On request" (a form on /aderisci, an admin approves it in Members and the newcomer gets the sign-in link) or "Open" (a confirmed email joins at once). Members only by default. - ๐Ÿ’ณ **Newcomers pay before ordering**: by default whoever joins this way never goes below zero, paying each order by card or from a balance already topped up. The admin can give them the group's credit instead. - [tech] ๐Ÿ—„๏ธ **Migration 0052** (`signup`): `app_settings.signup_mode`, `signup_role`, `signup_prepaid`, `members.joined_via`, table `membership_requests`. Additive, apply before deploying. - ๐ŸชŸ **Public page of the group**: in Settings > Group an admin can turn on /gruppo, a shop window for people who are not in yet: the group's text, the next order with its dates and, if wanted, its products, with buttons to sign in or ask to join. Whoever opens the app without signing in lands there. Off by default, hidden from search engines unless the admin chooses. - [tech] ๐Ÿ—„๏ธ **Migration 0053** (`public_page`): `app_settings.public_page_enabled`, `public_products_preview`, `public_page_indexable`, `public_intro`. Additive, apply before deploying. `/` without a session now redirects to `/gruppo`, which sends on to `/login` when the page is off. - ๐Ÿ“ฅ **Import members from a file**: in Members, "Import from file" reads a CSV from Excel or Google Sheets, shows what happens to each row (new, already a member, repeated, invalid email) before importing, then invites the new members 20 at a time. Existing members are never changed. - ๐Ÿงบ **Limited quantities**: in Settings > Group an admin can turn on limited quantities, then set on each product of a cycle how many units there are and how many one member may take. Members only see "Sold out"; if a product runs out while they order, the confirm shows what is left with "Fit to what is available". Off by default. They can also come from a listing imported into the cycle ("Disponibili" and "Massimo per socio" columns), and the public page marks finished products "Sold out". - [tech] ๐Ÿ—„๏ธ **Migration 0054** (`stock_limits`): `products.max_quantity`, `products.max_per_member`, `app_settings.stock_limits_enabled`, partial index `payments_order_pending_cycle_idx`. Additive, apply before deploying. New nightly invariant `product_max_quantity`. ### Security - [tech] ๐Ÿ”’ **Better Auth updated to 1.7.18**, which patches a critical advisory (the state of a Google sign-in accepted as a sign-in link, GHSA-965c-763c-88jm) and two lesser ones. The critical one was not exploitable here: sign-in links are stored hashed, so a Google state never matches one. The others concern the OAuth Proxy, not used here, and a rate-limit race on PostgreSQL. A link emailed before the update stops working; the code in the same email still does. ## [1.44.0] - 2026-11-05 *The order calendar, planned cycles, a clearer Home and emails in the group's look.* ### Added - ๐Ÿ“ฆ **Pickup to be confirmed.** The pickup date is often known for sure only after the close, once the supplier is heard: in the cycle an admin can tick **Pickup to be confirmed**, and members read "Pickup expected ..., to be confirmed" on Home, in the calendar (the pickup drawn dashed), in History and in the phone's calendar. When the admin unticks it, those who ordered get **Pickup confirmed**; if the date changes too, the usual pickup changed notice. While a closed cycle's pickup is still to be confirmed, **To do now** reminds you with **Confirm the pickup**. - ๐Ÿ“… **Order calendar.** A new page, reached from Home (and from Order when nothing is open), shows when you can order and when to pick up, for the open, planned and recent cycles. Choose a cycle with the buttons above the calendar (the most urgent one is chosen for you): its days to order are a coloured band, the last day a filled square, the pickup a package; **All** shows on each day the icons of what happens (opening, last day, pickup); the cycle buttons scroll sideways on a phone, so the calendar stays at the top. Tapping a day picks its cycle, and a card below says when it opens, until when to order and when to collect. - ๐Ÿ—“๏ธ **Planned cycles.** When creating a cycle, choose **Later** under "When the orders open": the cycle goes in the members' calendar with its dates (marked "Tentative dates" if they may still move) and its products as a preview, added by hand or from the supplier's Excel listing as usual. Nobody can order until an admin or orders referent taps **Open the orders**; "To do now" reminds them on the planned day, and a planned cycle can be deleted. The calendar on Home shows when it opens. - ๐Ÿ”” **"Tell me when it opens" and "Add to calendar".** On a planned cycle in the calendar you can ask for an email when its orders open (nobody gets it twice if they already receive the "new cycle" emails). Every cycle in the calendar can be added to your phone's calendar: the deadline with a reminder three hours before, and the pickup. - ๐Ÿ—„๏ธ [tech] **Migration `0048_planned_cycles.sql`.** New column `order_cycles.dates_tentative`, false for every cycle, and the fee freeze of 0026 now lets a planned cycle change its fee too; apply it before deploying. - ๐Ÿ—„๏ธ [tech] **Migration `0049_cycle_open_alerts.sql`.** New table `cycle_open_alerts` for the "tell me when it opens" requests; apply it before deploying. - ๐Ÿ—„๏ธ [tech] **Migration `0050_pickup_tentative.sql`.** New column `order_cycles.pickup_tentative`, false for every cycle (every pickup stays confirmed as before); apply it before deploying. ### Changed - โœ‰๏ธ **Emails in the group's look.** The app's emails (sign-in, notifications, family invites, "Notify me when it opens") show the group's logo and name on top, in its colours; the link to the app is a button that says where it leads ("Go to the order", "Open History", "Sign in"), the sign-in code a large box, and a notification has its title. - ๐Ÿ“… **The same calendar legend for one cycle and for All.** With a cycle chosen the legend also shows **Opens**, as in All. - ๐Ÿ  **A clearer Home: one list of cycles.** Each cycle shows once, in the group of what you have to do: **To order** (deadline with the weekday in full, "tomorrow" or "Last day", your order folded into one line, a small "Order", "Edit" or "Pay" button), **To collect** (closed cycles with your order and the pickup ahead) and **Coming up** (planned cycles). A date tile on each cycle stands in for the calendar; the full calendar is one tap away, and on a computer this month sits on the right. The balance is one small line at the bottom, and goes on top only when it is negative. ## [1.43.0] - 2026-11-01 *Who collected their order, and a new "Orders referent" to help run the cycles.* ### Added - ๐Ÿ“ฆ **Pickup register.** A closed cycle has a new **Pickups** tab: tick a member when they collect (the time is now) or tap the name to set another time, who collected and a note for the admins. A counter next to the cycle title shows how many collected, such as "8/10 collected". - ๐Ÿ”” **Reminders for missing pickups.** From the pickup day, "To do now" lists the cycles with members still to collect, and "Settle accounts" warns when someone has not collected yet. Members see "Collected on โ€ฆ" in History; the new "Order collected" notification is off unless they turn it on. - ๐Ÿ‘ฅ **"Orders referent".** A new kind of access for members who help run the orders without being admins: they open, edit and close the cycles they can see, send the order to the supplier, upload the sheet, mark pickups and run the catalogue; members read only, no treasury, accounts or settings. The member form now has two settings: "Access to the app" and "Cycles they see". - ๐Ÿ—„๏ธ [tech] **Migration `0046_cycle_pickups.sql`.** New table `cycle_pickups`; apply it before deploying. - ๐Ÿ—„๏ธ [tech] **Migration `0047_orders_referent.sql`.** New column `members.orders_referent`, false for everyone; apply it before deploying. ## [1.42.0] - 2026-10-29 *A shortcut to set the pickup of a cycle, even after it is closed.* ### Added - ๐Ÿ—“๏ธ **"Add the pickup" from the cycle overview.** A cycle with no pickup yet, open or closed, now says "Pickup: not set yet" in its Overview, with a button that opens the edit straight on the pickup. A new card in the admin guide explains that the pickup can be set or changed even after the close, and that members who ordered are told. ## [1.41.0] - 2026-10-28 *A notice when the pickup of a cycle you ordered in is set or changes.* ### Added - ๐Ÿ“… **Notice when the pickup changes.** When the admin sets, moves or clears the pickup date or time of a cycle, the members who ordered in it are told. In Notification preferences the new "Pickup date" group lets each member choose the app, email or both. ## [1.40.0] - 2026-10-28 *A weighing deposit for card cycles, and weighing gaps that move to the next payment instead of being written off.* ### Added - โš–๏ธ **Weighing deposit.** On card cycles the admin can add a percentage (for example 3%) on the products, paid with the order as its own line. When the accounts are settled after the weighing, the unused part goes back to the member's card by itself. It is set per cycle, with a default in Settings, Payments, New cycles. - [tech] ๐Ÿ—„๏ธ **Migration `0045_weighing_deposit.sql`.** Adds `order_cycles.weighing_deposit_pct` (empty = no deposit, card cycles only, at most 25%). Apply before deploying, rollback in `0045_weighing_deposit_down.sql`. ### Changed - โš–๏ธ **Weighing gaps move to the next payment.** With "Wallet balance in card payments" on, when the final weighing costs more than what was paid the gap stays on the balance and is added to the next card payment, under 0.50 too (it used to be written off). The member gets a notice saying so. ## [1.39.0] - 2026-10-27 *Tidier settings, a "None" preparation fee for card cycles too, and wallet top-ups that can be switched off.* ### Added - ๐Ÿ”’ **Wallet top-ups can be switched off.** A group that has every order paid by card can switch top-ups off in Settings, Payments, Wallet: members no longer see Top up, the IBAN or the reference (on Home, Profile, History and in the guide) and an online top-up is refused. Balances and movements stay, and Treasury can still record a payment by hand. Top-ups stay on by default. - [tech] ๐Ÿ—„๏ธ **Migration `0044_wallet_topups.sql`.** Adds `app_settings.wallet_topups_enabled` (on by default) and widens `app_settings_wallet_channel_check`: with top-ups off a wallet group may have no channel. Apply it before deploying, rollback in `0044_wallet_topups_down.sql`. ### Changed - ๐Ÿ—‚๏ธ **Settings split by topic.** A bar at the top leads to Payments, Group (name, logo, colours and contacts), Members & guide, Technical. Each panel stays folded and shows on one line how it is set; a tap opens it, and it opens by itself when something needs fixing. - ๐Ÿ’ณ **Card payments in one panel.** The Stripe connection, online top-up and wallet balance in card payments sit together under "Card (Stripe)", and Stripe's status is no longer repeated in several places. - ๐Ÿงพ **Proposed costs, more compact.** Shipping and preparation are picked from a menu with the amount next to it, the same for wallet cycles and card cycles. - ๐Ÿงพ **"None" preparation fee for card cycles too.** In Settings and in New cycle, card cycles now offer "None", like wallet cycles. ## [1.38.0] - 2026-10-26 *New cycles can start by card, with the right costs already proposed, and the wallet balance can go into the card payment.* ### Added - ๐Ÿ’ณ **The wallet balance goes into the card payment.** With the setting on, a member paying a card cycle by card also pays their negative balance; with a credit, the credit is taken off (and if it is enough, nothing is paid by card). Before paying the member sees the separate lines, and History and Treasury keep the order and the balance as separate movements. Switch it on in Settings, "Wallet balance in card payments". - [tech] ๐Ÿ—„๏ธ **Migration `0042_card_settles_wallet.sql`.** Adds `app_settings.card_settles_wallet` (off by default), `payments.balance_cents` and the `wallet_transfer` movement type (a pair linked by `counterpart`); three new nightly checks: `order_payment_split`, `order_refund_cap`, `wallet_transfer_pairs`. Apply it before deploying, rollback in `0042_card_settles_wallet_down.sql`. - ๐Ÿงพ **New cycles can start by card.** In Settings, "New cycles", choose wallet only, wallet with card on request, or card with wallet on request. It can change with cycles open: those already created stay as they are. - ๐Ÿšš **Proposed costs for each mode.** Also in "New cycles", set shipping and preparation fee for wallet cycles and for card cycles (for example 0 โ‚ฌ and 2%): "New cycle" fills them in. - ๐Ÿ—‚๏ธ **Tidier payment settings.** The options are split into New cycles, Card (Stripe), Bank transfer, Wallet and Advanced, each with its own Save. - [tech] ๐Ÿ—„๏ธ **Migration `0043_new_cycle_defaults.sql`.** Adds `app_settings.new_cycle_payment_mode` and `app_settings.new_cycle_defaults` (jsonb), both empty by default (behaviour as before). Apply it before deploying, rollback in `0043_new_cycle_defaults_down.sql`. ### Changed - ๐Ÿ—‚๏ธ **In Treasury, an order's movements stay together.** In a member's movements, the charge, shipping, corrections and refunds of the same cycle fold into one row with their net total; tap it to see them one by one. ## [1.37.0] - 2026-10-24 *Real names for every member, and a reliable price per kg when importing a price list.* ### Added - ๐Ÿ™‹ **The app asks members without a real name for one.** Members whose name is the first part of their email (for example those who joined with the email link) are asked "What's your name?" after signing in. In Settings admins choose whether to ask, whether it can be put off or is required; in Members the "names to complete" filter shows who is missing. - [tech] ๐Ÿ—„๏ธ **Migration `0041_member_name_prompt.sql`.** Adds `app_settings.member_name_prompt` (`off`, `optional`, `required`; `optional` by default); apply before deploying, rollback in `0041_member_name_prompt_down.sql`. - ๐Ÿ”Ž **Search in the Catalog.** In Admin, Catalog a search box finds products by name, variety, format, notes, category or supplier, together with the filters. ### Changed - ๐Ÿ–Š๏ธ **Products of a cycle can be edited again.** In Admin, Cycle, Products a pencil next to the bin opens the product's form under it (name, format, price, โ‚ฌ/kg, category, notes), and the list shows the โ‚ฌ/kg. Orders already placed keep their price. - โœ๏ธ **A catalog product is edited where it is.** Edit opens the form right under the product instead of at the top of the page, so products far down the list stay in sight. ### Fixed - โš–๏ธ **Price per kg right when importing a price list.** One column can no longer go to both Price and Price/kg; the preview flags a โ‚ฌ/kg equal to the pack price and offers the one worked out from the weight in the name or format ("6 kg box", "12 x 240 g"), and fills it in when the file has no such column. Importing a file again also updates a changed โ‚ฌ/kg. ## [1.36.0] - 2026-10-24 *Admins can choose the order of a cycle's products, and the Cycle page is calmer.* ### Added - โ†•๏ธ **Products in the order you prefer.** In Admin, Cycle, Products you choose between **Alphabetical** (as before) and **Custom**: products and categories move with the arrows or by dragging, and members see them in that order. **Use the last cycle's order** takes it from the previous cycle. - ๐Ÿ—‘๏ธ **Removing a product from the cycle is quieter.** A bin replaces the red button, red only on hover. - [tech] **Migration `0040_cycle_product_order.sql`.** Adds `order_cycles.product_order` (`alpha` by default) and `product_order_saved_at`; apply it before deploying. New dependency `@dnd-kit` for dragging. ### Changed - ๐ŸŽจ **A calmer Admin โ†’ Ciclo page.** "+ New cycle" now sits in plain sight at the top on phones and tablets, next to the list of cycles. "To do now" uses white cards with a small "Late" badge instead of red and yellow blocks, so the cycle's main action (Close cycle) is the only coloured button. ### Fixed - ๐Ÿท๏ธ **"Other" at the bottom.** In alphabetical order the products with no category come after every other category. ## [1.35.0] - 2026-10-22 *WeGrocery now speaks Spanish and French too, and History says when an order is still to pick up.* ### Added - ๐ŸŒ **The app in Spanish and French.** A group can now run WeGrocery in Spanish or French: screens, member and admin guides, emails and the supplier's order sheet. The "What's new" page stays in English for these groups. - [tech] **`brand.locale` accepts `"es"` and `"fr"`.** New language packs `lib/i18n/es.ts` and `fr.ts` and guides in `lib/guide`; dates and amounts use es-ES and fr-FR, decimal inputs a comma. ### Fixed - ๐Ÿงบ **"To pick up" instead of "Picked up".** In History a closed order no longer reads as already picked up: it stays "To pick up" until the pickup window ends, then turns "Done". - ๐Ÿ”ข **"1 movement", not "1 movements".** In Treasury, a member with a single movement no longer reads as plural. ## [1.34.1] - 2026-10-22 *The "by flylabs.ai" text under the sign-in card is easier to read.* ### Fixed - ๐Ÿ”ค **"by flylabs.ai" readable on the sign-in page.** Under the sign-in card it was too light on the page background; it now uses the same grey as the privacy link. ## [1.34.0] - 2026-10-20 *Admins can add a member's order before closing the cycle, and the "by flylabs.ai" signature steps back.* ### Added - ๐Ÿ›’ **Admins add a member's order before closing the cycle.** In a cycle's Orders, "+ Add order for a member" and "โœŽ Edit" now work while the cycle is open, after the deadline too: the order is charged at the close like the others, with no correction, and the member gets a notice. ### Changed - ๐Ÿงญ **The right order of the steps after the deadline.** "To do now" now says "Check the orders" and opens Orders; the Overview lists the steps before closing (orders, supplier, close) and the admin guide follows the same order. Closing is the last step, the one that charges members. - โœ๏ธ **A quieter "by flylabs.ai".** It no longer sits at the foot of every page: it is now small text next to the version in the Profile and under the sign-in card. Emails do not change. ## [1.33.0] - 2026-10-19 *Admins get their own guide and welcome, and the app is signed "by flylabs.ai" at its foot.* ### Added - ๐Ÿงญ **A guide for admins.** Admins now find an "Admin guide" in How it works and under Admin (โ‹ฏ on a phone, the side menu on a computer): 39 step-by-step cards on opening and closing a cycle, the supplier sheet, the treasury, the catalogue, members and settings, with search. Members do not see it: the pages answer "not found" and its words never reach their phone. - ๐Ÿ‘‹ **A welcome for admins.** The first time in Admin, a short step-by-step card walks through the work (what needs doing, opening and closing a cycle, the treasury, members, the guide) and ticks what the group has done already. "Skip" or "Got it" closes it; the admin guide shows it again. Every Admin section has a "How it works" link to the right guide card. New column `members.admin_welcome_dismissed_at` (migration 0039, additive only). - โœ๏ธ **"by flylabs.ai" at the foot of the app.** A small "by flylabs.ai", linked to flylabs.ai, now sits at the foot of the pages, under the sign-in card and under the logo in emails, never at the top: the app keeps the group's name and logo. Admins can switch it off in Impostazioni, Name, logo and colours. - [tech] ๐Ÿงฉ **FlyLabs Kit 0.12.** Module `firma` 1.0 (`components/by-flylabs.tsx`, tokens `--flylabs-ai` and `--flylabs-spark`, the logo's own colours, not the group's) and `email` 1.1 (lowercase "by flylabs.ai", link to `https://www.flylabs.ai/`, no UTM). The switch is `brand.flylabsSignature` (on by default) or a `group_identity` override; no migration. README titled "WeGrocery by flylabs.ai". ## [1.32.0] - 2026-10-17 *Groups can keep card-paid cycles switched off until they decide to use them.* ### Added - ๐Ÿ’ณ **Card cycles can be switched off.** In Settings, "Cycles paid by card" decides whether admins can choose Card when creating a cycle; when it is off, Card stays visible but greyed out, with a link to switch it on. Card cycles already created, online top-ups and refunds do not change. - [tech] ๐Ÿ—„๏ธ **Migration `0038_card_cycles_switch.sql`.** Adds `app_settings.card_cycles_enabled` (on by default, so nothing changes until a group switches it off); apply it before deploying, rollback in `0038_card_cycles_switch_down.sql`. ## [1.31.0] - 2026-10-17 *The FlyLabs look: clearer form fields, nicer emails, one set of icons and a What's new page written for members.* ### Added - โœ‰๏ธ **Emails with a proper look.** Every email from the app (sign-in, notifications, the supplier order) now arrives on a clean card in the app's colours, with links you can tap and the WeGrocery logo at the bottom; mail apps that show only text get the same words as before. ### Changed - โœจ **Cleaner icons, steadier dialogs.** The navigation, the guide topics and the close, edit and "more" buttons use one consistent icon set; after you answer a confirmation with the keyboard, focus goes back to the button you pressed instead of the top of the page. - ๐Ÿ”ค **Codes and amounts in the reading font.** The IBAN, the sign-in code and the email addresses in Soci and Cassa now use the same font as the text, and totals and balances line their figures up; the welcome card's title is no longer in the narrow label font. - ๐Ÿ“ฐ **What's new speaks to members.** The page shows the changes you notice in the app; the ones for whoever runs it (servers, database, updates) sit behind "Show technical details", marked "Technical". - [tech] ๐Ÿ“Š **Instance stats speak the FlyLabs Console's language.** `/api/instance-stats` also accepts the `x-flylabs-*` signature and then answers the FlyLabs Kit envelope (`app`, `counts`); the WeGrocery Console sends both and reads both shapes, so older installations keep working. `/api/health` gives up on a database that hangs after 3 seconds. - [tech] ๐ŸŽจ **Colour tokens with the FlyLabs names.** The CSS colour roles now use the shadcn names of the FlyLabs Playbook (`card`, `muted-foreground`, `primary-foreground`, `destructive`, `danger-bg`...), plus `input`, `ring`, `success` and `warning-bg`; the group's own colours and both themes look the same as before, and the contrast test covers the new names. - [tech] ๐Ÿงฉ **Dialogs on Base UI.** `Sheet` and `ConfirmDialog` move from Radix to Base UI Dialog (`@base-ui/react`) and the interface icons to `lucide-react`; swipe to close, Esc and focus return work as before, and the design guard refuses Radix and hand-drawn interface icons. - [tech] ๐Ÿงช **Integration tests carry the FlyLabs suffix.** They are now named `*.integration.test.ts` (FlyLabs Playbook 5.2); `npm test` still leaves them out and `npm run test:int` and CI still run them. - [tech] ๐Ÿ—„๏ธ **Migrations give up sooner on a busy table.** Each migration file waits at most 5 seconds for a lock (it was 10) and then rolls back whole; a file with a statement Postgres cannot run in a transaction (`CREATE INDEX CONCURRENTLY`, `VACUUM`) is refused before anything runs, and from 0036 on a test wants every migration's `_down.sql`. - โœ๏ธ **No more long dashes.** A missing value in tables and lists is now shown as a plain "-", and the version titles on the What's new page use the same short dash. - [tech] ๐Ÿ”˜ **Buttons on shadcn and Base UI.** `Button` is now shadcn's Button on Base UI with `class-variance-authority` (`buttonVariants` replaces `buttonClass`; `neutral` becomes `default`, `danger` becomes `destructive`); buttons look and behave as before. - [tech] ๐Ÿ—‚๏ธ **Card, Badge and Toaster in the shadcn shape.** `CardBody` becomes `CardContent`, `Badge` takes `variant` (`default`, `brand`, `accent`, `destructive`) instead of `tone`, and the Toaster moves to `components/ui/sonner.tsx`; cards, badges and notices look the same. - ๐Ÿ“ **Clearer form fields.** Field borders are now darker, so the boxes you type in are easier to see, and lists to choose from show the same arrow everywhere. - [tech] ๐Ÿงพ **Fields on shadcn.** `Input` (on Base UI Input), `Textarea`, `NativeSelect` and `Label` in `components/ui/` replace the forms' own `inputCls` and `labelCls`; field borders move from `border` to the 3:1 `input` token, and the design guard refuses raw text inputs, textareas and selects. ## [1.30.1] - 2026-10-17 *Maintenance: nothing new for members to learn.* ### Changed - [tech] ๐Ÿ” **The nightly accessibility check looks at the whole page.** The automatic check that verifies every night that the app is comfortable for everyone now scans the full page, with no more false alarms on rows hidden behind the phone's bottom bar. ## [1.30.0] - 2026-10-15 *The menu moves to the side on tablets and computers, and the order goes to the supplier before the close.* ### Added - ๐Ÿ“ง **The order goes to the supplier before the cycle is closed.** Once the order deadline has passed, the Supplier tab already shows: download the sheet and send it, then close the cycle uploading the completed one when it comes back. ### Changed - ๐Ÿงญ **Menu on the side on tablets and computers.** On a tablet the menu is a column on the left, on a computer a side menu with the admin sections under Admin; the app uses the whole screen. Nothing changes on phones. ## [1.29.0] - 2026-10-15 *The supplier sheet can be uploaded while closing the cycle.* ### Added - โš–๏ธ **The supplier sheet can be uploaded while closing the cycle.** The "Close the cycle" sheet has "Upload the supplier sheet": see the weights and shipping first, then one button closes and charges the real costs. Each member gets a single notice with the final cost. ### Fixed - ๐Ÿšš **A sheet downloaded before the close no longer zeroes the shipping.** It now starts from each member's shipping share, and reductions in the preview show their minus sign. ### Changed - [tech] ๐Ÿ” **New groups start with a restricted database role.** A group installed from the WeGrocery Console now connects with a role that can read and write data but never change the database's structure, as Porta Moneta already does. ## [1.28.0] - 2026-10-14 *The app gets a dark theme, and the database and build checks get safer.* ### Added - ๐Ÿ“Š **Usage at a glance.** Admin โ†’ Statistiche shows how many sign-ins, orders, top-ups and cycles the last 30 days saw: anonymous counts, no member and no text, and nothing from the demo. - ๐Ÿ‘‹ **The welcome tour remembers you.** It resumes at the step you left, on any device, and marks what you have already done (a top-up, an order, your notification choices, your family). - ๐Ÿ“ง **Unsubscribe in one click.** Notification emails now show your mail app's own "Unsubscribe" button, which turns off the emails of that kind (the alerts stay in the app), and a double click never sends the same email twice. - [tech] ๐Ÿ” **Restricted database role (optional).** The app can connect with a role that reads and writes data but cannot change the schema; `scripts/create-app-role.mjs` creates it and Configuration status shows it. - ๐ŸŒ™ **Dark theme.** Profile โ†’ App now has "Appearance": follow the phone, always light or always dark. The group's colours carry over and stay readable. ### Changed - ๐Ÿ”ค **New typefaces.** Text is set in Inter, titles in Geist, and the small uppercase labels in JetBrains Mono; amounts line up in columns. - [tech] ๐Ÿ—„๏ธ **Safer database updates.** Each migration file runs as a single step and stops if the database is busy, so a failed update leaves nothing half applied. Applying one to production now needs an explicit flag. ### Fixed - [tech] ๐Ÿž **Error reports reach Sentry.** Errors the app catches and reports itself (payments, sign-in emails, the instance stats) were only written to the server log; they now reach Sentry too, tagged with where they happened, and without the server log lines that could quote query values. ## [1.27.0] - 2026-10-12 *Each new group sets itself up from the app: name, logo, colours and Stripe, with every technical setting explained.* ### Added - ๐ŸŽจ **Name, logo and colours set from the app.** Admins change the group's name, logo, colours, contact addresses and links in Settings, with a live preview and a readability check: no redeploy, and the phone icon follows. - ๐Ÿงญ **First-run setup for a new group.** The first admin is guided step by step through identity, contacts, payments, "Our group" and a check of email and Stripe (a test email, the webhook's events). Existing groups do not get the prompt, and any admin can go through it again from Admin โ†’ Settings. - [tech] ๐Ÿ“Š **Anonymous stats for whoever runs several groups.** With `INSTANCE_STATS_SECRET` set, a signed request returns only counts (members, cycles, orders, version, configuration); without it the address does not exist. - ๐Ÿ› ๏ธ **Technical settings explained.** In Admin โ†’ Settings the setup status becomes "Technical settings", split into essential and optional, and each item says what it does and how whoever hosts the app turns it on. - ๐Ÿ’ณ **Connect Stripe from the app.** In Admin โ†’ Settings an admin pastes a restricted key of the group's Stripe account: the app checks its permissions and sets up the webhook by itself, and card payments go to the group's account. Where whoever hosts the app already set the keys, nothing changes. - [tech] ๐Ÿšจ **Error reporting with Vercel's Sentry integration.** Installing Sentry from the Vercel marketplace is enough: the app now picks up the address that integration sets, with no variable to copy by hand. ### Fixed - ๐Ÿงพ **Supplier sheet upload says why there is nothing to apply.** Instead of two empty lists, the preview tells how many products and members it recognized and that every amount already matches, or that nothing in the file could be matched. A CSV saved by Excel on Windows now keeps accented names. ## [1.26.0] - 2026-10-09 *A cleaner app on every screen, card payment for a single cycle, and the bank transfer reference filled in for you.* ### Added - ๐Ÿ’ณ **Card payment for a single cycle.** A group that runs on the wallet can now pick, when creating a cycle, whether members pay it from their balance or by card when they confirm the order. Card cycles are marked in Admin, and the money paid by card does not change anyone's balance until "Settle accounts". - ๐Ÿฆ **The bank transfer reference, filled in for each order.** Top up and each order in History show the reference to write on the transfer, with a Copy button, and where to send the receipt. Admins set the wording and the receipt address in Settings. ### Changed - ๐Ÿ”’ **One clear way to close a cycle.** "Close cycleโ€ฆ" opens a sheet that says how many members get charged and asks for confirmation there, instead of the browser's pop-up. Price adjustments sit behind "Adjust prices", and leaving with changed prices asks first. The order recap of an open cycle is read-only, since corrections only work after closing. - ๐Ÿ›’ **Smoother order buttons.** The "+" stays under your finger when a product goes from 0 to 1, and screen readers now say which product each button changes and the new quantity. - ๐Ÿ’ฌ **Messages you have time to read.** Errors and warnings stay longer and can be closed, and a failed save says to check the connection. Deleting an order starts on "Cancel", so a stray Enter deletes nothing. - โŒจ๏ธ **Easier to use with a keyboard.** Every button and field shows a clear outline when reached with Tab, a "Skip to content" link jumps past the menu, and each page has its own title in the browser tab. - ๐Ÿงฉ **Same look for the same things.** Confirmations in Admin (deleting a member, archiving a product, removing it from a cycle...) use the app's own window instead of the browser pop-up, and statuses, back links and buttons share one style. - ๐Ÿ“ฒ **Windows that fit the phone.** Every window (order sent, a past order or a movement in History, a member's movements in Cassa, closing accounts, cancelling a cycle, the supplier, merging members, importing a price list) rises from the bottom on phones with its buttons near the thumb, closes with Esc or the โœ•, and asks before throwing away what you typed. - ๐Ÿ’ฐ **Tidier Cassa and Members.** Every movement in Cassa reads the same way (name and amount on the right, then kind and day, then the note) with "Edit" and "Delete" underneath; in Members the role sits next to the name and the actions stay on one line, with Invite, Merge and Delete behind โ‹ฏ on phones and tablets. Every field and icon button in Admin has a name screen readers can say. - ๐Ÿ“ฑ **A lighter bar at the bottom.** Members see four items (Home, Order, History, Guide) instead of a greyed-out "Admin", the bell, the avatar and the "?" are easier to tap, and switching page no longer looks like a reload. - ๐Ÿ”ค **Easier to read.** Prices in the order and the text of notifications are bigger and in the normal font, and the Profile no longer shows "Utenti" under the name of ordinary members. - ๐Ÿ  **The open order first on Home.** The cycle you can order in comes before the balance, with one plain line on when it closes ("Closes in 5 days ยท Mon 13 Oct, 23:59") and pickup days written once. The ticking countdown appears only on the last day, and after the first visit the welcome folds to one line. - ๐Ÿ›’ **More room to shop on the Order page.** The bar at the bottom is one row (total, balance after and "Confirm"), with the breakdown behind "Details"; a refused order also says why right above the button. "Discard changes" appears only when you changed something, the + and โˆ’ buttons are bigger, and products without their own emoji no longer show a cart. - ๐Ÿท๏ธ **Find products faster.** On the Order page the categories stay at the top as chips that jump to each section, "In the cart (3)" shows only what you picked, and with more than 15 products a search box finds them by name. - ๐Ÿ‘† **Drag down to close.** On a phone, windows that rise from the bottom (confirmations included) close by dragging them down; on a confirmation that always means "Cancel". The window that closes a cycle closes only with its buttons. - ๐Ÿ”„ **Always up to date.** Coming back to the app after a few minutes reloads balance, cycle and notifications, tapping the current item of the bottom bar scrolls up and refreshes, and a line says when you are offline. The Order page is never refreshed while you edit. - ๐Ÿ”” **Clearer notifications.** Grouped by day (Today, Yesterday...), unread ones say "New" in words, and tapping one opens its page at once. - ๐Ÿงญ **A shorter Admin bar.** Cycle, Treasury, Members and Catalogue fit on a phone without scrolling, with Statistics and Settings behind โ‹ฏ (in line on a computer). Orders now sit under Cycle, Products and Suppliers under Catalogue, and old links still open the right page. - ๐Ÿ—‚๏ธ **One place per cycle in Admin.** Pick a cycle from the list (on the left on a computer, "All cycles" on a phone), then move between Overview, Products and Orders, or Supplier and Accounts once it is closed. Every past cycle is there with search and filters, not only the last 15, so older ones can still be corrected. - ๐Ÿ“‹ **A cycle's orders on one page.** Orders shows "By member" and "By product" (side by side on a computer) with a single "Download order sheet"; on a closed cycle weights and orders are corrected right there. A member's order history is now in Members, under "Orders", with a link to their movements in Treasury. - ๐Ÿ’ณ **Accounts to settle come first.** In Admin โ†’ Cycle the list opens with the card cycles whose accounts still need "Settle accounts" (never settled, to update after a correction, or a refund that failed), then the open ones; on a phone both sit above "All cycles". - ๐Ÿค **Supplier in three steps, Accounts in one place.** Supplier shows, numbered on the page, download the order sheet, send it, upload the completed one. Accounts shows what the cycle moved on balances, shipping and the corrections made (read only), how to correct a cycle, "Settle accounts" for card cycles and, at the bottom, cancelling it. - โœ… **"To do now" on top of Admin.** The three count tiles give way to the next step of each cycle, with one button: review and close a cycle whose deadline has passed (in red, with how long ago), send the order to the supplier, record the weights, settle accounts; then refunds to retry and possible duplicate members. "Already sent" and "Delivered as ordered" hide a step on that device only. - ๐Ÿงบ **One catalogue, one product form.** Products are edited only in Catalogue โ†’ Products; each supplier in Suppliers links to its own products ("5 products in the catalogue โ†’"), and editing a product no longer drops its icon. The guided import is the main way to load a price list, with the template and direct upload under "Other formats". The forms to add a member or a supplier stay closed until you need them. - ๐Ÿ–ฅ๏ธ **A real computer layout.** On a computer the app uses the same wider frame on every page, with logo, menu, bell and avatar on one line. Home has two columns (the cycle and your order on the left, balance, pickup and movements on the right); reading pages stay in a comfortable column. The bell, the avatar and Home (for Top up) show where you are. - ๐Ÿ“ฐ **Shorter What's new, clearer contacts, branded sign-in.** What's new opens the last three versions and folds the older ones. The guide's contact buttons say what they are for ("Write to the group", "Technical problems") and appear once when the address is the same. The sign-in page shows the group's logo, and an error is read out by screen readers. - ๐ŸŽจ **The same look everywhere.** The balance has the same sign and format on Home, History and Top up, and adjustment notifications no longer say "โ‚ฌ EUR". Recent movements on Home look like those in History and open them, the guide and empty pages use the app's own icons instead of emoji, and cards share one corner shape. - ๐Ÿ›’ **Order and History on a computer.** On a computer the Order page keeps your cart on the right (products picked, total, balance after and "Confirm"), next to the catalogue. History shows the list on the left and the selected order or movement on the right; the Orders and Movements tabs are in the address, so a link opens the right one. ## [1.25.0] - 2026-10-07 *A welcome for newcomers, and the group's own page in the guide.* ### Added - ๐Ÿ  **Our group, at the top of the guide.** Admins write where and when to collect, who to ask and the group's own rules in Impostazioni; members find it first in the guide, and the search finds it too. - ๐Ÿ‘‹ **A welcome for newcomers.** The first time on Home, a short card in a few steps explains how the group works, the balance (or how you pay), ordering, collection, notices, family, the app on your phone and where to find help. Its links keep your place: a bar on the page you opened takes you back. One tap closes it; the Guide can show it again. - ๐Ÿ” **What members could not find.** Impostazioni lists the guide searches that found nothing (only the words and how often, never who searched), so admins can add what is missing. ### Fixed - ๐Ÿ“ฑ **Order total on iPhone, for good.** In the installed app the order total could still show the old amount under the new one after adding a product; the total and the balance now redraw on every change. ## [1.24.0] - 2026-10-06 *Your settings in one place, and a guide you can search.* ### Added - ๐Ÿ‘ค **Your Profile.** Tap the circle with your initials, top right: your name (now editable), the emails you sign in with, family, notifications, balance, installing the app, the guide and sign-out, all in one place. ### Changed - ๐Ÿงญ **Tidier header.** The email and the Logout button made way for the Profile circle; notification preferences and Family moved inside the Profile (old links still work). - ๐Ÿ“– **A guide you can search.** The Guide now has a search box and topics, with step-by-step cards that open the right page of the app. A "?" next to the title of Order, Top up, Family and Notifications opens the right card. It only covers what your group has switched on, and the answers are up to date with the latest features. ## [1.23.0] - 2026-10-06 *Families share one account, and duplicate accounts point themselves out.* ### Added - ๐Ÿ‘ฏ **Possible duplicates in Members.** Admin โ†’ Members lists accounts that look like the same person (same name, or the name inside the other's address), with Merge already filled in and "Not the same person" to hide a pair. Migration `0028_member_duplicate_dismissals.sql`. - ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง **Families.** Members can invite each other into one account (Notifications โ†’ โš™ โ†’ Family): cart, balance and order history become shared, and each person keeps signing in with their own addresses. The invited person accepts or declines (in-app notice and email); either can leave. Off by default, admin โ†’ Settings switches it on; Members shows who is in which family, on every account of it. Migration `0029_families.sql`. ### Changed - ๐Ÿ”‘ **Clearer message when the card is not found.** A member whose card is not on their address is told to sign in with the address they registered the card with; an admin then merges the two accounts. - ๐Ÿ’ถ **Tidier Cassa tab.** "New top-up" is folded like "Outgoing movement" and opens with a tap; the balances list is split into Admin, Attivi and Utenti, as in the Members tab. ### Fixed - ๐Ÿ›’ **No more lost cart edits across devices.** If the cart was changed from another device (say the phone, while the computer was open), saving from the stale page no longer overwrites it: the page shows the latest cart and says so. - ๐Ÿ“ฑ **Readable order total on iPhone.** Adding a product could leave the old total drawn over the new one, and the balance after the order stuck on the previous value. ## [1.22.0] - 2026-10-04 *One person, one account: duplicates can now be merged.* ### Added - ๐Ÿ”— **Merge two accounts of the same member.** In Admin โ†’ Members, "Merge" joins a duplicate account into the one that stays: role and primary email stay, the other address becomes the secondary one, and open orders, notifications and balance move over. Typing another member's address in the edit form offers the same. Migration `0027_member_merge.sql`. ### Fixed - ๐Ÿ—‘๏ธ **Deleting a member who never ordered works again.** Admin โ†’ Members could not delete an account that had received a notification (almost every new account gets the open-cycle one) and showed a database error; now the account and its notifications go. ## [1.21.1] - 2026-10-04 *Notes that members can read, and a member list that fits on a phone.* ### Fixed - ๐Ÿ“ **Notes reach the members.** The notes an admin writes on a cycle now appear on Home and at the top of the order page, and each product's notes under its name in the order form and the recap. Before, only admins saw them. - ๐Ÿ“ฑ **Member list readable on phones.** In Admin โ†’ Members the email addresses no longer run under the buttons: the list shows name, last sign-in and actions, the addresses are in the edit form, and on narrow screens the buttons sit below the name. ## [1.21.0] - 2026-10-03 *Sign in with a code from the email, and the app on your phone's home screen.* ### Added - ๐Ÿ”ข **Sign in with a code too.** The sign-in email now also carries a 6-digit code: type it on the sign-in page when the link opens in the wrong browser or on another device. Same 15 minutes as the link, three tries per code. - ๐Ÿ“ฑ **Install the app on your phone.** On a phone the home page offers to add the app to the home screen (the install button on Android, the steps on iPhone), with icons drawn from your group's logo; the Guide explains it too. ### Fixed - ๐Ÿงฉ **The app description is reachable again.** It sat behind the sign-in: a browser asking for it without the session (always, on the sign-in page) got the sign-in page instead, so the app did not install properly. ## [1.20.0] - 2026-10-01 *Notification settings that say what they cover, a Cassa that names every movement, and Next.js 16 underneath.* ### Changed - ๐Ÿ”” **Clearer notification preferences.** The four groups now say what they cover: new cycle opened, charges and payments (including the settlement and online payment confirmations), order changes (including a cancelled cycle) and balance and refunds. Your saved choices are kept; payment confirmations now follow "Charges and payments". - [tech] ๐Ÿงฐ **Next.js 16 and TypeScript 7.** Same app, newer foundations; self-hosters need Node.js 20.19 or later, and lint now runs with `npm run lint`. - [tech] ๐ŸŒ™ **A sturdier nightly check.** The nightly money check no longer waits for the backup, and a failed or stuck night opens a GitHub issue. ### Fixed - ๐Ÿท๏ธ **Cassa names every movement.** Older card refunds and payments, shipping and corrections showed a raw code such as `ORDER_REFUND` in the movement badge; they now read "card refund", "order payment", "shipping" and so on, and an unknown type shows a plain "movement". - โœ๏ธ **Editing a cycle after it closed.** Saving a cycle's title or pickup from a form that was opened before the close no longer fails with "the fee can no longer change" when the fee is untouched. - ๐Ÿ‘ฅ **Closed-cycle details list every charged member.** A member charged shipping or the order preparation fee but left with no order line now appears in the list, so the members shown add up to the total. - ๐Ÿ’ฌ **Clearer credit message.** The balance card now says the difference you paid is your credit; two admin messages also state the fee cap in euros in English. ## [1.19.0] - 2026-10-01 *Install it for your own group in half an hour, and an order preparation fee that is a real, checked charge.* ### Added - [tech] ๐Ÿš€ **Run it for your group.** A step-by-step guide (`docs/self-hosting.md`) with a Deploy to Vercel button that creates the project and its Neon database and applies every migration at the first build; `docs/brand.example.json` lists every brand field. - [tech] ๐Ÿ‘‘ **First admin of a new installation.** The address in `BOOTSTRAP_ADMIN_EMAIL` becomes admin at its first sign-in, only while the group has no admin; Configuration status says when the variable can go. - ๐Ÿงพ **Order preparation fee.** A cycle can charge a fee for bank fees and running costs, in both payment modes: a percentage of the products or a fixed amount per member, up to 25% or โ‚ฌ10. Members see it before ordering; it is charged at the close as its own movement and checked every night. Upgrade note: apply `drizzle/0026_handling_charge.sql` right before deploying when `MIGRATE_ON_BUILD` is off. ### Changed - ๐Ÿ’ณ **Pay per order: the fee is a cost, not an estimate.** The group keeps it; settlement evens out products and shipping only. With proportional shipping each member pays their share at settlement. - [tech] ๐Ÿฉน **New installations no longer fail on the home page.** Three cycle columns were missing from the migrations; one more migration adds them (a no-op on existing installations). A CI test now compares the whole schema with a migrated empty database. Upgrade note: apply `drizzle/0025_schema_catch_up.sql`. - [tech] ๐Ÿงญ **Configuration status spots brand mistakes.** A brand field the app does not know (a typo) or a brand that does not parse shows up, with the reason, in Settings and in `npm run doctor`. - [tech] ๐Ÿ—๏ธ **Migrations at build on production only.** With `MIGRATE_ON_BUILD=true` preview builds no longer migrate: only production builds (and builds outside Vercel) do. ## [1.18.0] - 2026-10-01 *Pay each order by card, settle accounts after the cycle, and a ledger that never rewrites history.* ### Added - ๐Ÿ’ณ **Pay per order, selectable.** Admins can switch the group to paying each order by card in Settings, once no cycle is running; the card lists what stops the change and the balances before confirming. Upgrade note: apply `drizzle/0024_settlement.sql` before deploying; pay per order needs euros and a usable Stripe key. - ๐Ÿงฎ **Settle accounts.** On a closed or cancelled pay-per-order cycle, "Settle accounts" refunds to the card what each member paid beyond the final costs, asks for what is missing and writes off differences under โ‚ฌ0.50. The cycle shows where it stands: to settle, refunds in progress, settled, out of date, refund failed. - ๐Ÿ”ด **Amount due and credit.** When costs went beyond what a member paid, Home and the balances page show "Amount due" with "Pay now"; new order payments wait until it is paid. A credit shows as money the association gives back. - ๐Ÿงพ **Pays outside the app.** In pay-per-order an admin can mark a member who pays in cash: they confirm orders without the card, the treasurer records the money, and the settlement leaves them out. - ๐Ÿ“š **History and guide for pay per order.** Each cycle in History shows what was paid, the costs, the refunds and the net; the guide and FAQ explain the handling share, the settlement and refund times. ### Changed - ๐Ÿงพ **Corrections never rewrite history.** Editing or deleting a movement in Treasury, recomputing shipping on a closed cycle or importing the supplier's sheet now cancel the movement with a reversal and, when needed, add the corrected one; members see one movement marked "corrected on". Upgrade note: apply `drizzle/0023_ledger_append_only.sql` right before deploying (it makes the database refuse changes to past movements). ## [1.17.0] - 2026-09-30 *Sign in with an email link, and the groundwork for paying each order.* ### Added - โœ‰๏ธ **Sign in with an email link.** Type your address and you get a link that signs you in, no Google account needed; Google stays for whoever prefers it. Admins can send the link as an invitation from Members, and see each member's last sign-in. Upgrade note: apply `drizzle/0022_auth_sessions.sql` before deploying; email (Resend) must be set up; everyone signs in once more after the update; the Google redirect URI does not change. - [tech] ๐Ÿงฎ **Nightly check of the books.** After the backup, a read-only check makes sure every payment, refund and charge adds up, and fails loudly if not. - ๐Ÿงญ **Configuration status.** Settings shows what this installation has connected (database, sign-in, email, payments...) and what is missing, by name only; `npm run doctor` prints the same. Upgrade notes per version are in `docs/upgrading.md`, and `MIGRATE_ON_BUILD=true` applies migrations at every production build (optional). - ๐Ÿ’ณ **Pay per order, groundwork.** The app can now take an order's payment with Stripe, refund it when the order is cancelled or the payment arrives after the close, and retry a refund from Treasury. Not selectable yet: it becomes an option in Settings with the settlement. Upgrade note: apply `drizzle/0021_pay_per_order.sql` before deploying; no new variables, no new Stripe events. ### Changed - ๐Ÿ”• **No email by default when a cycle opens.** New members get the "cycle open" notice in the app only and can turn the email on in their preferences; members who already chose keep their choice. ## [1.16.1] - 2026-09-30 *A desktop layout, and the groundwork to watch the app's health.* ### Added - [tech] ๐Ÿฉบ **Health check and optional error reporting.** `/api/health` says whether the app and its database answer, and server errors can go to Sentry. Upgrade note: no migration; `SENTRY_DSN` is optional, without it nothing changes. ### Changed - ๐Ÿ–ฅ๏ธ **A proper desktop layout.** On a computer the menu moves to the top and the pages keep a comfortable reading width; only Admin uses the wider window, and Treasury shows the forms next to the member balances. - ๐Ÿ”ค **Slightly larger reading text.** Descriptions and lists in the member pages go from 13 to 14 px. - โœ‰๏ธ **Your email, out of the way.** On a phone it no longer takes a line under the logo: you find it on the Notifications page. ## [1.16.0] - 2026-09-30 *Text you can read, in any group's colours.* ### Changed - ๐Ÿ‘“ **Text you can read.** Buttons, links, labels and amounts now have enough contrast on every screen: dark text on the coloured buttons, darker shades for coloured and grey text, a deeper red for negative amounts. - ๐ŸŽจ **Colours that follow the group's palette.** Text colours are worked out from the brand colours, so a group with a different palette stays readable. Upgrade note: nothing to do; theme colours must be hex (`#rgb` or `#rrggbb`), anything else falls back to the default palette with a `[brand]` warning in the logs. - ๐Ÿ”Ž **Nothing smaller than 12 px.** Labels, badges and captions that were 10 or 11 px are now 12 px, and on a phone the form fields no longer zoom the page when you tap them. ### Fixed - ๐Ÿ’ถ **Balance on one line.** On Home the balance no longer wraps after the sign in English formats. ## [1.15.0] - 2026-09-30 *Card refunds you can follow.* ### Added - โš ๏ธ **Refunds that do not go through.** If a card refund fails after it was sent, the amount goes back on the balance, History shows "Refund failed", and the member and the admins are told how it will be returned. ### Changed - ๐Ÿ’ณ **Card refunds recorded one by one.** Every refund of an online top-up is recorded once, as soon as Stripe accepts it, even when it arrives in more than one step (migration `0020`). ## [1.14.1] - 2026-09-30 *Tidier amounts in Settings.* ### Fixed - โš™๏ธ **Maximum balance with cents.** Settings shows a saved amount like 35,20 โ‚ฌ with both cent digits, instead of 35,2. ## [1.14.0] - 2026-09-29 *Payment settings in the app, and orders that wait for you.* ### Added - โš™๏ธ **Payment settings for admins.** A new Settings tab (gear icon) sets the group's overdraft limit, a maximum balance, and which top-up channels members see: bank transfer (holder and IBAN) and online payment. Until an admin saves, nothing changes (migration `0019`). - ๐Ÿ›’ **Your order waits for you.** Changes to an order are saved as you go: leave the page and come back, even from another device, and they are still there, marked "Changes not confirmed yet" until you confirm or discard them. - ๐Ÿงพ **Movement details.** Tap a movement in History to see date and time, cycle, note, method and reference, the online payment's status and who recorded it. ### Changed - ๐Ÿ’ถ **Top-ups respect the maximum balance.** Online top-ups offer only what fits, the bank details say how much you can still top up, and a member in debt gets the exact amount to pay it off as the first option. - ๐Ÿฆ **Treasury flags balances above the maximum.** A top-up recorded in Treasury is never refused, but the admin is told when it takes the balance past the maximum, and a new filter lists those members. ## [1.13.0] - 2026-09-29 *A fuller Cassa, and a history that adds up to the balance.* ### Added - ๐Ÿ’ธ **Outgoing movements in Cassa.** Admins can record a balance paid back to a member (never beyond the balance), a manual charge or the membership fee, each with a reason the member reads in the notification. - ๐Ÿฆ **Manual top-ups with method and reference.** Search the member by name or email, pick the method (bank transfer, cash, Satispay, other) and add the CRO/TRN: a reference already used is refused, a similar top-up in the last days asks for confirmation, and a recap comes before saving (migration `0018`). - ๐Ÿงบ **Pick the cycle when more than one is open.** "Order" lists the open cycles with their supplier instead of opening the first one, and the countdown button on the home page opens its own cycle. ### Changed - ๐Ÿ“’ **History matches the balance.** Each cycle shows products (after weighing), shipping, corrections and the total charged to the balance, and every movement has a clear name and its own icon: Top-up, Shipping, Refund, Adjustment, Balance returned, Membership fee. - โž• **Amounts with their sign.** Balance and movements always show + or -, and a negative balance on the home page reads "To top up". - ๐Ÿšš **Shipping follows edits to closed orders.** Editing a member's order after closing re-splits everyone's shipping on the actual totals (after weighing), unless it came from the supplier's sheet; only members whose share moved are notified. - ๐Ÿ” **A deactivated member is signed out at once.** Deactivating a member, admins included, ends their session on the next request instead of at token expiry. ### Fixed - ๐Ÿ“ง **Emails and aliases are no longer shared between members.** Saving a member with an email or secondary email another member already uses, in any casing, is refused with that member's name (migration `0017`). - โš ๏ธ **Readable error messages.** In production, expected refusals (cycle closed, missing field, order changed meanwhile) now show their own text instead of a generic error, and the order page reloads by itself when the cycle has closed. ## [1.12.2] - 2026-09-29 *Smaller online top-ups.* ### Changed - ๐Ÿ’ถ **Online top-ups from 0,50 โ‚ฌ**, the smallest amount Stripe accepts (was 20 โ‚ฌ). ## [1.12.1] - 2026-09-28 *Clearer top-up details.* ### Changed - ๐Ÿฆ **IBAN in groups of four** on the Top up page, easier to check by eye; the copy button still copies it without spaces. - ๐Ÿ“– **Guide and FAQ point to the Top up page** for bank transfers and online payment. ## [1.12.0] - 2026-09-28 *Top up your balance online.* ### Added - ๐Ÿ’ณ **Online top-up.** A new "Top up" page (from the home balance card) lets members top up by card or the other methods the group enables, through a Stripe payment page. The balance updates by itself as soon as the payment is confirmed, and refunds made from Stripe show up in the history. - ๐Ÿฆ **Bank details on the same page.** When the group sets them, the page also shows holder, IBAN and payment reference for a bank transfer, each with a copy button. ### Changed - ๐Ÿ”’ **Online payments stay tied to Stripe.** In Cassa, top-ups and refunds that came from an online payment can no longer be edited or deleted: the money moved on Stripe, so the fix is a refund there or a separate correction. ## [1.11.0] - 2026-09-28 *Open to every card-holding member, with safer money flows.* ### Added - ๐Ÿชช **Members with an active membership card can sign in on their own.** The first Google login with the email used for the card checks it with the membership provider and creates the account; no admin whitelisting needed. Cards are rechecked before an order grows, and the login page explains what to do when access is refused. - ๐Ÿ’ณ **Credit limit.** An order that would take the balance (counting orders still open on other cycles) below the group's limit is refused with the amount still available; lowering or cancelling an order always works. - ๐Ÿ” **Privacy policy link** on the login page and in the footer. ### Changed - ๐Ÿ‘ฅ **Roles and cycle access now share the same three names: Admin, Attivi, Utenti.** Admins see every cycle, Attivi see standard and private cycles, Utenti see standard cycles only. The member form no longer defaults an unrecognised role to Admin, and "enabled members" now names the on/off switch on an account. ### Fixed - ๐Ÿ•ฐ๏ธ **Times follow Rome everywhere.** Closing and pickup times no longer shift by two hours between cards, forms and emails, a cycle stops taking orders at the hour it shows, and the switch to winter time on 25 October is handled. - ๐Ÿงพ **Editing a Cassa movement keeps its sign.** Changing only the note of a refund no longer turns it into a charge, and an empty amount is rejected instead of corrupting the balance. Order and shipping charges are corrected with a new entry rather than edited in place. - โš–๏ธ **Editing a closed order keeps the weighed quantities**, so re-weighing afterwards can no longer refund a member twice. - ๐Ÿšš **Saving a closed cycle keeps shipping imported from the distinta**, instead of resetting everyone's share and sending wrong notifications. - ๐Ÿ”’ **Closing a cycle is all-or-nothing.** Charges, shipping and the status change are written together, and a second charge for the same cycle is rejected by the database. ### Security - [tech] โšก **Next.js updated to 15.5.25**, patching two critical remote-code-execution advisories. One requires a Windows-hosted server (we run on Vercel/Linux); the other was in image optimization, already narrowed to the brand's own logo host. `sharp` moved to 0.35.4 alongside it. - [tech] ๐Ÿ“ค **A crafted supplier file could no longer stall a distinta import.** Re-importing a `.ods` re-save (e.g. from LibreOffice) used an XML parser with a denial-of-service bug on long runs of whitespace, now fixed. - [tech] ๐Ÿ“Š **A dormant advisory in the spreadsheet library, fixed anyway.** `exceljs` bundles an old, vulnerable `uuid`; unreachable here since the one call site never touches the vulnerable code path, but pinned to the patched release regardless. - [tech] ๐Ÿงน **A development-only dependency** (`js-yaml`) with a denial-of-service advisory refreshed. It never shipped to users. --- ## [1.10.3] - 2026-09-06 *Same product, same shelf.* ### Fixed - ๐Ÿฅ• **A product no longer splits across categories.** "Cicoria" (or any other product) now always lands in the same category no matter which variant or import batch it came from โ€” the name-based guess wins over a supplier file's own inconsistent category column, everywhere products get loaded into an order. - ๐Ÿ”ค **Products are actually sorted now.** The order screen (and every other product list) sorts alphabetically by product, then variety, then format and price, instead of whatever order the last import happened to load them in. --- ## [1.10.2] - 2026-08-30 *Fewer vegetables getting lost in "Other".* ### Fixed - ๐Ÿฅฌ **Products land in the right category more often.** A supplier file that labels most rows "Altro"/"Varie" no longer overrides a confident guess โ€” a zucchina, a melanzana, a patata now sort into Verdura even when the supplier's own sheet didn't bother. - ๐ŸŒฟ **More products get an automatic icon.** Basil, parsley, and other aromatic herbs โ€” including compound names like "Basilico viola da trapiantare" โ€” now get a matching icon instead of the generic cart. Plural forms (zucchine, carote, funghi, asparagi...) match too, and a handful of previously-unmapped items (pancetta, gamberi, calamari, mandarino, olive) now have one. --- ## [1.10.1] - 2026-08-27 *Making sure the supplier's inbox actually sees it.* ### Fixed - ๐Ÿ“ฌ **The supplier order email is less likely to land in spam.** Replies now go straight to the admin who sent it, the subject leads with your cooperative's name instead of the app's, and the message is sent as proper HTML alongside plain text โ€” three signals spam filters use to trust a message. --- ## [1.10.0] - 2026-08-27 *A way back when a cycle goes wrong after it's already closed.* ### Added - ๐Ÿšซ **Cancel a closed cycle and refund everyone.** When a supplier fails to deliver on an order that's already been charged, an admin can now cancel that cycle: every member who was charged gets refunded in full (products, and shipping unless you opt out), with a mandatory reason and a full trail โ€” a "cancelled" badge on the cycle, a marked movement in each member's history, an audit log entry, and a notification to each refunded member. --- ## [1.9.0] - 2026-08-07 *One notification fewer, and one moving part fewer behind it.* ### Removed - ๐Ÿ”• **The "cycle closing soon" reminder is gone.** It arrived in your notifications when a cycle was about to close and you hadn't ordered; the cycle-opened notification already tells you the closing date, so this was mostly a second copy of the same information. - โš™๏ธ **Its toggle has left the notification settings.** One row fewer to read through; reminders you received in the past stay in your notification list. --- ## [1.8.1] - 2026-07-28 *Security patches for the login layer and the image pipeline.* ### Security - [tech] ๐Ÿ”’ **Auth.js updated to the version that patches four advisories**, two of them critical (`next-auth` 5.0.0-beta.32, `@auth/core` 0.41.3). None were exploitable here โ€” the app has no magic-link provider, never calls `getToken()`, has a single OAuth provider with no account linking, and every access check reads `session.user.email` rather than the truthiness of the auth object โ€” but the fix is a patch-level bump, so there's no reason to sit on it. - [tech] ๐Ÿ–ผ๏ธ **The image endpoint no longer accepts any host on the internet.** It used to allow `https://**`, which in a self-hosted deployment turns `/_next/image` into an open proxy: anyone could have the server fetch arbitrary remote images and run them through the image library. It now allows exactly the brand logo's own URL, taken from the deployment's own configuration. - [tech] โšก **Next.js updated to 15.5.22** for a denial-of-service fix in image optimization, and the image library forced to a build with the patched `libvips` (`sharp` 0.35.3), which upstream has not yet picked up. - [tech] ๐Ÿงน **Two development-only dependencies** with denial-of-service advisories (`js-yaml`, `brace-expansion`) refreshed. They never shipped to users. --- ## [1.8.0] - 2026-07-20 *Confirming an order now says so, and you can change your mind until the cycle closes.* ### Added - โœ… **Confirming an order opens a proper confirmation.** A dialog recaps what was sent and when you can still change it, instead of a toast that slid away after a second. - ๐Ÿ“‹ **Your confirmed order greets you when you come back.** The order page opens on a recap of what's on file โ€” products, quantities, total, balance after โ€” rather than dropping you back into the product list. - โœ๏ธ **Edit or cancel any time until the cycle closes.** Both actions sit under the recap; cancelling asks for a confirmation and removes the order so nothing is charged at closing. ### Changed - ๐Ÿ“ฐ **The changelog reads like release notes, not a report.** Short bullets with a topical emoji, a one-line summary per release, and category chips you can scan. - ๐Ÿ”” **The closing reminder can arrive up to ~3 hours before a cycle closes** (was exactly 2). The scheduled job doesn't run at perfectly regular intervals, and the wider window stops it skipping a cycle. - ๐Ÿค **Choosing a supplier is now required when opening a cycle**, so a cycle can no longer close without one. - ๐Ÿ”ค **Nothing renders below 10px any more.** 55 micro-labels across the admin and member views were raised. Verified at 375px: nothing overflows. ### Fixed - ๐Ÿค **The supplier can now be set or corrected on a closed cycle.** The field used to vanish at closing, permanently stranding any cycle created without one. - ๐Ÿ”’ **An order confirmed the instant an admin closes the cycle can no longer slip through uncharged.** Saving locks the cycle inside the same transaction, so a simultaneous close waits for the save, or the save is cleanly rejected. - ๐Ÿ›ก๏ธ **Deactivated accounts can no longer act through a still-open session.** Orders and admin actions re-check the active flag on every request, and quantities are validated before anything is written. - ๐ŸŒ **The Guide's "What's new" box follows the app language.** English deployments were showing the Italian teaser. - ๐ŸŽจ **The 404 page is translated and uses the group's colours.** Both error pages had hardcoded colours, on exactly the pages that bypass the themed layout. - ๐Ÿ—ฃ๏ธ **The last Italian strings on English deployments** โ€” the order-rectification notification and the negative-balance warning โ€” now follow the app language. --- ## [1.7.0] - 2026-07-10 *Notification preferences with an email channel, and a guided import of the supplier's own price list.* ### Added - ๐Ÿ”” **Per-member notification preferences, with email as an optional channel.** Bell โ†’ โš™ lets everyone choose app and/or email per category. Two new events ship with it: a cycle opening, and a reminder before closing for members who haven't ordered yet. - ๐Ÿ“ฅ **Guided import of a supplier price list.** A three-step wizard reads the supplier's own `.xlsx` or `.csv`, detects the header row and the supplier, lets you map whatever it couldn't recognise, then previews every row before writing anything. - ๐Ÿ“ฆ **"Catalogue in preparation" empty state** in the order form, so an open cycle with no products yet no longer looks broken. - ๐Ÿ”’ **A 10 MB cap on admin uploads**, checked before the file is decoded, plus a decompression-bomb guard on `.ods` parsing. - [tech] ๐Ÿ—„๏ธ **Unique indexes on order lines and per-cycle products**, so concurrent imports can't slip duplicates past the app-side checks (migration `0008`). - [tech] ๐Ÿงช **Tests for the money-adjacent pure functions** โ€” shipping split, changelog parser, header heuristics, spreadsheet number parsing. Suite up to 78. ### Changed - ๐Ÿ“… **Easier pickup entry.** The second pickup is optional behind a toggle, and times come from a 15-minute dropdown, so 19:30 is always selectable instead of being rejected as invalid. - ๐Ÿ“ค **The completed order sheet can be uploaded as `.ods` or `.csv`** too. With `.csv`, which can't carry the hidden mapping, names are matched and anything ambiguous is flagged and skipped โ€” never guessed. - โœ๏ธ **The two rectification paths in the order recap are now distinct** โ€” โœŽ Prodotti for quantities, a per-line โœŽ for actual weight or price โ€” with a hint that works on a phone, where there is no hover. - ๐Ÿ–ฅ๏ธ **Tidier "Carica prodotti" row** in Admin โ†’ Prodotti: the destination-supplier dropdown gets its own labelled line and the three actions stay readable on mobile. ### Fixed - ๐Ÿ† **Wrong auto-suggested emojis** for aubergine, rice and peppers โ€” overlap bugs in the first-match-wins table, now pinned by regression tests. - ๐Ÿ›’ **Saving an order is atomic.** Delete and insert used to be two independent requests, so an interruption between them could silently leave the order empty. - ๐ŸŒ **Corrupted uploads show a localized error** instead of the parsing library's raw English, and the last three hardcoded Italian admin strings follow the locale. - ๐Ÿ“ฑ **Open-cycle action buttons no longer run off the screen**, and the pickup date/time rows wrap on narrow phones. Verified down to 320px. --- ## [1.6.0] - 2026-05-21 *Supplier sheets that make the round trip, per-line rectifications, and real analytics.* ### Added - ๐Ÿ”„ **A supplier sheet that comes back.** ๐Ÿ“ง Fornitore sends an `.xlsx` laid out the way suppliers already work โ€” products as rows, members as columns, live totals โ€” and ๐Ÿ“ค Carica distinta reads the returned file, previews the diff, and applies both line corrections and per-member shipping. - โš–๏ธ **Record what was actually delivered, line by line.** Tap an order line to enter the real quantity and cost (1 kg ordered, 800 g received); the delta posts as a correction and the member is notified. - ๐Ÿ“Š **Filters in Admin โ†’ Statistiche** by cycle, supplier or member, combinable, with a one-click reset. - โœ๏ธ **Edit a cycle after it's closed** โ€” title, notes, pickup dates, shipping โ€” without reopening it. - ๐Ÿšš **Shipping recomputes automatically on closed cycles**, and every affected member gets a notification showing the old and new share. - ๐Ÿ“ง **Send the order to the supplier by email**, with the acting admin and the shared GAS archive in CC and a per-product CSV attached. - ๐Ÿงพ **Shipping is visible in the order recap**, so the totals on screen match what members were actually billed. - [tech] ๐Ÿ’พ **Weekly off-site database backup to Google Drive**, complementing Neon's 7-hour point-in-time history. ### Changed - ๐Ÿค **Every supplier action lives in one ๐Ÿค Fornitore dialog** โ€” download, email, upload โ€” and a single canonical workbook now circulates everywhere instead of divergent formats. - ๐Ÿ’ฐ **Admin โ†’ Cassa leads with three summary cards**, including a clickable "Saldo < 0" filter that used to be buried in Admin โ†’ Ciclo. - ๐Ÿ“ˆ **The Admin โ†’ Ciclo cards became a timeline**: Aperti / In scadenza (โ‰ค7 days) / Chiusi (last 7 days). - ๐Ÿ“Š **Statistics filters are multi-select** with a search box, and a filtered view is still shareable by link. - ๐Ÿ“„ **The product template is an Excel file** with one pre-filled example per common category; the importer still accepts `.csv`. - ๐Ÿงพ **Admin โ†’ Ordini totals include rectifications and shipping**, so each member's row matches what they were actually charged. - ๐Ÿ“ฑ **Cleaner "Ultimi cicli" on mobile** โ€” the status pill moved left so it reads as a label, and the actions wrap underneath. - ๐Ÿท๏ธ **"Fatturato" renamed to "Spesa"** across the statistics, and it now folds in shipping. - ๐Ÿ“‹ **One consistent `qty ร— price = total` line format** in the recap, with rectified rows showing ordered against actual. ### Fixed - ๐Ÿ“Š **Statistics crashed when filtering by cycle or supplier.** The Neon HTTP driver doesn't serialize JS arrays as Postgres arrays, so the filter never bound; the query now uses `inArray()` everywhere. - ๐Ÿ”ค **Supplier sheets sort alphabetically and case-insensitively**, each sheet by the key that matches how it's actually read. - ๐Ÿ“‹ **Order lines no longer read `1 1 ร— โ‚ฌ2,00`.** A legacy "Unitร " field stored as the literal string "1" is now treated as no unit. --- ## [1.5.0] - 2026-05-17 *Fix a member's order after the cycle has closed.* ### Added - โœ๏ธ **Edit a member's order after closing** โ€” change quantities, add products, or build an order from scratch for someone who didn't originally take part. For the "I forgot to put the eggs in your bag" case. - ๐Ÿงพ **Corrections never touch the original charge.** The delta posts as a separate `correction` entry, so the audit trail stays intact and any change can be reversed. - ๐Ÿ”” **The member is notified** with a readable diff and their new balance. --- ## [1.4.5] - 2026-05-17 *One mobile fix.* ### Fixed - ๐Ÿ“ฑ **The admin's open-cycle buttons no longer overflow on phones.** Below 640px they stack under the title instead of clipping the last action. --- ## [1.4.4] - 2026-05-17 *One cosmetic fix.* ### Fixed - ๐Ÿท๏ธ **Dropped the dangling "/1" after prices** everywhere. It came from a legacy "Unitร " field that was hidden from the form but still rendered. --- ## [1.4.3] - 2026-05-17 *A simpler, better-explained product form.* ### Added - โš–๏ธ **Optional reference price-per-kg** on every product, shown to members next to the unit price wherever a price appears. - โ“ **Inline help on every field of the product form**, one line and one example each. ### Changed - ๐Ÿ“ **The product form lost the "Unitร " field.** It duplicated the format string and confused admins. - ๐Ÿ—‚๏ธ **Category is a dropdown now** โ€” preset categories merged with whatever the supplier already uses, plus an inline "add new". - ๐Ÿ“„ **The CSV template follows the new column layout**; the importer still accepts the old one. --- ## [1.4.2] - 2026-05-17 *Pick an emoji, and start from the real balances.* ### Added - ๐Ÿ˜€ **A searchable emoji picker** for the product icon, filtered by Italian keywords, replacing the free-text field. ### Changed - ๐Ÿ’ฐ **Member balances reset to match the legacy CASSA spreadsheet** ahead of going live, one seed entry per member. --- ## [1.4.1] - 2026-05-14 *The changelog moves into the app.* ### Added - ๐Ÿ“ฐ **A "What's new" page at `/changelog`**, linked from the Guide, with its own IT/EN toggle. - ๐Ÿ‘€ **A teaser of the latest release inside the Guide**, linking to the full page. ### Changed - ๐Ÿ“„ **The supplier CSV is itemized per member** and sorted supplier โ†’ product โ†’ member, so it can be used directly to prepare each bag. - ๐Ÿงฎ **Subtotal rows removed from the supplier CSV**, so nothing can be double-counted by summing both. --- ## [1.4.0] - 2026-05-14 *Numbers for the admin.* ### Added - ๐Ÿ“Š **An analytics dashboard** in the admin panel: top products, revenue trend over the last 12 closed cycles, supplier ranking, member participation, plus four overview cards. - ๐Ÿ“ˆ **Insight cards on the admin home** for cycles closing soon, negative balances and the 30-day best seller, each deep-linking into the right tab. - ๐Ÿ“„ **Supplier CSV export** from the closed-cycle modal, in the layout Italian Excel expects. - [tech] ๐Ÿ“š **An English README** with architecture notes. --- ## [1.3.0] - 2026-05-10 *Repeat your last order in one tap.* ### Added - ๐Ÿ” **"Repeat last order"** prefills the cart from your most recent order, matched by product identity. Only offered when the cart is empty, so it can't overwrite work in progress. - ๐Ÿ“… **A "Next pickup" card** on the home page with the day, time window, supplier and a days-until counter. ### Performance - [tech] โšก **Indexes on `products.cycle_id` and `ledger_entries.cycle_id`**, both queried on every admin and order page load. --- ## [1.2.0] - 2026-05-10 *Shipping splits and weight-based price adjustments.* ### Added - ๐Ÿšš **Proportional shipping split** as an alternative to flat per-member, with rounding drift absorbed deterministically so the total stays exact to the cent. - โš–๏ธ **Close a cycle with price adjustments** for weight-based items: edit each final unit price and every order line and ledger entry is recomputed before charges are posted. - [tech] ๐Ÿ“š **SETUP.md**, a step-by-step local-development guide covering the `vercel env pull` gotchas. ### Fixed - [tech] ๐Ÿ—„๏ธ **`drizzle-kit push` reads `.env.local`** via Node's `--env-file`. It used to load only `.env` and fail silently with an empty url. --- ## [1.1.0] - 2026-05-10 *Hardening the cycle-close path.* ### Fixed - ๐Ÿ”’ **Race condition on cycle close (critical).** Closing is now an atomic compare-and-swap, so two admins clicking at once can no longer post duplicate charges. - ๐Ÿ›’ **Closing a cycle mid-order gives feedback.** The order form refreshes with a toast instead of failing silently. - ๐Ÿงพ **Negative balances are red on the Movimenti tab**, matching the home page. - ๐Ÿ”” **The cycle-close notification mentions shipping** and deep-links to that cycle in the history. - ๐Ÿ–ผ๏ธ **The header logo links back home.** - ๐Ÿ“ฑ **The bottom nav respects the iPhone home-indicator safe area.** - ๐Ÿ—‚๏ธ **Uncategorized products group under "Altro"** instead of rendering an unlabeled section. --- ## [1.0.0] - 2026-05-05 *First production release of the Next.js rewrite.* ### Added - ๐Ÿš€ **The Next.js 15 rewrite goes live**, migrating the group off Apps Script. - ๐Ÿ›’ **The member app**: balance, order form with per-product steppers, order and movement history, in-app notifications, FAQ guide. - ๐Ÿ› ๏ธ **The admin panel** with six tabs โ€” cycles, products, orders, cash, members, suppliers. - ๐Ÿ”’ **Google OAuth via Auth.js**, with an email whitelist on the members table. - [tech] ๐Ÿ—„๏ธ **Neon Postgres and Drizzle ORM**, deployed on Vercel with auto-deploy from `main`. --- [1.45.2]: https://github.com/flylabs-ai/wegrocery/releases/tag/v1.45.2 [1.45.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.45.1 [1.35.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.35.0 [1.34.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.34.1 [1.34.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.34.0 [1.33.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.33.0 [1.32.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.32.0 [1.31.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.31.0 [1.30.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.30.1 [1.30.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.30.0 [1.29.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.29.0 [1.28.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.28.0 [1.27.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.27.0 [1.26.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.26.0 [1.25.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.25.0 [1.24.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.24.0 [1.23.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.23.0 [1.22.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.22.0 [1.21.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.21.1 [1.21.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.21.0 [1.20.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.20.0 [1.19.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.19.0 [1.18.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.18.0 [1.17.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.17.0 [1.16.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.16.1 [1.16.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.16.0 [1.15.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.15.0 [1.14.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.14.1 [1.14.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.14.0 [1.13.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.13.0 [1.12.2]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.12.2 [1.12.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.12.1 [1.12.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.12.0 [1.11.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.11.0 [1.9.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.9.0 [1.8.1]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.8.1 [1.8.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.8.0 [1.7.0]: https://github.com/federicodecillia/wegrocery/releases/tag/v1.7.0