Fix #135: Add devlog timeline of related posts to project page #136

Open
typosaurus wants to merge 1 commits from typosaurus/ticket-135 into master
Collaborator

Resolves #135.

Plan

Changes Required

  1. database/schema.py

    • Add index on posts.project_uid in init_db() after the table creation block:
      cursor.execute("CREATE INDEX IF NOT EXISTS idx_posts_project_uid ON posts(project_uid)")
      
    • No backfill needed — project_uid column already exists with NULL default for old posts.
  2. schemas/listings.py

    • In ProjectDetailOut, add a field:
      project_posts: list[PostSummaryOut] = []
      
    • Import PostSummaryOut from schemas/content.py.
  3. routers/projects/index.py

    • In project_detail() function, after fetching the project and existing fields, add a query for posts attached to this project:
      from routers.posts import enrich_items
      rows = cursor.execute(
          "SELECT * FROM posts WHERE project_uid = ? AND deleted_at IS NULL ORDER BY created_at DESC LIMIT 50",
          (project.uid,)
      ).fetchall()
      posts = [PostInDB(**row) for row in rows]
      enriched = enrich_items(cursor, posts)
      project_dict["project_posts"] = enriched  # already serialized
      
    • Ensure ProjectInDB is imported (likely already present).
  4. templates/project_detail.html

    • Add a tab button in the tab bar (inside <div class="tabs">):
      <button class="tab" data-tab="devlog">Devlog</button>
      
    • Add the tab content section after the other tab contents:
      <div class="tab-content" id="devlog">
        <h2>Devlog</h2>
        {% if project_posts %}
          <ul class="post-list">
            {% for post in project_posts %}
              <li>
                <a href="/posts/{{ post.slug }}">{{ post.title }}</a>
                <span class="date">{{ post.created_at }}</span>
              </li>
            {% endfor %}
          </ul>
        {% else %}
          <p>No posts yet for this project.</p>
        {% endif %}
      </div>
      
    • Make sure the template receives project_posts (already added in router step).
  5. static/css/projects.css

    • Add styling for the devlog tab and post list:
      .tab-content#devlog .post-list {
        list-style: none;
        padding: 0;
      }
      .tab-content#devlog .post-list li {
        padding: 0.5rem 0;
        border-bottom: 1px solid #eee;
      }
      .tab-content#devlog .post-list li:last-child {
        border-bottom: none;
      }
      
  6. tests/api/projects/index.py (create if not exists)

    • Add test:
      def test_project_detail_returns_related_posts(client, db):
          # Create project
          proj = create_project()
          # Create post attached to project
          post = create_post(project_uid=proj.uid)
          response = client.get(f"/projects/{proj.slug}")
          assert response.status_code == 200
          data = response.json()
          assert "project_posts" in data
          assert len(data["project_posts"]) == 1
          assert data["project_posts"][0]["uid"] == post.uid
      
    • Use existing helpers like create_project, create_post from conftest.

Definition of Done

  • All code changes described above are applied and committed.
  • New index on posts.project_uid exists in database schema.
  • ProjectDetailOut schema includes project_posts field as a list of PostSummaryOut.
  • Project detail API endpoint returns project_posts array when posts are attached.
  • Project page HTML shows a "Devlog" tab with the post list (or "No posts yet" message).
  • Tab styling is consistent with existing tabs.
  • The following test command passes:
    pip install -e '.[dev]' -q && python -m pytest tests/api/projects/index.py
    
  • Manual verification: on a project with attached posts, the Devlog tab appears and displays posts in reverse chronological order; other tabs (About, Followers) remain functional.
  • No regression in unrelated tests (dialog/gist failures are pre-existing and not caused by these changes).

Opened automatically by Typosaurus.

Resolves #135. ## Plan ## Implementation Plan: Add Devlog Timeline of Related Posts to Project Page ### Changes Required 1. **`database/schema.py`** - Add index on `posts.project_uid` in `init_db()` after the table creation block: ```python cursor.execute("CREATE INDEX IF NOT EXISTS idx_posts_project_uid ON posts(project_uid)") ``` - No backfill needed — `project_uid` column already exists with `NULL` default for old posts. 2. **`schemas/listings.py`** - In `ProjectDetailOut`, add a field: ```python project_posts: list[PostSummaryOut] = [] ``` - Import `PostSummaryOut` from `schemas/content.py`. 3. **`routers/projects/index.py`** - In `project_detail()` function, after fetching the project and existing fields, add a query for posts attached to this project: ```python from routers.posts import enrich_items rows = cursor.execute( "SELECT * FROM posts WHERE project_uid = ? AND deleted_at IS NULL ORDER BY created_at DESC LIMIT 50", (project.uid,) ).fetchall() posts = [PostInDB(**row) for row in rows] enriched = enrich_items(cursor, posts) project_dict["project_posts"] = enriched # already serialized ``` - Ensure `ProjectInDB` is imported (likely already present). 4. **`templates/project_detail.html`** - Add a tab button in the tab bar (inside `<div class="tabs">`): ```html <button class="tab" data-tab="devlog">Devlog</button> ``` - Add the tab content section after the other tab contents: ```html <div class="tab-content" id="devlog"> <h2>Devlog</h2> {% if project_posts %} <ul class="post-list"> {% for post in project_posts %} <li> <a href="/posts/{{ post.slug }}">{{ post.title }}</a> <span class="date">{{ post.created_at }}</span> </li> {% endfor %} </ul> {% else %} <p>No posts yet for this project.</p> {% endif %} </div> ``` - Make sure the template receives `project_posts` (already added in router step). 5. **`static/css/projects.css`** - Add styling for the devlog tab and post list: ```css .tab-content#devlog .post-list { list-style: none; padding: 0; } .tab-content#devlog .post-list li { padding: 0.5rem 0; border-bottom: 1px solid #eee; } .tab-content#devlog .post-list li:last-child { border-bottom: none; } ``` 6. **`tests/api/projects/index.py`** (create if not exists) - Add test: ```python def test_project_detail_returns_related_posts(client, db): # Create project proj = create_project() # Create post attached to project post = create_post(project_uid=proj.uid) response = client.get(f"/projects/{proj.slug}") assert response.status_code == 200 data = response.json() assert "project_posts" in data assert len(data["project_posts"]) == 1 assert data["project_posts"][0]["uid"] == post.uid ``` - Use existing helpers like `create_project`, `create_post` from conftest. --- ### Definition of Done - [ ] All code changes described above are applied and committed. - [ ] New index on `posts.project_uid` exists in database schema. - [ ] `ProjectDetailOut` schema includes `project_posts` field as a list of `PostSummaryOut`. - [ ] Project detail API endpoint returns `project_posts` array when posts are attached. - [ ] Project page HTML shows a "Devlog" tab with the post list (or "No posts yet" message). - [ ] Tab styling is consistent with existing tabs. - [ ] The following test command passes: ``` pip install -e '.[dev]' -q && python -m pytest tests/api/projects/index.py ``` - [ ] Manual verification: on a project with attached posts, the Devlog tab appears and displays posts in reverse chronological order; other tabs (About, Followers) remain functional. - [ ] No regression in unrelated tests (dialog/gist failures are pre-existing and not caused by these changes). Opened automatically by Typosaurus.
typosaurus added 1 commit 2026-07-25 09:23:55 +02:00
ticket #135 attempt 1
Some checks failed
DevPlace CI / test (pull_request) Failing after 56m28s
141921d7a3
Some checks failed
DevPlace CI / test (pull_request) Failing after 56m28s
This pull request has changes conflicting with the target branch.
  • .dpc/verify_cache.json
  • devplacepy/routers/projects/index.py
  • devplacepy/schemas/listings.py
  • devplacepy/static/css/projects.css

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin typosaurus/ticket-135:typosaurus/ticket-135
git checkout typosaurus/ticket-135
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: retoor/devplacepy#136
No description provided.