Commit Graph

15 Commits

Author SHA1 Message Date
prosolis
90a74967e0 Refine item form and preview
- Item form: subtitle + fields grouped into hairline-separated labeled
  sections (Basics / Alerts / Schedule and marketplaces / Filters /
  Advanced) instead of one flat card; refined Advanced summary.
- Preview: refined headings; best-price hero keeps a 160px product image;
  Other results becomes a thumbnailed feed via the shared components.
- New .v-form-section-title helper.
2026-06-20 12:52:25 -07:00
prosolis
3760571d84 Roll out refined-minimal styling and product thumbnails across pages
Apply the dashboard's refined direction to the rest of the app:
- Items: page-title header, product thumbnail (best-price image) beside
  each item name via the shared thumbSm component.
- Results: refined headers; per-item and global tables get standardized
  thumbnails (global table gains a thumbnail column).
- Settings: page-title + subtitle, section headings restyled.
- Item form: page-title header.
- Shared: thumbSm component + compact thumbnail CSS variant.
2026-06-20 12:47:13 -07:00
prosolis
9a7f8b47a3 Redesign dashboard: refined-minimal layout with product thumbnails
Move the dashboard from boxed glass cards to an airy, hairline-separated
layout where type and whitespace carry the page, then surface listing
images as the visual anchor.

- Solid surfaces (drop backdrop-filter glass, per spec); calm flat field
  with a single cool top-glow replacing the drifting aurora and dot-grid.
- Recent results / recent alerts are now product feeds with 52px
  thumbnails, listing titles, and price; image_url threaded through
  ResultRow/AlertRow (data already stored, just unsurfaced).
- ListResults gains an OnlyAlerted filter so the alerts panel reuses its
  decryption path instead of a raw query.
- Dashboard recent results capped at 8 for a balanced snapshot.
2026-06-20 12:42:00 -07:00
prosolis
ed03494edf Window dashboard Money Saved to 30-day average 2026-06-20 11:57:54 -07:00
prosolis
2fd4019103 Let Authentik own forward-auth user emails; add forward-auth tests
For SSO users the email address is the IdP match key, so allowing them
to edit it in Veola orphaned the row on next sign-in. PostEmailPrefs now
keeps the synced Authentik email for forward users (only the deal-alert
and digest toggles stay editable); the settings form renders the field
read-only with a Managed by Authentik note. Local break-glass users keep
an editable field.

