DataTalksClub / DataTalksClub/website

Populate internal event pages and replace Luma registration CTAs

Open
#127 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accessibility admin content data-migration enhancement events frontend integration P0 security seo testing
Dominant language
Python
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Outcome

Visitors can read the real event description at the canonical internal detail page and start registration at the canonical internal registration page. No public page, metadata, feed, or structured data sends a visitor to Luma. Luma is a reviewed one-time migration source only; it is never a runtime dependency or a second event system.

This is the smallest P0 content-and-integration slice. It does not create the Event model or registration lifecycle and it does not redesign the event surfaces.

Normative contracts

If this issue and a normative specification differ, the specification wins unless the owner approves a decision change.

Required dependencies and gates

Blocked: do not implement or activate this issue yet.

  • #45 must first supply the accepted canonical database-backed Event identity, content, lifecycle, public detail, Studio, and admin API contracts. This issue must not introduce an alternate event/content model.
  • #46 must first supply the accepted /events/<slug>/register route and accountless verified-registration service. Its dependencies, including #17 and #49, remain owned there.
  • #22 must approve the event verification/confirmation Relay purposes before the internal registration CTA is enabled. The current specification fails every non-course purpose closed.
  • #23 is a production activation gate for privacy notice, retention, and erasure behavior. Candidate public content can be verified before that decision, but registration cannot go live around it.
  • #124 is already satisfied and remains the Relay boundary. The website creates the business state, one logical EmailDelivery, and one durable job atomically; only the leased after-commit job calls Relay.

#112 is an independent, already-present aggregate-only overlay and must remain unchanged. #130 owns event/homepage visual composition and CSS; #127 owns migrated body content, link/CTA behavior, and integration with the registration form. Neither issue depends logically on the other, but the second implementation must rebase on the first accepted template work rather than overwrite it.

Source baseline

The reviewed local source is /home/alexey/tmp/luma-exporter/luma-events from exporter commit a0ede3c1451d34c5bc99acf58459ef1c65ae51df:

  • 168 checkpoint JSON files and 168 matching, non-empty Markdown descriptions;
  • public-event allowlist digest b2859a7be33fb29821d53e25265ce91c37f376f1de7467780a351d707294fbc5;
  • description-manifest digest 6ffd000db03b71c7308d83328a5d744ccec298b1cca458aa04831689431b030a.

These digests cover only the reviewed public-safe projection, never checkpoint guest arrays or CSV identity data. The source directory is local operator input; it is not copied wholesale, committed, read during requests/builds, or contacted over the network.

Source precedence and reconciliation

  1. The accepted #45 Event import owns canonical Event UUID, slug/path, lifecycle, title, time/timezone, type, speakers, and existing useful recording links for records already known to the website.
  2. The reviewed Luma snapshot owns candidate Markdown description content and migration provenance only. It may suggest source registration state but cannot silently replace canonical identity, lifecycle, title, or time.
  3. Produce a deterministic review manifest that classifies every snapshot event as match, create, or exclude, names the canonical Event slug for every match/create, and records a bounded reason. Exact normalized source URL/ID or exact title plus instant may generate a candidate; fuzzy matching never writes or activates data. Every candidate is reviewed.
  4. Source-only current events cannot be silently dropped. They are created only from the strict public allowlist after review, with a stable non-colliding slug, or excluded with an explicit reason. Existing projection-only events remain valid. In particular, do not invent a body or relationship for a projection event absent from the source.
  5. Conflicting title, time, slug, duplicate mapping, or one source event targeting multiple canonical events fails the candidate run for review. No last-write-wins behavior is allowed.
  6. After activation, the database Event and the shared #45 application services are authoritative. Studio and the admin API edit the same revisioned content. A future exporter snapshot creates another dry-run/review candidate; it never overwrites operator edits automatically.

Public-safe import boundary

Add a network-free, explicitly invoked, idempotent migration command using the project uv workflow. It must support dry-run/report and explicit apply, validate the source baseline/schema, preflight the complete candidate, and apply atomically through #45 services. A failed or stale run changes nothing. Reapplying the same reviewed candidate is a no-op; rollback uses the project revision/activation mechanism rather than deleting history.

Only allowlisted public event fields and the matching Markdown description may cross the boundary. Raw checkpoint files, guests, attendee/guest CSVs, names/emails/answers, meeting or join URLs, access codes, private organizer/contact fields, API data, tokens, filenames/paths tied to attendee evidence, and whole-checkpoint hashes must never enter repository fixtures, database rows, reports, logs, metrics, screenshots, or rendered output. Public speaker identities already approved by the canonical Event record are unaffected; source text that appears to contain a private identity or access secret fails review rather than being guessed safe.

The command must reject unreadable/missing input, unexpected schema, invalid UTF-8, oversized content, duplicate basenames/IDs, traversal or symlink escape, unsafe fields, and partial description/checkpoint sets with a bounded non-sensitive error.

Markdown and link policy

  • Parse Markdown through the project's allowlisted sanitizer. Raw HTML, unsafe schemes/attributes, scripts, embeds, forms, tracking pixels, and unsafe remote images fail or are removed according to one tested policy; no source HTML is trusted.
  • Rewrite known datatalks.club links to exact canonical routes. Rewrite courses.datatalks.club only through an explicit accepted compatibility map. A missing or ambiguous internal target blocks activation rather than producing a broken link.
  • Classify every luma.com/lu.ma destination. A mapped event-detail link becomes /events/<slug>; a mapped registration-intent link becomes /events/<slug>/register; obsolete/unmapped Luma links are explicitly removed or block review. No Luma URL survives in rendered HTML, attributes, metadata, JSON-LD, feeds, sitemap material, or stored public content.
  • Do not hotlink Luma CDN assets. A reviewed image is imported as a checksum-addressed local asset with required accessible metadata, or omitted with a visible review warning.
  • Preserve safe, useful non-registration destinations such as recordings. This issue does not broadly migrate or reclassify historical Eventbrite data, but no external destination may be selected as the current primary registration CTA.

Visitor behavior

  • /events/<slug> remains the no-trailing-slash canonical detail from #45 and renders the sanitized description as meaningful structured content. A missing description has a truthful compact fallback; it never receives invented copy.
  • When the Event is published and registration is available under #45/#46, the primary CTA is Register and links only to /events/<slug>/register.
  • Closed, completed, cancelled, unpublished, or otherwise unavailable events show the truthful lifecycle state and no active registration CTA. Existing useful recording actions remain clearly labelled.
  • /events/<slug>/register and its form behavior, privacy copy, uniform responses, verification/cancellation, abuse controls, and trailing-slash compatibility are exactly those accepted in #46. This issue consumes that service and must not duplicate it.
  • Missing/unpublished details return the #45-safe 404; registration ineligible/missing behavior follows #46 without leaking event capability or attendee identity. Detail errors and every registration response are non-cacheable where the specifications require it.
  • Event hub/homepage links enter the internal detail first. Public event pages expose neither external provider identifiers/provenance nor any attendee identity. The optional N registered display remains exclusively governed by #112.
  • Canonicals, robots, metadata, sitemap inclusion, caching, and query handling follow the route registry. Registration pages/outcomes are private, no-store, and non-indexable.

Studio and admin API parity

Imported description, lifecycle-derived availability, source mapping summary, and revision state are managed through #45's shared services. Studio and the admin API expose equivalent authorized operations, validation, optimistic conflict behavior, audit events, and safe errors; public views are read-only consumers. Provenance is management-only and redacted. Raw source payloads and attendee data are never returned.

Registration record operations, exports, attendance, bulk messaging, and provider diagnostics remain owned by #46/#47/#49 and are not added here.

