feat(templates): persist template_id; finalize_meeting returns it (T8.1, FR-NOTE-5)
NewMeeting/Meeting gain template_id; finalize_meeting now returns it (fetched via one cheap scalar SELECT) so callers that only have segments/speakers in memory (not a fetched Meeting) can resolve the template without a separate round-trip.
This commit is contained in:
@@ -36,6 +36,11 @@ impl From<sqlx::Error> for StoreError {
|
||||
pub struct NewMeeting {
|
||||
pub title: String,
|
||||
pub calendar_event_id: Option<String>,
|
||||
/// Note-template id (Phase 8, T8.1, FR-NOTE-5) — resolved against
|
||||
/// `notes::templates::catalog()`, kept alongside the meeting so
|
||||
/// re-rendering notes.md on reprocess/resume reapplies the same
|
||||
/// section structure instead of losing it.
|
||||
pub template_id: Option<String>,
|
||||
}
|
||||
|
||||
/// `list_meetings` filters (Phase 8, FR-SEARCH-2). All fields are ANDed
|
||||
@@ -89,6 +94,9 @@ pub struct Meeting {
|
||||
pub calendar_event_id: Option<String>,
|
||||
/// Tags (Phase 8, FR-SEARCH-2), sorted.
|
||||
pub tags: Vec<String>,
|
||||
/// Note-template id (Phase 8, T8.1, FR-NOTE-5), if one was picked at
|
||||
/// creation — resolved against `notes::templates::catalog()`.
|
||||
pub template_id: Option<String>,
|
||||
}
|
||||
|
||||
/// A calendar event with its attendees (T6.3/T6.4, FR-CAL-1/3) — the
|
||||
@@ -123,7 +131,14 @@ pub struct Retention {
|
||||
#[async_trait]
|
||||
pub trait Store: Send + Sync {
|
||||
async fn create_meeting(&self, m: NewMeeting) -> Result<MeetingId, StoreError>;
|
||||
async fn finalize_meeting(&self, id: &MeetingId, s: FinalizeMeeting) -> Result<(), StoreError>;
|
||||
/// Returns the meeting's `template_id` (set at creation, Phase 8 T8.1) so
|
||||
/// callers can re-render notes.md with the same section structure
|
||||
/// without a separate fetch.
|
||||
async fn finalize_meeting(
|
||||
&self,
|
||||
id: &MeetingId,
|
||||
s: FinalizeMeeting,
|
||||
) -> Result<Option<String>, StoreError>;
|
||||
async fn list_meetings(
|
||||
&self,
|
||||
filter: MeetingFilter,
|
||||
@@ -490,8 +505,8 @@ impl Store for SqliteStore {
|
||||
let audio_path = folder.join("audio.wav");
|
||||
let now = now_unix();
|
||||
sqlx::query(
|
||||
"INSERT INTO meetings (id, title, started_at, folder_path, audio_path, status, calendar_event_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 'recording', ?, ?, ?)",
|
||||
"INSERT INTO meetings (id, title, started_at, folder_path, audio_path, status, calendar_event_id, template_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 'recording', ?, ?, ?, ?)",
|
||||
)
|
||||
.bind(&id)
|
||||
.bind(&m.title)
|
||||
@@ -499,6 +514,7 @@ impl Store for SqliteStore {
|
||||
.bind(folder.display().to_string())
|
||||
.bind(audio_path.display().to_string())
|
||||
.bind(&m.calendar_event_id)
|
||||
.bind(&m.template_id)
|
||||
.bind(now)
|
||||
.bind(now)
|
||||
.execute(&self.pool)
|
||||
@@ -506,7 +522,11 @@ impl Store for SqliteStore {
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
async fn finalize_meeting(&self, id: &MeetingId, s: FinalizeMeeting) -> Result<(), StoreError> {
|
||||
async fn finalize_meeting(
|
||||
&self,
|
||||
id: &MeetingId,
|
||||
s: FinalizeMeeting,
|
||||
) -> Result<Option<String>, StoreError> {
|
||||
let now = now_unix();
|
||||
sqlx::query(
|
||||
"UPDATE meetings SET status = 'ready', ended_at = ?, duration_secs = ?, recorded = ?,
|
||||
@@ -553,7 +573,12 @@ impl Store for SqliteStore {
|
||||
serde_json::to_string_pretty(&transcript).map_err(|e| StoreError::Db(e.to_string()))?;
|
||||
std::fs::write(paths::meeting_dir(id).join("transcript.json"), json)?;
|
||||
self.reindex_fts(id).await?;
|
||||
Ok(())
|
||||
let template_id: Option<String> =
|
||||
sqlx::query_scalar("SELECT template_id FROM meetings WHERE id = ?")
|
||||
.bind(id)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
Ok(template_id)
|
||||
}
|
||||
|
||||
async fn list_meetings(
|
||||
@@ -625,7 +650,7 @@ impl Store for SqliteStore {
|
||||
|
||||
async fn get_meeting(&self, id: &MeetingId) -> Result<Meeting, StoreError> {
|
||||
let row = sqlx::query(
|
||||
"SELECT id, title, started_at, ended_at, duration_secs, status, recorded, language, backend_used, model_used, calendar_event_id
|
||||
"SELECT id, title, started_at, ended_at, duration_secs, status, recorded, language, backend_used, model_used, calendar_event_id, template_id
|
||||
FROM meetings WHERE id = ?",
|
||||
)
|
||||
.bind(id)
|
||||
@@ -696,6 +721,7 @@ impl Store for SqliteStore {
|
||||
summary,
|
||||
calendar_event_id: row.get("calendar_event_id"),
|
||||
tags,
|
||||
template_id: row.get("template_id"),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user