Add forward-auth integration tests over the full Routes() chain: trusted
proxy provisions an admin, untrusted peer's spoofed headers are ignored,
role re-syncs per request, and the email-prefs round trip confirms a form
cannot change a forward user's IdP email.
2026-06-20 11:26:02 -07:00
prosolis
7c95e4fd4e Add Authentik SSO, budget visibility, Resend email, 12h item default
Opens Veola up to more users (Parodia's Authentik) and makes Apify spend
visible to everyone.

- Auth: Traefik forward-auth (trust X-Authentik-* headers only from
  trusted_proxies CIDRs, keyed by email, role synced from admin_group),
  keeping local password login as break-glass. New [auth] config,
  CaptureDirectIP + ForwardAuth middleware, deploy/authentik-forward-auth.md.
- Budget: count every Apify run (apify_api_usage table) and show
  calls + estimated cost to all users on the dashboard, with an optional
  monthly-budget bar. New [budget] config + settings.
- Email: Resend client for opt-in deal alerts and a weekly digest
  (Mon 09:00). Per-user email + toggles on Settings. New [resend] config.
- Defaults: new items default to a 12-hour poll interval to cut spend.

users table gains email/auth_source/email-pref columns (migrated in place).
go build/vet/test green; boots and migrates cleanly.
2026-06-20 11:12:11 -07:00
prosolis
b6fadf6504 Let empty-result previews be tracked for future-listing alerts 2026-06-19 21:53:18 -07:00
prosolis
cf438f1a2d Upgrade build toolchain: Tailwind v4, htmx 2.0.9, Chart.js 4.5.1, Go 1.26
Tailwind v3.4.17 → v4.3.0: drop tailwind.config.js, move @source globs into
static/css/input.css (CSS-first config), rename bare `rounded` → `rounded-sm`
in templates for the renamed v4 radius scale.

Go 1.25 → 1.26.3 (toolchain directive), modernc.org/sqlite v1.50.0 → v1.50.1,
plus indirect bumps via go get -u.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 09:21:36 -07:00
prosolis
ea3577a45e Items-list sparklines, retro CSS, pinned tooling, deploy docs
- Bulk-load recent price points per item and render a sparkline in
  the items list (new LoadRecentPriceHistory query avoids N+1).
- Add retro.css visual layer and refreshed login/items/layout styling.
- Swap the logo from webp to avif.
- Pin htmx/Chart.js/Tailwind/templ versions in the Makefile with
  vendor / tools / update-deps targets; README documents the
  dependency-bump flow and the hardened systemd deploy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 19:10:56 -07:00
prosolis
0ec97afafb Fix price chart growing unbounded on item results page
Wrap the canvas in a fixed-height container so Chart.js's
responsive + maintainAspectRatio:false combo has a stable parent
to size against, instead of feeding back into itself each tick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 19:09:49 -07:00
prosolis
edb732ee1f Auction end times, visual flair, and pre-launch cleanup
Auction handling:
- Capture itemEndDate from eBay Browse API and ending_date from ZenMarket
  (Yahoo JP); plumb through results.ends_at column. Permissive ZenMarket
  parser (multiple layouts, JST when offset missing).
- Per-row "Ends" countdown column + "Ending soon" banner on results pages,
  live-ticked by flair.js with urgent/critical tinting under 1h/5m.
- Backfill ends_at for known auctions when their URL reappears in a poll
  (dedup hit no longer drops the new end time).
- Hide ended auctions from result listings by default via
  ResultsQuery.ExcludeEnded; rows stay in the DB.

Visual flair:
- Glassy backdrop-blur v-cards with gradient-mask borders and hover-lift.
- htmx swap fade-in via transient .v-just-swapped class.
- Count-up animation on dashboard stats. All animations gated behind
  prefers-reduced-motion.

eBay condition + region filters (auctions-style scoping):
- items.condition and items.region columns; threaded through item form,
  CreateItem/UpdateItem, scheduler eBay plan input, and previewKey so
  cache invalidates when these change.
- ebay.SearchParams gains conditionIds and itemLocationCountry filters.

Run Now reload + countdown engine:
- Run Now now sets HX-Refresh: true (non-htmx fallback: 303 redirect) so
  the entire results view — best price, chart, badge, last polled —
  reflects the new poll, instead of swapping just one partial.

Pre-launch hardening (P1 set):
- auth.EqualizeLoginTiming on no-such-user branch.
- (*App).serverError centralizes 500s; replaces err.Error() leaks across
  results/settings/items/users/dashboard handlers.
- main.go server: ReadTimeout 30s / WriteTimeout 60s / IdleTimeout 120s
  alongside the existing ReadHeaderTimeout.
- noListFS wrapper blocks static directory listings.
- Credential fields in settings no longer render value=; blank submission
  preserves the saved value, with per-field "Saved in settings / Set in
  config.toml / Not set" status indicator.

Misc:
- -debug flag wires slog to LevelDebug; raw ZenMarket items logged for
  format diagnosis.
- /healthz public endpoint for reverse-proxy probes.
- deploy/veola.service systemd unit template (hardening flags, single
  ReadWritePaths=/var/lib/veola).
- handlers_test.go covers /healthz, setup-gate redirect, auth gate, and
  /login render with httptest + in-memory sqlite.
- best_price_currency on items; templates pick the right symbol per row.
- .gitignore now excludes *.log / veola-debug.log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:47:09 -07:00
prosolis
d87536c879 Fix bugs found in local testing
- Dashboard auto-refresh rendered the full layout into its own
  refresh container, producing a duplicate sidebar every 60s; it now
  renders only the body partial.
- 'Run Now' runs synchronously with a bounded timeout and returns
  refreshed results plus success/error feedback, instead of
  firing-and-forgetting with no signal.
- Price-history chart data moved from a <script> block to a data-
  attribute: templ does not interpolate expressions inside <script>
  element content, so the JSON was emitted literally.
- The htmx indicator spinner was permanently visible due to CSS
  source order; the indicator rules now follow .v-spinner.

Also refreshes README for this session's changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:11:07 -07:00
prosolis
08ff1695e0 Vendor Tailwind via the standalone CLI; drop the Play CDN
Tailwind is now compiled from static/css/input.css into a committed static/css/tailwind.css by the standalone CLI, fetched on demand into bin/ (gitignored) so no Node toolchain is required. layout.templ loads the local stylesheet instead of cdn.tailwindcss.com. Adds a Makefile with generate/css/build/run/test/clean targets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:10:57 -07:00
prosolis
1ae2c50b9a Add eBay Browse API integration with daily call quota
eBay marketplaces are now polled through eBay's official Buy > Browse API (client-credentials OAuth2) instead of an Apify scraper actor; Apify still handles Yahoo JP and Mercari. Browse API calls are tracked per day in a new ebay_api_usage table and capped (default 5000, configurable) on eBay's Pacific-time reset clock, so polling halts before the limit is hit. Credentials live in config.toml [ebay] and are overridable via /settings, which also surfaces the day's running call count.

Also carries the server.secure_cookies config plumbing (field, accessor, example) consumed by the following commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:10:39 -07:00
cfa01bd4ef Initial commit 2026-05-13 19:42:49 -07:00