Goal
Implement the backend for a new daily trading log system in EdgeFinder. This feature should track performance separate from P/L by day, with three sections:
- Preparation
- Execution
- Reflection
This issue is backend-only. Do not build frontend UI in this issue.
Current context:
- The current Prisma schema has
User, Trade, and Strategy.
Trade should remain a clean raw trade record.
- Do not re-add execution booleans like
properEntry, R, alignedWithTrend, properConditions, followedTpPlan, or properSize to the Trade table.
- Execution tracking should be stored at the daily log level, with optional links to trades when a mistake maps to one or more trades.
Backend requirements
Create a daily trading log backend system that supports:
- One daily log per user per trading date.
- Preparation score and preparation checklist fields.
- Execution score, execution mistakes, leakage calculations, and optional links from mistakes to trades.
- Reflection notes and rule-break analysis.
- Monthly aggregation endpoints for process performance.
Required schema design
Update access-control/prisma/schema.prisma.
Update User model
Add relation:
dailyTradingLogs DailyTradingLog[]
Main table: DailyTradingLog
This is the parent record for one trading day.
model DailyTradingLog {
id String @id @default(cuid())
userId String
date DateTime
// Overall daily scores
totalScore Int @default(0)
preparationScore Int @default(0)
executionScore Int @default(100)
reflectionScore Int @default(0)
// P/L summary pulled from trades for this date
actualPnl Decimal @default(0) @db.Decimal(10, 2)
tradeCount Int @default(0)
// Execution-adjusted P/L metrics
ruleBasedPnl Decimal @default(0) @db.Decimal(10, 2)
executionDelta Decimal @default(0) @db.Decimal(10, 2)
leakageCost Decimal @default(0) @db.Decimal(10, 2)
ruleViolationGain Decimal @default(0) @db.Decimal(10, 2)
// Daily summary
mainIssue String?
nextSessionFocus String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
preparation DailyPreparationLog?
reflection DailyReflectionLog?
executionMistakes DailyExecutionMistake[]
@@unique([userId, date])
@@map("daily_trading_logs")
}
Preparation section
The preparation section should be logged once per daily log.
Preparation scoring
Suggested scoring total: 20 points.
| Field |
Points |
| Reviewed previous trades |
5 |
| Completed market analysis |
5 |
| Created watchlist |
4 |
| Reviewed rules |
3 |
| Wrote emotional/risk note |
3 |
Preparation table
model DailyPreparationLog {
id String @id @default(cuid())
dailyTradingLogId String @unique
reviewedPreviousTrades Boolean @default(false)
completedMarketAnalysis Boolean @default(false)
createdWatchlist Boolean @default(false)
reviewedRules Boolean @default(false)
wroteEmotionalRiskNote Boolean @default(false)
marketAnalysisNotes String?
watchlistNotes String?
emotionalState String?
riskNote String?
score Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
dailyTradingLog DailyTradingLog @relation(fields: [dailyTradingLogId], references: [id], onDelete: Cascade)
@@map("daily_preparation_logs")
}
Execution section
Execution should be daily-log based, not per-trade based.
Trades remain raw records. Execution mistakes are logged as daily events. A mistake may optionally link to one or more trades.
Execution concepts
Daily actual P/L should be pulled from trades for that user/date.
Each mistake stores:
actualPnlImpact
ruleBasedPnlImpact
executionDelta = actualPnlImpact - ruleBasedPnlImpact
leakageCost = max(ruleBasedPnlImpact - actualPnlImpact, 0)
ruleViolationGain = max(actualPnlImpact - ruleBasedPnlImpact, 0)
Daily rule-based P/L:
dailyRuleBasedPnl = dailyActualPnl - sum(executionDelta)
This handles all cases:
| Situation |
Actual impact |
Rule-based impact |
Meaning |
| Ineligible trade loses |
-150 |
0 |
Trade should not exist; full loss is leakage |
| Ineligible trade wins |
+220 |
0 |
Bad-process profit; counted as rule violation gain |
| Valid trade exits early |
+120 |
+300 |
$180 of leakage |
| Stop loss violation |
-150 |
-60 |
$90 of leakage |
Execution mistake table
model DailyExecutionMistake {
id String @id @default(cuid())
dailyTradingLogId String
ruleCode ExecutionRuleCode
category ExecutionMistakeCategory
label String
severity ExecutionMistakeSeverity
// True if this mistake means the affected trade should not have been taken.
invalidatesTrade Boolean @default(false)
// Money fields
actualPnlImpact Decimal @db.Decimal(10, 2)
ruleBasedPnlImpact Decimal @db.Decimal(10, 2)
executionDelta Decimal @db.Decimal(10, 2)
leakageCost Decimal @db.Decimal(10, 2)
ruleViolationGain Decimal @db.Decimal(10, 2)
pointsLost Int
technicalReason String?
emotionalReason String?
correction String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
dailyTradingLog DailyTradingLog @relation(fields: [dailyTradingLogId], references: [id], onDelete: Cascade)
tradeLinks DailyExecutionMistakeTrade[]
@@map("daily_execution_mistakes")
}
Optional link table from mistakes to trades
model DailyExecutionMistakeTrade {
id String @id @default(cuid())
dailyExecutionMistakeId String
tradeId String
dailyExecutionMistake DailyExecutionMistake @relation(fields: [dailyExecutionMistakeId], references: [id], onDelete: Cascade)
trade Trade @relation(fields: [tradeId], references: [id], onDelete: Cascade)
@@unique([dailyExecutionMistakeId, tradeId])
@@map("daily_execution_mistake_trades")
}
Add this relation to Trade:
executionMistakeLinks DailyExecutionMistakeTrade[]
Execution rule enums
enum ExecutionMistakeCategory {
TRADE_ELIGIBILITY
SETUP_SELECTION
MARKET_CONDITIONS
ENTRY
POSITION_SIZE
STOP_LOSS
TAKE_PROFIT
TRADE_MANAGEMENT
}
enum ExecutionMistakeSeverity {
MINOR
MODERATE
MAJOR
CRITICAL
}
enum ExecutionRuleCode {
NOT_ALIGNED_WITH_TREND
NOT_RELATIVE_STRENGTH_WEAKNESS
NO_HTF_KEY_LEVEL
NO_VOLUME_CONFIRMATION
WRONG_SIDE_EMA_VWAP
POOR_MARKET_CONDITIONS
INVALID_SETUP_SELECTION
IMPROPER_SIZE
IMPROPER_ENTRY
STOP_LOSS_VIOLATION
MOVED_STOP_INCORRECTLY
EARLY_FIRST_TRIM
EARLY_SECOND_TRIM
FULL_EXIT_TOO_EARLY
HELD_PAST_SELL_SIGNAL
}
Rule defaults
Implement a backend helper that maps rule code to defaults:
| Rule |
Invalidates trade |
Default points lost |
| NOT_ALIGNED_WITH_TREND |
true |
20 |
| NOT_RELATIVE_STRENGTH_WEAKNESS |
true |
20 |
| NO_HTF_KEY_LEVEL |
true |
20 |
| NO_VOLUME_CONFIRMATION |
true |
15 |
| WRONG_SIDE_EMA_VWAP |
true |
20 |
| POOR_MARKET_CONDITIONS |
true |
25 |
| INVALID_SETUP_SELECTION |
true |
30 |
| IMPROPER_SIZE |
false |
20 |
| IMPROPER_ENTRY |
false |
15 |
| STOP_LOSS_VIOLATION |
false |
35 |
| MOVED_STOP_INCORRECTLY |
false |
30 |
| EARLY_FIRST_TRIM |
false |
10 |
| EARLY_SECOND_TRIM |
false |
15 |
| FULL_EXIT_TOO_EARLY |
false |
20 |
| HELD_PAST_SELL_SIGNAL |
false |
20 |
Reflection section
Reflection should be logged once per daily log.
Reflection scoring
Suggested scoring total: 15 points.
| Field |
Points |
| Reviewed all trades |
4 |
| Identified rule breaks |
4 |
| Explained technical reason |
3 |
| Explained emotional reason |
3 |
| Defined one fix for next session |
1 |
Reflection table
model DailyReflectionLog {
id String @id @default(cuid())
dailyTradingLogId String @unique
reviewedAllTrades Boolean @default(false)
identifiedRuleBreaks Boolean @default(false)
explainedTechnicalReason Boolean @default(false)
explainedEmotionalReason Boolean @default(false)
definedNextSessionFix Boolean @default(false)
whatWentWell String?
whatWentPoorly String?
rulesFollowed String?
rulesBroken String?
technicalReason String?
emotionalReason String?
nextSessionFix String?
score Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
dailyTradingLog DailyTradingLog @relation(fields: [dailyTradingLogId], references: [id], onDelete: Cascade)
@@map("daily_reflection_logs")
}
Backend logic requirements
Create helpers/services for recalculating daily log totals.
Preparation score helper
preparationScore =
reviewedPreviousTrades ? 5 : 0
+ completedMarketAnalysis ? 5 : 0
+ createdWatchlist ? 4 : 0
+ reviewedRules ? 3 : 0
+ wroteEmotionalRiskNote ? 3 : 0
Reflection score helper
reflectionScore =
reviewedAllTrades ? 4 : 0
+ identifiedRuleBreaks ? 4 : 0
+ explainedTechnicalReason ? 3 : 0
+ explainedEmotionalReason ? 3 : 0
+ definedNextSessionFix ? 1 : 0
Execution score helper
executionScore = Math.max(0, 100 - sum(pointsLost))
Mistake P/L helper
executionDelta = actualPnlImpact - ruleBasedPnlImpact
leakageCost = Math.max(ruleBasedPnlImpact - actualPnlImpact, 0)
ruleViolationGain = Math.max(actualPnlImpact - ruleBasedPnlImpact, 0)
Daily totals helper
actualPnl = sum trade.pnl for trades on the log date
tradeCount = count trades on the log date
executionDelta = sum mistake.executionDelta
leakageCost = sum mistake.leakageCost
ruleViolationGain = sum mistake.ruleViolationGain
ruleBasedPnl = actualPnl - executionDelta
totalScore = preparationScore + executionScore + reflectionScore
Note: total score can exceed 100 if using 20 + 100 + 15. That is okay if intentionally represented as /135. Alternatively normalize later in frontend. Backend should store raw section scores.
API endpoints
Create a new controller, likely:
access-control/controllers/dailyTradingLogController.ts
Add routes under something like:
Required endpoints:
GET /daily-logs
GET /daily-logs/:id
GET /daily-logs/by-date/:date
POST /daily-logs
PUT /daily-logs/:id
DELETE /daily-logs/:id
Preparation:
PUT /daily-logs/:id/preparation
Reflection:
PUT /daily-logs/:id/reflection
Execution mistakes:
POST /daily-logs/:id/execution-mistakes
PUT /daily-logs/:id/execution-mistakes/:mistakeId
DELETE /daily-logs/:id/execution-mistakes/:mistakeId
Aggregations:
GET /daily-logs/monthly-summary?year=2026&month=5
Monthly summary should return:
{
year: number;
month: number;
tradingDays: number;
actualPnl: number;
ruleBasedPnl: number;
executionDelta: number;
leakageCost: number;
ruleViolationGain: number;
averagePreparationScore: number;
averageExecutionScore: number;
averageReflectionScore: number;
averageTotalScore: number;
mostCommonRuleBreak: string | null;
mostExpensiveRuleBreak: string | null;
}
Important behavior
When creating a daily log:
- Enforce one log per user/date.
- Pull trades for that user/date.
- Sum actual P/L from those trades.
- Default rule-based P/L to actual P/L unless execution mistakes exist.
When adding/editing/deleting an execution mistake:
- Calculate mistake money fields.
- Save optional trade links.
- Recalculate the parent
DailyTradingLog totals.
When an execution mistake has invalidatesTrade = true:
- If linked to a trade, default
actualPnlImpact to that trade’s P/L.
- Default
ruleBasedPnlImpact to 0.
- This captures both ineligible losers and ineligible winners.
When an execution mistake has invalidatesTrade = false:
- User must provide
actualPnlImpact and ruleBasedPnlImpact.
- This handles stop violations, early trims, early full exits, holding too long, improper size, and poor entry.
Validation
Use express-validator or equivalent existing project pattern.
Validate:
- Date format.
- Money fields are numeric.
- Scores and points are integers.
ruleCode, category, and severity are valid enum values.
- User can only access their own logs, trades, and mistakes.
- Linked trades must belong to the authenticated user.
Acceptance criteria
- Prisma schema is updated with the new daily log models/enums.
- Migration is created.
- Daily log CRUD endpoints work.
- Preparation update endpoint calculates and stores preparation score.
- Reflection update endpoint calculates and stores reflection score.
- Execution mistake create/update/delete endpoints calculate money fields and refresh daily totals.
- Monthly summary endpoint returns actual P/L, rule-based P/L, leakage, rule violation gain, and process scores.
- Existing trade journaling still works unchanged.
Trade remains clean and does not regain old execution boolean fields.
Goal
Implement the backend for a new daily trading log system in EdgeFinder. This feature should track performance separate from P/L by day, with three sections:
This issue is backend-only. Do not build frontend UI in this issue.
Current context:
User,Trade, andStrategy.Tradeshould remain a clean raw trade record.properEntry,R,alignedWithTrend,properConditions,followedTpPlan, orproperSizeto theTradetable.Backend requirements
Create a daily trading log backend system that supports:
Required schema design
Update
access-control/prisma/schema.prisma.Update User model
Add relation:
Main table: DailyTradingLog
This is the parent record for one trading day.
Preparation section
The preparation section should be logged once per daily log.
Preparation scoring
Suggested scoring total: 20 points.
Preparation table
Execution section
Execution should be daily-log based, not per-trade based.
Trades remain raw records. Execution mistakes are logged as daily events. A mistake may optionally link to one or more trades.
Execution concepts
Daily actual P/L should be pulled from trades for that user/date.
Each mistake stores:
Daily rule-based P/L:
This handles all cases:
Execution mistake table
Optional link table from mistakes to trades
Add this relation to
Trade:Execution rule enums
Rule defaults
Implement a backend helper that maps rule code to defaults:
Reflection section
Reflection should be logged once per daily log.
Reflection scoring
Suggested scoring total: 15 points.
Reflection table
Backend logic requirements
Create helpers/services for recalculating daily log totals.
Preparation score helper
Reflection score helper
Execution score helper
Mistake P/L helper
Daily totals helper
Note: total score can exceed 100 if using 20 + 100 + 15. That is okay if intentionally represented as
/135. Alternatively normalize later in frontend. Backend should store raw section scores.API endpoints
Create a new controller, likely:
Add routes under something like:
Required endpoints:
Preparation:
Reflection:
Execution mistakes:
Aggregations:
Monthly summary should return:
Important behavior
When creating a daily log:
When adding/editing/deleting an execution mistake:
DailyTradingLogtotals.When an execution mistake has
invalidatesTrade = true:actualPnlImpactto that trade’s P/L.ruleBasedPnlImpactto 0.When an execution mistake has
invalidatesTrade = false:actualPnlImpactandruleBasedPnlImpact.Validation
Use express-validator or equivalent existing project pattern.
Validate:
ruleCode,category, andseverityare valid enum values.Acceptance criteria
Traderemains clean and does not regain old execution boolean fields.