Commit Graph
6 Commits
Author SHA1 Message Date
m105 b181dd7e1c Add sitemap.xml/robots.txt and a clearer guest message on site pages
Sitemap lists the static pages plus one URL per indexed site (644
URLs currently); not sharded — fine at this scale, but the sitemap
protocol caps a single file at 50,000 URLs, so this will need a
sitemap index if the site count ever gets there. robots.txt moved
from a static public file to a route so it can point at the real
sitemap URL in any environment (a static file would also silently
shadow the dynamic route in production, since webservers serve
existing public/ files before hitting Laravel's router at all).

Site detail page: guests now get one prominent banner up top ("you're
viewing limited data — register or sign in to see everything") in
addition to the existing per-section "N of M results" notices, so the
overall gating is obvious immediately rather than only on scroll.
Also gave site pages a real per-page meta description (using the
site's own description/title) instead of falling back to the generic
site-wide one — worth doing now that these pages are actually in the
sitemap and indexable.

Caught and fixed a real Blade bug along the way: an inline
:description="..." expression on <x-layouts.app> with escaped
double-quoted PHP strings corrupted the compiler's directive parsing
in a way that only surfaced as a 500 on a page rendering the guest
@guest block below it (mismatched @if/@endif at compile time) — not
on the expression itself. Fixed by computing the description in a
@php block first and passing a plain variable instead.

Verified over real HTTP: sitemap.xml validates as well-formed XML
(644 <url> entries), robots.txt correctly emits the live sitemap URL,
the guest banner and site-specific meta description both render
correctly. Full test suite (31 tests) passes.
2026-07-25 16:25:08 +03:00
m105 6435bccb20 Replace hand-rolled auth with Laravel Breeze (Livewire stack)
Adds the auth Breeze scaffolds that were missing before: password
reset and email verification, plus a profile page (update name/email,
change password, delete account). User now implements MustVerifyEmail
so verification is actually enforced, not just scaffolded.

This does mean accepting Tailwind v3 (postcss/tailwind.config.js)
over the v4 CSS-first setup the app started with, and Livewire drops
from ^4.3 to ^3.6.4 — both forced by Breeze/Volt's current
compatibility requirements. Restored the Instrument Sans font Breeze's
installer dropped so styling stays close to what we had.

Reconciliation, since Breeze's installer assumes a blank-slate app:
- Deleted the hand-rolled Login/Register Livewire components/views/
  test — superseded by Breeze's Volt-based auth pages
  (resources/views/livewire/pages/auth/*), which also cover
  forgot-password, reset-password, verify-email, and confirm-password.
- Deleted Breeze's own default welcome/dashboard views and its
  separate app layout + nav component — kept our existing
  components/layouts/app.blade.php as the one real app layout, used
  Breeze's minimal layouts/guest.blade.php only for the auth pages.
- Rewrote routes/web.php merging our routes (home, sites, discover)
  with routes/auth.php; replaced every hardcoded route('dashboard')
  reference (5 Blade files plus, easy to miss, a plain PHP controller
  VerifyEmailController) with sites.index.
- Logout: Breeze's Actions\Logout::__invoke() returns void, so wired
  directly as a route it silently no-ops instead of redirecting;
  fixed with a thin closure that calls it then redirects.
- Fixed Breeze's own generated tests (Auth/AuthenticationTest,
  RegistrationTest, EmailVerificationTest, PasswordConfirmationTest)
  where they assumed the deleted dashboard route/nav component.

Verified: full suite (28 tests, including Breeze's Registration/
Authentication/PasswordReset/PasswordConfirmation/PasswordUpdate/
EmailVerification/Profile tests plus our own GuestPreviewTest) passes
against the huginn_testing MySQL database. Also smoke-tested for real:
all key pages return 200, /profile redirects guests to /login, guest
preview capping still works, and a real password-reset email was
generated and logged with correct branding and a working link.
2026-07-25 15:36:43 +03:00
m105 f5c9129774 Add authentication, a public landing page, and guest data preview
Hand-rolled login/register/logout on Laravel's built-in Auth facade
rather than Breeze/Jetstream, which scaffold Tailwind v3 config and
would fight our existing Tailwind v4 CSS-first setup. Login/Register
are Livewire components; logout is a plain POST route (auth-gated,
CSRF-protected).

Routing: "/" is now a public landing page describing the project;
the sites list moved from "/" to "/sites" to make room for it.

Data gating: App\Support\GuestPreview::paginate() forces page 1 and a
5-row page size for unauthenticated visitors on Sites, Discover, and
a site's Pages/Backlinks tables, while total() still reflects the
real match count — authenticated users get the existing full
pagination unchanged. A shared guest-preview-notice component shows
"N of M results, sign in to see all" and only renders when something
is actually being hidden.

Testing: pointed the test suite at a dedicated MySQL database
(huginn_testing) instead of the default in-memory SQLite, since the
existing fulltext index migration isn't SQLite-compatible — this app
is MySQL-specific by now regardless. Added AuthFlowTest (register,
login, wrong-password rejection, logout) and GuestPreviewTest (guest
capped to a preview, authenticated sees everything), all passing.

Also fixed a real bug the tests caught: request()->session() isn't
reliably attached during Livewire's in-process test action calls;
switched Login/Register to the session() helper, which resolves the
session store directly and works in both contexts.
2026-07-25 15:22:42 +03:00
m105 cefb846a19 Add competitor-discovery search (/discover)
The actual "who sells honey with a .es domain" feature: search sites
by keyword — matched against page title/description/keywords/body
text via a new MySQL fulltext index on site_pages — combined with an
optional TLD filter on the domain. Results are sites ranked by number
of matching pages. Shows nothing until a filter is entered, so it
doesn't just duplicate the plain Sites browse page.

Verified against real .es data pulled in for the test (dominio ->
4 matching sites, correctly ranked and TLD-filtered).
2026-07-22 21:22:14 +03:00
m105 f15eb5aec1 Add first pass of the web interface: Sites index + detail, via Livewire
Home page is now a Livewire-powered, searchable/paginated Site list
(search by domain) instead of the stock Laravel welcome page. Clicking
a site goes to a plain controller-rendered detail page listing its
pages. Shared layout at resources/views/components/layouts/app.blade.php.
2026-07-22 21:16:17 +03:00
m105 1c9fc5d423 Initial commit: Laravel scaffold + Common Crawl site indexing
Adds Site/SitePage models and the crawlindex:fetch command, which pulls
CDX index records from Common Crawl and optionally enriches them with
page title/description/keywords/body text extracted from the WARC
archive. CDX/WARC access and the site/page upsert logic live in
CommonCrawlIndexService and WarcRecordFetcher.
2026-07-20 00:04:45 +03:00