Commit Graph
19 Commits
Author SHA1 Message Date
openhands 179484642f feat: per-account login lockout, mail index, resend captcha, i18n scoping
Gitea Actions Runner Test / test-job (push) Successful in 2s
CI / check (push) Successful in 28s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Failing after 1m45s
CI / tests-ui (push) Successful in 2m29s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
Closes the four HIGH/MEDIUM items left open after the previous pass.

Login lockout
- The only login limits were keyed on the client IP, so a distributed attempt
  could grind on one account indefinitely. Added a per-account lockout with a
  budget of 8 failures per 15 minutes.
- The bucket is keyed on the RESOLVED account id, not on the submitted string:
  users may sign in with either username or e-mail and neither the lookup nor
  the input normaliser folds case, so an input-keyed bucket would hand out a
  fresh budget per spelling of the same account.
- precheckLogin and NextAuth's authorize share the bucket, so the pre-check
  cannot be used to buy extra attempts and a client that skips it entirely is
  still bounded. Both check the lockout BEFORE verifying the password: the
  success path clears the counter, which would otherwise walk a locked account
  straight back in on the right password.
- A successful login clears the failures, which needs two new primitives in
  rate-limit.ts: peekRateLimit (read-only, does not consume a unit) and
  clearRateLimit.
- Fixed a latent inconsistency while doing so: the in-process bucket capped its
  counter at the limit while Redis' INCR kept climbing, so the two backends
  disagreed about how far over the limit a key was. Both now track the true
  count.

Mail lookup index
- Added an index on users.mail (0035). Password reset, e-mail verification and
  the resend cooldown all resolve a single account from a submitted address and
  were full table scans of `users`. Deliberately non-unique: legacy rows can
  hold the same address more than once, so a unique index would fail to apply.

Resend captcha
- /verify's resend form triggers real outbound mail and was reachable with only
  a cooldown. It now runs the configured captcha before the account lookup and
  before any send.

Client message payload
- The root layout serialised the whole catalogue into every page. pages.admin
  and admin are ~177 KB of the ~235 KB and are unreachable from the public route
  group, so that layout now installs its own provider with the staff namespaces
  removed. Nested providers replace rather than merge, which is why this has to
  live in the segment layout. /admin, /mod, /client and /admin-next keep the
  full set; a guard test fails if a public page ever references a staff
  namespace.
2026-10-09 17:12:50 +02:00
openhands 6cc45d7413 feat: harden atoms-nexst against review findings (37 items)
Gitea Actions Runner Test / test-job (push) Successful in 2s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Failing after 1m49s
CI / tests-ui (push) Successful in 2m31s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
Second review pass covering security, performance, admin tooling and the
public/room flows. All HIGH and MEDIUM findings from the audit are resolved;
nothing in this commit changes the visible feature set.

Authentication & session security
- CSP is now set on the request headers in the proxy, which is what Next.js
  uses to derive the render nonce, so the nonce is effective.
- 2FA: an already-enabled user cannot re-enroll, the setup endpoint is
  rate-limited per account, and confirmed codes are persisted so the second
  secret no longer silently never applies.
- Password reset revokes the ticket, authTicket and all personal access
  tokens, and bumps the token version so existing sessions die. The same
  revocation is now wired into the staff-side password reset.
- /reset and /verify return a stable error code instead of raw text; the
  mail lookups are ordered by id so duplicates cannot vary between runs.
- Resending the verification mail gets a per-address cooldown on top of the
  per-user limit.
- Issue API tokens with the narrower radio/ticket ability set instead of "*".

Authorization & input handling
- Mid-rank staff can no longer keep dynamically granted non-view admin.*
  permissions: existing grants are revoked by migration and the grant lookup
  is restricted to "%.view". Rank guards use the dynamic super-admin check.
- Alerting a user is permission-checked and audited like the other tools.
- Material mutations (giveCredits/giveDuckets/giveDiamonds, the admin user
  actions route, bulk user actions) are capped and rank-guarded, and bulk
  ids are bounded.
- updateRoom / updateRoomItem write through a field allowlist, and items
  may only be edited through their own room.
- Classnames reaching the filesystem are validated before use so a crafted
  value cannot escape the asset directories.
- The word filter now also covers offline mails, guild forum threads and
  replies, and user mottos.
- Media uploads are validated by magic bytes, /api/media requires the page
  edit permission, APP_URL must be configured once mail is enabled, and the
  diagnostics error route checks the fetch site header.

Admin tooling
- Secret settings render masked and cannot be overwritten with a blank or
  an arbitrary raw key; radio credentials are new password inputs.
- Commandocentrum balance changes are audited.
- Admin list pagination reads the caller's per-page instead of the max, and
  the log exporter caps offset and search length.

