Skip to content

Merge staging to main - #90

Open
itexpert120 wants to merge 158 commits into
mainfrom
staging
Open

itexpert120 wants to merge 158 commits into
mainfrom
staging

Conversation

@itexpert120

@itexpert120 itexpert120 commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Merges staging into main: work orders and payouts, and the everything.dev v2 migration (#85).

Production env vars (Railway app, production)

Generate new

  • PAYOUTS_SECRET_KEY
  • GOOGLE_TOKENS_SECRET_KEY
  • WORK_ORDERS_RUN_SECRET (also as a GitHub secret, plus the repo variable WORK_ORDERS_BASE_URL=https://multiagency.ai)

Prod credentials from the provider

  • NEAR_INTENTS_AGENT_API_KEY, NEAR_INTENTS_AGENT_API_URL (staging uses the demo endpoint)
  • DOCUMENSO_API_KEY
  • GITHUB_TOKEN
  • REGISTRY_TOKEN_MAINNET

Copy from staging

  • DOCUMENSO_API_URL

To confirm

  • PLATFORM_URL, PLATFORM_DEPLOYMENT, PLATFORM_APP_CREDENTIAL

Optional

  • GOOGLE_* (Google Docs)
  • ANTHROPIC_API_KEY (AI review)

GitHub secret

  • BOS_STORAGE_API_KEY

Before deploying

  • Merging does not deploy prod: deploy.yml is a stub until the v2 storage and CDN decision is made.
  • Repoint the app image to everything-dev:v2.0.0-rc.27. ci.railway.service is set to dashboard.
  • Back up the prod databases (migrations 0019–0038 run on boot).

jlwaugh and others added 30 commits September 29, 2026 16:21
# Conflicts:
#	bos.config.json
jlwaugh and others added 17 commits October 28, 2026 17:43
Runs bos upgrade on the hand-migrated branch so it has a sync baseline
and the framework-owned files nearbuilders.org, nostr and citynode use.

Kept where the upgrade was lossy or unsafe: changeset scripts,
ensure-auth-types in types:gen, strict test/typecheck loops, and the
disabled production deploy. Release now triggers on CI success since
the template ci.yml drops the notify job. Declares BETTER_AUTH_SECRET
on the API for the template plugin.dev.ts. Drops the dangling
@effect/oxc link and @types/bun.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…etail pages

Work order creation
- Prefill the builder's GitHub login and email from their profile or the
  Agency's last work order (new builderDefaults route, Agency-scoped)
- Create a project or builder inline from the form; project slugs avoid
  collisions
- Keep an unsent work order as a local draft per user, network and Agency;
  representative details are never stored and drafts clear on sign-out
- Import repositories from GitHub (NEARBuilders and MultiAgency by default,
  or any organization); public repositories only, cached for 10 minutes,
  each chosen repo shown as a link
- Explain why "Send for signature" is disabled

Home and lists
- New Home page with the work orders waiting on you; Home added to the menu
- Work orders list: one row of tabs, full titles, builder account,
  "$X of $Y" budget
- list() loads requests, documents, signatures and builders in batches

Work order page
- Overview, payouts and documents tabs (old tab links still work), key
  facts strip, Edit and More menu, Terminate for offered orders
- "Withdraw and delete" checks Documenso first: it refuses when the builder
  already signed, when Documenso can't be checked, or when the envelope
  can't be cancelled
- Payout account shows "Confirmed when they sign" only for Documenso
  signing; no duplicate payout-account warning on accepted orders
- Shows how the order was signed (Documenso, Google Docs or MultiAgency)

Fixes
- Store created/updated times in UTC (PGlite and pg sessions)
- Renewals keep the project title and slug; "Unknown project" instead of
  raw ids, and documents refuse to generate without a project title
- Editing an order never auto-fills terms from builder defaults
- Shorter setup and status copy across admin pages
Simpler first work order, Home, GitHub repo import, clearer list and detail pages
# Conflicts:
#	api/src/index.ts
#	bos.config.json
#	ui/src/routes/_authenticated/admin/index.tsx
#	ui/src/routes/_authenticated/admin/work-orders/$id.tsx
Migrate to everything.dev v2 (rc.27)
fix(work-orders): email everyone who has to act; tell builders about terminate and withdraw
fix(work-orders): renewals go out for signature; summary names the services agreement and how it was signed
itexpert120 and others added 10 commits November 2, 2026 18:59
…s open

Once a DAO payment has started, rejecting the request let the builder
request again while the unlinked Transfer proposal stayed live on chain,
so the DAO could still approve it and pay twice. Rejection now scans the
Agency DAO's proposals since the request was approved and refuses while
an unbilled transfer to the builder in the payout token is InProgress,
Failed or Approved; it also refuses when the DAO can't be read. Updates
the DAO payment note and the proposal dialog copy accordingly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ments

Zod's z.url() accepts javascript: and data: URLs, and the builder page
rendered a manual item's url and the attached document's url straight
into href. Manual item and attachDocument inputs now require http(s),
and the builder page renders those links through safeHttpHref, falling
back to plain text, so links already stored stay inert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…O payment starts

For work orders denominated in a token and paid in NEAR, linkProposal
didn't require a started DAO payment and the paymentProposal preview
doesn't set one, so a proposal made from the preview stayed live while
automatic payment kept retrying, and both could pay. Linking now needs
startDaoPayment first, as USD orders already did; startDaoPayment is
what turns automatic payment off. The test of a link racing a settling
automatic payout is replaced, since that race can no longer happen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A proposal still InProgress or Failed on chain but past the DAO's
current proposal_period reads as Expired. That inferred status was
persisted to the proposals table and cached forever, so if the DAO
later lengthened its voting period the app would never see the proposal
reopen. Only statuses the chain itself reports as terminal are saved and
cached for good now; an inferred expiry is re-read on the normal TTL.
Rewriting Failed to Expired is kept: Sputnik checks expiry first for
Failed proposals too, so past the period they can't be executed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… non-Error

findProposal read (err as Error).message to tell a missing proposal from
a failed lookup, so a rejection that isn't an Error turned into a
TypeError hiding what failed. The check now reads the message safely.
Callers already degrade per request (payment sync, the scheduled run,
linking, billings), and a genuinely missing proposal still reads as null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ships

The memberships query filtered on o.status = 'active', which drops rows
whose status is NULL, while the session path treats a missing status as
active. Both now agree via COALESCE(o.status, 'active'). The re-check of
a missing status column is left as is: it is what lets the filter turn
on without a restart once the auth migration adds the column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tick and the run take different locks, and the run can also be
started over HTTP outside the scheduler's queue, so both can follow up
the same paying request at once. blockPayout deduped on the stale
autoPayBlockedAt and autoPayHoldNotified of the row it was handed, so
both told the managers and announced the hold. It now claims each with
a conditional update and notifies only when its update matched; a failed
announcement releases the hold claim so the next run retries it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The settings route had no manager gate: the nav hides it from members,
but opening /admin/settings ran the agencyConfig loader, which the
server refuses for members, so the whole page errored. Members now skip
that loader and see the Organization's name and slug read-only plus a
notice that owners and admins manage the rest. Managers see the page as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OpenDocumentButton opened a blank tab and then sent it to the document's
Drive or blob URL without clearing window.opener. It now uses
openPendingTab, which clears the opener as the other pending tabs do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the image

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matches the runtime image's effect rc.118 / oRPC beta.45. Overrides now
follow the catalog like the framework's. Route error components take
`unknown` errors per the newer TanStack Router types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants