Skip to content

Make /slack the canonical destination for Slack links in the Docs #184

Description

@alexeygrigorev

User outcome

Every link in rendered source-backed content that sends a reader to the DataTalks.Club Slack
community lands on this site's own /slack page instead of going straight to an external
Slack URL. /slack is the one canonical destination for community-Slack links.

Owner note (recorded at intake): the /slack page itself does not need to show a Slack
join/invite link. That is an explicit non-goal; the missing invite is not a gap.

Normative links

  • _docs/specs/02-url-link-seo-compatibility.md § "Route rules that must remain exact"
    (historical hub aliases redirect permanently in one hop, queries preserved; no catch-all
    redirects) and § "Link preservation checks" (rendered-page link resolution).
  • _docs/specs/01-platform-architecture.md § "Member signup, profile, Slack, and course
    registration" (the authenticated Slack-access reveal is a different, member-flow surface —
    see Non-goals).
  • Issue Repair stale and broken links in rendered documentation #167 (closed, commit 14b7812) established the render-time rewrite layer this issue
    extends.

Current state at main (9603342)

Already canonical today

  • /slack is served by content/review_views.py::slack from
    content/review_projection.json (slack record: title, lead, 8 channel chips, one
    troubleshooting CTA) and is primary navigation
    (templates/core/_site_shell_head.html:25,197).
  • Route and alias contract is exact and tested
    (content/tests/test_canonical_routes.py::test_slack_route_and_alias_have_exact_method_and_query_contracts):
    GET/HEAD /slack → 200 with canonical https://datatalks.club/slack; POST → 405
    (Allow: GET, HEAD, no-store); GET/HEAD /slack.html?<query> → 301 to
    /slack?<query> preserving the raw query byte-for-byte (website/urls.py:73).
  • Render-time hub-alias rewrites to /slack already exist:
    • Docs (content/docs_projection.py _INTERNAL_HUB_PATHS, lines 145-152): /slack.html
      and /slack/guidelines.html, both relative and https://datatalks.club absolute, inside
      Markdown link spans, preserving query and fragment.
    • Course FAQ (content/faq_data.py::render_faq_answer, the
      https?://datatalks.club/slack.html substitution).
    • Article FAQ (content/article_faq.py::_rewrite_legacy_links, same family).

Remaining inventory (checked projections at main)

Verified by scanning Markdown link destinations in content/docs_projection.json and
content/faq_projection.json:

  1. Workspace deep links in Docs — the core gap. 32 distinct external Slack URLs for this
    workspace (31 https://app.slack.com/client/T01ATQK62F8/<channel> plus
    https://datatalks-club.slack.com/archives/<channel>), 72 link occurrences across 16 pages,
    concentrated in /docs/general/slack/ (channel directory), course "getting started",
    "resources", and zoomcamp-logistics pages, and community guidelines pages. All still go
    straight to Slack.
  2. FAQ workspace links. One app.slack.com/client/T01ATQK62F8/... link and one
    datatalks-club.slack.com/archives/... link, in answers rendered on
    /faq/machine-learning-zoomcamp.html and /faq/llm-zoomcamp.html.
  3. Absolute canonical-form links in Docs. 6 pages link
    https://datatalks.club/slack (already the right destination, wrong form: absolute
    same-host instead of root-relative /slack). The Repair stale and broken links in rendered documentation #167 map does not normalize it.

Classification of what is not a community-Slack link and must stay untouched:

  • https://slack.com/help/articles/... (2 in Docs, 1 in FAQ): Slack's own product
    documentation, cited as reference, not an entry to our community.
  • /docs/general/slack/ and {{ '/general/slack/' | relative_url }} links: Docs-internal
    pages about Slack, already routed correctly by _docs_url.
  • Event descriptions: content/event_description_link_policy.py already removes
    app.slack.com (provider action) and forbids join.slack.com (join host) in reviewed event
    descriptions. There are no join.slack.com invite links anywhere in the Docs projection.

Destination contract

  • The canonical destination for community-Slack links in rendered source-backed content is
    the root-relative /slack (canonical https://datatalks.club/slack).
  • A link is a community-workspace link when its host is datatalks-club.slack.com (any
    path) or its host is app.slack.com and its first path segment is T01ATQK62F8 (this
    workspace's ID). Workspace links rewrite to /slack and drop their query and fragment:
    both address Slack's own UI (/client/..., /archives/...), not anchors on /slack.
  • Hub aliases (/slack.html, /slack/guidelines.html, absolute https://datatalks.club/slack)
    continue to rewrite to /slack preserving query and fragment per the existing Repair stale and broken links in rendered documentation #167
    mechanism; absolute https://datatalks.club/slack joins the map so it normalizes to
    root-relative.
  • Preserving a ?utm_*/?source= tag on hub-alias rewrites stays safe: /slack has no
    strict query grammar (the view ignores the query string), so the catalogue-query strictness
    addressed in 643ea32 does not apply here.
  • Rewrites happen at render time, keeping the checked projections byte-identical — the
    architecture Repair stale and broken links in rendered documentation #167 set and the immutability test enforces
    (content/tests/test_docs_projection.py::test_rendering_keeps_projection_source_and_metadata_immutable).

Scope

  1. Extend the render-time link policy in content/docs_projection.py with the
    community-workspace rule above (Docs Markdown link destinations only, not literal text or
    code spans, matching the existing span-scanning approach).
  2. Extend content/faq_data.py::render_faq_answer with the same community-workspace rule.
  3. Normalize absolute https://datatalks.club/slack link destinations in Docs to /slack.
  4. Add the missing legacy alias: GET/HEAD /slack/guidelines.html?<query> → 301
    /slack?<query> in one hop, query preserved, with the same method/cache contract as
    /slack.html (website/urls.py, alongside line 73). This serves inbound legacy links that
    today get a 404, per spec 02's no-unexplained-404 parity rule.
  5. Documentation: add one clarifying sentence to _docs/specs/01-platform-architecture.md
    § "Member signup, profile, Slack, and course registration" distinguishing the public
    /slack landing page from the specified authenticated
    /accounts/community/slack/ reveal surface. No change to that member-flow contract.
  6. Focused tests: new rewrites (Docs and FAQ), unaffected links byte-for-byte, the new
    redirect's method/query contract, and projection immutability.

Non-goals

  • No join/invite link on /slack (owner note above) and no change to the /slack page's
    content, channels list, or design.
  • No per-channel anchors on /slack (e.g. /slack#ml-zoomcamp): the page lists channels as
    plain chips today; adding 30+ targets is a separate product decision. Deep links rewrite to
    plain /slack, accepting the loss of channel-specific landing.
  • No edits to content/docs_projection.json, content/faq_projection.json, or the upstream
    content source; the immutability tests must stay green.
  • No changes to the event-description link policy (already removes these hosts there) or the
    article-FAQ pipeline (zero workspace links in content/article_faq.json today; adding
    untestable rewrite code there is not part of this slice).
  • No rewriting of slack.com/help/... product documentation links or any other external host.
  • No decision here on the member-flow Slack-access reveal: whether/how
    /accounts/community/slack/ gets built stays with the member-onboarding flow and
    _docs/specs/open-decisions.md (open decision 19). This issue only clarifies the wording.
  • No newsletter, Luma, or other hub-link changes (Repair stale and broken links in rendered documentation #167 owns those).

Dependencies

Acceptance criteria

  • Rendered Docs Markdown link destinations matching the community-workspace rule emit
    href="/slack"; no rendered Docs page emits href="https://app.slack.com/client/T01ATQK62F8/…"
    or href="https://datatalks-club.slack.com/…".
  • All 16 affected Docs pages and both affected FAQ answers are covered by focused tests
    that assert the rewrite (the FAQ test asserts the rendered answer HTML, not the source).
  • Absolute https://datatalks.club/slack link destinations in Docs render as
    root-relative /slack with query and fragment preserved.
  • Links to slack.com/help/..., /docs/general/slack/, and every unrelated external link
    remain byte-for-byte unchanged in rendered output.
  • GET/HEAD /slack/guidelines.html?x=1 returns 301 to /slack?x=1 preserving the raw
    query; POST returns 405 with Allow: GET, HEAD and Cache-Control: no-store, max-age=0,
    matching the /slack.html contract.
  • content/docs_projection.json and content/faq_projection.json are byte-identical
    before and after rendering (existing immutability tests stay green and cover the new rule).
  • Link-preservation/compat checks over rendered pages stay green with the rewritten links
    resolved internally against /slack.
  • Spec 01 clarification sentence added; the member-flow contract text is otherwise
    unchanged.
  • Tester screenshots at desktop and mobile for /docs/general/slack/,
    /docs/courses/ml-zoomcamp/getting-started/, /faq/machine-learning-zoomcamp.html, and
    /slack show the expected pages with working links, not errors or broken layouts.

Browser scenarios

  1. Open /docs/general/slack/; every channel entry links to /slack; following one lands on
    /slack (community page with channel chips), not Slack.
  2. Open /docs/courses/ml-zoomcamp/getting-started/; the community/asking-questions links
    land on /slack; a slack.com/help/... citation still opens Slack's own article in a new
    context without being redirected.
  3. Open /faq/machine-learning-zoomcamp.html; the "How do I get help if I'm stuck?" answer's
    Slack link lands on /slack.
  4. Visit /slack/guidelines.html?utm_source=docs; the browser ends at
    /slack?utm_source=docs in one hop showing the community page.
  5. Repeat 1-3 at mobile width; content and links remain readable and usable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Important follow-upcontentArea: contentenhancementNew feature or requestseoArea: seo

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions