Commit Graph
100 Commits
Author SHA1 Message Date
NeilClack 177b7bb13a Flag overnight blocks in the v2 schedule API 2026-09-11 18:24:51 -05:00
NeilClack 750a9286c9 Support overnight blocks in schedule validation 2026-09-11 18:24:48 -05:00
NeilClack c177e7953d Document the v2 schedule endpoint 2026-09-11 18:16:08 -05:00
NeilClack 5f4116b8e8 Add schedule page with block editor and proclamation browser 2026-09-11 18:16:06 -05:00
NeilClack 545fb22910 Add v2 schedule API endpoint 2026-09-11 18:16:04 -05:00
NeilClack 4922e941ae Add schedule validation and service layer 2026-09-11 18:16:00 -05:00
NeilClack e6b492a335 Add schedule data model and migration 2026-09-11 18:15:57 -05:00
NeilClack 960673bbc6 Add a site-wide dark mode
Build and Push to Digital Ocean Container Registry / build-and-push (push) Failing after 4s
Build and Push to Digital Ocean Container Registry / migrate (push) Skipped
2026-09-11 12:49:46 -05:00
NeilClack a909db39b1 Delete "API Key" page 2026-09-11 12:44:44 -05:00
NeilClack 020289966d Remove "User Roles" admin page 2026-09-11 12:44:25 -05:00
NeilClack fa614b8c37 Fix staff(+) unable to edit or delete addresses 2026-09-11 12:43:41 -05:00
NeilClack cf8fc7b719 Fix users unable to edit or delete their own addresses 2026-09-11 12:42:35 -05:00
NeilClack 848e646880 Remove the extra page separator in the Login page 2026-09-11 12:41:49 -05:00
NeilClack 98d9b095d9 Document v2 API with OpenAPI schema 2026-09-10 16:19:53 -05:00
NeilClack 2bbee98594 Add dedicated v2 proclamation category/group endpoints and catalog specs 2026-09-10 16:19:53 -05:00
NeilClack 4d929df604 Remove stale admin overhaul and API update docs 2026-09-10 16:19:52 -05:00
NeilClack 10aad07e6d Add admin Audit Log page 2026-09-10 15:10:16 -05:00
NeilClack d16965dab6 Add AuditLog table and Prisma audit extension 2026-09-10 15:10:11 -05:00
NeilClack 7596937f30 Enforce roleId checks on all admin page actions 2026-09-10 14:59:32 -05:00
NeilClack 0cb4b2148a Expose roleId on the Better Auth session user 2026-09-10 14:59:28 -05:00
NeilClack 9de0e2e25a Fix Super admins being blocked from editing proclamations 2026-09-10 14:50:08 -05:00
NeilClack 9cd5397395 Add Resend email template HTML files 2026-09-10 14:35:54 -05:00
NeilClack f6b8cad15e Add subject to password reset email 2026-09-10 14:14:45 -05:00
NeilClack 29d53af8dd Remove unauthenticated /send email endpoint 2026-09-10 14:14:44 -05:00
NeilClack 809ced6d8a Automated signups use the registration-email set-password link 2026-09-10 14:08:56 -05:00
NeilClack 84c905c9ff Add shared registration invite helper and use it for admin-created users 2026-09-10 14:08:51 -05:00
NeilClack ae8d661364 Fix reset-password page to look up the reset token correctly 2026-09-10 13:42:36 -05:00
NeilClack 5ec3018f8b Email a set-password link when an admin creates a user 2026-09-10 13:42:33 -05:00
NeilClack 8a3c1587b4 Fix admin modals getting stuck after a successful submit 2026-09-10 13:33:33 -05:00
NeilClack e60d61e90a Fix admin modals replaying old action results after create or edit 2026-09-10 13:26:54 -05:00
NeilClack f1d80279e9 Record last validation time in v2 license endpoint 2026-09-10 13:18:22 -05:00
NeilClack 4979d955c2 Show active check and last verified date on dashboard license table 2026-09-10 13:18:18 -05:00
NeilClack 0175cab0b4 Add lastValidatedAt to license keys 2026-09-10 13:18:15 -05:00
NeilClack 1aecc51bbd Replace account and license-keys pages with profile page and dashboard 2026-09-10 13:11:41 -05:00
NeilClack f50eb34769 Add createdAt to license keys 2026-09-10 13:11:34 -05:00
NeilClack 4a1777de87 Keep legacy subscription tables as unmanaged instead of dropping them 2026-09-10 11:48:49 -05:00
NeilClack d89fc6837c Add default roleId 4 to new users 2026-09-10 11:48:20 -05:00
NeilClack 5e8851e070 Fix lint debt from admin overhaul; make check/lint/test/build green
- Scope @typescript-eslint/no-explicit-any off for *.spec.ts test doubles
- Type enhance() submit callbacks with SubmitFunction in api-keys page
- Drop as-any casts in proclamations upsert by using typed form data
- Fix useless regex escapes in profiles phone validation
- Remove unused locals param from api-keys load
- Use resolve() for admin nav/error links; store literal hrefs in adminModels
- Update README admin section and ADMIN_OVERHAUL lint caveat
2026-09-10 09:43:16 -05:00
NeilClack 91d162c746 Rebuild admin pages around DataTable/AdminModal; restructure categories/groups and v2 groups API
Remove the generic $lib/svelte-admin CRUD layer and AdminTable.svelte; each
admin route now owns its own form/modal logic. Add DataTable.svelte,
superform-errors.ts, and profile-specific modal/field components.

