Skip to content

OUT-3663 | Auto-archive: daily cron job & activity log#1198

Merged
arpandhakal merged 11 commits intoOUT-3662from
OUT-3663
May 6, 2026
Merged

OUT-3663 | Auto-archive: daily cron job & activity log#1198
arpandhakal merged 11 commits intoOUT-3662from
OUT-3663

Conversation

@arpandhakal
Copy link
Copy Markdown
Collaborator

@arpandhakal arpandhakal commented Apr 29, 2026

Changes

  • Cron script for auto archiving tasks.
  • What the job basically does is:
    - Auto archives eligible tasks for a workspace. For a task to be eligible in a workspace: workspace's autoArchiveAfter days should be a valid number and:
    - Task should not be deleted.
    - Task should not be archived.
    - Task should be completed
    - Task should not have open subtasks.
    - Task should only be a parent task.
    - Task's completedAt should be older than workspace's autoArchiveAfterDays.
    - If a parent task is eligible after checking the above conditions, their subtasks are also auto archived.
    - Activity logs for all auto archived tasks + subtasks.

Testing Criteria

  • Test case for workspace 'us-west-2_M5FSvMUap' having 7 autoArchiveAfterDays.
  1. Fetch eligible tasks:
WITH eligible_parents AS (
  SELECT
    t.id,
    t.title,
    t."parentId",
    t."workspaceId",
    t."completedAt",
    t.path,
    EXTRACT(EPOCH FROM (NOW() - t."completedAt")) / 86400 AS days_since_completed
  FROM "Tasks" t
  JOIN "WorkflowStates" ws ON ws.id = t."workflowStateId"
  WHERE t."workspaceId" = 'us-west-2_M5FSvMUap'
    AND t."parentId" IS NULL
    AND ws."type" = 'completed'::"StateType"
    AND t."isArchived" = false
    AND t."deletedAt" IS NULL
    AND t."completedAt" IS NOT NULL
    AND t."completedAt" < NOW() - (7 * INTERVAL '1 day')
    AND NOT EXISTS (
      SELECT 1
      FROM "Tasks" sub
      JOIN "WorkflowStates" sub_ws ON sub_ws.id = sub."workflowStateId"
      WHERE sub."parentId" = t.id
        AND sub."isArchived" = false
        AND sub."deletedAt" IS NULL
        AND sub_ws."type" <> 'completed'::"StateType"
    )
),
cascade_descendants AS (
  SELECT
    t.id,
    t.title,
    t."parentId",
    t."workspaceId",
    t."completedAt",
    t.path,
    EXTRACT(EPOCH FROM (NOW() - t."completedAt")) / 86400 AS days_since_completed
  FROM "Tasks" t
  JOIN "WorkflowStates" ws ON ws.id = t."workflowStateId"
  WHERE t."workspaceId" = 'us-west-2_M5FSvMUap'
    AND t."isArchived" = false
    AND t."deletedAt" IS NULL
    AND ws."type" = 'completed'::"StateType"
    AND t.path IS NOT NULL
    AND EXISTS (
      SELECT 1 FROM eligible_parents ep
      WHERE ep.path IS NOT NULL
        AND t.path <@ ep.path
        AND t.id <> ep.id
    )
)
SELECT 'eligible_parent' AS reason, id, title, "parentId", "workspaceId", "completedAt",
       ROUND(days_since_completed::numeric, 2) AS days_since_completed, path
FROM eligible_parents
UNION ALL
SELECT 'cascade_descendant' AS reason, id, title, "parentId", "workspaceId", "completedAt",
       ROUND(days_since_completed::numeric, 2) AS days_since_completed, path
FROM cascade_descendants
ORDER BY reason, "completedAt";

result : 134
image

  1. Total archived and unarchived tasks in database:
SELECT *
FROM "Tasks"
WHERE "isArchived" = true || false
ORDER BY "lastArchivedDate" DESC
LIMIT 1000000;

Archived : 163
image

UnArchived : 11030
image

  1. Run the auto archived script manually:

Only one workspace has autoArchived enabled:
image

Entries to be executed (numbers are correct):
image

Auto Archived completed:
image

  1. Re-querying (1) and (2) for matching the numbers.
  • Eligible task to be archived after running the query : 0
image
  • Number of Archived tasks: 297
image
  • Number of Unarchived tasks: 10896
image
  1. Activity log in recently archived tasks
image

@linear-code
Copy link
Copy Markdown

linear-code Bot commented Apr 29, 2026

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tasks-app Ready Ready Preview, Comment May 5, 2026 5:11pm

