@@ -31,11 +31,13 @@ export class DevlogService {
3131 private static readonly TTL_MS = 5 * 60 * 1000 ; // 5 minutes TTL
3232 private database : DataSource ;
3333 private devlogRepository : Repository < DevlogEntryEntity > ;
34+ private noteRepository : Repository < DevlogNoteEntity > ;
3435
3536 private constructor ( private projectId ?: number ) {
3637 // Database initialization will happen in ensureInitialized()
3738 this . database = null as any ; // Temporary placeholder
3839 this . devlogRepository = null as any ; // Temporary placeholder
40+ this . noteRepository = null as any ; // Temporary placeholder
3941 }
4042
4143 /**
@@ -47,6 +49,7 @@ export class DevlogService {
4749 console . log ( '[DevlogService] Getting initialized DataSource...' ) ;
4850 this . database = await getDataSource ( ) ;
4951 this . devlogRepository = this . database . getRepository ( DevlogEntryEntity ) ;
52+ this . noteRepository = this . database . getRepository ( DevlogNoteEntity ) ;
5053 console . log (
5154 '[DevlogService] DataSource ready with entities:' ,
5255 this . database . entityMetadatas . length ,
@@ -79,7 +82,7 @@ export class DevlogService {
7982 return existingInstance . service ;
8083 }
8184
82- async get ( id : DevlogId ) : Promise < DevlogEntry | null > {
85+ async get ( id : DevlogId , includeNotes = true ) : Promise < DevlogEntry | null > {
8386 await this . ensureInitialized ( ) ;
8487
8588 // Validate devlog ID
@@ -94,7 +97,51 @@ export class DevlogService {
9497 return null ;
9598 }
9699
97- return entity . toDevlogEntry ( ) ;
100+ const devlogEntry = entity . toDevlogEntry ( ) ;
101+
102+ // Load notes if requested
103+ if ( includeNotes ) {
104+ devlogEntry . notes = await this . getNotes ( id ) ;
105+ }
106+
107+ return devlogEntry ;
108+ }
109+
110+ /**
111+ * Get notes for a specific devlog entry
112+ */
113+ async getNotes (
114+ devlogId : DevlogId ,
115+ limit ?: number ,
116+ ) : Promise < import ( '../types/index.js' ) . DevlogNote [ ] > {
117+ await this . ensureInitialized ( ) ;
118+
119+ // Validate devlog ID
120+ const idValidation = DevlogValidator . validateDevlogId ( devlogId ) ;
121+ if ( ! idValidation . success ) {
122+ throw new Error ( `Invalid devlog ID: ${ idValidation . errors . join ( ', ' ) } ` ) ;
123+ }
124+
125+ const queryBuilder = this . noteRepository
126+ . createQueryBuilder ( 'note' )
127+ . where ( 'note.devlogId = :devlogId' , { devlogId : idValidation . data } )
128+ . orderBy ( 'note.timestamp' , 'DESC' ) ;
129+
130+ if ( limit && limit > 0 ) {
131+ queryBuilder . limit ( limit ) ;
132+ }
133+
134+ const noteEntities = await queryBuilder . getMany ( ) ;
135+
136+ return noteEntities . map ( ( entity ) => ( {
137+ id : entity . id ,
138+ timestamp : entity . timestamp . toISOString ( ) ,
139+ category : entity . category ,
140+ content : entity . content ,
141+ files : entity . files || [ ] ,
142+ codeChanges : entity . codeChanges ,
143+ metadata : entity . metadata ,
144+ } ) ) ;
98145 }
99146
100147 async save ( entry : DevlogEntry ) : Promise < void > {
@@ -139,9 +186,55 @@ export class DevlogService {
139186 }
140187 }
141188
142- // Convert to entity and save
143- const entity = DevlogEntryEntity . fromDevlogEntry ( validatedEntry ) ;
144- await this . devlogRepository . save ( entity ) ;
189+ // Handle notes separately - save to DevlogNoteEntity table
190+ const notesToSave = validatedEntry . notes || [ ] ;
191+
192+ // Convert to entity and save (without notes in JSON)
193+ const entryWithoutNotes = { ...validatedEntry } ;
194+ delete entryWithoutNotes . notes ; // Remove notes from the main entity
195+
196+ const entity = DevlogEntryEntity . fromDevlogEntry ( entryWithoutNotes ) ;
197+ const savedEntity = await this . devlogRepository . save ( entity ) ;
198+
199+ // Save notes to separate table if entry has an ID
200+ if ( savedEntity . id && notesToSave . length > 0 ) {
201+ await this . saveNotes ( savedEntity . id , notesToSave ) ;
202+ }
203+ }
204+
205+ /**
206+ * Save notes for a devlog entry to the notes table
207+ */
208+ private async saveNotes (
209+ devlogId : number ,
210+ notes : import ( '../types/index.js' ) . DevlogNote [ ] ,
211+ ) : Promise < void > {
212+ // Get existing notes to determine which are new
213+ const existingNotes = await this . noteRepository . find ( {
214+ where : { devlogId } ,
215+ select : [ 'id' ] ,
216+ } ) ;
217+ const existingNoteIds = new Set ( existingNotes . map ( ( n ) => n . id ) ) ;
218+
219+ // Only save new notes (ones that don't exist in DB)
220+ const newNotes = notes . filter ( ( note ) => ! existingNoteIds . has ( note . id ) ) ;
221+
222+ if ( newNotes . length > 0 ) {
223+ const noteEntities = newNotes . map ( ( note ) => {
224+ const entity = new DevlogNoteEntity ( ) ;
225+ entity . id = note . id ;
226+ entity . devlogId = devlogId ;
227+ entity . timestamp = new Date ( note . timestamp ) ;
228+ entity . category = note . category ;
229+ entity . content = note . content ;
230+ entity . files = note . files || [ ] ;
231+ entity . codeChanges = note . codeChanges ;
232+ entity . metadata = note . metadata ;
233+ return entity ;
234+ } ) ;
235+
236+ await this . noteRepository . save ( noteEntities ) ;
237+ }
145238 }
146239
147240 async delete ( id : DevlogId ) : Promise < void > {
0 commit comments