Flatten proclamation categories/groups and drop subscription levels; add the
v2 groups API; update v1/v2 endpoints, serializers, auth, and regenerated
Prisma client with the new migrations.

Document the overhaul plan in docs/ADMIN_OVERHAUL.md.
2026-09-10 09:38:01 -05:00
NeilClack f4e736c92d Update builder name
Build and Push to Digital Ocean Container Registry / build-and-push (push) Successful in 1m56s
Build and Push to Digital Ocean Container Registry / migrate (push) Failing after 10s
2026-08-18 20:14:44 -05:00
NeilClack 5096118ef5 Remove user proclamations page
Users should not be able to view proclamations from the web portal.
2026-08-18 13:38:05 -05:00
NeilClack 86b6720676 Move to pure git clone
Build and Push to Digital Ocean Container Registry / build-and-push (push) Successful in 1m23s
Build and Push to Digital Ocean Container Registry / migrate (push) Canceled after 0s
2026-08-17 21:32:37 -05:00
NeilClack 94c9877eab Update action URLs to Github
Build and Push to Digital Ocean Container Registry / build-and-push (push) Failing after 36s
Build and Push to Digital Ocean Container Registry / migrate (push) Skipped
2026-08-17 21:29:42 -05:00
NeilClack 0753cfaa56 Remove v2API key
Build and Push to Digital Ocean Container Registry / build-and-push (push) Failing after 2s
Build and Push to Digital Ocean Container Registry / migrate (push) Skipped
2026-08-17 21:08:50 -05:00
NeilClack 7211beef69 Changed action runner to label 2026-08-07 14:09:42 -05:00
NeilClack dea5cd291a Update runner to runner name 2026-08-07 14:09:11 -05:00
NeilClack 64f7070ad7 Build API v2 2026-08-07 14:06:20 -05:00
NeilClack b2091deae0 update package.json 2026-07-19 08:45:01 -05:00
NeilClack 74896234f9 Add API_KEYS_ACTIVE toggle to API key middleware 2026-07-19 08:44:10 -05:00
NeilClack cca26c0578 Merge main into dev 2026-07-18 15:51:43 -05:00
NeilClack 23e232d5ea fix: license key not showing in email when created via admin page
Problem:
The admin createKey action had two issues preventing the license key from
appearing in the delivery email:

1. Wrong variable name: passed 'licenseKey' (camelCase) but the Resend
   template expects 'license_key' (snake_case).

2. Wrong template: used the default RESEND_TEMPLATE_ID (a generic
   template) instead of the 'license-key-delivery' template that the
   automation endpoint uses for license key emails.

Solution:
- Changed template variable from 'licenseKey' to 'license_key'
- Added explicit templateId: 'license-key-delivery' to match the
  automation endpoint (api/v1/automations/create/account)
