11const express = require ( 'express' ) ;
22const cors = require ( 'cors' ) ;
33const AvailabilityService = require ( './services/availabilityService' ) ;
4+ const AssetMetadataService = require ( './services/assetMetadataService' ) ;
45const AutoReclaimWorker = require ( './services/autoReclaimWorker' ) ;
56
67const app = express ( ) ;
@@ -9,14 +10,23 @@ const port = 3000;
910app . use ( cors ( ) ) ;
1011app . use ( express . json ( ) ) ;
1112
13+ // Initialize services
14+ const availabilityService = new AvailabilityService ( ) ;
15+ const assetMetadataService = new AssetMetadataService ( ) ;
16+
1217app . get ( '/' , ( req , res ) => {
1318 res . json ( {
1419 project : 'LeaseFlow Protocol' ,
1520 status : 'Active' ,
16- contract_id : 'CAEGD57WVTVQSYWYB23AISBW334QO7WNA5XQ56S45GH6BP3D2AVHKUG4'
21+ contract_id : 'CAEGD57WVTVQSYWYB23AISBW334QO7WNA5XQ56S45GH6BP3D2AVHKUG4' ,
22+ services : {
23+ availability : 'active' ,
24+ metadata : 'active'
25+ }
1726 } ) ;
1827} ) ;
1928
29+ // Availability endpoints
2030app . get ( '/api/asset/:id/availability' , async ( req , res ) => {
2131 try {
2232 const { id } = req . params ;
@@ -86,6 +96,310 @@ app.get('/api/assets/availability', async (req, res) => {
8696 }
8797} ) ;
8898
99+ // Asset metadata endpoints
100+ app . get ( '/api/asset/:id/metadata' , async ( req , res ) => {
101+ try {
102+ const { id } = req . params ;
103+ const { refresh } = req . query ;
104+
105+ if ( ! id || isNaN ( id ) ) {
106+ return res . status ( 400 ) . json ( {
107+ error : 'Invalid asset ID. Must be a number.' ,
108+ code : 'INVALID_ASSET_ID'
109+ } ) ;
110+ }
111+
112+ const metadata = await assetMetadataService . getAssetMetadata ( id , refresh === 'true' ) ;
113+
114+ if ( ! metadata ) {
115+ return res . status ( 404 ) . json ( {
116+ error : 'Asset metadata not found' ,
117+ code : 'METADATA_NOT_FOUND'
118+ } ) ;
119+ }
120+
121+ res . json ( {
122+ success : true ,
123+ data : metadata
124+ } ) ;
125+
126+ } catch ( error ) {
127+ console . error ( `Error fetching metadata for asset ${ req . params . id } :` , error ) ;
128+
129+ res . status ( 500 ) . json ( {
130+ error : 'Failed to fetch asset metadata' ,
131+ code : 'METADATA_ERROR' ,
132+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
133+ } ) ;
134+ }
135+ } ) ;
136+
137+ app . get ( '/api/assets/metadata' , async ( req , res ) => {
138+ try {
139+ const { ids, refresh } = req . query ;
140+
141+ if ( ids ) {
142+ const assetIds = ids . split ( ',' ) . map ( id => id . trim ( ) ) . filter ( id => id && ! isNaN ( id ) ) ;
143+
144+ if ( assetIds . length === 0 ) {
145+ return res . status ( 400 ) . json ( {
146+ error : 'No valid asset IDs provided' ,
147+ code : 'INVALID_ASSET_IDS'
148+ } ) ;
149+ }
150+
151+ const metadata = await assetMetadataService . getMultipleAssetMetadata ( assetIds , refresh === 'true' ) ;
152+
153+ res . json ( {
154+ success : true ,
155+ data : metadata
156+ } ) ;
157+ } else {
158+ const metadata = await assetMetadataService . getAllAssetMetadata ( ) ;
159+
160+ res . json ( {
161+ success : true ,
162+ data : metadata
163+ } ) ;
164+ }
165+
166+ } catch ( error ) {
167+ console . error ( 'Error fetching assets metadata:' , error ) ;
168+
169+ res . status ( 500 ) . json ( {
170+ error : 'Failed to fetch assets metadata' ,
171+ code : 'METADATA_ERROR' ,
172+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
173+ } ) ;
174+ }
175+ } ) ;
176+
177+ app . post ( '/api/asset/:id/metadata' , async ( req , res ) => {
178+ try {
179+ const { id } = req . params ;
180+ const metadata = req . body ;
181+
182+ if ( ! id || isNaN ( id ) ) {
183+ return res . status ( 400 ) . json ( {
184+ error : 'Invalid asset ID. Must be a number.' ,
185+ code : 'INVALID_ASSET_ID'
186+ } ) ;
187+ }
188+
189+ const result = await assetMetadataService . saveAssetMetadata ( {
190+ assetId : id ,
191+ ...metadata
192+ } ) ;
193+
194+ res . status ( 201 ) . json ( {
195+ success : true ,
196+ message : 'Asset metadata saved successfully' ,
197+ data : result
198+ } ) ;
199+
200+ } catch ( error ) {
201+ console . error ( `Error saving metadata for asset ${ req . params . id } :` , error ) ;
202+
203+ res . status ( 500 ) . json ( {
204+ error : 'Failed to save asset metadata' ,
205+ code : 'SAVE_ERROR' ,
206+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
207+ } ) ;
208+ }
209+ } ) ;
210+
211+ app . put ( '/api/asset/:id/metadata' , async ( req , res ) => {
212+ try {
213+ const { id } = req . params ;
214+ const updates = req . body ;
215+
216+ if ( ! id || isNaN ( id ) ) {
217+ return res . status ( 400 ) . json ( {
218+ error : 'Invalid asset ID. Must be a number.' ,
219+ code : 'INVALID_ASSET_ID'
220+ } ) ;
221+ }
222+
223+ const result = await assetMetadataService . updateAssetMetadata ( id , updates ) ;
224+
225+ res . json ( {
226+ success : true ,
227+ message : 'Asset metadata updated successfully' ,
228+ data : result
229+ } ) ;
230+
231+ } catch ( error ) {
232+ console . error ( `Error updating metadata for asset ${ req . params . id } :` , error ) ;
233+
234+ if ( error . message . includes ( 'not found' ) ) {
235+ return res . status ( 404 ) . json ( {
236+ error : 'Asset not found' ,
237+ code : 'ASSET_NOT_FOUND'
238+ } ) ;
239+ }
240+
241+ res . status ( 500 ) . json ( {
242+ error : 'Failed to update asset metadata' ,
243+ code : 'UPDATE_ERROR' ,
244+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
245+ } ) ;
246+ }
247+ } ) ;
248+
249+ app . delete ( '/api/asset/:id/metadata' , async ( req , res ) => {
250+ try {
251+ const { id } = req . params ;
252+
253+ if ( ! id || isNaN ( id ) ) {
254+ return res . status ( 400 ) . json ( {
255+ error : 'Invalid asset ID. Must be a number.' ,
256+ code : 'INVALID_ASSET_ID'
257+ } ) ;
258+ }
259+
260+ const result = await assetMetadataService . deleteAssetMetadata ( id ) ;
261+
262+ if ( ! result ) {
263+ return res . status ( 404 ) . json ( {
264+ error : 'Asset metadata not found' ,
265+ code : 'METADATA_NOT_FOUND'
266+ } ) ;
267+ }
268+
269+ res . json ( {
270+ success : true ,
271+ message : 'Asset metadata deleted successfully' ,
272+ data : result
273+ } ) ;
274+
275+ } catch ( error ) {
276+ console . error ( `Error deleting metadata for asset ${ req . params . id } :` , error ) ;
277+
278+ res . status ( 500 ) . json ( {
279+ error : 'Failed to delete asset metadata' ,
280+ code : 'DELETE_ERROR' ,
281+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
282+ } ) ;
283+ }
284+ } ) ;
285+
286+ app . get ( '/api/assets/search' , async ( req , res ) => {
287+ try {
288+ const { q } = req . query ;
289+
290+ if ( ! q || q . trim ( ) . length === 0 ) {
291+ return res . status ( 400 ) . json ( {
292+ error : 'Search query is required' ,
293+ code : 'MISSING_QUERY'
294+ } ) ;
295+ }
296+
297+ const results = await assetMetadataService . searchAssets ( q . trim ( ) ) ;
298+
299+ res . json ( {
300+ success : true ,
301+ data : results ,
302+ query : q . trim ( ) ,
303+ count : results . length
304+ } ) ;
305+
306+ } catch ( error ) {
307+ console . error ( `Error searching assets with query "${ req . query . q } ":` , error ) ;
308+
309+ res . status ( 500 ) . json ( {
310+ error : 'Failed to search assets' ,
311+ code : 'SEARCH_ERROR' ,
312+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
313+ } ) ;
314+ }
315+ } ) ;
316+
317+ app . post ( '/api/asset/:id/refresh' , async ( req , res ) => {
318+ try {
319+ const { id } = req . params ;
320+
321+ if ( ! id || isNaN ( id ) ) {
322+ return res . status ( 400 ) . json ( {
323+ error : 'Invalid asset ID. Must be a number.' ,
324+ code : 'INVALID_ASSET_ID'
325+ } ) ;
326+ }
327+
328+ const result = await assetMetadataService . refreshAssetCache ( id ) ;
329+
330+ res . json ( {
331+ success : true ,
332+ message : 'Asset cache refreshed successfully' ,
333+ data : result
334+ } ) ;
335+
336+ } catch ( error ) {
337+ console . error ( `Error refreshing cache for asset ${ req . params . id } :` , error ) ;
338+
339+ res . status ( 500 ) . json ( {
340+ error : 'Failed to refresh asset cache' ,
341+ code : 'REFRESH_ERROR' ,
342+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
343+ } ) ;
344+ }
345+ } ) ;
346+
347+ app . get ( '/api/metadata/stats' , async ( req , res ) => {
348+ try {
349+ const stats = await assetMetadataService . getCacheStatistics ( ) ;
350+
351+ res . json ( {
352+ success : true ,
353+ data : stats
354+ } ) ;
355+
356+ } catch ( error ) {
357+ console . error ( 'Error fetching metadata statistics:' , error ) ;
358+
359+ res . status ( 500 ) . json ( {
360+ error : 'Failed to fetch metadata statistics' ,
361+ code : 'STATS_ERROR' ,
362+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
363+ } ) ;
364+ }
365+ } ) ;
366+
367+ app . get ( '/api/health' , async ( req , res ) => {
368+ try {
369+ const health = await assetMetadataService . healthCheck ( ) ;
370+
371+ res . json ( {
372+ success : true ,
373+ data : health
374+ } ) ;
375+
376+ } catch ( error ) {
377+ console . error ( 'Error performing health check:' , error ) ;
378+
379+ res . status ( 500 ) . json ( {
380+ error : 'Failed to perform health check' ,
381+ code : 'HEALTH_ERROR' ,
382+ details : process . env . NODE_ENV === 'development' ? error . message : undefined
383+ } ) ;
384+ }
385+ } ) ;
386+
387+ if ( require . main === module ) {
388+ // Initialize and start services
389+ Promise . all ( [
390+ availabilityService . initialize ( ) ,
391+ assetMetadataService . initialize ( )
392+ ] ) . then ( ( ) => {
393+ app . locals . availabilityService = availabilityService ;
394+ app . locals . assetMetadataService = assetMetadataService ;
395+
396+ app . listen ( port , ( ) => {
397+ console . log ( `LeaseFlow Backend listening at http://localhost:${ port } ` ) ;
398+ console . log ( 'Availability Service started' ) ;
399+ console . log ( 'Asset Metadata Service started' ) ;
400+ } ) ;
401+ } ) . catch ( error => {
402+ console . error ( 'Failed to initialize services:' , error ) ;
89403if ( require . main === module ) {
90404 const availabilityService = new AvailabilityService ( ) ;
91405
0 commit comments