{"openapi":"3.1.0","info":{"title":"Dalrymple Ramos Public Portfolio API","version":"1.0.0","description":"Read public profile, projects, and published article metadata. No authentication is required."},"servers":[{"url":"https://dalrympleramos.dev"}],"security":[],"paths":{"/api/portfolio":{"get":{"operationId":"getPortfolio","summary":"Read or search the public portfolio","parameters":[{"name":"q","in":"query","required":false,"description":"Case-insensitive search of project descriptions and article metadata; all terms must match. Blank queries are rejected.","schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"\\S"}}],"responses":{"200":{"description":"Full portfolio without q; matching projects and posts with q.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Portfolio"},{"$ref":"#/components/schemas/SearchResults"}]}}}},"400":{"description":"Invalid search query.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/health":{"get":{"operationId":"getHealth","summary":"Check application liveness","responses":{"200":{"description":"The portfolio application is serving requests.","content":{"application/json":{"schema":{"type":"object","required":["status","service"],"properties":{"status":{"const":"ok"},"service":{"const":"portfolio"}}}}}}}}}},"components":{"schemas":{"Profile":{"type":"object","required":["name","title","location","about","experience","contact","url","identityLinks"],"properties":{"name":{"type":"string"},"title":{"type":"string"},"location":{"type":"string"},"about":{"type":"string"},"url":{"type":"string","format":"uri"},"identityLinks":{"type":"array","items":{"type":"string","format":"uri"}},"experience":{"type":"array","items":{"type":"object","required":["role","company","period","detail"],"properties":{"role":{"type":"string"},"company":{"type":"string"},"period":{"type":"string"},"detail":{"type":"string"},"url":{"type":"string","format":"uri"}}}},"contact":{"type":"object","required":["email","linkedin"],"properties":{"email":{"type":"string","format":"email"},"linkedin":{"type":"string","format":"uri"}}}}},"Project":{"type":"object","required":["slug","title","summary","description","tags","links","url"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"description":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"url":{"type":"string","format":"uri"},"contributionRole":{"enum":["creator","contributor"]},"image":{"type":"string"},"imageAlt":{"type":"string"},"imageFit":{"enum":["cover","contain"]},"links":{"type":"array","items":{"type":"object","required":["label","url"],"properties":{"label":{"type":"string"},"url":{"type":"string","format":"uri"}}}}}},"Post":{"type":"object","required":["slug","title","description","date","publishedAt","authorId","url"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"date":{"type":"string"},"publishedAt":{"type":"string","format":"date"},"updatedAt":{"type":"string","format":"date"},"authorId":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"seoTitle":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"relatedProjects":{"type":"array","items":{"type":"string"}},"image":{"type":"object","required":["src","alt","width","height"],"properties":{"src":{"type":"string"},"alt":{"type":"string"},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1}}}}},"SearchResults":{"type":"object","required":["projects","posts"],"additionalProperties":false,"properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}}},"Portfolio":{"type":"object","required":["profile","projects","posts"],"properties":{"profile":{"$ref":"#/components/schemas/Profile"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}