Update project documentation and code comments to remove platform-specific references
Refactor documentation files and code comments to remove references to Replit, specific task numbers, and other platform-specific identifiers. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: fa18e5d4-a810-4bd5-8cde-2a60d64d9e3f Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/kI0sxlu Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* One-shot, idempotent migration for Task #121.
|
||||
* One-shot, idempotent migration for.
|
||||
*
|
||||
* Adds the `executive_meetings.access` permission, grants it to admin + all
|
||||
* executive_* roles, and links it to the `executive-meetings` app via
|
||||
|
||||
@@ -156,7 +156,7 @@ router.post("/apps", requireAdmin, async (req, res): Promise<void> => {
|
||||
// can gate the app at creation time. Pulling it out before the insert
|
||||
// keeps appsTable.values strictly typed against the Drizzle schema.
|
||||
const { permissionIds: rawPermissionIds, ...appValues } = parsed.data;
|
||||
// Task #517: validate externalUrl scheme on create (mirror PATCH).
|
||||
// validate externalUrl scheme on create (mirror PATCH).
|
||||
// External URLs are launched in a new tab or rendered in an iframe for
|
||||
// every user; restricting to http(s) prevents javascript:/data:/file:
|
||||
// payloads from being shipped tenant-wide.
|
||||
@@ -293,7 +293,7 @@ router.get("/apps/:id", requireAuth, async (req, res): Promise<void> => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Task #517: per-user visibility gate. The new /embedded/:id page
|
||||
// per-user visibility gate. The new /embedded/:id page
|
||||
// calls this endpoint to read `externalUrl`, so without an auth
|
||||
// check any logged-in user could enumerate restricted apps and load
|
||||
// their externalUrl in an iframe / new tab. Reuse the same
|
||||
@@ -327,7 +327,7 @@ router.patch("/apps/:id", requireAdmin, async (req, res): Promise<void> => {
|
||||
.from(appsTable)
|
||||
.where(eq(appsTable.id, params.data.id));
|
||||
|
||||
// Task #517: lock the route AND slug fields for built-in apps. Their
|
||||
// lock the route AND slug fields for built-in apps. Their
|
||||
// paths are hardcoded in artifacts/tx-os/src/App.tsx — letting an
|
||||
// admin retype the path silently breaks the launcher entry (the user
|
||||
// reported this after editing the Executive Meetings app). We also
|
||||
@@ -361,7 +361,7 @@ router.patch("/apps/:id", requireAdmin, async (req, res): Promise<void> => {
|
||||
}
|
||||
}
|
||||
|
||||
// Task #517: validate externalUrl scheme. This URL is launched in a
|
||||
// validate externalUrl scheme. This URL is launched in a
|
||||
// new tab (external_tab) or rendered inside an iframe (external_iframe)
|
||||
// for every user. Allowing javascript:, data:, file:, etc. would let
|
||||
// an admin (or anyone who compromises an admin account) ship XSS or
|
||||
|
||||
@@ -118,7 +118,7 @@ async function userOwnsFolder(userId: number, folderId: number): Promise<boolean
|
||||
return !!row;
|
||||
}
|
||||
|
||||
// Folder-level access helpers (Task #454).
|
||||
// Folder-level access helpers.
|
||||
//
|
||||
// `userCanEditFolder` returns true if the caller is the owner OR has a share
|
||||
// row with permission="edit" for the folder. Used by every write path that
|
||||
@@ -477,7 +477,7 @@ router.post("/notes", requireAuth, async (req, res): Promise<void> => {
|
||||
* Body: { folderId: number | null, isPinned: boolean, orderedIds: number[] }
|
||||
*
|
||||
* Auth: each id must be a note the caller owns OR a note inside a folder
|
||||
* they have edit permission on (Task #463). Foreign ids (and ids that
|
||||
* they have edit permission on. Foreign ids (and ids that
|
||||
* don't actually live in the named bucket) are silently skipped — that
|
||||
* keeps the endpoint safe against stale client state without blowing up
|
||||
* the whole reorder.
|
||||
@@ -585,7 +585,7 @@ router.patch("/notes/:id", requireAuth, async (req, res): Promise<void> => {
|
||||
// Two-step lookup so non-owners get a precise 403 (instead of an
|
||||
// ambiguous 404). Recipients of a shared folder may now also mutate
|
||||
// the owner's notes when their share grants permission="edit"
|
||||
// (Task #454).
|
||||
//.
|
||||
const [existing] = await db
|
||||
.select()
|
||||
.from(notesTable)
|
||||
@@ -691,7 +691,7 @@ router.patch("/notes/:id", requireAuth, async (req, res): Promise<void> => {
|
||||
res.json(withLabels);
|
||||
});
|
||||
|
||||
// Task #512: per-recipient delete. The recipient does not own the
|
||||
// per-recipient delete. The recipient does not own the
|
||||
// underlying note, so a regular DELETE /notes/:id (which is owner-only)
|
||||
// can't help them clear an unwanted incoming note. This endpoint
|
||||
// removes ONLY the caller's own `note_recipients` row, leaving the
|
||||
@@ -730,7 +730,7 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
// Task #512: bulk variant. Accepts up to BULK_RECEIVED_DELETE_MAX ids
|
||||
// bulk variant. Accepts up to BULK_RECEIVED_DELETE_MAX ids
|
||||
// in a single request and reports per-id success/notFound so the UI
|
||||
// can render a precise toast even on partial misses (e.g. a note the
|
||||
// sender just hard-deleted between page load and click). One SQL
|
||||
@@ -792,9 +792,9 @@ router.delete("/notes/:id", requireAuth, async (req, res): Promise<void> => {
|
||||
return;
|
||||
}
|
||||
// Two-step lookup so non-owners (e.g. shared-folder view-only recipients)
|
||||
// get a precise 403 instead of a 404 — see Task #445 acceptance criteria.
|
||||
// get a precise 403 instead of a 404 — see acceptance criteria.
|
||||
// Editors with permission="edit" on the note's folder are allowed
|
||||
// (Task #454).
|
||||
//.
|
||||
const [existing] = await db
|
||||
.select({ userId: notesTable.userId, folderId: notesTable.folderId })
|
||||
.from(notesTable)
|
||||
@@ -1185,7 +1185,7 @@ router.post("/notes/:id/read", requireAuth, async (req, res): Promise<void> => {
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
// Task #438: collaborative checklist toggle. The owner OR any active
|
||||
// collaborative checklist toggle. The owner OR any active
|
||||
// (non-archived) recipient can flip an item's `done` flag; the change
|
||||
// is persisted to the live `notes.items` AND mirrored to every
|
||||
// `note_recipients.items` snapshot so all collaborators see the same
|
||||
@@ -1253,7 +1253,7 @@ router.post(
|
||||
),
|
||||
);
|
||||
const sentToMe = !!recipientRow && recipientRow.status !== "archived";
|
||||
// Task #454: also accept folder editors on a shared folder. We
|
||||
// also accept folder editors on a shared folder. We
|
||||
// can't call resolveFolderEditAccess here (different db handle),
|
||||
// so re-implement the lookup against `tx` for transactional read
|
||||
// consistency.
|
||||
@@ -1332,7 +1332,7 @@ router.post(
|
||||
actorUserId: userId,
|
||||
});
|
||||
}
|
||||
// Task #454: also notify shared-folder viewers (owner + every other
|
||||
// also notify shared-folder viewers (owner + every other
|
||||
// editor / viewer of the folder) so the shared-folder note list
|
||||
// refetches and shows the toggled item — the per-recipient
|
||||
// `note_checklist_changed` audience above only covers users in the
|
||||
@@ -1821,7 +1821,7 @@ router.put(
|
||||
return;
|
||||
}
|
||||
const body = req.body;
|
||||
// Task #454: accept BOTH the legacy `recipientUserIds: number[]`
|
||||
// accept BOTH the legacy `recipientUserIds: number[]`
|
||||
// shape (treated as permission="view") AND the new
|
||||
// `recipients: [{ userId, permission }]` shape so older clients keep
|
||||
// working. Internally we collapse to a single Map<userId, permission>.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Task #517: PATCH /apps/:id must reject route changes whose target row's
|
||||
// PATCH /apps/:id must reject route changes whose target row's
|
||||
// slug is in BUILTIN_APP_SLUGS — those routes are hardcoded in the SPA
|
||||
// (artifacts/tx-os/src/App.tsx) and silently break the launcher when an
|
||||
// admin edits them. Other fields (icon, image, color, name, openMode,
|
||||
@@ -72,7 +72,7 @@ before(async () => {
|
||||
adminCookie = await loginAndGetCookie(adminUsername, TEST_PASSWORD);
|
||||
|
||||
// Non-admin user used to verify GET /apps/:id visibility gating for
|
||||
// the new external-iframe / embedded flow (Task #517).
|
||||
// the new external-iframe / embedded flow.
|
||||
userUsername = `user_lock_${stamp}`;
|
||||
const userRow = await pool.query(
|
||||
`INSERT INTO users (username, email, password_hash, display_name_en, preferred_language, is_active)
|
||||
|
||||
@@ -76,7 +76,7 @@ after(async () => {
|
||||
|
||||
// Defensive sweep: kill any leftover services whose name_en matches the
|
||||
// per-run test prefix, plus their child rows in service_orders. Mirrors
|
||||
// the apps-side sweep added in Task #116.
|
||||
// the apps-side sweep added in.
|
||||
const svcSweep = await pool.query(
|
||||
`SELECT id FROM services WHERE name_en LIKE $1`,
|
||||
[`${SVC_PREFIX}%`],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// API contract tests for the cell-merge overlay added by task #152
|
||||
// API contract tests for the cell-merge overlay added by
|
||||
// to the executive-meetings PATCH endpoint. Covers:
|
||||
//
|
||||
// 1. Setting a merge writes mergeStartColumn / mergeEndColumn /
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// API contract tests for the shared row-colour overlay added by task #288
|
||||
// API contract tests for the shared row-colour overlay added by
|
||||
// to the executive-meetings PATCH endpoint. Covers:
|
||||
//
|
||||
// 1. Setting a colour persists it on the row and round-trips back
|
||||
|
||||
@@ -255,7 +255,7 @@ test("Meetings: PUT /attendees replaces the attendee list", async () => {
|
||||
assert.ok(!body.attendees.find((a) => a.name === "Old One"));
|
||||
});
|
||||
|
||||
// --- Attendee payload contract (Task #221) ---------------------------------
|
||||
// --- Attendee payload contract ---------------------------------
|
||||
// Server is `.strict()` on the attendee schema so client-only fields like
|
||||
// `_sid` (the React row id used by the drag-and-drop editor) are rejected
|
||||
// loudly with 400 instead of being silently stripped. This locks down the
|
||||
@@ -1510,7 +1510,7 @@ test("Reorder: rejects orderedIds containing duplicates with code duplicate_ids"
|
||||
"duplicate ids must be reported with the duplicate_ids code");
|
||||
});
|
||||
|
||||
// Task #311: dragging a visible meeting from one row to another must not
|
||||
// dragging a visible meeting from one row to another must not
|
||||
// disturb cancelled rows on the same day. The schedule view hides
|
||||
// cancelled meetings (#273), so dnd-kit can only ever drag visible
|
||||
// rows; the reorder endpoint must accept an orderedIds payload that
|
||||
@@ -1729,7 +1729,7 @@ test("Reorder: rejects ids that do not all belong to meetingDate", async () => {
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Task #312: Auto-sort the day chronologically on every write that
|
||||
// Auto-sort the day chronologically on every write that
|
||||
// affects time/order. The user reported a row showing 13:00 sitting
|
||||
// above a 12:00 row after editing a single startTime — that bug exists
|
||||
// because the inline-edit PATCH never re-derived `daily_number`. These
|
||||
@@ -2170,7 +2170,7 @@ test("Reorder: user without executive role is denied (403)", async () => {
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Phase-2 task #112 additions:
|
||||
// Phase-2 additions:
|
||||
// - per-role meeting CRUD permissions
|
||||
// - request reject / withdraw flows
|
||||
// - task assignee-only status updates
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Task #438: API tests for the collaborative checklist toggle endpoint
|
||||
// API tests for the collaborative checklist toggle endpoint
|
||||
// `POST /notes/:id/checklist/:itemId/toggle`. Owner + active recipients
|
||||
// can flip an item; the change is mirrored to every recipient snapshot.
|
||||
import { test, after } from "node:test";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Task #512: per-recipient inbox delete + bulk delete.
|
||||
// per-recipient inbox delete + bulk delete.
|
||||
// A recipient can detach their note_recipients row (DELETE
|
||||
// /notes/received/:id and bulk variant) without touching the
|
||||
// underlying note or other recipients' rows. Non-recipients get 404.
|
||||
|
||||
@@ -511,7 +511,7 @@ test("GET /notes/my returns the same payload as GET /notes (alias)", async () =>
|
||||
);
|
||||
});
|
||||
|
||||
// Task #454: per-recipient folder permission (view vs edit).
|
||||
// per-recipient folder permission (view vs edit).
|
||||
test("folder share permissions: view-only is rejected on writes; edit can mutate; permission roundtrip works", async () => {
|
||||
const owner = await createUser("notes_perm_owner");
|
||||
const viewer = await createUser("notes_perm_viewer");
|
||||
|
||||
@@ -245,7 +245,7 @@ test("status transitions matrix: receiver flows + owner/admin cancel rules", asy
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal((await res.json()).status, "completed");
|
||||
|
||||
// Cannot transition completed → anything (non-admin); now 409 order_unavailable per Task #80
|
||||
// Cannot transition completed → anything (non-admin); now 409 order_unavailable
|
||||
res = await call(cr, "PATCH", `/orders/${order.id}/status`, {
|
||||
status: "preparing",
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Tests for Task #524 — MR-H1 / MR-H2 / MR-M7.
|
||||
// Tests for — MR-H1 / MR-H2 / MR-M7.
|
||||
//
|
||||
// Coverage map (matches the "Required tests" list in the task spec):
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user