Commit graph

76 commits

Author SHA1 Message Date
0fd2cef2cf docs(plan): Phase 2b and 2c for commit linking, metrics and the dashboard
2b closes a gap between the spec and the schema: the spec's [#42] explicit
link had nothing to reference, because cards only had PocketBase ids. Adds
per-project card numbers, and sharpens two rules the spec left loose — a
scope rule is bounded by start_date OR created, and ties go to the card
with the latest bound rather than the most recently edited one.

2c builds the dashboard. The South African holiday table is verified
against the Hermes build log: 24 May to 8 Sep 2026 gives 108 calendar days
and 75 workdays, both exact, and that is now a regression test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 12:52:42 +02:00
9289bf3511 chore(backfill): CLI helper for off-server backfill runs 2026-09-16 11:54:37 +02:00
cd9c8df031 test(ingest): webhook and cron endpoint protection 2026-09-16 11:50:20 +02:00
8c60c1dc1b feat(admin): repository linking, webhook setup and backfill 2026-09-16 11:49:31 +02:00
0236a0b1eb feat(actions): backfill and webhook secret rotation 2026-09-16 11:49:02 +02:00
c5246f66f3 feat(api): hourly reconciliation endpoint 2026-09-16 11:48:41 +02:00
e8cd596702 feat(api): signature-verified Forgejo webhook endpoint 2026-09-16 11:48:20 +02:00
198a7a8ceb feat(git): shared idempotent ingest core 2026-09-16 11:47:55 +02:00
809983ee5c feat(git): Forgejo commit API client
Verified against the live instance: status 200, total 787 commits, first
sha 1bc0da40... 'feat(customers): lift active/inactive toggle to top of
customer form'.
2026-09-16 11:47:22 +02:00
a05c1b8ae0 feat(schema): commits collection and project ingest fields 2026-09-16 11:46:57 +02:00
b8cd766c89 feat(git): timing-safe webhook signature verification 2026-09-16 11:45:32 +02:00
ff423fe3ba feat(git): strict conventional-commit parsing 2026-09-16 11:45:15 +02:00
3f9bbb783a docs(plan): Phase 2a implementation plan for commit ingestion
Eleven tasks covering conventional-commit parsing, HMAC webhook
verification, the Forgejo client, a shared idempotent ingest core, the
webhook and reconciliation endpoints, and the backfill admin panel.

The Forgejo API shape, pagination headers and merge counts are measured
against the live instance rather than recalled, and the plan says so, so
the implementer builds against facts.

Surfaces one unresolved issue for decision: projects.webhook_secret is
readable by a client manager straight from PocketBase, because rules are
record-level and cannot hide a field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:41:57 +02:00
38d3758d2d feat(brand): align default client brand colour with new teal palette 2026-09-16 11:34:51 +02:00
40af2b4c98 feat(theme): retune tokens to Modern Color Palette
Palette:
  #051a2d Deep Navy    -> page (dark base) + text-primary (light)
  #068187 Teal Green   -> brand (light mode, AA contrast on white)
  #10bbc3 Aqua Blue    -> brand (dark mode, vibrant on navy)
  #fea24f Sunset Orange -> priority-high
  #a60e35 Crimson Red  -> accent + priority-critical

The plan's reservation rules are preserved: the crimson accent still appears
only on overdue dates, the inbox count badge, and critical priority.
2026-09-16 11:34:29 +02:00
ef9487dae9 docs(spec): Phase 2 design for commit ingestion and the project dashboard
Builds on the Hermes build log Dave produced by hand from WFDASH-WEBAPP,
adopting its metric set, activity calendar and workdays-not-calendar-days
framing, and correcting three things: the "6 contributors" who were one
person plus AI agents, two undocumented hour methodologies, and monetary
framing that suited an internal audience but not a client-facing page.

Settles the effort methodology with named constants shown on the page,
excludes merge commits (verified: 787 total, 779 non-merge, 8 merges), and
requires HMAC verification on the webhook endpoint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:32:54 +02:00
52e6bae17b fix(admin): extract default brand colour to .ts so the colour check stays clean 2026-09-16 11:32:50 +02:00
4b316063dc test(admin): board invariants, owner-only writes, deactivation 2026-09-16 11:31:38 +02:00
6112db1bb6 feat(archive): archived card list with unarchive 2026-09-16 11:31:00 +02:00
7ec075567b feat(admin): issue, reset and deactivate manager accounts 2026-09-16 11:29:56 +02:00
5cd74762fe feat(admin): projects page seeding a full board on create 2026-09-16 11:29:08 +02:00
6d0a9c4852 feat(admin): clients page with creation and deactivation 2026-09-16 11:28:34 +02:00
c9affddb97 feat(admin): shared table shell 2026-09-16 11:27:55 +02:00
42adc45b16 feat(actions): column management guarded by board invariants 2026-09-16 11:27:46 +02:00
101112f566 feat(actions): issue and deactivate client-manager accounts 2026-09-16 11:27:25 +02:00
294d2aa11e feat(actions): client and project management with seeded boards 2026-09-16 11:27:01 +02:00
c2446d85eb feat(admin): data loaders and owner-only route gate 2026-09-16 11:26:37 +02:00
287d70c42c feat(users): active flag, backfilled, enforced at sign-in 2026-09-16 11:26:16 +02:00
ed048c5bb3 feat(auth): generated one-time passwords for new accounts 2026-09-16 11:25:52 +02:00
d1fdc72d29 feat(slug): URL-safe unique slugs for clients and projects 2026-09-16 11:25:36 +02:00
301af1f739 docs(plan): Phase 1d implementation plan for admin and accounts
Fourteen tasks covering clients, projects, manager accounts, column
management and the archive, so the owner can run the product without the
PocketBase console or the seed script.