Acceptance criteria

  • A dry run classifies all 168 source event/description pairs and every source-only current event; every row has one reviewed match, create, or exclude decision and no fuzzy or unclassified write path.
  • Apply is all-or-nothing, repeatable, and network-free. Missing/stale/malformed/unsafe source, mapping conflicts, and invalid links produce bounded errors with no writes or private data disclosure.
  • Only public-safe allowlisted values enter Event revisions. Automated canary tests prove guest/CSV/private checkpoint values cannot cross into fixtures, storage, logs, reports, APIs, pages, or screenshots.
  • Every activated matched/created Event renders its reviewed sanitized description at /events/<slug>; an unmatched or intentionally empty Event renders the accepted fallback without fabricated content.
  • The public crawl and stored activated body/link fields contain zero luma.com, lu.ma, Luma CTA, or Luma CDN destination. Known internal links resolve directly to canonical paths; useful recording links still work.
  • Every eligible event's sole primary registration CTA targets /events/<slug>/register; unavailable events expose no actionable registration CTA and accurately state why.
  • #46's anonymous registration, uniform submission, verification/management, CSRF, rate-limit, honeypot, token, and email-failure regression suite passes through the CTA journey. #22/#23 gates are approved before live activation.
  • Studio and admin API edits affect the same canonical Event revision and public view, have permission/parity/conflict/audit tests, and never expose raw migration or attendee data.
  • #112's complete-total, omitted-total, no-identity, zero-store, and no-double-counting tests remain unchanged and pass. No historical aggregate import sends mail or creates a native registration.
  • Templates remain readable and non-minified. The accepted #130 composition, if already present, is preserved; this issue adds no independent visual redesign.
  • Full Django/unit/integration/link/security tests pass via uv-backed commands, with no unexplained route, canonical, metadata, cache, sitemap, accessibility, or existing recording-link regression.

Browser acceptance scenarios

Verify at web.dtcdev.click at desktop (1440px) and mobile (390px), in light and dark modes where #130 supplies them. Screenshots must use synthetic addresses and contain no source/private registration data.

  1. Upcoming eligible event: enter from homepage and /events; both link to the internal detail. Confirm meaningful description hierarchy, safe links, exact canonical, internal Register CTA, readable form, keyboard focus, labels/errors, and the uniform submitted state.
  2. Completed event with recording: confirm description and recording remain usable, state is truthful, and there is no registration CTA.
  3. Cancelled/closed/unpublished/missing event: confirm the accepted closed state or non-enumerating 404, no stale CTA, no private cacheability, and no existence/registration leak.
  4. No source description: confirm the compact fallback and absence of invented content.
  5. Link edge cases: confirm an old internal URL reaches the exact canonical directly, a mapped Luma registration link is internal, unsafe/unknown links cannot activate, and the rendered DOM/source has no Luma URL.
  6. Registration failures: invalid input, duplicate submit, throttling, Relay unavailable, and verification/cancellation link edge cases retain #46's accessible, enumeration-resistant, no-store behavior and do not lose committed business state.
  7. Management parity: with authorized and unauthorized staff roles, edit/publish/revert the description through Studio and the API and confirm equivalent validation, conflict, audit, denial, and public activation behavior.

Non-goals

  • Event schema/lifecycle/slug/Studio/API creation (#45).
  • Registration records, verification/cancellation semantics, privacy fields, capacity/waitlist, or registration email/outbox implementation (#17/#18/#46/#49).
  • #111 optional questions, sponsor evidence, or newsletter behavior.
  • #47 attendee operations, attendance, exports, bulk update/cancellation messaging, or provider operations.
  • Changing #112 totals, importing attendee rows, deriving identities/digests, or interpreting source status as attendance.
  • Homepage/event visual redesign, CSS system, or layout composition (#130).
  • Runtime Luma API/exporter calls, scheduled synchronization, provider fallback, or a second mutable content store.
  • A broad Eventbrite migration or cleanup of unrelated historical external links.
  • Production registration activation before the owner decisions and dependency acceptance listed above.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the contracts in _docs/specs/02-url-link-seo-compatibility.md, _docs/specs/05-events-registration-email.md, and the dependency issues #45 and #46. Use the reviewed /home/alexey/tmp/luma-exporter/luma-events source and the project uv workflow to run a network-free dry run before any apply. Done means all 168 pairs are reviewed, safe content is imported atomically, internal routes replace Luma links, and the acceptance and regression checks pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend-api-design, content, full-stack
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.