- Updated email subject to 'Your Rhemawave License Key' for consistency

Tests:
Added page.server.spec.ts for the admin license-keys createKey action
covering: unauthenticated rejection, missing email/level validation,
user-not-found error, successful key creation with correct template ID
and license_key variable, fallback to user.name when profile is missing,
and graceful handling when email sending fails.
2026-07-18 15:46:41 -05:00
NeilClack b746d89448 Fix non-serializable accessFilter in admin load, add error boundary and tests 2026-07-17 14:52:09 -05:00
NeilClack dd8c194de2 Remove broken COPY command 2026-07-17 13:28:40 -05:00
NeilClack c52474d69b Update environment variables in resend module 2026-07-17 12:42:42 -05:00
NeilClack fd630ff714 Resolve build errors 2026-07-17 11:51:14 -05:00
NeilClack bcd216bd56 Add startup script to automate database migrations 2026-07-17 11:24:02 -05:00
NeilClack 849d806c03 synchronize database migrations 2026-07-17 11:19:55 -05:00
NeilClack c860596f96 Merge dev 2026-07-17 11:06:32 -05:00
NeilClack 7c7b179110 Testing a different method of authenticating with DOCR 2026-07-17 10:53:05 -05:00
NeilClack 9eb4674a3d Remove doctl commands entirely, relying on system-installed and configured doctl command 2026-07-17 10:45:27 -05:00
NeilClack c5eae2f624 Installed doctl system-wide and removed install line 2026-07-17 10:35:06 -05:00
NeilClack 6006725182 Switch doctl to snap version 2026-07-17 10:33:43 -05:00
NeilClack 8939f58dca Change runs-on from self-hosted to ubuntu-latest 2026-07-17 10:29:10 -05:00
NeilClack b8eede93ea Change runs-on to self-hosted from actions-server 2026-07-17 10:25:22 -05:00
NeilClack de36a6e7a0 update ci actions 2026-07-17 10:23:22 -05:00
NeilClack 65ae7675ba Complete docker build in preparation for app-runner deployment 2026-07-16 22:01:36 -05:00
NeilClack f5896aa575 Update AGENTS.md 2026-07-16 20:23:59 -05:00
NeilClack 2d0cf98ed3 fix tests: add subject to email-verification assertion, add url + api-key mock to hooks test 2026-07-08 15:36:11 -05:00
NeilClack 3243f1d4a1 docs: update AGENTS.md with API routes, GHL webhook, templates, drag-and-drop, key generation 2026-07-08 15:34:12 -05:00
NeilClack 92f54e829e add subject line to verification email 2026-07-08 15:29:45 -05:00
NeilClack f0093ca131 remove debug logs, add proper email subject lines 2026-07-08 15:26:13 -05:00
NeilClack e05e0fada2 add console.log tracing to /create/account webhook 2026-07-08 15:11:32 -05:00
NeilClack 55a29b9c1a feat: wire GHL webhook to Resend email templates
- Replace raw Resend text emails with sendMail using Resend templates
- automated-user-registration template: firstName, tempPassword,
  verifyUrl, loginUrl
- license-key-delivery template: firstName, license_key
- Remove requestPasswordReset call (temp password is the one-time
  credential; verification link handles email confirmation)
- Add .catch() to Better Auth email callbacks to prevent unhandled
  rejections from missing templates crashing the server
