Relaunch: AI-builders repositioning — new shell & feed, URL/SEO restructure, moderation pipeline, achievements, hardening#1331
Merged
NiallJoeMaher merged 188 commits intoJun 13, 2026
Conversation
Shift positioning from 'the free web developer community' / 'Ireland's largest web developer community' to 'Codú — the community for AI builders & indie hackers' across the homepage, app layouts, hero, newsletter CTA, structured data (website + organization JSON-LD), manifest, RSS feed, the advertise page, and the profile/volunteer title metadata. Also refocus SEO keywords away from generic web-dev/React terms toward the AI-builder / indie-hacker stack (LLM apps, agents, RAG, prompt engineering, vibe coding, SaaS, MVP, bootstrapping), and reconcile the advertise metrics by dropping the contradictory '100,000+' and the 'Ireland' geography claim. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New server-rendered About page reusing the Sponsorship visual system: hero with the positioning line, a 'What Codú is for' manifesto, a 'What you get' card grid (tutorials, feed, newsletter, Discord), a small honest founder note (not a flex), and a closing CTA. Add /about to the sitemap's indexed routes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build the job board from the existing create-form stub: - job table + job_type/job_status enums + migration 0020 (AI-native tagging, featured/paid tier, full lifecycle, payment columns for a future provider) - tRPC jobRouter: create (+ admin email), public list (remote/AI-native/type filters, featured-first, keyset pagination) + getBySlug, owner getById/myJobs, admin adminList/moderate/setFeatured, and a markPaid payment stub - wire the create form to the mutation; add AI-native toggle + tags input - /jobs listing + /jobs/[slug] detail pages - flag-gated Jobs nav link in the sidebar (+ the /about nav link) Positioned for AI developer roles (employment), not indie hackers (self-employed builders aren't job-seeking). Jobs UI is gated behind FEATURE_FLAGS.JOBS (auto-on in dev, dark in prod until the PostHog flag is enabled). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Expand the content aggregator toward the AI-builder positioning: add 26 RSS-verified AI sources (Latent Space, Simon Willison, Ahead of AI, Import AI, Eugene Yan, Lilian Weng, Chip Huyen, Hamel Husain, Jay Alammar, Interconnects, One Useful Thing, AI Snake Oil, The Gradient, Google DeepMind, Microsoft AI, AWS ML, NVIDIA, Together AI, Replicate, Ollama, LlamaIndex, Roboflow, fast.ai, Answer.AI, BAIR, Apple ML) to drizzle/seed-sources.ts. Takes the 'ai' category from 6 to 32 sources. Additive only — existing web-dev sources are kept (web-dev content stays, just no longer the headline). Seed is idempotent (insert-by-url), so re-running only adds the new feeds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A dev-gated (NODE_ENV) design canvas at /kitchen-sink for iterating on the redesign. Proposes a fresh, editorial direction — cool dark canvas, Bricolage Grotesque display, Hanken Grotesk body, JetBrains Mono micro-labels — and drops the orange/pink gradient entirely. Renders four fresh accent options (Mint, Lime, Sky, Iris) side-by-side plus tokens, buttons, form controls, tags, a job card, and an applied hero so we can lock a theme before touching real pages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s living design system - Load Bricolage Grotesque / Hanken Grotesk / JetBrains Mono via next/font in the root layout and expose them as --font-display / --font-sans / --font-mono. - Rebuild /kitchen-sink as the canonical, dev-only LIVING design system: Mint accent locked, cool-dark tokens, organized Foundations / Components / Patterns to grow as we build real pages. - Apply the anti-trope direction researched this session: editorial 'number + hairline + display-title' section headers instead of the common '// label' dev-tool convention, hairline rules over soft shadows, no bento/blobs. - Include a side-by-side section-label comparison (code-comment vs slash vs editorial) to decide the structural device. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the prototype's inline styles with a real system:
- Add CSS-variable-driven design tokens (canvas/surface/elevated/hairline/fg/
muted/faint/accent) in styles/globals.css (dark-first via .dark) and register
them in tailwind.config.js with opacity support, plus font-display/sans/mono.
- Restyle global .primary-button / .secondary-button / .focus-style to the Mint
accent — removes the orange→pink gradient app-wide.
- Add reusable components/ds: Eyebrow ('// label' mono, the approved convention)
and Tag (default/accent/soft pills).
- Refactor /kitchen-sink to consume theme classes + ds components (no inline
colors/fonts), wrapped in 'dark' so it always shows the canonical palette.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nnel) Start the growth-driven page rebuild: - New NewsletterCapture ds component (inline + compact) with real on-site beehiiv capture via a subscribeNewsletter server action (degrades gracefully in dev). Replaces the old blue->pink gradient NewsletterCTA on the homepage rail. - Rebuild the Hero as a token-driven server component: editorial dotted-grid atmosphere (no gradient/starfield), Bricolage display H1 with the accent on 'AI builders', mono eyebrow, single primary CTA (Join free) + Browse feed. - Rework the post-hero band from a clashing light-gray duplicate CTA into a dark, on-system 'the community / build in public' beat with one CTA. No vanity metrics (social proof deferred per owner). Funnel: cold -> subscribe, warm -> join free. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stop re-skinning the old app shell — give the front door its own layout. - Force dark-only (next-themes forcedTheme + html.dark). - New (marketing) route group: top-nav + footer shell (no app sidebar), full-bleed, with the org JSON-LD and a footer newsletter capture. - Rebuild the homepage from scratch as an editorial landing: hero (accent glow + dotted grid), a real 'Fresh from the feed' proof-of-life grid (live AI posts), a numbered 'why Codú' value grid, and a community beat — all token-driven, no vanity metrics. Move it out of the (app) sidebar layout. - The (app) sidebar shell stays for the logged-in app pages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make 'Fresh from the feed' read as clickable articles, not an info box: - pull post cover images and render them as CSS background images (external feed domains aren't allowed by next/image), with an on-brand dotted fallback when a post has no cover - switch from the seamless gap-px grid to separated cards with hover-lift, accent border on hover, and a 'Read ›' affordance Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…existing logo - Move get-started into a new (auth) route group with a bare layout (no nav, no sidebar, no footer) for a zero-distraction sign-in/sign-up. - Rebuild the auth UI on the new tokens: mono eyebrow, Bricolage heading, clean bordered GitHub/GitLab buttons (no orange/pink gradient), terms/privacy note. - Use the existing Codú wordmark logo (/images/codu.png) in the auth header, marketing nav, and footer instead of a text wordmark (new logo is a later task). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move /about out of the app sidebar layout into (marketing), rebuilt token-driven (editorial hero, manifesto, what-you-get cards, small founder note, CTA) — drop the old orange/pink Sponsorship-style sections and retire components/About. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…letter card sitewide - App sidebar: canvas bg + hairline border + mint active icons (was bg-black / neutral); footer + socials to tokens. - Swap the old blue->pink NewsletterCTA for the token-driven NewsletterCapture on /feed and /articles, and delete the dead NewsletterCTA component. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- De-bootstrap the nav: animated accent underline on links, refined spacing. - Capture competitive learnings from IndieHackers (right-rail conversion hub with Submit-a-Post/Advertise, the Build Board leaderboard, content-forward layout) in the growth doc as the next-build backlog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ct form - Move /advertise into (marketing), rebuilt token-driven: hero, 'ways to partner' offering cards (newsletter/jobs/events/content), real past-partner logos kept as legit proof, dropped the vanity metrics + generic testimonial. - Recolor the 3-step sponsor ContactForm from orange/pink to mint tokens. - Retire the old (app)/advertise route + unused Sponsorship section components (keep ContactForm). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Recolor every remaining orange/pink utility to the mint accent across ~55 app + component files (feed, jobs, admin, editor, comments, badges, search, 404, etc.). Archived /letters posts left untouched. - Homepage feed cards: remove the jump-on-hover; keep a subtle image zoom + chevron slide. Same de-jump applied to /about cards. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New ConversionHub ds component (Write a post / Post a job / Advertise) surfaced at the top of the feed sidebar, and retoken the 'About the Feed' card. Gives content pages a clear contribute/monetise hub like IH's right rail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WS3 v1, built safely (engagement never breaks core actions): - Schema + migration: append-only point_event (with dedupe/anti-gaming index) and per-user user_streak. - server/lib/engagement: award() (never throws) + recordDailyActivity() (idempotent daily streak roll-forward). - Award points on post publish + comment create; roll the daily streak in the app layout for signed-in users. - engagement tRPC router: myStats (streak + points) and leaderboard (week/all). - UI: StreakBadge (🔥) in the app header for signed-in users; BuildBoard weekly leaderboard in the feed rail — flag-gated (FEATURE_FLAGS.BUILD_BOARD) and hidden while empty to avoid a ghost-town board. - Fix the header Create button contrast (black on mint). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y + engagement-plan doc - Kill remaining grey: retokenize UnifiedContentCard, the inline /articles ArticleCard + skeleton, SavedItemCard, PopularTagsSidebar, legacy ArticlePreview, and the feed Filters dropdowns to the design tokens (surface/canvas, hairline, fg/muted/faint, accent hover). - Simplify taxonomy: remove the redundant rail 'Sources' filter (it duplicated the Topics dropdown via source category); sources remain as card attribution. Relabel the dropdown to 'Topics'. - Add codu-relaunch/04-community/engagement-plan.md (shipped / building / deferred / last). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New HeroBackdrop: refined mint aurora glows, a deterministic twinkling constellation, and occasional shooting stars — restrained, reduced-motion aware (motion-safe only). Replaces the flat dotted-grid+blur hero backdrop. - Add reusable keyframes/animations to the Tailwind theme (twinkle/aurora/drift/ shoot/rise) and a staggered load reveal on the hero eyebrow/H1/sub/CTAs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…play) - Schema + migration: badge + user_badge (unique per user/badge). - engagement.ts: BADGE_RULES + checkBadges() (runs after award; first post, 7/30-day streak, 100/500 points; connector wired in the referral step) + getUserBadges(). - Seed 6 starter badges (drizzle/seed-badges.ts). - Display badge pills on the profile header. - Reference + AI design prompt: codu-relaunch/04-community/badges.md; auto-mod plan: ai-moderation-plan.md (deferred). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… aurora - Add ogl + a themed GradientBlinds component (reactbits-derived) — animated mint gradient blinds with a cursor spotlight, reduced-motion aware (single static frame). - Use it as the homepage hero backdrop with a readability scrim; retire HeroBackdrop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Schema + migration: user.referralCode (unique) + user.invitedBy; add 'referral' to the point_action enum. - engagement.ts: ensureReferral() (lazy code-gen + cookie attribution → award the referrer 'referral' points + checkBadges → Connector badge); wire real referral count into the connector badge rule. - /get-started captures ?ref into a cookie; the app layout attributes it on next visit (idempotent, never throws). - engagement.myReferral query; ReferralCard (invite link + count) in Settings → 'Invite friends'. - Backfill referral codes for existing users (drizzle/seed-referral-codes.ts). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…first, composer
- Schema + migration: follow table (follower/following, unique pair, indexes).
- follow tRPC router: follow / unfollow / isFollowing / counts.
- Feed: 'following' filter in content.getFeed (+ fix the previously-unused tag
filter) and a For-you / Following tab on /feed (signed-in), with an empty state.
- Profiles: FollowButton (Follow/Following, optimistic invalidation) + follower/
following counts in the header.
- Feed-first: signed-in users are redirected from / to /feed (marketing stays for
logged-out + SEO).
- Inline composer ('What are you building?') at the top of the feed.
- Datastore note: recommend staying on Postgres over a Mongo migration
(codu-relaunch/01-platform/datastore-consideration.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…llowing lists - Follow notifications: NEW_FOLLOWER type, created on a new follow; widen the notification read filters (type 0/1/2, drop the postId-not-null requirement) and render 'started following you' in the notifications list. - Achievements section on profiles (engagement.profileEngagement): current/longest streak, points, and the full badge set with earned + LOCKED states + criteria (the 'potential awards' view). Replaces the simple header pills. - Followers / Following lists: follow.getFollowers/getFollowing + clickable counts that reveal the list (with avatar, name, Follow button per row). Verified logged-in: Follow → Following toggle, live count, followers list, and the achievements panel all work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 0 of the design-handoff recreation. Treat the handoff at design_handoff_codu/ as the source of truth. - styles/globals.css: full token set (surface ladder hover/inset, border-strong, on-accent, status colors success/warning/danger/info), fix dark --color-faint #5b6472 -> #757e8c for WCAG AA, align fg/accent-soft to handoff hexes, add focus-ring/shadow ladder CSS vars - globals base layer: global mint :focus-visible ring, display-font headings, .eyebrow/.slash + .card utilities, reconcile primary/secondary/ghost buttons to handoff (on-accent text, radius-md, press translate), drop dead .old-input - tailwind.config.js: expose new colors + washes (opacity modifiers), radii scale, boxShadow, container maxWidth, fontSize/letterSpacing scale, motion tokens, bg-grid-lines - components/ds: Tag/FollowButton text-black -> text-on-accent - kitchen-sink: full color ladder + status + elevation/radii + toggle refs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 1. Replace the single-sidebar layout with the handoff shell. - components/Layout/AppShell: sticky TopBar over the .app-main 3-column grid (LeftRail / center / RightRail) + ⌘K palette + logged-out SignInBar; global ⌘K/Esc keydown handling - TopBar: logo→/feed, search-button styled like an input (opens palette), Feed/Discussions/Jobs nav, Write + avatar menu / Log in + Join free - LeftRail: primary nav (+ Notifications/Saved/Profile when authed), Your topics tags, bottom-pinned Privacy/Conduct/Advertise/About footer - RightRail (now global on every page): ProgressCard (points+streak+next milestone from engagement.myStats) / JoinCard → trending tags → ConversionHub / NewsletterCapture - CommandPalette: quick actions + live tag search (tag.search); posts/people via Algolia is a follow-up - styles/globals.css: .app-topbar/.app-main/.app-leftrail/.app-rightrail grid with bespoke 1080/720 breakpoints - feed/_client: drop internal rail+grid (rails are global now), render center column only; text-black→text-on-accent on the composer CTA - (app)/layout: render AppShell; drop Algolia sidebar wiring Old SidebarAppLayout/sidebar-layout/MinimalHeader/AppSidebar now unused. Note: /discussions nav target lands in Phase 6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 2. Per the handoff, the feed is the landing surface; there is no marketing homepage. - (marketing)/page.tsx: 308 permanentRedirect / -> /feed (canonical home). Drop the GradientBlinds hero / value-prop / feed-preview landing (the GradientBlinds component stays for reuse on /about). - Logged-out visitors land on the public, indexable feed (getFeed is a publicProcedure) with the shell's sign-in bar + Join free. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion kinds Phase 3. - schema: add `til` + `question` to the post_type enum (migration 0025_normal_nuke); extend ContentTypeSchema + toDbType/toFrontendType so QUESTION maps to a real `question` kind and TIL is first-class - UnifiedContentCard: rebuilt as an editorial row — kind chip (Article/TIL/ Question/Discussion/Link), author + @handle · time (· via source), display title with ↗ for links, 2-line excerpt, OG thumb / striped placeholder, mono #tag metadata, reaction bar (▲ helpful · replies · Save · Share with copy-link). Vote/bookmark/click mutations preserved; drop legacy chevron/ bookmark-icon body and dead URL helpers - feed: dismissible OnboardingBanner (first-win 3 steps, useSyncExternalStore) + low-bar Composer (Tip/Ask/Share/Write chips → /create?kind=) - FeedFilters: add TIL option; feed type validation accepts `til` Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 4. Visual restyle of the three reader clients (user article, curated
link, user link) under app/(app)/[username]/[slug]/ — functionality, data,
voting/bookmark/share, FollowButton, and the comments component preserved.
- ‹ Back to feed ghost link, // eyebrow (tag/source · meta), large display
title, author row + Follow, cover in a hairline frame / grid-dots placeholder
- mono editorial reaction footer; "Discussion {count}" header above comments
- swap all hardcoded neutral/blue/green/red + dark: colors for design tokens;
text on accent is text-on-accent
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t resolvers AI crawlers don't execute JS — the homepage, /discussions, /s/ pages and member link posts previously shipped empty shells. The first page of each list (and the full article/link bodies) now renders server-side and hands off to the client queries as initialData; interactivity stays in client islands. Adds an in-process tRPC caller (no HTTP self-fetch) and React cache() on the per-request resolvers, halving DB round trips that generateMetadata + page were paying twice; getServerAuthSession is now request-deduped too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- app layout, checkBadges, and engagement procedures batch their independent queries with Promise.all; badge grants are one multi-row insert instead of a per-row loop - new rateLimited middleware in trpc.ts; profile.edit/updateEmail, job.create, discussion create/edit/vote/follow, follow, tag.getOrCreate and comment edit/delete/vote are now throttled (previously unthrottled) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… screen wiring - getRelativeTime consolidated from five drifted copies into utils/relativeTime.ts; ComposeModal uses getHostname; /s/ resolvers use parseUrlId; PostReader renders Markdoc once (cast gone); dead mirrored vote state removed from UnifiedContentCard - SITE_ORIGIN/SITE_HOST in config/site.ts replace ~20 hardcoded www.codu.co literals (JSON-LD, sitemap, RSS, robots, IndexNow, canonical builders); buildCanonicalUrl and memberPostUrl now share buildContentHref instead of duplicating the URL scheme - gatePublish runs the screenContent heuristic ahead of Bedrock review (was only the Bedrock-off fallback); cron lambda fails closed if the siteUrl SSM param is unreadable (was silently POSTing prod) - tag pages get crawlable ?page=N pagination; llms.txt links top tag pages; footer stops linking redirecting legacy paths Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ti on every badge
- new onboarding_complete badge ('First Steps' 👣) granted when the three
onboarding steps are done; inserted idempotently by the migration so it
exists in every environment and shows in the achievements tab
- onboarding's third step is now 'leave your first comment' instead of
publishing a post — finishing onboarding earns exactly one badge, and
first_post stays locked as the next-step tease
- generic BadgeCelebration replaces OnboardingCelebration: every newly
earned badge fires confetti + the unlock dialog (queued oldest-first),
driven by a new user_badge.celebratedAt column (backfilled for existing
badges so nothing retro-celebrates); firstWinCelebratedAt and its
mutation are gone
- discussion.create (the live commenting path) now awards comment_created
points like legacy comment.create did — it previously awarded nothing,
so comments earned no points and never triggered badge checks
- follow and topics-save run checkBadges explicitly (no points awarded
there); badge checks now also see comments, topics, and follow counts
- achievements tab shows '{n} earned' instead of '{n} of {total}' since
the catalogue will keep growing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…en magic-link provider id
- docker-compose now ships Mailpit (host ports 1027/8027 — 1025/8025 are
commonly taken locally); EMAIL_PROVIDER=local routes every outgoing
email (magic links, moderation/report mail) to it instead of SES, in
dev and E2E. Hard-disabled on production deploys.
- e2e/mailpit.ts helpers + email.spec.ts assert real delivery through
Mailpit's API; the spec skips cleanly when Mailpit isn't running
- the new spec immediately caught a real bug: next-auth v5 registers the
Nodemailer provider as 'nodemailer' while the sign-in UI calls
signIn('email') — magic-link sign-in never sent anything. Provider id
pinned to 'email'.
- editor e2e specs updated for moderator-only scheduling: the removed
user-facing schedule controls are now asserted ABSENT instead of
visible (3 stale tests were failing)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…suite - npm audit: 53 vulnerabilities (1 critical, 13 high) → 8 (0 high/critical). next 16.1.1→16.2.9, drizzle-orm 0.39→0.45.2 (SQLi advisory GHSA-gpj5), drizzle-kit →0.31.10, constructs →^10.5, sentry + transitive bumps via audit fix; esbuild override ^0.28.1 lifts drizzle-kit's stale copies. Residual (documented): nodemailer 7.x moderate (next-auth peer-pins ^7; the vulnerable envelope.size param is never user-controlled here) and Next's internally-pinned postcss copy. - drizzle 0.45 fixed the auth adapter type mismatch — stale @ts-expect-error removed - e2e: badge celebrations can pop mid-test and block clicks — login helpers auto-dismiss via addLocatorHandler; saved.spec gets a dedicated bookmark fixture so it can't race other specs; local workers capped at 4 (unbounded workers over-subscribed the dev server causing timeout flake — capped run is green 131/131 and faster) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- content.update({published:true}) on a scheduled/in_review/rejected post
now throws like content.publish does — it was the one remaining path
where an author could force-publish around a moderator's schedule or
rejection
- SessionProvider now receives the server session, so session-derived
query keys (feed 'following') are stable through hydration and SSR
initialData attaches to the right key; discussions page mirrors the
client's derivation exactly and skips the fetch when the client query
would be disabled
- feed no longer hides published rows with NULL publishedAt (legacy/
imported data)
- migration 0037 pre-grants the onboarding badge (already celebrated) to
users who already qualify — without it every established member would
get a nonsensical 'First Steps' confetti after deploy
- notification links to aggregated /s/ content resolve again (source slug
included); ComposeModal routes 'View post' per content kind, refreshes
the badge celebration, and its stale 'posted' comment is gone
- isLocalMail gates on NODE_ENV (covers non-Vercel prod + previews);
sample.env no longer pre-sets EMAIL_PROVIDER=local; port comments match
the 1027/8027 mapping
- suppressHydrationWarning on Date.now()-derived relative times in the
now-SSR'd cards; dead SideBarSavedPosts (stale duplicate logic) removed
- ops docs: CRON_SECRET in sample.env, /env/siteUrl + /env/cronSecret SSM
prerequisites in cdk/README, preview-deploy migration note in README
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…the deploy The /sitemap.xml route is the only one that queries the DB during prerender. On Vercel preview/build (where the database isn't reachable at build time) the unwrapped queries threw and aborted the whole build. Wrap every query in a safeRows() helper that degrades to an empty list on failure; revalidate=3600 still regenerates the full sitemap at runtime once the DB is reachable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ter refs - Reframe the intro from "community of web developers" to the relaunch positioning (AI builders & indie hackers), grounded tone, and surface the real post kinds (articles, TILs, discussions, questions). - Replace stale Pages Router boilerplate (pages/index.tsx, pages/api) with accurate App Router guidance (app/ routes, app/(app)/page.tsx home feed, Route Handlers under app/api). - Minor: Postgres "15.0" -> "15" to match docker-compose (postgres:15-alpine). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
These files were committed unformatted; the PR head was a stale fork branch so CI never checked them. Now that the branch is current, `npm run prettier` (prettier 3.7.4 + prettier-plugin-tailwindcss class sorting) flagged 38 files. Pure formatting — whitespace and Tailwind class ordering, no logic changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…T DISTINCT) Migration 0029 adds `UNIQUE NULLS NOT DISTINCT` on point_event (the dedupe / anti-gaming key), which is Postgres 15+ syntax. The RDS instance was pinned to 14.5, so `db:migrate` failed on every Vercel deploy. Bump the engine to 15.8 (local dev already runs postgres:15-alpine) and set allowMajorVersionUpgrade so RDS accepts the major-version change. NOTE: requires `cdk deploy` of the StorageStack to take effect (in-place RDS major upgrade, brief downtime). Vercel stays red until that deploy completes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RDS rejected 15.8 ("cannot find upgrade path from 14.22 to 15.8"); the valid
PG15 target from the live 14.22 instance is 15.17. The cdk subproject's
aws-cdk-lib (2.233.0) predates the VER_15_17 enum member, so use
PostgresEngineVersion.of("15.17", "15"). Verified on Dev: RDS accepted the
change and upgraded in place.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…quirement The Vercel Build Command is overridden to `db:migrate && ci-build`, so every target migrates (preview->dev DB, prod->prod DB) and a failing migration reds the build. Also document that connections need `sslmode=require` (rds.force_ssl). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rather than inheriting force_ssl from the default.postgres15 group (whose default flipped 0->1 vs postgres14 and silently required SSL post-upgrade), make it intentional in code. Share one pgVersion const between the instance and the parameter group so they can't drift. NOTE: deploying associates a new parameter group with the instance (needs a reboot to finalize); behaviour is unchanged since force_ssl is already 1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The full Codú relaunch: repositioned as the community for AI builders & indie hackers, with a new product surface, a new content-URL scheme built for SEO/AEO, a moderation-gated publishing pipeline, achievements, and a long hardening pass. 181 commits, migrations
0011–0037(run automatically byvercel-buildon production).Product
App shell & design system
/): editorial rows with kind chips, vote/save/share actions, Type · Sort · Topic filters;/discussionsindex. Post kindstilandquestionadded.Achievements
badge/user_badge) with 7 badges; every newly earned badge fires an app-wide confetti unlock dialog exactly once across devices (user_badge.celebrated_at, backfilled so nothing retro-celebrates; existing qualifying members are pre-granted the onboarding badge silently — migration0037).point_event,user_streak);discussion.createnow awards comment points (it previously awarded nothing).Moderation pipeline (env-gated:
MODERATION_ENABLED)/api/cron/promote-scheduled(secret-authenticated, idempotent go-live side effects: points, notification, IndexNow).publishedAt, or force-publish around a moderator's schedule/rejection on any mutation path (publish and update are guarded; the legacy/alphaeditor and its unguardedpost.*write mutations are deleted outright).URLs, SEO & AEO
/{username}/{slug-urlId}for member content,/d/{slug}discussions,/s/{source}/{slug}aggregated content,/tag/{slug}landing pages (paginated). Slugs end with an immutableurlId, so title edits and renames 301 forever; legacy URLs (/articles/*,/feed/*, sources,/courses,/alpha) all 301.lower(username)unique index), every resolver 301s to stored casing./s/pages and link posts server-render their first page/content (AI crawlers don't run JS); JSON-LD (Article, NewsArticle, DiscussionForumPosting incl. comments, ProfilePage, Organization, WebSite, breadcrumbs); rebuilt sitemap (content, tags, sources, non-thin profiles); IndexNow pings on every go-live path;llms.txt; robots policy with explicit AI-crawler allowances; RSS rebuilt on the new tables/URLs./ogimages 500ed for all Twitter cards (and were robots-blocked), magic-link sign-in was silently broken (next-auth v5 provider-id mismatch), session callback never setsession.user.username.Hardening & performance
RATE_LIMIT_TABLE).httpUrl()zod hardening, report-email throttling, urlId-collision hijack guard.cache()dedupes metadata+page resolution (content pages ~halved their queries), parallelized layout/engagement queries, feed stops shipping full post bodies,lower(username)/urlId/feed indexes.npm audit53 vulnerabilities (1 critical / 13 high) → 8 (0 high/critical). next → 16.2.9, drizzle-orm → 0.45.2 (SQLi advisory), drizzle-kit → 0.31.10, sentry + transitive bumps. Residual: nodemailer 7.x moderate (next-auth peer-pins ^7; vulnerable param never user-controlled here) and Next's internally-pinned postcss.Testing & DX
tsc/eslint clean; prod build verified.EMAIL_PROVIDER=local, UI atlocalhost:8027) — dev and e2e exercise real email delivery without SES; hard-disabled on production builds.Deploy checklist
MODERATION_ENABLED=true,RATE_LIMIT_TABLE,CRON_SECRET(must match the per-account/env/cronSecretSSM param),EMAIL_AUTH_ENABLEDas desired./env/siteUrl,/env/cronSecret(lambda fails closed without them) — seecdk/README.md.CronStack(scheduled-post promotion lambda + EventBridge rule).npm run db:migrate).🤖 Generated with Claude Code