mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix: a trashed note file leaves its note, quieter MCP sweep, bounded compose logs
A note's attachment moved to the trash from the file manager kept showing on the note; the hydration read now skips it, as the chat one already did. The MCP session sweep logged a line every minute while any session was open; it logs only when it cleaned something. The compose file caps the container log, and three test mocks that pointed at modules long gone are removed.
This commit is contained in:
@@ -9,7 +9,6 @@ import TourDetailDialog from './TourDetailDialog'
|
||||
|
||||
vi.mock('../../../../server/src/config', () => { throw new Error('Config initialization is forbidden in client tests') })
|
||||
vi.mock('../../../../server/src/db/database', () => { throw new Error('Legacy database imports are forbidden in client tests') })
|
||||
vi.mock('../../../../server/src/nest/database/database.service', () => { throw new Error('Database service imports are forbidden in client tests') })
|
||||
vi.mock('better-sqlite3', () => { throw new Error('SQLite imports are forbidden in client tests') })
|
||||
|
||||
const place = buildPlace({
|
||||
|
||||
@@ -12,7 +12,6 @@ import { TourPlannerRail, TourPlannerToursRail } from './TourPlannerPanels'
|
||||
|
||||
vi.mock('../../../../../server/src/config', () => { throw new Error('Config initialization is forbidden in client tests') })
|
||||
vi.mock('../../../../../server/src/db/database', () => { throw new Error('Legacy database imports are forbidden in client tests') })
|
||||
vi.mock('../../../../../server/src/nest/database/database.service', () => { throw new Error('Database service imports are forbidden in client tests') })
|
||||
vi.mock('better-sqlite3', () => { throw new Error('SQLite imports are forbidden in client tests') })
|
||||
|
||||
const tour: TourListItem = {
|
||||
|
||||
@@ -87,10 +87,6 @@ vi.mock('../components/Planner/DayDetailPanel', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../components/Memories/MemoriesPanel', () => ({
|
||||
default: () => React.createElement('div', { 'data-testid': 'memories-panel' }),
|
||||
}));
|
||||
|
||||
vi.mock('../components/Collab/CollabPanel', () => ({
|
||||
default: () => React.createElement('div', { 'data-testid': 'collab-panel' }),
|
||||
}));
|
||||
|
||||
@@ -68,6 +68,12 @@ services:
|
||||
- ./uploads:/app/uploads
|
||||
# - ./storage-config.json:/app/data/storage-config.json:ro # optional seed-once storage provisioning (wiki: Admin-Storage)
|
||||
restart: unless-stopped
|
||||
# Docker's json-file driver keeps every line forever by default.
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: 10m
|
||||
max-file: "3"
|
||||
healthcheck:
|
||||
# Through a shell so a changed PORT is followed.
|
||||
test: ["CMD-SHELL", "wget -qO- http://localhost:$${PORT:-3000}/api/health || exit 1"]
|
||||
|
||||
@@ -192,12 +192,18 @@ export class CollabNotesRepository extends TrekRepository<CollabNotes> {
|
||||
// `TripFilesRepository`.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** CB6 (`formatNote`'s hydration read) — `SELECT id, filename, original_name, file_size, mime_type FROM trip_files WHERE note_id = ?`. */
|
||||
/**
|
||||
* CB6 (`formatNote`'s hydration read) — `SELECT id, filename, original_name,
|
||||
* file_size, mime_type FROM trip_files WHERE note_id = ? AND deleted_at IS
|
||||
* NULL`. A note's file can be moved to the trash from the file manager; it
|
||||
* leaves the note then, as a chat attachment leaves its message.
|
||||
*/
|
||||
async listAttachmentsForNote(note_id: number): Promise<NoteAttachmentRow[]> {
|
||||
return await this.kysely<NoteAttachmentsKyselyDB>()
|
||||
.selectFrom('trip_files')
|
||||
.select(['id', 'filename', 'original_name', 'file_size', 'mime_type'])
|
||||
.where('note_id', '=', note_id)
|
||||
.where('deleted_at', 'is', null)
|
||||
.execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,9 @@ const sessionSweepInterval = setInterval(() => {
|
||||
for (const [key, entry] of rateLimitMap) {
|
||||
if (entry.windowStart < rateCutoff) rateLimitMap.delete(key);
|
||||
}
|
||||
if (cleaned > 0 || sessions.size > 0) {
|
||||
// Only when something was cleaned: logging every minute while any session
|
||||
// is open wrote 1,440 lines a day into a log nothing rotates.
|
||||
if (cleaned > 0) {
|
||||
console.log(`[MCP] Session sweep: cleaned ${cleaned}, active ${sessions.size}`);
|
||||
}
|
||||
}, 60 * 1000); // sweep every 1 minute
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* The implementation moved to nest/realtime: the connection lifecycle and the
|
||||
* handshake are RealtimeGateway, the wire protocol is TrekWsAdapter, and the
|
||||
* socket registry is ws-state.ts. This file stays because it is the import path
|
||||
* the rest of the tree knows, including 115 test files that `vi.mock` it to
|
||||
* the rest of the tree knows, including the more than 160 test files that `vi.mock` it to
|
||||
* assert on broadcasts. Repointing them all would be a large diff that proves
|
||||
* nothing, and this re-export keeps every one of those mocks working.
|
||||
*
|
||||
|
||||
@@ -28,10 +28,6 @@ vi.mock('../../src/websocket', () => ({
|
||||
broadcastToUser: vi.fn(),
|
||||
getOnlineUserIds: vi.fn(() => []),
|
||||
}));
|
||||
vi.mock('../../src/services/memories/immichService', () => ({
|
||||
uploadToImmich: vi.fn(async () => null),
|
||||
getImmichCredentials: vi.fn(() => null),
|
||||
}));
|
||||
|
||||
import { db as testDb } from '../../src/db/database';
|
||||
import { buildApp } from '../../src/bootstrap';
|
||||
|
||||
@@ -874,6 +874,10 @@ describe('repository parity', () => {
|
||||
// CB6's narrow attachment projection.
|
||||
const legacyAttachments = testDb.prepare('SELECT id, filename, original_name, file_size, mime_type FROM trip_files WHERE note_id = ? ORDER BY id ASC').all(note.id);
|
||||
expect(await notesRepo.listAttachmentsForNote(note.id)).toEqual(legacyAttachments);
|
||||
|
||||
// A file moved to the trash from the file manager leaves the note.
|
||||
testDb.prepare("UPDATE trip_files SET deleted_at = CURRENT_TIMESTAMP WHERE note_id = ? AND original_name = 'b.png'").run(note.id);
|
||||
expect((await notesRepo.listAttachmentsForNote(note.id)).map(a => a.original_name)).toEqual(['a.pdf']);
|
||||
});
|
||||
|
||||
it('COLLAB-REPO-002: CollabPollsRepository/CollabPollVotesRepository match the legacy queries for a multiple-choice poll voted on every option', async () => {
|
||||
|
||||
Reference in New Issue
Block a user