22 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 7b60fe452e ci: use arch-scoped buildkit service (buildkit-<arch>) instead of per-instance
ci/woodpecker/push/container Pipeline was successful
2026-06-04 19:10:28 +03:00
Oleks 597f089c53 ci: echo build arch (uname -m) as first line of every step for visibility
ci/woodpecker/push/container Pipeline was successful
2026-06-02 13:44:45 +03:00
Oleks c284c27aa8 style: auto-format from pre-push hooks
ci/woodpecker/push/container Pipeline was successful
2026-06-02 09:29:45 +03:00
Oleks d8de7617fb ci(#192): thin .woodpecker via #196 escape-hatch (emmett#44)
ci/woodpecker/push/container Pipeline was successful
cms-plugins is an Astro/emdash web app whose image is built by npm/astro
against an upstream package-lock.json (better-sqlite3 native build) and
cannot be expressed as Nix on emmett/amd64, so it stays on docker buildx.

Apply the cluster #196 OCI escape-hatch: move all build/tag/registry truth
into ci/local.sh, parameterized by BUILDKIT_ADDR (local docker-container
default, dry-run; CI overrides to the in-cluster native arm64 remote +
PUBLISH=1). CI now runs the same script a developer runs, so CI and local
can't drift. The three-tag Flux ImagePolicy contract (0.1.<pipeline>,
<branch>, <branch>-latest) and the arm64/kotkan targeting are preserved
verbatim; the Dockerfile is unchanged.
2026-06-02 09:29:38 +03:00
Oleks 0b1f2ebfbc docs(#3): go-live note — floating tags must exist before flux resume
ci/woodpecker/push/container Pipeline was successful
While HRs are suspended (Phase 0) the staging/production tags are referenced by
no live workload, so gitea-oci-cleanup can reap them. Document the registry-pins
mitigation and a pre-resume existence check in the first-deploy checklist.
2026-06-02 05:05:30 +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 6e6fd76459 chore(docker): satisfy hadolint on the hardened Dockerfile
ci/woodpecker/push/container Pipeline was successful
- DL3008: explicit `hadolint ignore` on the two apt-get installs — bookworm-slim
  tracks current security-patched versions; pinning is brittle (reference image
  is also unpinned).
- DL3059: fold `npm run build` + `npm prune --omit=dev` into one RUN layer.
2026-06-02 04:59:20 +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 bdc43bb1d6 fix(deploy): align fleet-overlay blueprint with the live kotkan deploy
ci/woodpecker/push/container Pipeline was successful
The deploy/fleet-overlay templates had drifted from what actually runs in
anton-helm-workloads (verified live + against the emdash-kotkanagrilli
reference). Canonical design co-locates everything in the `kotkan` namespace:

- source.yaml: GitRepository flux-system -> kotkan, so the HelmRelease
  chart sourceRef resolves same-namespace (no cross-namespace ref).
- secrets.yaml: deploy-key Secret -> kotkan, defined once in the staging
  overlay; dropped the duplicate definition from the production overlay
  (production references the shared key by name).
- image-automation.yaml: IUA write-back sourceRef
  anton-workloads-image-automation/flux-system -> anton-helm-workloads/kotkan
  (the existing read source already has push access).
- README.md / DEPLOYMENT.md: namespace + ownership docs corrected.
2026-06-02 03:24:52 +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 4beb58ff48 README: add Windows / WSL2 note for ddev contributors
ci/woodpecker/push/container Pipeline was successful
2026-05-20 14:13:38 +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 14f57885d8 style: auto-format from pre-push hooks
ci/woodpecker/push/container Pipeline was successful
2026-05-20 12:29:20 +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 4ef082bd7d trigger: first CI build
ci/woodpecker/push/container Pipeline failed
2026-05-20 11:43:29 +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