Commit graph

30 commits

Author SHA1 Message Date
19c0cbb232 qa: auto-fix safe findings + per-finding instructions box
- qa-autofix.php queues Web Designer tasks for safe findings (alt, internal
  links) with 6h dedup; runQaFlow runs it after each pass and kicks the queue
  (QA_AUTOFIX env, on by default)
- adminqa fix() accepts optional human instructions; /admin/qa adds an
  instructions input per finding for the judgment calls
2026-07-24 10:39:15 +00:00
29938fcd7f content: remove outdated GitHub link (footer, resume, JSON-LD) 2026-07-24 10:33:16 +00:00
042cc8a7c0 web designer: QA fix: a11y — /resume
[published via task queue]
2026-07-24 10:30:04 +00:00
18db0de37b changelog: log the QA agent + sitemap coverage fix 2026-07-24 10:20:39 +00:00
d548d8a8a8 qa: hourly in-process heartbeat + run pruning
- runner: QA_HEARTBEAT_MIN (default 60) in-process timer runs a scheduled QA
  pass; one pulse ~90s after boot. Triage (LLM) skipped on clean scheduled runs
  to save tokens; only manual runs or runs with errors get a written summary.
- qa-finish.php prunes to the 50 most recent runs.
- systemd unit exposes QA_HEARTBEAT_MIN for tuning.
2026-07-24 09:47:29 +00:00
56c1926b81 qa: QA agent — HTTP site testing with one-click Web Designer fixes
- migration 013: cja_qa_runs + cja_qa_findings
- runner: runQa (crawl pages/links/images/external/contact-probes/health/
  SEO/meta/sitemap/a11y), qaTriage (LLM summary via qa skill), /devconsole/qa/run
- qa-start/finish/routes.php CLI bridge
- adminqa controller (runs/findings/fix/ignore); fix() chains to the Web
  Designer queue; /admin/qa report page + nav link
- qa skill; contact form probed via honeypot (writes nothing)
2026-07-24 03:30:13 +00:00
f832752118 changelog: log this session's admin fixes + attribution/self-logging 2026-07-24 02:52:55 +00:00
75dcfc3098 Revert "web designer: Changelog self-log test"
This reverts commit d0924ffadf.
2026-07-24 02:47:24 +00:00
d0924ffadf web designer: Changelog self-log test
[published via task queue]
2026-07-24 02:46:57 +00:00
df5e5f9456 changelog: 'by' attribution + Web Designer self-logs via the skill
- migration 012: cja_changelog.actor column
- seed-changelog: optional 5th 'by' element (defaults to Carlos Arias);
  display shows 'Added · time · by <actor>'
- changelog skill documents the actor field + attribution logic (agents name
  themselves, human/CLI edits are Carlos Arias)
- Web Designer prompt now logs each change to the changelog via the skill,
  attributed to 'Website Designer Agent'; runner reseeds cja_changelog when the
  seed file changed (the agent has no shell)
2026-07-24 02:45:53 +00:00
497f55364b changelog: admin + Web Designer arc; document the engine update
- seed-changelog: 5 entries (admin console, self-editing agent, uploads,
  project builder, Web Designer + task queue)
- .memory/webdesigner.md: core Astroagent console update — architecture,
  decisions, safety model, files, and the site-coupling caveat
2026-07-24 01:28:09 +00:00
7fc99415b4 web designer: task queue engine + CLI-native design skills
- .claude/skills/: brand skill (from BRAND.md) + ui-ux symlink, so the CLI
  loads design skills natively
- cja_tasks queue (migration 011) + admintasks controller (create/list/get/cancel)
- api/cli/tasks-next.php (atomic claim) + tasks-finish.php
- runner: buildDesignPrompt, runDesignTask (clean-tree guard, build-gate,
  auto-publish commit or revert), drainTasks loop, POST /devconsole/tasks/run
2026-07-24 00:16:39 +00:00
ad0892a539 Revert "web designer: Queue engine test"
This reverts commit d4ee3ff960.
2026-07-24 00:14:44 +00:00
d4ee3ff960 web designer: Queue engine test
[published via task queue]
2026-07-24 00:14:28 +00:00
faef1c3229 admin: Web Designer agent builds full project pages from a brief
- console /build-project: Read-only agent reads uploaded images and authors a
  complete cja_projects record (copy, kind/period/role, categories, stack,
  grouped skills, metrics, per-image captions). Server re-zips gallery srcs.
- adminprojects save()/get(): handle skills + metrics JSON columns
- New Project form: 'Build with Web Designer' + full editable preview
  (skills groups, metric cards, captions merged into gallery)
- editor: round-trip skills + metrics editing
2026-07-23 23:44:50 +00:00
a88cc41557 admin: New Project page with agent-drafted copy + full editor
- /admin/projects/new: name, category, description draft, agent prompt,
  image upload, Instagram link
