Atomic phase-1 final per design-questions Q1.2 Option (b) and the
2026-05-29T00:30Z architecture-decisions lock-in. Removing the
prvkey?: string field from the User interface flips the type system
into the pressure mechanism that forces phase-2 to start: every
remaining bucket-B sign-site (chat / forum / nostr-feed /
activities-bookmarks/RSVP / market / tasks) now fails vue-tsc until
it migrates to signEventViaLnbits() against POST /api/v1/auth/sign-event
(aiolabs/lnbits PR #29, deployed on aio-demo).
Changes:
- src/lib/api/lnbits.ts:
- Drop `prvkey?: string` from User interface.
- getCurrentUser(): /auth/nostr/me used to merge prvkey alongside
pubkey; post-cascade the endpoint returns only the pubkey.
Updated the comment + cleaned the merge object.
- src/modules/base/auth/auth-service.ts:
- updateProfile() no longer threads `prvkey` through the merge.
Server-side PATCH /auth publishes kind-0 via the signer per
869f67c3; the webapp doesn't keep prvkey at all.
- src/modules/nostr-feed/components/NostrFeed.vue +
src/modules/nostr-feed/components/ScheduledEventCard.vue:
- Repoint the `ScheduledEvent` type import from the deleted
`../services/ScheduledEventService` to
`@/modules/tasks/services/TaskService`. Trivial post-#81-merge
cleanup that fell through the dedup PR; same file exports the
same interface.
vue-tsc --noEmit fails with 8 errors after this commit, all
TS2339 "Property 'prvkey' does not exist". The failing sites are
exactly the bucket-B targets the design doc enumerates as
phase-2 migration work:
| Failing site | Bucket B kind |
|-----------------------------------------------|---------------|
| activities/composables/useBookmarks.ts:92,113 | kind 10003 (NIP-51 bookmarks) |
| activities/composables/useRSVP.ts:153,187 | kind 31925 (NIP-52 RSVP) |
| base/services/NostrTransportService.ts:100,112| kind 21000 (NIP-44 v2 RPC envelope) |
| market/composables/useMarket.ts:455 | NIP-44 gift-wrap (kind 1059) unwrap |
| nostr-feed/components/NostrFeed.vue:408 | kind 5 (deletion of own post) |
NOT caught by vue-tsc but still bucket-B (BaseService injection
pattern types `this.authService` as `any`, so optional chaining
bypasses the type check):
- chat/services/chat-service.ts:341,511,714
- forum/services/SubmissionService.ts:755,1167
- nostr-feed/services/SubmissionService.ts:769,1226
- nostr-feed/components/NoteComposer.vue:306
- nostr-feed/components/RideshareComposer.vue:423
- tasks/services/TaskService.ts:507,562,616
Those sites will runtime-fail (prvkey is undefined from the API
post-cascade) but won't surface at compile time. Phase 2's
per-module migration (Q5.2) catches them as each module flips.
The webapp WILL NOT BUILD CLEANLY after this PR merges to dev
until phase 2 lands. That's the intended trade-off per Q5.1 +
Q1.2; the broken-build interval is the design-intended pressure
mechanism to start phase 2. server-deploy's webapp-demo flake.lock
bump will fail until phase 2 lands; demo will stay on the
pre-PR-#84 webapp during that interval.
Refs:
- log:2026-05-29T00:30Z (consolidated decisions; Q1.2 Option (b)
+ Q5.1 risk: demo gap acceptable)
- log:2026-05-29T17:30Z (lnbits confirming this PR stays
atomic-after-the-two-bucket-A PRs)
- ~/dev/coordination/webapp-design-questions.md Q1.2 + Q5.1
- Parent initiative: aiolabs/lnbits#9 (signer abstraction / bunker)
- Sibling PRs (stacked base→head): #82 → #83 → this
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The aiolabs/events extension on its signer-abstraction branch (commit
66076d6) constructs and publishes kind-31922 NIP-52 calendar events
server-side via NostrSigner — POST /events/api/v1/events accepts a
CreateEventRequest payload, signs through the operator's signer, and
broadcasts to configured relays. The webapp no longer needs to sign
calendar events client-side.
Changes:
- ActivitiesNostrService.ts: delete publishCalendarEvent() and its
helper imports (finalizeEvent, EventTemplate, buildCalendarTimeEventTags,
the local hexToUint8Array). The subscribe / query paths stay — the
service still reads NIP-52 events off relays for the activity feed.
Docstring updated to reflect the read-only role and point at the
events extension for the publish path.
- CreateActivityDialog.vue: swap the publish flow.
- Drop ActivitiesNostrService injection + currentUser.value.prvkey read.
- Inject TicketApiService instead; pull invoiceKey from
currentUser.value.wallets[0].inkey (same pattern as EventsPage.vue
handleCreateEvent).
- Build CreateEventRequest with amount_tickets: 0, price_per_ticket: 0
(events extension treats 0 as unlimited/not-ticketed per
models.py:45-46 per lnbits 22:30Z audit).
- Fold summary + description into the events extension's `info`
field since CreateEventRequest has no separate summary slot.
- Update toast on success to "Activity created!" (server publishes
to relays via the signer, not the webapp).
Approval-workflow caveat documented inline in the submit handler:
non-admin users on instances with auto_approve=false (the default)
land in the proposal queue and don't publish to relays until an admin
approves. Admins / auto_approve=true instances publish immediately.
This is the intended new behavior — operators can flip auto_approve
on the events extension config per-instance if they want the legacy
direct-publish moderation posture.
This is webapp's second bucket-A leg per aiolabs/lnbits#9 phase-1.
The remaining `currentUser.value.prvkey` reads stay until the
atomic User.prvkey field-removal PR (Q1.2 Option (b)).
Refs:
- log:2026-05-28T22:30Z (lnbits Q2.1 audit verifying ticket-less
acceptance + approval-workflow caveat)
- ~/dev/coordination/webapp-design-questions.md Q2.1
- aiolabs/events signer-abstraction commit 66076d6 (the server-side
publish path)
- aiolabs/lnbits cascade tip 861f427c deployed to aio-demo
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>