Performance
- Catalog translations are cached per module, with a cheap revision hash;
  the public online count uses a stale window instead of hammering the DB.
- The cache warmup now primes the payload the home route actually reads.
- TopHeader batches its queries into one round trip, and LCP avatars load
  eagerly.
- motion/react and sonner are no longer part of the root layout; the nav
  dropdown and mobile nav panels are lazy client chunks. Anonymous visitors
  again get the navigation chrome, and public pages get an edge cacheable
  response.

Accessibility
- Nested <main> elements in phase pages became <section>; the page entrance
  and route progress animations are pure CSS that respect reduced motion.
2026-10-09 16:19:48 +02:00
openhands 97012a78f6 feat(site): drifting cloud puffs across the public background
CI / check (push) Successful in 2m40s
CI / deploy (push) Successful in 2m13s
CI / publish-container (push) Successful in 2m10s
Add a fixed, decorative layer of soft clouds that slowly float across
the Habbo sky behind the content:
- Five clouds at staggered sizes, heights, opacities and loop timings
  (60s–190s) so the drift feels organic.
- Dimmed further in dark mode; frozen by prefers-reduced-motion.
- Pure decoration: aria-hidden, pointer-events: none, no color
  utilities in markup (cloud shapes live in globals.css).
2026-09-12 17:12:55 +02:00
openhands 5e598a08b4 fix: remove ssr:false from dynamic imports in server components
CI / runtime-diagnostics (push) Skipped
CI / check (push) Failing after 0s
CI / deploy (push) Skipped
CI / release (push) Skipped
Turbopack rejects ssr:false in Server Components.
Removed from 4 dynamic imports in:
- src/app/(site)/layout.tsx (RadioPlayerGate)
- src/app/admin/analytics/economy/page.tsx (RevenueChart)
- src/app/admin/analytics/page.tsx (DashboardChart, PeakHoursHeatmap)
- src/app/admin/media/page.tsx (AdminMediaGrid)
2026-09-03 16:04:48 +02:00
openhands 30c95b1a5c feat: comprehensive CMS improvements
CI / runtime-diagnostics (push) Skipped
CI / release (push) Skipped
CI / check (push) Failing after 0s
CI / deploy (push) Skipped
- Fix DOMPurify SSR crash (use isomorphic-dompurify)
- Fix SanitizedHtml to sanitize by default
- Add auth guards to studio/catalog maintenance pages
- Add update/edit to vouchers CRUD
- Add update/edit to rare-values CRUD
- Add approve workflow to applications page
- Add edit form to guilds detail page
- Add SEO metadata to all public pages (21 pages)
- Fix mobile nav accessibility (focus trap, aria attributes)
- Fix missing labels and table accessibility
- Add dynamic imports for heavy client components (6 components)
- Fix silent error swallowing (40+ locations)
- Add content scheduling for articles (publishAt, status)
- Wire up 12 missing webhook notification triggers
- Add global search to admin panel
- Add bulk actions to admin users table
- Fix JSON formatting and a11y issues
2026-09-03 16:00:32 +02:00
openhands adf0658916 feat: extend theme builder with block visibility, layout, effects, media, and custom CSS tabs
CI / check (push) Failing after 29s
CI / release (push) Skipped
CI / deploy (push) Skipped
- Add theme-blocks.ts registry with 24 themeable blocks across 4 categories
- Extend resolver to resolve blocks, layout, effects, media, and custom CSS per scope
- Add data-theme-block attributes to all site layout blocks
- Extend ScopedThemeVars to generate CSS for block visibility, layout vars, effect vars, media vars, and custom CSS
- Rewrite admin UI with 6 tabs: Colors, Blocks, Layout, Effects, Media, Custom
- Extend server actions to save/load all new setting types
- No database migration needed - uses existing theme_scope_values table with prefixed keys
2026-08-31 17:44:29 +02:00
openhands 903d175f2d Polish responsive design across all screen sizes and refine card blocks
CI / check (push) Failing after 26s
CI / release (push) Skipped
CI / deploy (push) Skipped
- Enhance SurfaceCard with refined borders, layered shadows, and polished
  primary-tinted header with an icon container
- Update homepage blocks (hero, features, stats, login, news, photos) for
  proper mobile/tablet/desktop responsiveness and tighter mobile spacing
- Improve content-card, stat-block, card-grid and card styling with subtle
  depth (layered shadow + inner hairline) and smoother hover states
- Refine site header, footer, top header and site layout spacing for small
  screens while keeping a consistent professional look on large screens
