Commit Graph
4 Commits
Author SHA1 Message Date
steve e22bdd6cab Copy a garden (deep duplicate) from the gardens list (#46)
Build image / build-and-push (push) Successful in 16s
Co-authored-by: Steve Dudenhoeffer <[email protected]>
2026-07-21 03:58:39 +00:00
steveandClaude Opus 4.8 0793fef17c Address Gadfly review on #10: clearable color/props, column lists, dedup
Build image / build-and-push (push) Successful in 7s
Fixes from the PR #28 adversarial review (considered; not graded).

Correctness / API
- PATCH /objects/:id can now clear nullable color/props back to NULL: the
  request takes them as json.RawMessage, and ObjectPatch carries an explicit
  Set flag so an explicit `null` (clear) is distinguished from an absent
  field (unchanged) — the strongest cross-model finding (6 hits). New test.

Maintainability
- store/plantings.go + plants.go use explicit qualified column lists
  (qualifyColumns helper) instead of SELECT *, matching gardens/objects and
  surviving a future column add.
- Consolidated objectKinds + plantableByDefault into one kind→traits map.
- objectForRole factors the fetch-then-authorize shared by UpdateObject and
  DeleteObject; dropped the redundant kind check in CreateObject
  (finalizeObject is the single validation point).
- Request→service mapping via toInput()/toPatch() methods (matches gardens).
- Renamed handler gardenFull → getGardenFull (verbNoun); test helper
  decodeGarden → decodeMap; generic bind-error messages.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JdQpdYYsTgtkJBxbcpAszi
2026-07-18 19:47:10 -04:00
steveandClaude Opus 4.8 0f3dedab73 Address Gadfly review findings on Phase 0
Applied the fixes warranted by the adversarial review of PR #21 (all
findings graded in the gadfly store):

Store (highest impact):
- buildDSN always merges busy_timeout/journal_mode/foreign_keys pragmas
  into the DSN, even for file: URIs or paths with a query string — the
  prior passthrough silently disabled FK enforcement for those PANSY_DB
  values. Also escape '#' in the path and tighten in-memory detection to
  an exact ':memory:' token or mode=memory param (no substring misfire).
- migrate.go: detect duplicate migration versions with a clear error;
  wrap appliedVersions' rows.Err() with the store: prefix.

API:
- SetTrustedProxies failure now falls back to trust-none instead of
  leaving gin's trust-everyone default (X-Forwarded-For spoofing).
- SPA: 404 embedded directories (was a directory listing), 404 bare /api,
  add X-Content-Type-Options: nosniff, cache index.html bytes once at
  startup, single fs.Stat existence check, shared writeAPIError helper.
- Move gin.SetMode out of package init() into New().

Config: validate PANSY_PORT range (fall back to 8080 with a warning).

Web:
- api.ts: serialize the request body before the fetch try so a
  JSON.stringify failure isn't misreported as a network error.
- AppShell: move state-specific/conflicting utilities into
  active/inactiveProps so concatenated Tailwind classes don't collide.

Tests: added store DSN-pragma/memory-detection cases and SPA
directory-404 case. go build/vet/test clean (CGO off); web tsc + build
clean; re-verified in a browser (SPA, deep links, /assets 404, nav).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JdQpdYYsTgtkJBxbcpAszi
2026-07-18 15:19:30 -04:00
steveandClaude Opus 4.8 91da9ff945 Phase 0: backend + frontend scaffold, single-binary build
Gadfly review (reusable) / review (pull_request) Successful in 10m8s
Adversarial Review (Gadfly) / review (pull_request) Successful in 10m9s
Implements the Pansy v1 scaffold (epic #20, phase 0).

#1 Backend: Go module (pure-Go, builds with CGO_ENABLED=0), env config,
   gin server with slog + recovery + /api/v1/healthz, modernc SQLite store
   with WAL/busy_timeout/foreign_keys pragmas, embedded numbered-migration
   runner, full initial schema (users, sessions, gardens, garden_shares,
   garden_objects, plants, plantings), domain structs + sentinel errors,
   graceful shutdown.

#2 Frontend: Vite + React 19 + TS (strict) + Tailwind 4 + TanStack
   Router/Query, typed /api/v1 fetch wrapper (ApiError carries status +
   body so later issues can read 409 conflict rows), dev proxy /api -> :8080,
   responsive app shell with stub pages for all five routes.

#3 Single binary: //go:embed of the web build with a committed placeholder,
   SPA fallback (deep links, immutable asset caching, JSON 404 for unmatched
   /api and missing assets), Makefile (web/build/dev/test), README quickstart
   + env var table.

Verified: go build/vet/test clean (CGO off); binary migrates idempotently and
serves healthz; web tsc + build clean; integrated binary serves the SPA, deep
links, and correct cache headers; app mounts and navigates all five routes at
desktop and 375px widths.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JdQpdYYsTgtkJBxbcpAszi
2026-07-18 14:52:05 -04:00