Request Review

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR introduces a nightly Trigger.dev cron job that auto-archives completed tasks (and their descendants via ltree path) for workspaces with autoArchiveAfterDays configured, and wires up activity log entries for all archived tasks with a null userId to mark them as system-initiated. To support this, ActivityLogs.userId is made nullable across the DB migration, Prisma schema, Zod schemas, and the ActivityLog UI component.

Confidence Score: 5/5

Safe to merge; no P0 or P1 issues found — only minor UI consistency and forward-compatibility P2 notes.

All previously flagged concerns (activity log entries, subtask cascade, per-workspace error isolation) have been addressed. Remaining findings are P2: a missing DotSeparator in the system-activity render path and an overly specific isSystemActivity type guard.

No files require special attention beyond the P2 notes on ActivityLog.tsx.

Important Files Changed

Filename Overview
src/jobs/auto-archive/auto-archive-completed-tasks.ts New cron job archiving completed tasks in batches with per-workspace error isolation and activity log creation; LIMIT applies only to eligible_parents so UPDATE and createMany can touch far more than BATCH_SIZE rows when parents have many descendants.
src/app/detail/ui/ActivityLog.tsx System activity path renders 'Task was auto-archived' but omits DotSeparator, creating a minor visual inconsistency; isSystemActivity check is also scoped only to ARCHIVE_STATE_UPDATED type.
prisma/migrations/20260501000001_make_activity_log_user_id_nullable/migration.sql Straightforward migration to make ActivityLogs.userId nullable, matching the updated Prisma schema.
src/app/api/activity-logs/services/activity-logger.service.ts createdBy.userId now accepts null; userId resolution correctly distinguishes between 'createdBy not provided' (infer from token) and 'createdBy provided with null userId' (system activity).
src/app/api/activity-logs/services/activity-log.service.ts Type signatures widened to accept null userId; isIuLog filter correctly makes system activities visible to clients, and null userId doesn't accidentally match any real client/company member.
src/cmd/backfill-completed-tasks/index.ts Added null guard on latestLog.userId before assigning completedBy, correctly preventing null from being propagated as a user identity.
src/app/api/activity-logs/const.ts DBActivityLogSchema updated to make userId nullable, aligning with schema and migration changes.
src/app/api/activity-logs/schemas/LogResponseSchema.ts LogResponseSchema userId made nullable, consistent with other schema updates.
src/jobs/auto-archive/index.ts Simple barrel export for the new auto-archive job.

Sequence Diagram

sequenceDiagram
    participant Trigger as Trigger.dev (2 AM cron)
    participant Job as auto-archive job
    participant DB as PostgreSQL

    Trigger->>Job: run(payload)
    Job->>DB: SELECT workspaces WHERE autoArchiveAfterDays > 0
    DB-->>Job: [{workspaceId, autoArchiveAfterDays}, ...]

    loop per workspace
        loop batch until 0 rows returned
            Job->>DB: CTE eligible_parents (LIMIT 200) + cascade_targets<br/>UPDATE Tasks SET isArchived=true RETURNING id
            DB-->>Job: archivedRows[]
            Job->>DB: activityLog.createMany({userId:null, userRole:internalUser})
        end
        Job->>Job: log workspace totals
    end

    Job->>Trigger: return {totalArchived, workspaceCount}
Loading

Reviews (2): Last reviewed commit: "fix(OUT-3663): system activity logs uses..." | Re-trigger Greptile

Comment thread src/jobs/auto-archive/auto-archive-completed-tasks.ts Outdated
Comment thread src/jobs/auto-archive/auto-archive-completed-tasks.ts Outdated
Comment thread src/jobs/auto-archive/auto-archive-completed-tasks.ts Outdated
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 1, 2026

Deployment failed with the following error:

Deploying Serverless Functions to multiple regions is restricted to the Pro and Enterprise plans.

Learn More: https://vercel.link/multiple-function-regions

@arpandhakal
Copy link
Copy Markdown
Collaborator Author

@greptileai

@arpandhakal
Copy link
Copy Markdown
Collaborator Author

@greptileai please review

Comment thread src/app/api/activity-logs/services/activity-logger.service.ts
Comment thread src/app/detail/ui/ActivityLog.tsx Outdated
Comment thread src/app/detail/ui/ActivityLog.tsx Outdated
Copy link
Copy Markdown
Collaborator

@priosshrsth priosshrsth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arpandhakal arpandhakal merged commit a2fbd09 into OUT-3662 May 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants