12 Commits

Author SHA1 Message Date
Oleks 0be268307e style: auto-format from pre-push hooks
ci/woodpecker/push/container Pipeline was successful
2026-06-14 14:25:22 +03:00
Oleks 0072716733 fix(seed): rename reserved 'status' field to 'parity_status'
ci/woodpecker/push/container Pipeline was canceled
emdash reserves 'status' as a built-in entry field (publish state), so
'emdash seed' rejected the plugins collection's custom 'status' select
with 'Field slug status is reserved' — leaving the catalog empty. Rename
the domain field slug to parity_status (label stays 'Migration status')
across the seed field def + 39 entries, the collections type, and all
plugin-data reads. The public ?status= URL filter param and StatusBadge
prop name are unchanged.
2026-06-14 14:25:15 +03:00
Oleks 9b1090b614 style: auto-format from pre-push hooks
ci/woodpecker/push/container Pipeline was successful
2026-06-14 14:06:48 +03:00
Oleks 87eb6a0f84 fix(seed): add required id to seed entries + make seed non-fatal
ci/woodpecker/push/container Pipeline was canceled
emdash seed validates that every content entry has an id (validate.ts),
but seed/seed.json entries only had slug — so seed aborted with 'id is
required' and, under set -e, crash-looped the pod (502). Set id=slug for
all 42 entries (conflict-detection keys off slug, so id is just the
seed-local ref key). Also move the seed step out from under set -e: a bad
content seed should log loudly but not take the whole site down (init
migrations stay fatal).
2026-06-14 14:06:41 +03:00
Oleks 96c220825f fix: seed catalog on boot + emit https canonical/og:url
ci/woodpecker/push/container Pipeline failed
- entrypoint: run 'emdash seed' after 'emdash init' (init no longer loads
  JSON seeds in newer emdash, so the catalog booted empty). Idempotent
  onConflict=skip.
- Base.astro: derive canonical/og:url base from EMDASH_SITE_URL (per-env
  https URL the chart injects) instead of Astro.url.origin, which is plain
  http behind Traefik TLS termination.