- console /draft endpoint: one-shot Claude copy drafting (summary/lede/body)
- editor now edits all project text fields, not just gallery
- adminprojects create() + expanded save()
2026-07-23 23:23:33 +00:00
a2da708418 Phase 2/3: projects media admin (galleries + Instagram)
- /admin/projects list + /admin/projects/edit gallery editor (AdminLayout chrome,
  session-guarded). Upload/replace images per slot, captions, add/remove,
  Instagram reel URL. Save -> cja_projects -> rebuild -> live.
- adminprojects API (list/get/save); media path validation (local paths only).
- runner /rebuild endpoint: build public/ + commit after structured edits.
- Ownership: app/ + public/ now owned by carlos-arias-agent:caweb so the agent
  can rebuild its own output; www serves via the caweb group. Documented in
  SETUP.md — never build as root.

Verified end to end: upload image -> save to gallery -> rebuild -> image live on
the project page and served.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 22:55:32 +00:00
dc69d1fd0d Phase 2: media upload pipeline
- cja_media table; POST /api/media/upload (admin-gated, multipart).
- Images optimised with GD (downscale to 1600px, re-encode; WebP for
  transparency, JPG for photos). Video via ffmpeg (scale, compress, drop audio).
- Stored in app/public/media/ (source tree) so uploads survive rebuilds and are
  copied into public/ on build.
- requireAdmin() moved to PublicController base (fixes a static/non-static
  clash with AdminAuth). Type detection uses getimagesize (fileinfo ext absent).

Note: php-fpm must be in the caweb group to write app/public/media (restart
after adding www to caweb).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 22:45:45 +00:00
b967419717 Phase 1: admin login page + secret-link token auth
- /admin login page (public, noindex): password form + signed-in panel that
  activates the in-page console. Verified in-browser: login -> panel -> the
  astroagent handle appears on other pages.
- Secret-link login: visit /admin/<token> to sign in without a password.
  adminauth token() validates a bcrypt-hashed token, sets the session, 302s to
  /admin. nginx routes the token path to PHP. set-admin-token.php generates it.
- Password login kept as a fallback.

Verified: token link -> session -> console access; bad token -> /admin?e=1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 22:15:50 +00:00
e57856173a Phase 1: console runner service + nginx gate + systemd
- agents/console/server.mjs: Node runner (as carlos-arias-agent, 127.0.0.1:3011).
  run/stream(SSE)/publish/discard/ping/auth. Agent edits files (no Bash); the
  runner builds isolated previews and git-commits on publish. Git ops scoped to
  content paths (app, brand, api/db, api/cli) — never infra or secrets.
- adminauth check() — nginx auth_request target (204 admin / 401 not).
- nginx: /devconsole + /_preview gated by auth_request, runner proxied,
  previews admin-only. Runner never exposed directly.
- systemd unit (hardened: NoNewPrivileges, ProtectSystem, scoped ReadWritePaths).

Verified end to end: admin login -> agent edits about.astro -> isolated preview
(admin-gated) -> discard reverts. Unauthenticated access is 401 throughout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 20:53:32 +00:00
59019d2f32 Phase 0: admin console foundation
- cja_admin + cja_admin_log tables (dedicated single-admin tier + audit trail)
- AdminAuth controller: /api/adminauth login/logout/me, session-based,
  rate-limited, every attempt logged
- set-admin-password CLI (bcrypt, run manually so the password never enters
  an agent context)
- requireAdmin() guard for future privileged console endpoints
- agent env scaffold (git-ignored)

Foundation only — no agent runner or features yet. Preview/publish, media,
and the dashboard come in phases 1-3 per agents/console/PLAN.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 20:23:48 +00:00
43ae1e2015 Baseline: full site build (brand, pages, DB, agent-editable)
Establishes the deploy baseline on main so the admin agent's publish/rollback
has a clean starting point. Everything built to date: sumi-e brand system,
homepage, projects (DB-driven case studies), resume, about, services +
website-design detail, contact form + DB, changelog, favicon + share card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a
2026-07-23 20:21:28 +00:00
41f1b941fa Merge: trusted-IP throttle exemption + session hardening 2026-07-11 09:16:30 -05:00
5d1505d666 Merge: user auth (email + Google OAuth), Mailer, CLI bridges 2026-07-11 09:16:30 -05:00
1f33296e30 feat: user auth (email + Google OAuth), Mailer, and CLI bridges
Generic framework features, code-only — the tables come from the schema snapshot:

- controllers/account.php — email signup (verified) + Google OAuth (server-side auth-code
  flow, async-popup friendly); native password_hash sessions on sp_users; sp_oauth_accounts +
  sp_user_tokens; PublicController origin+throttle guards; {ok,data,error} envelope.
- Helpers/Mailer.php — transactional email: Brevo HTTP API (Guzzle) -> SMTP fallback
  (PHPMailer) -> logs; config in sp_settings (encrypted).