2026-07-08 15:01:08 -05:00
NeilClack e6ef7d3b36 feat: implement GHL webhook endpoint for auto account + license key creation
POST /api/v1/automations/create/account accepts JSON with email,
name, and subscription_level. Creates a Better Auth user via signUpEmail
with a temporary password, sends a password reset email so the user
can set their own password, generates and persists a license key,
and emails the key to the user. Returns success/error as JSON.
2026-07-08 14:16:31 -05:00
NeilClack 4d21288511 api: switch license endpoint to POST/JSON, fix active check, add key copy button
- Change /api/v1/license from GET with query params to POST with JSON body
- Request body uses license_key and email_address
- Response returns key, email_address, subscription_level
- Add active check (reject deactivated license keys)
- Exclude /api/v1/automations/ from API key auth (GHL webhook)
- Add copyableFields prop to AdminTable with clipboard icon
- Enable copy button on license key field in license-keys admin page
2026-07-08 14:11:01 -05:00
NeilClack 46b2cdf53d api: API key authentication with rotation and grace period
- Add ApiKey Prisma model (keyHash, expiresAt, revokedAt)
- Protect /api/v1/* routes with Authorization: Bearer header check in hooks
- create rotateApiKey() utility: normal (48h grace) and emergency (immediate)
- Add Super-only /admin/api-keys page for key rotation with one-time reveal
- Fix roleId check by using parent layout's DB-fetched adminUser
- Add API Keys link to admin sidebar
2026-07-08 13:18:19 -05:00
NeilClack 6266be0edf admin: category drag-and-drop reorder + modal-based license key management
- Add sortOrder column to ProclamationCategory with migration
- Implement drag-and-drop reorder in AdminTable with persist-to-DB
- Refactor AdminTable to use $derived + dragOverride (no $effect sync)
- Replace window.location.reload with invalidateAll for reorder

- Convert license key create to modal with subscription level dropdown
- Add LicenseKeyForm.svelte following the CategoryForm pattern
- Add replace action (delete + generate new key with same level)
- Remove deactivateOld checkbox; each key has its own level
- Use use:enhance with update() to refresh list after create/replace
2026-07-08 12:59:55 -05:00
NeilClack 93d941569e proclamation-categories: sub-category management inline in parent form
- Registry: Remove 'parent.name' from listFields (all shown records
  are top-level with no parent), remove 'parent: true' from include
  since unused
- +page.server.ts: Custom load filters to parentId=null (top-level
  only); custom upsert syncs children (create/update/delete) and
  handles P2002 duplicate-name errors; custom delete cascades to
  children first to avoid FK constraint violations
- CategoryForm.svelte: Replace parentId select dropdown with dynamic
  list of sub-category inputs. Each row has a name field and Remove
  button. Pre-populates from record.children when editing existing
  categories. Add Sub-category button appends new rows
- +page.svelte: Remove unused relationOptionsData prop from
  CategoryForm; rename submit button label from 'Update' to 'Save'
- prisma: Add ProclamationCategorySubscriptionLevel join table
  migration and regenerate client
- General: Update TipTap mock, Toast, license-keys page, proclamations
  server/route tests, README, AGENTS.md, and other admin forms
2026-07-08 10:31:28 -05:00
NeilClack 37bed4f64c Update AGENTS.md with detailed Svelte 5 gotchas, testing patterns, and admin form architecture
Covers select binding workaround, / sync pattern,
Playwright locator API, test patterns, dirty-state submit, and
Super-only proclamation restrictions.
2026-07-07 22:29:13 -05:00
NeilClack f7d255b744 Add unit/component tests for proclamation admin forms
Server tests cover load content stripping per role and upsert/delete
role enforcement. Client tests verify field rendering, pre-fill on
edit, content visibility per role, and submit button dirty-state.

Switched selects from bind:value/value to selected attribute pattern
to work around Svelte 5 select value reactivity in test env.
2026-07-07 22:27:19 -05:00
NeilClack 9ddad9d834 Fix proclamation form fields not auto-filling on edit
Switch from  initialized from prop to -synced
values so form fields always populate when the record changes.
Key the TipTap editor on record.id to force re-render.
2026-07-07 22:14:23 -05:00
NeilClack ce42414214 Restrict proclamation editing and content to Super admins only
- Only roleId <= 1 (SUPER) can create/edit/delete proclamations
- Content field is stripped from records for non-Super users
- Content field is hidden from the form for non-Super users
- Server actions reject upsert/delete from non-Super users
2026-07-07 22:10:54 -05:00
NeilClack 4cef38a1ab Commit 2: Delete AdminForm.svelte and AdminPage.svelte 2026-07-07 21:01:02 -05:00
NeilClack 22b6adee3f Commit 1: Create individual form components per route, remove generic AdminForm dependency
- Add per-route form components: UserRoleForm, UserForm,
  ProclamationForm (with category cascade), CategoryForm,
  FreqForm, LevelForm
- Update all admin +page.svelte files to use AdminTable + AdminModal
  + their specific form component instead of AdminPage
- Update profiles page to inline fields instead of using AdminForm
- Add custom Proclamation server action with category fallback logic
  (categoryId falls back to parentCategoryId when no sub-category)
- Remove cascade/were/fieldLabels logic from generic crud.ts
- Remove outdated cascade/where tests from crud.spec.ts
- Remove fieldLabels from AdminModelConfig type
2026-07-07 21:01:02 -05:00
NeilClack 2073248576 fix: Superforms SSR import from /server path and Prisma client version mismatch
- Import superValidate from sveltekit-superforms/server instead of default
  path to avoid pulling SuperDebug.svelte into SSR
- Upgrade @prisma/client to match prisma CLI version (7.2.0 -> 7.8.0)
  so generated client's query_compiler_fast_bg files exist at runtime
- Add regression test verifying superValidate works in server context
- Add regression test verifying generated Prisma client compiler imports
  reference real files
2026-07-07 13:39:11 -05:00
NeilClack 38d1752f5b admin: Superforms + Zod validation, three-address-defaults schema, profiles toast fix
- Add Superforms + Zod 4 for all admin form validation
- Replace address isDefault with three separate boolean defaults (Mailing, Billing, Shipping)
- Update profiles page with three-checkbox address form and toast improvements
- Convert all admin page server actions to pass request directly to crud
- Export superFormErrorsToFieldErrors helper for profiles server actions
- Regenerate Prisma client for new schema fields
2026-07-07 13:36:23 -05:00
NeilClack 38347f5f24 profiles: add address management, user edit, fix form redirect
- Add type (Mailing/Billing/Shipping) and isDefault fields to Address
  schema with migration. Unique default enforced server-side.
- Rewrite profiles page with inline address creation form and
  editable user name/email within the profile modal.
- Add upsertAddress and updateUser form actions.
- Fix form redirect by adding use:enhance to AdminForm.
- Disable Update button in AdminForm until a field is changed
  (prevents accidental submissions).
2026-07-07 13:20:35 -05:00
NeilClack faacbab1de admin: remove NavBar Admin Panel link, make users list-only
- Remove redundant Admin Panel link from top navigation bar. The
  sidebar already has the full admin model tree and the Dashboard
  shows a Proclamations card for Staff+ users.
- Add listOnly: true to users admin config. Users are created via
  registration, not the admin panel. RUD operations still work.
2026-07-07 13:07:34 -05:00
NeilClack 27aae18b3a refactor: inline single-use components, remove dead code
- Inline TopBar into root layout (+layout.svelte) — only used there
- Inline Center into home page (+page.svelte) — only used there
- Remove ComboBox.svelte — dead code, no imports
- Remove TipTap.svelte — dead code, no imports
- Remove empty container/ui/admin/tiptap directories
- Keep Window.svelte in components/containers/ — used by 4 pages
2026-07-07 10:40:59 -05:00
NeilClack b87e2b0936 fix: replace CSS variable inversion with standard Tailwind dark: classes
The :root.dark CSS variable inversion caused contrast problems -
text-gray-900 and bg-gray-950 both became light in dark mode, making
text invisible on backgrounds.

Fix:
- Remove :root.dark { --color-gray-*: ... } block from layout.css
- Change :root.dark selector to .dark for form element styles
- Add standard Tailwind dark: classes throughout every .svelte page
  - dark:bg-gray-950 (page backgrounds)
  - dark:bg-gray-900 (card/surface backgrounds)
  - dark:bg-gray-800 (table headers, elevated surfaces, active nav links)
  - dark:bg-gray-700 (primary buttons)
  - dark:text-gray-100 (primary text)
  - dark:text-gray-300 (secondary text, labels)
  - dark:text-gray-400 (muted text, inactive nav links, links)
  - dark:border-gray-700 (borders)
  - dark:border-gray-600 (input borders)
  - dark:hover:bg-gray-800 (sidebar hover)
  - dark:hover:bg-gray-600 (button hover)
  - dark:prose-invert (rich text content)
- TopBar: full dark mode support (bg, links, toggle button)
- Sidebar: all nav links, active states, admin submenu get dark mode
- Auth pages (login, register, forgot, reset): full dark mode
- Protected pages (dashboard, account, setup, license-keys,
  proclamations, categories): full dark mode
- Home page, error page, admin page: dark:text-gray-100
2026-07-07 10:27:08 -05:00
NeilClack d97ed88031 feat: full dark mode with :root.dark and dark: classes
layout.css
- Change .dark → :root.dark so variable overrides match Tailwind's
  :root, :host specificity and actually take effect
- Add global dark mode styles for input/select/textarea elements

All .svelte files:
- bg-white → bg-white dark:bg-gray-100 (cards, tables, containers)
- text-white → text-white dark:text-gray-950 (button text)
- Add dark:bg-gray-950 to main page containers (dashboard, account,
  license-keys, proclamations, proclamations/[id])
- Add dark:border-gray-300 to bordered elements (cards, tables, forms)
- Add dark:bg-gray-200 to secondary backgrounds (table headers,
  address form, price badges)
- Add dark:hover:bg-gray-300 / dark:hover:bg-gray-700 to hover states
  (sidebar nav links, clear button, admin categories table)
2026-07-07 10:00:00 -05:00
NeilClack 03ecfbd635 feat: add dark/light mode toggle
- Add blocking inline script in app.html that reads localStorage
  'theme' and applies .dark class before render (no flash)
- Invert gray scale in .dark via CSS custom properties so all
  grayscale colors reverse automatically (light becomes dark)
- Add @custom-variant dark to enable dark: utility classes
- Add border-button toggle ("Dark"/"Light") in TopBar far right
- Persist preference in localStorage
2026-07-07 09:54:32 -05:00
NeilClack 5a13f2516c style: strip to grayscale wireframe
- Remap all non-gray colors (blue, green, red, purple, slate) to gray
  equivalents via Tailwind v4 @theme overrides in layout.css
- Zero out all border-radius values (square everything)
- Zero out all shadow values (no depth)
- Disable all transitions and animations globally
- Change theme-color meta tag from purple (#7B2D8E) to gray (#6b7280)
- Clean up undefined 'underlined' class and typo bg-grey-200
2026-07-07 09:50:57 -05:00
NeilClack 24f3a9f465 Add AI skills 2026-07-07 09:41:07 -05:00
NeilClack 6ff8e878a4 test: add unit tests for all auth backend logic
- Register: edge cases for non-Error throws, error message assertions,
  and verify signUpEmail was called with correct payload
- Forgot-password: empty/missing email, Error/non-Error throws
- Reset-password: load (missing/expired/valid token) and action (short
  password, mismatch, throw, success redirect)
- Account setup: load (unauthorized, returns user), action (redirect,
  falsy create, throws, isRedirect passthrough)
- Email-verification: correct URL construction, sendMail delegation,
  throw propagation
- Hooks: sets/omits locals, passes building/auth to svelteKitHandler
- Fix Svelte 5  warning on setup page by using  with
  one-time guard instead of top-level prop read
2026-07-07 09:22:56 -05:00
NeilClack 1e391c9252 redirect setup page to /dashboard instead of /account 2026-07-07 09:18:45 -05:00
NeilClack d160186925 feat: pre-fill first/last name on setup page from user's registered name 2026-07-07 09:16:54 -05:00
NeilClack 5f1edc3174 fix: prevent redirect loop on /account/setup for users without profile
- Skip profile redirect when already on /account/setup so users
  who just signed up/logged in land on the page without looping
- Add test for the skip-redirect case
2026-07-07 09:14:14 -05:00
NeilClack 209fd8456d auth: show email verified banner on login page after verification
- Append ?verified=true to callbackURL in verification link
- Login page reads query param and shows green success banner
  when user lands after email verification
2026-07-07 09:10:11 -05:00
NeilClack fc2790f6fa fix: handle duplicate email sign-up and null user in protected layout
- Register action now returns success instead of redirecting to /account/setup
  so users without a session (duplicate email with requireEmailVerification)
  see a 'check your email' message instead of crashing
- Protected layout guards against null/undefined locals.user before querying
  Prisma (was passing id: undefined)
- Updated register page to show success banner with verification instructions
- Updated test to match new action response
2026-07-07 09:05:29 -05:00