2026-06-14 13:59:21 +03:00
Oleks 90a4b8088b fix(#4): consistent normalized plugin↔CMS join + orphan-ref check
Interim fix for the free-text title-match footguns (issue #4); durable ULID
reference + seed migration tracked separately.

- New lib/cms.ts: single normCms() match key + cmsSlugByTitle / resolveCmsSlug,
  used by all three join sites so a plugin can no longer link from its own page
  yet vanish from a CMS list over case/whitespace drift.
- cms/index.astro + cms/[slug].astro: counts and "plugins from / targeting"
  lists now use the normalized key (were exact-match).
- plugins/[slug].astro: drop the local normalize copy; link target_cms too
  (was source-only) for parity.
- warnOrphanCmsRefs(): logs any source_cms/target_cms that resolves to no CMS,
  so silent orphans surface in the server log.
2026-06-02 05:05:30 +03:00
Oleks 8c119efff8 harden(deploy): apply safe fixes from review report-only items
- #3 Liveness probe targets full SSR DB-querying / route, coupling pod liveness to SQLite
- #4 Chart values-staging/production.yaml are dead config under Flux; drift trap
- #6 tsconfig includes gitignored emdash-env.d.ts that only the dev server generates
- #7 Dockerfile package-lock glob + npm install fallback can silently build an unlocked image
- #8 Dockerfile creates runtime user without pinning its GID
- #9 entrypoint.sh gates `emdash init` on data.db absence, skipping migrations on PVC reuse
- #10 pullPolicy: Always vs digest pinning
- #11 Dockerfile state symlinks contradict the STATE_DIR contract; Dockerfile does not set ENV STATE_DIR
- #12 astro is a production dependency, so npm prune --omit=dev keeps build-only tooling
- #14 Two ImageUpdateAutomations write back to the same anton-helm-workloads main branch
- #16 memoryCache provider is per-process; correctness depends implicitly on replicas:1
- #17 Root catch-all [slug].astro couples nav links to pages-collection rows + DB hit per unmatched path
- #18 Detail pages render a 200-style body under a 404 status and have no try/catch around getEmDash* calls
- #19 vite allowedHosts hardcodes ddev hostnames (dev-only; no prod impact)
2026-06-02 04:50:54 +03:00
Oleks 0c2cea8c25 fix: architecture + UI/UX review fixes
Architecture:
- Cap homepage plugin list at PLUGIN_FETCH_CAP like other pages
- Declare @types/node directly instead of relying on transitive dep
- Single-source status label text (statuses.ts vs seed.json drift)

UI/UX:
- Stop auto-submitting filter selects so keyboard navigation works
- Fix heading hierarchy (add h2) on flat list pages
- Improve homepage title beyond bare "Plugins"
- Make status taxonomy descriptions self-contained
- Render only relevant statuses in the legend, not all 7
- Fix PluginCard "WordPress -> —" for missing target
- Clarify "{n} from / {n} targeting" microcopy
- Use proper count meta markup on CMS list
- Allow header nav row to wrap
- Fix bare CMS URL horizontal overflow
- Add standard line-clamp fallback to cards
- Even out footer stacked paragraph spacing
- Center plugin detail status line (drop margin-left hack)
- Raise toolbar tap targets to 44px
- Surface status badge meaning beyond title attribute
- Include source-CMS breadcrumb step on lookup miss
- Add link into filtered catalog from CMS detail
2026-06-02 04:16:58 +03:00
Oleks bfc6a65638 fix(app): architecture + UI/UX review fixes
Multi-agent arch/UX review pass. Architecture: real HTTP 404 on not-found,
breadcrumb links by slug not lowercased title, CMS pages surface their
plugins, shared status taxonomy (src/lib/statuses.ts) consumed by all three
frontend consumers, data-driven status filter, typed emdash collections
(src/emdash-collections.d.ts), removed unused @astrojs/react + react deps and
dead pnpm block, tsconfig extends Astro strict preset, dev deps pruned from
the runtime image. UI/UX: fixed StatusBadge WCAG-AA contrast, labelled the
search/filter controls, canonical URL + BreadcrumbList JSON-LD + og:type,
human status labels, filtered result count + recoverable empty state,
auto-submit filters, mobile overflow fixes, skip-to-content, :focus-visible.

Commit the npm lockfile so the Dockerfile's `npm ci` path engages.
astro check: 0 errors / 0 warnings / 0 hints.
2026-06-02 03:24:52 +03:00
Oleks cd2a663935 ddev bootstrap: make app/.env optional, add .env.example
Fresh clones errored out on `ddev start` because the compose file's
env_file: pointed at app/.env (gitignored). No env vars are actually
required by the code — STATE_DIR is the only one and has a default.

- Switch env_file to the path:+required:false form (Docker Compose
  2.24+; bundled with DDEV) so missing app/.env is non-fatal.
- Commit app/.env.example as documentation for contributors who do
  need overrides.
2026-05-20 14:13:38 +03:00
Oleks 14da750032 fix: bump astro to ^6.3.0 for @astrojs/node peer compat
ci/woodpecker/push/container Pipeline was successful
2026-05-20 11:55:27 +03:00
Oleks 67b07634ae initial scaffold: emdash catalog, helm chart, woodpecker pipeline, ddev
- app/: Emdash scaffold (Astro 6, node target) with cmses/plugins/pages collections
- app/seed/seed.json: WordPress→Emdash parity for kotkanagrilli.fi (~30 entries)
- Dockerfile + docker/entrypoint.sh: multi-stage build, single PVC at /app/state
- deploy/helm/: chart mirroring emdash-kotkanagrilli (single-replica, sqlite, kotkan)
- deploy/fleet-overlay/: HelmRelease/source/image-automation templates for
  anton-helm-workloads (staging + production)
- .woodpecker/container.yaml: arm64 build, three OCI tags per push
  (immutable 0.1.<pipeline> + floating <branch> + <branch>-latest)
- .ddev/: local dev with nginx proxy to emdash on :4321
- README/DEPLOYMENT/ARCHITECTURE/CLAUDE: docs covering the three-repo
  pipeline (cms-plugins + anton-helm-workloads + Gitea OCI registry)
2026-05-20 11:19:00 +03:00