feat: full plan execution - CI/CD, critical fixes, UX polish, secondary/advanced features, E2E + docs
Phase 0 (CI/CD): fix root typecheck to cover api+worker+web; reconcile migration story into idempotent db:migrate (db:sync + db:triggers); add Gitea Actions quality/deploy/smoke workflow; rewrite README/AGENTS/DEPLOY docs; add requireWorkspaceAccess + recordActivityForEntity conventions. Phase 1 (critical fixes): calendar delete + drag/resize DnD; canvas card CRUD + bulk save + debounced autosave; logout route; graph edge workspaceId derivation; real analytics endpoints (drop Math.random); task board droppable columns + reorder persistence; Tiptap notes editor with sanitized HTML rendering; remove insecure passkey auth; domain/owner scoping (IDOR) on all by-ID routes + search/ export/realtime scoping; command palette routing + agent mention fetch; agent activity SSE handler; graph fly-to with tracked positions. Phase 2 (UX polish): login on design system; Sonner toasts app-wide; shared Loading/Empty/Error state components; working density/sidebarPos/reduce-motion settings; Inter typography; consolidated status-colors lib; unified detail routes; dashboard sort/realtime/responsive fixes; mobile responsive; a11y (radiogroups, sanitized snippets, badge labels). Phase 3 (features): daily notes timezone fix + delete + autosave + mood/energy create; active-domain store + topbar picker; graph domain picker + navigable entity links; tag assign/remove UI + server-side tag filter; real CSV export + import validation; custom fields on tasks. Phase 4 (advanced): migrate job worker into apps/worker (webhook delivery with HMAC, recurring spawn, ai_dispatch disabled); webhook queue helper + entity event enqueuing + test endpoint fix; recurring scheduledJobs pipeline; agents CRUD + permission editing + activity filters; real notifications feed; MCP polish (validation, error codes, domain scoping, dead sql leftover). Phase 5 (E2E + docs): rewrite Playwright suite for the Vite SPA (15 specs, new auth helpers, chromium-only in CI); add ephemeral-Postgres e2e CI job; rewrite docs/API.md for the real Hono API.
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
# AGENTS.md — Project E v2 Agent Contract
|
||||
|
||||
## Stack
|
||||
|
||||
- Monorepo: Turborepo + Bun workspaces, `packageManager bun@1.3.14`. Use `bun` for every command. Do not use `npm`.
|
||||
- `apps/web`: Vite + React 19 SPA (TanStack Router/Query, shadcn/ui, Tailwind). Dev server on :3000 proxies `/api` and `/mcp` to :3001.
|
||||
- `apps/api`: Hono API server on Bun, port 3001 (Docker) / 3000 via the Vite proxy in dev.
|
||||
- `apps/worker`: Bun background worker (`src/index.ts`). The root `worker/` directory is legacy and NOT used.
|
||||
- `apps/web-legacy`: legacy v1 app, kept for reference only. Do not edit.
|
||||
- `packages/db`: Drizzle ORM + `postgres` client. `packages/shared`: shared types, schemas, constants.
|
||||
|
||||
## Core Rules
|
||||
|
||||
Every API route that writes data (INSERT/UPDATE/DELETE) MUST follow this pattern:
|
||||
@@ -8,6 +17,13 @@ Every API route that writes data (INSERT/UPDATE/DELETE) MUST follow this pattern
|
||||
2. **Activity feed insert** — Call `recordActivity()` with actor, action, entity_type, entity_id, changes, workspace_id
|
||||
3. **pg_notify** — `recordActivity()` handles this automatically via `pg.notify('project_e_events', payload)`
|
||||
|
||||
## Shared Helpers
|
||||
|
||||
Both live in `apps/api/src/middleware/`. Use them; do not re-implement.
|
||||
|
||||
- `requireWorkspaceAccess(c, workspaceId)` (`middleware/auth.ts`) — verifies a workspace exists and the current user owns it. Returns the domain row. Throws 403 FORBIDDEN when the id is missing/empty or not owned, 404 NOT_FOUND when no such workspace exists. Call it at the top of every workspace-scoped route.
|
||||
- `recordActivityForEntity({ actor, action, entityType, entityId, changes, workspaceId })` (`middleware/activity.ts`) — same as `recordActivity()` but resolves the workspace from the entity row when `workspaceId` is omitted. Unknown entity types or unresolvable entities are logged and skipped, never fatal to the request.
|
||||
|
||||
## Soft-Delete Only
|
||||
|
||||
- Never use SQL `DELETE` on user data tables
|
||||
@@ -38,9 +54,17 @@ Standard codes: `VALIDATION_ERROR`, `NOT_FOUND`, `UNAUTHORIZED`, `FORBIDDEN`, `C
|
||||
- Every entity table has a `domain_id` FK (or `workspace_id` for activity_feed/webhooks)
|
||||
- Use `requireWorkspaceAccess(workspaceId)` to verify the workspace exists
|
||||
|
||||
## CI/CD Contract
|
||||
|
||||
- CI runs on Gitea Actions (`.gitea/workflows/ci.yml`) on the self-hosted runner `projecte-runner`.
|
||||
- Every push and pull request must pass the `quality` job: `bun install --frozen-lockfile` → `bun run typecheck` → web build (`cd apps/web && bun run build`) → `docker compose build`.
|
||||
- A push to `main` (or a manual `workflow_dispatch`) triggers `deploy`, which runs `bash script/deploy.sh`. The `smoke` job then checks API health, SPA HTML, and login.
|
||||
- Do not commit build artifacts (`.next/`, `dist/`, `.turbo/`, `*.tsbuildinfo`).
|
||||
|
||||
## Build Before Commit
|
||||
|
||||
- Run `npm run build --workspace=apps/web` before committing
|
||||
- Run `bun run typecheck` (typechecks api, worker, and web)
|
||||
- Run `cd apps/web && bun run build` to verify the SPA builds
|
||||
- Do NOT commit build artifacts (`.next/`, `dist/`, `.turbo/`)
|
||||
|
||||
## Schema
|
||||
@@ -50,6 +74,11 @@ Standard codes: `VALIDATION_ERROR`, `NOT_FOUND`, `UNAUTHORIZED`, `FORBIDDEN`, `C
|
||||
- Use Drizzle ORM for all database operations
|
||||
- Never write raw SQL except for `pg_notify` calls
|
||||
|
||||
## Migrations
|
||||
|
||||
- Migrations live in `drizzle/` (0000–0005). Generate a new one with `bun run db:generate` after editing the schema.
|
||||
- `bun run db:migrate` is the deploy-time migration: `db:sync` (`drizzle-kit push --force`) then `db:triggers` (`script/apply-triggers.ts`, search-vector triggers). Both are idempotent; safe to run on every deploy.
|
||||
|
||||
## Realtime
|
||||
|
||||
- SSE endpoint at `/api/realtime` uses PostgreSQL LISTEN/NOTIFY
|
||||
|
||||
Reference in New Issue
Block a user