- Add min-tap-height targets and responsive typography on mobile
2026-08-31 11:45:02 +02:00
Simo b1ddda66ff Revert "Merge pull request 'Complete Housekeeping migration and /ase cutover' (#52) from codex/housekeeping-complete into main"
CI / check (push) Successful in 27s
CI / release (push) Skipped
CI / deploy (push) Successful in 43s
This reverts commit 488b6e57c4, reversing
changes made to b506b4499a.
2026-08-30 21:31:34 +02:00
Simo 2b8f73a91d feat(housekeeping): cut over administration to ase 2026-08-30 20:35:22 +02:00
openhands 51ef7602ca perf: migrate pages to Cache Components via root layout opt-out
Remove the per-route 'export const instant = false' opt-outs now that the root layout carries the single Cache Components opt-out. Child pages inherit the opt-out, so admin/mod/radio leaf pages that only access cached or DB data stay instant while runtime-dependent pages remain dynamic. Update the staff-smoke contract test to assert the root-layout contract.
2026-08-07 18:51:45 +02:00
openhands dc8fb8a6ed feat: speed up admin clone import and enable Cache Components
- Clone import: defer FurnitureData.json writes and append all entries in a
  single batched write instead of one read-modify-write per item, removing
  the main serialization bottleneck for large batches.
- Clone import: raise SSE batch concurrency cap from 5 to 10 and bump the
  clone client/route default from 2 to 6.
- Add a flush hook to runSseBatch so callers can batch deferred work before
  batch_complete is emitted, and surface flush errors as an error event.
- Enable Next.js Cache Components (instant: false opt-out) and silence the
  related build warnings in next.config.ts.
- Switch isomorphic-dompurify to dompurify and refresh dependencies.
2026-08-05 11:10:16 +02:00
openhands 17847545dd Improvements: remove dead config, fix ESM, add URL validation, unify types, add missing logging
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m52s
- Remove .prettierrc (dead config, Biome replaces Prettier)
- Rename lighthouserc.json to lighthouserc.cjs with module.exports for ESM compat
- Add logger.warn to empty catch blocks in auth, register, site-settings, prisma-cache, redis, security, rate-limit
- Unify ActionResult type: action-helper.ts uses 'ok' consistent with safe-action-shared.ts
- Add noUnusedLocals + noUnusedParameters to tsconfig + fix 25 pre-existing unused vars
- Replace barrel export src/types/index.ts with direct @/types/common imports
- Make trustHost conditional (development only) in auth.ts
- Add pre-flight URL validation to update-Nitrov3.sh to catch image.library.url misconfigurations
- Improve NITRO_IMAGE_LIBRARY_URL content validation in pre-flight & post-compute checks
2026-07-26 20:28:11 +02:00
openhands a847ecae04 fix: restore lange banner (SiteHeader) for logged-in users, keep Enter button in TopHeader
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m50s
2026-07-26 13:03:02 +02:00
openhands 2818d2eb20 fix: remove lange banner (SiteHeader) for logged-in users; add online counter and Enter button in TopHeader
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m50s
2026-07-26 12:59:50 +02:00
openhands 6b2819aa20 Hide all top bars for unauthenticated users
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m54s
2026-07-22 18:40:09 +02:00
openhands ffd434485e Hide navigation bar for unauthenticated users
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m56s
2026-07-22 18:39:22 +02:00
SimoandCursor 803e8f36c1 feat: shop buy, forum replies, tickets, messages, sessions, and UX hardening
Deploy / release (push) Skipped
Deploy / deploy (push) Failing after 4m23s
Complete remaining product gaps: credit-based shop purchases, guild thread replies, help ticket detail/reply/close, offline message compose, sign-out-everywhere via JWT version, ads delete confirm, soft-fail feedback, rate limits, loading states, and single auth() in site layout.

Co-authored-by: Cursor <[email protected]>
2026-07-21 21:21:02 +02:00
openhands a3b077c488 feat: add smooth site-wide animations with framer-motion
Local Build and Deploy / deploy (push) Successful in 53s
- Add framer-motion and tailwindcss-animate for transitions
- Add page transitions via AnimatePresence in the site layout
- Convert nav dropdown and mobile menu to animated motion components
- Add entry animation to the radio player widget
- Add reveal/stagger animations to the home page views
- Add shared motion utilities and reusable animated components
2026-07-16 20:58:18 +02:00
SimoandCursor 367f69a439 Decouple admin from public max-w-7xl via (site) route group.
Local Build and Deploy / deploy (push) Successful in 54s
Public chrome and width live only under (site). /admin and /client inherit the root layout alone, so housekeeping width is no longer tied to the public template.

Co-authored-by: Cursor <[email protected]>
2026-07-15 21:12:52 +02:00