- cli/rebuild.php — queue a static rebuild (sp_settings rebuild_pending flag) after DB edits.
- cli/resources.php — read a curated source registry (mde_resources) per agent_type.
- db/seed_google_oauth.php, db/seed_email.php — env-seeded encrypted secrets into sp_settings.
- templates/emails/verify.html — verification email template.
- composer.json — declare guzzlehttp/guzzle ^7.10 (account.php + Mailer use GuzzleHttp\Client).

Depends on the schema-snapshot branch (sp_users / sp_oauth_accounts / sp_user_tokens /
sp_settings / mde_resources) plus `composer require guzzlehttp/guzzle`. No data.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FMQeUnUrAeexcZ7P2Hxa6G
2026-07-11 09:14:25 -05:00
c542092a2a chore(db): add full schema snapshot (structure only) to bring the base current
Structure-only export from a live SeedProject site (68 tables: the sp_ framework — users,
oauth, tokens, settings, roles/permissions, api_requests, orgs, saas/billing, menus, kathe —
plus the mde_ content model: content, directory, events, comments, reactions, categories…).

Every table is CREATE TABLE IF NOT EXISTS, so it composes with the existing 001/002 migrations
and only fills in what's missing. This modernizes the base off the legacy `usergen`/`api_requests`
schema and is the prerequisite for porting the auth system, Mailer, and resource registry upstream.
No data included.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FMQeUnUrAeexcZ7P2Hxa6G
2026-07-11 09:08:46 -05:00
3f69000d27 feat: never throttle trusted server-local callers + harden session cookie
Two self-contained framework fixes, no schema dependencies:

- throttle(): exempt trusted callers via new Functions::isTrustedIp() — loopback, the
  server's own IP, and an optional TRUSTED_IPS config allowlist (IPs/CIDRs). Fixes the SSG
  build (which fetches the read API from the box thousands of times per build) tripping the
  public rate limit and baking empty data into the deploy. Public client IPs stay limited.
- public/index.php: set secure session cookie params (httponly, SameSite=Lax, secure on
  https) before session_start, so session/login state rides on a hardened cookie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FMQeUnUrAeexcZ7P2Hxa6G
2026-07-11 09:01:49 -05:00
f41fa652ac fix: repair the fresh-clone flow — track api/public + app/public, fix installer schema
Three bugs found deploying a fresh clone to seedproject.com, each fatal
to the documented "spin up a new site" flow:

- .gitignore: the unanchored `public/` pattern (meant for the root build
  output) also ignored api/public/ (the framework's front controller,
  controllers, models, views) and app/public/ (theme static assets:
  fonts, avatar placeholder). Neither was ever committed, so every fresh
  clone 500'd on all /api routes and 404'd on theme assets. Anchor the
  pattern to /public/ and commit both directories.

- api/install/dump.sql: stray `CREATE DATABASE ochenta80_db123` (SQLyog
  export artifact) aborted `php console app:install` for any
  non-privileged DB user. The schema must import into whatever database
  the installer connects to.

- PluginManager::boot() queries sp_plugins on every request, but no
  shipped schema creates it — even a successful install 500'd on every
  endpoint. Add migration 002_create_sp_plugins.sql matching the columns
  PluginManager reads/writes.

Also empty api/system/errors.json, which shipped with stale error logs
from an unrelated project.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3JqxTe7TKaR7xufcMr7Ds
2026-07-05 00:15:55 +00:00
1fdfc3174b feat(api): Foundation — installer, migrations, two-tier auth, health round-trip
Builds the /api Foundation into the base (per api/.memory/foundation-plan.md):
- app/Services/Installer.php  DB test + dump.sql import + crypto keys + /api config + lock
- app/Services/Migrator.php   versioned db/migrations/*.sql runner (+ migrations table)
- commands/InstallCommand.php (app:install), commands/MigrateCommand.php (db:migrate)
- app/Controllers/{JsonController,PublicController,ApiController}  envelope + two-tier auth
- public/controllers/{health,admin}.php  GET /api/health (public), /api/admin/ping (bearer)
- db/migrations/001_*.sql  smoke migration
- install/controllers/index.php  web wizard now delegates to Installer (path bugs fixed, lock)
- console + composer.json  register commands / add commands to classmap
- app/src/pages/api-health-test.astro  browser round-trip proof page

Verified (no DB): composer install OK; php console lists app:install + db:migrate;
PSR-4 classes autoload; CLI fails gracefully (validation, bad DB, missing config) with
no artifacts left; app builds 14 pages. Live DB + HTTP round-trip pending a served instance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYHWLHihq3v9nxNwoPCKSn
2026-07-04 23:23:51 +00:00
1559ce017d chore: scaffold SeedProject base (Phase 1)
Clean-room copy of the reusable engines from comiida, with all
instance data, secrets, dependencies, and build output excluded:
- app/         Astro theme skeleton (no comiida blog posts; hero image -> placeholder)
- api/         SeedProject PHP framework (no vendor/.env/config.php)
- content-pipeline/  engine only (scripts/admin/prompts; empty runtime state)
- astroagent.config.json + app/.astroagent/skills

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYHWLHihq3v9nxNwoPCKSn
2026-07-04 22:53:10 +00:00