Release v0.18.0#232
Draft
JustTB wants to merge 170 commits into
Draft
Conversation
docker compose up --build skips profile services. Explicit build ensures the scripts image has the latest source after each git pull. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass locale to API; API joins CropTranslation to override commonNames for both crops. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blocks sign-in for unverified accounts so an attacker cannot register with an ADMIN_EMAILS address and gain privileges. - better-auth: requireEmailVerification + sendVerificationEmail via SMTP_* vars - Dev fallback: logs verification URL to console when SMTP not configured - auth-panel: shows "check your email" state after signup instead of auto-closing - All 10 locales: add checkYourEmail + verifyEmailSent translation keys Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…buttons (#233) t('COMPANION')/t('AVOID') not in Contribute namespace; use lowercase 'companion'/'avoid' keys which map to descriptive label text. Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Users can now submit direct data entries, not just personal observations. Updates all UI-facing strings in en/de/fr/es/pt/ru/zh-Hans/ja/hi/ar. Keeps PERSONAL_OBSERVATION source-type label and observedDesc unchanged. Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- ResearchRequest.cropBId now nullable; single-plant requests supported (partial unique indexes replace the old compound unique constraint) - New GET /api/plants/search: returns matched plants with companions/ antagonists grouped, plus a no-data tier with research request state - Relationships page redesigned: one card per plant, companion/antagonist sections, no source count shown, URL ?q= param for back/share - Inline vote button on no-data plant cards; POSTs single-plant research request to /api/research-requests - Research requests page handles null cropB (single-plant requests) - 31 new/updated tests; 318/318 passing Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(search): grouped plant search with inline research voting - ResearchRequest.cropBId now nullable; single-plant requests supported (partial unique indexes replace the old compound unique constraint) - New GET /api/plants/search: returns matched plants with companions/ antagonists grouped, plus a no-data tier with research request state - Relationships page redesigned: one card per plant, companion/antagonist sections, no source count shown, URL ?q= param for back/share - Inline vote button on no-data plant cards; POSTs single-plant research request to /api/research-requests - Research requests page handles null cropB (single-plant requests) - 31 new/updated tests; 318/318 passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): guard nullable cropB in fetch-unreviewed-pairs; refresh seed.sql - Filter cropBId: not null in modeVoted query (single-plant requests must not appear as pairs in the research script) - Use ! assertion for cropB access after the null filter - Regenerate db/seed.sql + seed-enrichment-attempts.sql.gz to include the 20260607 nullable-cropB migration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(migration): use IF NOT EXISTS for partial indexes CI loads seed.sql (which already has the indexes) then runs prisma migrate deploy on top — causing duplicate index error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(search): grouped plant search with inline research voting - ResearchRequest.cropBId now nullable; single-plant requests supported (partial unique indexes replace the old compound unique constraint) - New GET /api/plants/search: returns matched plants with companions/ antagonists grouped, plus a no-data tier with research request state - Relationships page redesigned: one card per plant, companion/antagonist sections, no source count shown, URL ?q= param for back/share - Inline vote button on no-data plant cards; POSTs single-plant research request to /api/research-requests - Research requests page handles null cropB (single-plant requests) - 31 new/updated tests; 318/318 passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): guard nullable cropB in fetch-unreviewed-pairs; refresh seed.sql - Filter cropBId: not null in modeVoted query (single-plant requests must not appear as pairs in the research script) - Use ! assertion for cropB access after the null filter - Regenerate db/seed.sql + seed-enrichment-attempts.sql.gz to include the 20260607 nullable-cropB migration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(migration): use IF NOT EXISTS for partial indexes CI loads seed.sql (which already has the indexes) then runs prisma migrate deploy on top — causing duplicate index error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(seed): regenerate seed.sql with migration record in _prisma_migrations Previous dump was taken after applying the SQL directly (not via prisma migrate deploy), so _prisma_migrations lacked the entry. CI loads seed.sql then runs migrate deploy — seeing 1 pending migration and failing freshness check. Now seed.sql includes the row. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
localisedCrop was using a tMap built only from matched crops, so companion plants in relationship rows got no translation. Each crop already has its own translations field from the cropSelect — use that directly instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace generic "Companion"/"Avoid" badge with actual type (Companion, Attracts, Nurse crop, Trap crop, Avoid). Heading already provides section context so the badge now adds signal instead of duplicating it. Adds i18n keys for ATTRACTS, NURSE, TRAP_CROP across all locales. Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…es, and leaderboard - Prisma: 10 new models (UserCredit, CreditTransaction, ResearchQueue, ResearchLog, ResearchPrice, PotTransaction, ResearchFunder, UserBadge, FeedbackVote, FeedbackComment) with 7 new enums; migration applied to dev DB - Credits: atomic spend/top-up/refund via Stripe payment intents + webhook - Community pot: Ko-fi webhook → pot ledger → auto-fund top-voted pair via cron - Research queue: FIFO, deduped by crop pair, PERSONAL/POT/ADMIN triggers - Badges: INCREMENTAL (1/10/30/50/100…), PLANT (per botanical name), PAIR; slug-keyed dedup - Leaderboard API: research count by period (all/yearly/monthly/weekly/daily), community aggregated entry, hidden if ≤1 user in period - Admin: /admin/research-queue page (enqueue pair, update status); nav link added - Stripe: create-payment-intent + webhook routes (503 when keys absent) - Ko-fi: webhook route with verification token guard, idempotent via transaction id Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced Jun 8, 2026
Job was noisy and no longer needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(payments): add Stripe frontend payment flow - Install @stripe/stripe-js and @stripe/react-stripe-js - Add GET /api/credits/balance route returning user balance - Add TopUpModal with preset €2/€5/€10 + custom amount, Stripe Elements checkout, and success state - Add UserBalance component showing balance + top-up button in header - Replace ResearchFundButton Ko-fi link with TopUpModal; falls back to disabled button when NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is unset Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(payments): wire UserBalance to nav, enable Stripe Tax Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add Stripe env vars to .env.example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(payments): restore Ko-fi as fallback when Stripe not configured Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(payments): show Ko-fi and Stripe simultaneously, not as fallbacks Ko-fi = public/anonymous funding, Stripe = private logged-in top-up. Both render independently when their respective env vars are set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update pnpm lockfile with @stripe/react-stripe-js and @stripe/stripe-js Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(admin): add index page redirecting to /admin/feedback * fix(admin): add landing page with nav links; add mobile hamburger menu - /admin now shows card grid linking to sub-pages instead of redirecting - Header admin link points to /admin (was /admin/feedback) - Mobile: hamburger toggles slide-down nav; desktop nav unchanged Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…arams types (#247) Co-authored-by: JustTB <franz.gatzke@googlemail.com>
…243) - credits: replace upsert+check with upsert then SELECT FOR UPDATE to prevent concurrent overdraw - credits: add idempotency guard in applyTopUp — skip if stripePaymentIntentId already recorded - admin queue: call refundCredits() for personal funders when admin takes over a pending entry - pot: fix tryFundFromPot filter to check exact (cropAId, cropBId) pair via raw SQL subquery instead of broad cropA.researchQueueA.none filter that excluded all pairs sharing cropA - badges: change PLANT badge slug to use botanicalName so two cultivars of same species share one badge - stripe webhook: remove dead Pages Router config export - kofi webhook: reject non-2-decimal-place currencies (JPY etc.) with 422 to prevent 100x overcrediting - auth: refactor sendEmail helper shared by verification and password reset; add sendResetPassword - auth-panel: add forgot password flow (email → reset link sent confirmation) and resend verification button - reset-password page: new page at /[locale]/reset-password handling better-auth token from URL - i18n: add 13 new Auth keys to all 10 locale files Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…244) * fix(enrich): restrict GBIF vernacular lookup to de/es/fr/pt GBIF crowd-sourced coverage is near-zero for ar/hi/ja/ru/zh-Hans. Running GBIF for those locales burns 2 API calls per crop for days with 0 results. Add GBIF_SUPPORTED_LOCALES guard that silently downgrades source to wikidata for unsupported locales. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(enrich): add hi to GBIF_SUPPORTED_LOCALES GBIF returns real Hindi vernacular names (language: "hin") sourced from Catalogue of Life — confirmed for common cultivated plants. Coverage is partial (~20-40%) but real data exists. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(enrich): add AGROVOC source for Arabic (ar) translations Parses the AGROVOC NT bulk dump (CC BY IGO 3.0) to build an in-memory en→ar label index via skos:prefLabel/@ar + skos:altLabel/@en triples, then matches each crop by botanical name, canonical name, English common names, and synonyms. No network calls after file read — runs offline. Usage: pnpm enrich:translate-names --locale ar --source agrovoc --agrovoc-dump ./agrovoc_base.nt Download dump from https://www.fao.org/agrovoc/releases (choose NT format). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(enrich): auto-download AGROVOC dump for ar enrichment Downloads agrovoc_core.nt.zip (~70 MB) from the FAO latestAgrovoc redirect, extracts the NT file to a temp dir, parses it, then deletes all temp files in a finally block — no persistent files left behind. Pass --agrovoc-dump <path> to skip the download and use a local NT file instead (useful for repeated test runs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(enrich): fix AGROVOC NT parser for SKOS-XL label structure AGROVOC uses skos-xl:prefLabel/altLabel (two-hop indirection via xl_lang_TIMESTAMP label nodes) rather than plain skos:prefLabel literals. Old regex matched nothing — 0 en→ar mappings. New parser collects concept→labelNode and labelNode→text separately, filtering to /xl_ar_/ and /xl_en_/ URIs to skip all other languages. Joins in two passes (prefLabel then altLabel) to build en→ar index. Tested on dev DB: 54,401 en→ar mappings built, 2,119 new ar crop translations saved on top of 5,034 already from Wikidata. Also moves download progress to stderr to avoid polluting stdout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(enrich): tighten AGROVOC lookup — botanical names only, Arabic script guard Remove English commonNames from lookup candidates; only botanical name, canonical name, and botanical synonyms are used. English common names are too broad (e.g. 'onion' matches multiple species). Add Arabic script guard (/[-ۿ]/) to reject AGROVOC results that contain no Arabic characters — filters Latin names stored as Arabic labels in AGROVOC. Result: 2,371 clean ar translations saved (vs 2,119 before filter). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(enrich): rename 'synonyms' → 'botanicalSynonyms' in log labels Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(enrich): extend AGROVOC source to ru and ja Generalize buildAgrovocIndex(ntPath, targetLang) to support any locale with AGROVOC coverage. Add AGROVOC_SUPPORTED_LOCALES = {ar, ru, ja}. AGROVOC has ~41K Russian and ~30K Japanese agricultural concepts — same NT dump, same SKOS-XL parsing, different xl_{lang}_ URI filter. Tested on dev DB: ru: 54,405 en→ru mappings, 20 new translations (Wikidata already covers most) ja: 39,691 en→ja mappings, 1,835 new translations Also replaces the Arabic-script-only guard with isBotanicalName() which works across all three locales (rejects Latin-name fallbacks AGROVOC uses when no vernacular translation exists). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
JustTB
commented
Jun 9, 2026
…248) Extends admin-digest tests with: weekly/Monday skip logic, 24h vs 7d date window verification, and email content checks (from, to, subject, html table rows). Adds admin-test-email tests: auth guard, SMTP/ADMIN_EMAILS validation, send behaviour, recipient and sender address assertions. Also converts require('nodemailer') in test-email route to dynamic import() — ESM is intercepted by vitest mocks, CJS require() is not. Co-authored-by: JustTB <franz.gatzke@googlemail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: JustTB <franz.gatzke@googlemail.com>
Co-authored-by: JustTB <franz.gatzke@googlemail.com>
- auth.setup.ts: creates e2e-admin + e2e-user via sign-up API, marks
emailVerified via Prisma, saves session cookies to .auth/admin.json
and .auth/user.json
- playwright.config.ts: adds 'setup' project (runs auth.setup.ts first);
chromium project depends on it
- admin.test.ts: extends existing unauth tests with:
- non-admin user: redirect + 403 guards + no Admin header link
- admin user: all pages reachable, card grid visible, sub-nav shown,
all GET API endpoints return 200 with correct shapes
- ci-e2e.yml: adds ADMIN_EMAILS=e2e-admin@test.local env var
- .gitignore: excludes tests/e2e/.auth/ (session state files)
Co-authored-by: JustTB <franz.gatzke@googlemail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…cate stripe deps Adds 20260608000001_add_research_funding_system tables/types to seed.sql. Removes duplicate @stripe/react-stripe-js and @stripe/stripe-js entries from package.json introduced by stash-pop merge conflict. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All NEXT_PUBLIC_* vars now flow through at runtime with no values needed at docker build time, making the image a generic OSS artifact. How it works: - src/lib/client-env.ts: thin wrapper that reads window.__ENV__ in the browser and process.env[key] (bracket notation) on the server. Bracket notation bypasses Next.js DefinePlugin so the server bundle never has values statically inlined. - src/app/[locale]/layout.tsx: server component injects window.__ENV__ via an inline <script> tag rendered at request time, reading from the real process.env. Runs before any client JS, so window.__ENV__ is always set when client modules initialise. - Client components (research-fund-button, top-up-modal, auth-client): replace process.env.NEXT_PUBLIC_* with clientEnv helpers. - API routes (mcp, agent-instructions): bracket notation so server bundle reads from runtime env, not a build-time baked string. - Dockerfile: remove placeholder ENV block (no longer needed). - docker-entrypoint.sh: remove sed replacement (no longer needed), just migrate + start server. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The build->runtime env migration moved NEXT_PUBLIC_APP_URL into the app service's runtime environment but missed the Stripe publishable key and Ko-fi URL, which were build args on the prior image. With build-time baking gone they were dropped entirely. Restore them as runtime env so window.__ENV__ exposes them again. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With env injected at runtime via window.__ENV__, the NEXT_PUBLIC_ prefix is misleading (implies build-time baking) and a footgun: any dot-notation process.env.NEXT_PUBLIC_X read would be inlined to "" at build. Rename to plain names — APP_URL, STRIPE_PUBLISHABLE_KEY, KOFI_URL — which Next.js cannot inline into the client bundle, so the clientEnv helper is the only path to them on the client. Updates code, compose, CI, .env.example, and deploy docs. BREAKING (deploy): rename these three vars in staging/prod .env files.
Add brand to the runtime public-env helper (clientEnv.brand(),
default "power2plant"), injected through window.__ENV__ on the
client and read from process.env on the server. No build-time
baking — the image stays unflavored and the brand is set per
deployment through docker compose environment.
Replace user-facing brand literals: header logo, page-metadata
title, auth emails, Mollie payment/donation descriptions, feedback
digest subject, research agent instructions, low-balance admin
alert. i18n backHome strings use a {brand} placeholder.
Wire BRAND_NAME as runtime env in docker-compose.yml and
docker-compose.dev.yml; document it in .env.example.
Technical identifiers (localStorage keys, MCP server name, HTTP
User-Agent, app URL) intentionally left literal.
Stacked on #299 (feat/ghcr-build) for the runtime-env infra.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lled text Light-mode foreground (#2D4A3E) and muted-foreground (#5A6E60) were too similar — placeholder text was nearly indistinguishable from real input. Apply placeholder:text-muted-foreground/50 to: - ui/Input base component (covers all Input-based fields) - feedback-button.tsx textareas (raw <textarea>) - admin/feedback raw <input> - admin/settings raw <input> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a (landing) layout that renders SiteHeader (matching the (app) layout), so the landing page carries the same nav/brand/auth header as the rest of the app. Drop the landing's bespoke top bar (LocaleSwitcher + AuthPanel) now that the header provides them. Update the smoke tests that still assumed the old card landing with a `power2plant` <h1>: assert the header banner + brand link and the hero <h1> instead, and anchor the sign-in no-layout-shift check on the banner. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat: build Docker images on GH Actions, runtime env injection
fix(ui): reduce placeholder opacity to distinguish from filled text
feat: configurable brand name at runtime (NEXT_PUBLIC_BRAND_NAME)
feat(admin): research session detail + real LLM cost capture
feat(ui): public user profile page with badges
feat(ui): show genus sources on relationship detail page
feat(ui): show research funders on companion page
feat(ui): unreviewed/conflicting badges on relationship pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(ui): research leaderboard page
next build's PageProps validation requires dynamic route params to be a Promise (unwrapped via React use()); the merged #292 used a sync `{ params: { id } }` signature, which passed tsc but broke the build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
github.repository is "Ecohackerfarm/power2plant" (capitalised org), but ghcr.io rejects uppercase repository paths, so the staging image push failed. Hardcode the lowercase image name via an env var. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
next build runs with NODE_ENV=production but without runtime secrets (they are injected at container start), so the module-load checks for BETTER_AUTH_SECRET / BETTER_AUTH_URL threw while collecting page data and broke the image build. Gate them on NEXT_PHASE so they only fire at real runtime, not during the build phase. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The funders feature (#291) added a prisma.researchQueue.findFirst call to the companions route, but the unit test's prisma mock lacked researchQueue, so every test threw on undefined.findFirst. Add the mock and default it to null (no funders). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The images publish to ghcr.io as private packages, but the VPS deploy did `docker compose pull` with no registry auth, so it would fail unauthorized. Add scripts/server/ghcr-login.sh (run before each pull in deploy.sh and staging-deploy.sh) that logs the deploy user into ghcr.io using GHCR_USER/GHCR_TOKEN from .env. No-op when GHCR_TOKEN is unset, so making the package public later needs no code change. Document GHCR_USER/GHCR_TOKEN (read:packages scope) in .env.example, server-setup.md, and the setup.sh post-install hints. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fine-grained tokens don't support the GHCR container registry, so the deploy token has to be a classic PAT with the read:packages scope. Correct .env.example and server-setup.md accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ghcr.io authenticates by the PAT; the docker login username is a throwaway (helper defaults it when unset). Relabel GHCR_USER as optional and put GHCR_TOKEN first across .env.example, server-setup.md, and setup.sh hints. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ump-prod dump-prod-anonymized.sh pulls the private ghcr.io/.../:scripts image but never logs in, so it only worked when the image was already cached. The nightly staging-dump-refresh timer and any manual run hit `error from registry: unauthorized` whenever the image is absent or the deploy user's ghcr token has rotated. deploy.sh authenticates via ghcr-login.sh, but that logs in the deploy user and assumes the caller then runs compose as deploy. This script runs its compose calls as the invoking user (root for a manual run), so log in that same user inline before the first pull. No-op when GHCR_TOKEN is unset. Once pulled the image is daemon-global, so later sudo -u deploy steps in staging-dump-refresh.sh find it locally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two schema-drift failures surfaced once the ghcr pull was fixed and the
dump actually ran:
- `set-admin-credentials.ts` failed with P2022 (column user.trustedResearcher
does not exist). It ran inside dump-prod-anonymized.sh, i.e. against the
freshly prod-restored DB, before the app applies pending migrations. The
typed Prisma client selects every modelled column, so it needs the current
schema. Move the step into staging-dump-refresh.sh, after the app restart
(which runs `prisma migrate deploy`) and before the step-2 dump-save, so the
schema is current and the known password lands in the saved staging dump.
- The anonymize step aborted on `DELETE FROM "UserApiToken"` when prod's schema
lags staging (table not created yet). Guard it with a to_regclass check.
Also drops the now-dead `docker compose build scripts` line — the scripts
service is a pulled ghcr image with no build context ("No services to build").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(scripts): make staging dump-refresh + admin login work end-to-end
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's in this release
Features
Infrastructure / fixes
DB migrations (run `pnpm prisma migrate deploy`)
ENV variables
App (docker-compose `app` service) — new in this release
Research worker (`research-worker` service)
Invoice service (`profiles: [invoice]`) — opt-in via `COMPOSE_PROFILES=invoice`
Deployment steps (beyond rebuild + deploy)
Test plan
🤖 Generated with Claude Code
Update — v0.18.0 finalization (supersedes notes above where they conflict)
Merged after the original notes: #299, #307, #323, #292, #290, #291, #293, #294, #334, plus CI fixes.
Image build & deploy changed (#299)
ghcr.io/ecohackerfarm/power2plant(:stagingonrelease/*,:latest/:scriptsonmain). No build on the VPS.docker compose pull && docker compose up -d(scripts/server/deploy.sh,staging-deploy.sh).window.__ENV__(server readsprocess.env); nothing is baked into the image — it's a generic OSS artifact..envNEXT_PUBLIC_*dropped (runtime-injected now, not build args). The env table above uses the OLD names; use these instead:NEXT_PUBLIC_APP_URL→APP_URLNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY→STRIPE_PUBLISHABLE_KEYNEXT_PUBLIC_KOFI_URL→KOFI_URLNew env vars
BRAND_NAME— optional (defaultpower2plant); runtime-configurable brand name (feat: configurable brand name at runtime (NEXT_PUBLIC_BRAND_NAME) #334).GHCR_TOKEN(prod/staging) — classic PAT withread:packagesto pull the private image.GHCR_USERoptional (token authenticates; login defaults the username). Leave both unset only if the ghcr package is made public.Other merges
deletedAtfilter (feat(ui): unreviewed/conflicting badges on relationship pages #294)Extra one-time deploy steps
GHCR_TOKEN, or set the package Public.NEXT_PUBLIC_*vars in staging/prod.env(see above).Closes #222, #240, #241, #242, #285, #229