Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/configurations/common/queue-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const QueueName = {
MOODLE_SYNC: 'moodle-sync',
ANALYTICS_REFRESH: 'analytics-refresh',
AUDIT: 'audit',
ERROR_LOG: 'error-log',
REPORT_GENERATION: 'report-generation',
} as const;

Expand Down
1 change: 1 addition & 0 deletions src/entities/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ MikroORM entity definitions. All domain state lives here.
- Adding a new entity requires registering it in `index.entity.ts` AND creating a migration (`npx mikro-orm migration:create`). Forgetting the migration silently diverges the dev DB from production.
- Relation decorators (`@ManyToOne`, `@OneToMany`) need matching inverse sides or MikroORM will silently drop joins.
- When writing new repos, prefer `em.fork()` + query builder inside the repo — don't leak query building into services.
- **`uq_analysis_pipeline_active_scope` is a recurring CLI suggestion trap.** This partial unique index (FAC-132, see `Migration20260414155236_fac-132-pipeline-scope-unique-index.ts`) uses `COALESCE(...,'NONE')` over nullable scope FKs and a `WHERE status NOT IN (...)` clause. MikroORM decorators can't represent it, so `migration:create` will propose dropping it on every run. **Never accept that drop** — it reopens the bug FAC-132 fixed (duplicate active pipelines for the same scope). Always strip the `drop index "uq_analysis_pipeline_active_scope"` line from generated migrations before committing.

## Pointers

Expand Down
65 changes: 65 additions & 0 deletions src/entities/error-log.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Entity, Index, Opt, PrimaryKey, Property } from '@mikro-orm/core';
import { v4 } from 'uuid';

// Error log rows capture unhandled 5xx exceptions for admin-side diagnostics.
// Never soft-deleted — queries must use `filters: { softDelete: false }`.
// Matches the SyncLog/AuditLog precedent of opting out of the global filter.
@Entity()
export class ErrorLog {
@PrimaryKey()
id: string & Opt = v4();

@Index()
@Property()
statusCode!: number;

@Property()
method!: string;

@Index()
@Property()
path!: string;

@Index()
@Property({ nullable: true })
userId?: string;

@Property({ nullable: true })
userName?: string;

@Index()
@Property()
errorName!: string;

@Property({ type: 'text' })
message!: string;

@Property({ type: 'text', nullable: true })
stack?: string;

@Property({ type: 'jsonb', nullable: true })
requestBody?: Record<string, unknown>;

@Property({ type: 'jsonb', nullable: true })
requestQuery?: Record<string, unknown>;

@Property({ nullable: true })
browserName?: string;

@Property({ nullable: true })
os?: string;

@Property({ nullable: true })
ipAddress?: string;

@Index()
@Property({ nullable: true })
acknowledgedAt?: Date;

@Property({ nullable: true })
acknowledgedBy?: string;

@Index()
@Property({ defaultRaw: 'now()', length: 6 })
occurredAt: Date & Opt = new Date();
}
3 changes: 3 additions & 0 deletions src/entities/index.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { Section } from './section.entity';
import { TopicModelRun } from './topic-model-run.entity';
import { SyncLog } from './sync-log.entity';
import { AuditLog } from './audit-log.entity';
import { ErrorLog } from './error-log.entity';
import { ReportJob } from './report-job.entity';

export {
Expand Down Expand Up @@ -67,6 +68,7 @@ export {
TopicModelRun,
SyncLog,
AuditLog,
ErrorLog,
ReportJob,
};

Expand Down Expand Up @@ -104,5 +106,6 @@ export const entities = [
TopicModelRun,
SyncLog,
AuditLog,
ErrorLog,
ReportJob,
];
Loading
Loading