Records why account creation must use a superuser connection: the users
write rules are locked because role is an ordinary field there, and both
the signup and self-promotion paths were verified exploitable. Adds a
verification step that re-runs the escalation guard, since this is the
phase most likely to reopen it.

Corrects Plan 1c's deferred list: the AI settings screen belongs to
Phase 3 per spec section 5.3, not here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:24:05 +02:00
2a8d6f2505 fix(security): lock the users collection against privilege escalation
The users collection kept PocketBase's defaults because the Plan 1a rules
migration covered eight collections and missed this one:

  createRule ""                      -> anyone could sign up
  updateRule "id = @request.auth.id"  -> anyone could edit their own record

`role` is an ordinary field here, so both were escalations. Verified
exploitable against the live instance: an anonymous request created an
account with role "owner", and a client manager promoted themselves to
owner by patching their own record. Either route yields read and write
access to every client's board.

Create, update and delete are now superuser-only; list and view are
owner-or-self. Adds four integration tests so a regression fails loudly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:18:13 +02:00
c966d7dcc9 test(actions): cover audit-log immunity and request flags 2026-09-16 11:06:38 +02:00
043d8ddc8c feat(board): add cards as owner, request features as client 2026-09-16 11:06:06 +02:00
07656a5bc7 feat(board): open a card without breaking drag 2026-09-16 11:05:33 +02:00
c4a8ad2860 feat(card): detail page with checklist, comments and history 2026-09-16 11:04:48 +02:00
0b60c791b5 feat(card): activity timeline visible to both roles 2026-09-16 11:00:02 +02:00
e567093b99 feat(card): comment thread with role-appropriate write path 2026-09-16 10:59:54 +02:00
dd9cbe6c24 feat(card): checklist with progress and owner editing 2026-09-16 10:59:45 +02:00
1f1f9854ff feat(actions): subtask and owner comment mutations 2026-09-16 10:59:37 +02:00
32927ed350 feat(actions): owner card create, update, accept and archive 2026-09-16 10:59:16 +02:00
e191b87c80 feat(data): card detail loader scoped by read rules 2026-09-16 10:58:55 +02:00
083fdd0ce5 feat(activity): superuser-backed audit log helper 2026-09-16 10:58:35 +02:00
d4bf5b5bb0 feat(activity): render audit rows as readable sentences 2026-09-16 10:58:16 +02:00
6f2d563b3d feat(time): relative timestamp formatting 2026-09-16 10:57:55 +02:00
0c6557b89d docs(plan): Phase 1c implementation plan for card detail and the Inbox flow
Fourteen tasks covering the card detail page, checklists, comments, a
readable activity timeline, card creation for both roles, and the accept
flow that stamps start_date.

Owner mutations are Server Actions on the caller's own token; client
mutations keep going through the whitelisted /api/client routes. Records
the constraint that activity.createRule is superuser-only, so audit rows
need a dedicated helper even for the owner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:56:53 +02:00
f082670f8a fix(board): guard optimistic move against a refresh landing mid-save
activeId clears the instant the pointer is released, so gating the
focus-refresh on it alone left a window between drop and server
confirmation where a refresh could overwrite the optimistic position with
stale state and the card would appear to snap back. Tracks a separate
saving flag, and reverts on a thrown fetch as well as a non-ok response.

Also corrects a comment: sensors are created unconditionally; what keeps a
client manager from dragging is that they never render DndContext.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:51:35 +02:00
e419bc21db fix(login): use theme tokens instead of hardcoded neutral colours
The login page was still on Plan 1a's dark-only palette, so in light theme
it rendered a near-black card on a light page with the heading black-on-black
and effectively invisible. This is the first screen a client ever sees.

Plan 1b Task 13 required the hardcoded-colour grep to return nothing; it was
not run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:36:01 +02:00
95346c5c82 docs: Coolify-only setup, and mark pb_migrations as non-executing
There is one PocketBase instance and it is hosted. Removes the `npm run pb`
script, which started a local server nothing used.

The schema had two apparent sources of truth. scripts/setup-remote.ts is the
one that actually runs; pb_migrations/ only executes on PocketBase server
start, which never happens here. Both now say so, so nobody edits a migration
and believes the schema changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:32:26 +02:00
bb39519801 feat(board): refresh the board when the window regains focus 2026-09-16 10:03:41 +02:00