feat(desktop+web): Phase 3.3 Auto push on write + transcript fallback + dashboard Link (빅뱅 Phase 5 Part 3)
Desktop — CloudSyncService: - pushOne(table, id) 제네릭 단건 push 신규 (history/dictionary/meetings/meeting_memos/meeting_documents) - 로그인 미상태 silent noop, 실패 시 warn만 (로컬 write 절대 차단 금지) - 5개 row→payload 매퍼(_mapHistoryPayload 외 4개) private 메서드로 추출, pushAll과 공유 (DRY) Desktop — write hook 8곳 fire-and-forget 연결: - HistoryService.create / generateTitle - MeetingSummaryService.generateSummary (summaryText 저장 후) - DictionaryService.add / update - MeetingModeService.startRecording (부모 meeting pre-push — 자식 memo/doc RLS 통과용) - MeetingModeService.addMemo / generateDocument - MeetingModeService._runPostProcessing (완료 상태 최종 저장 후) Web — meeting detail page: - transcripts 테이블이 비고 status!=recording인 경우 meeting.raw_transcript(또는 edited_transcript) 를 whiteSpace:pre-wrap으로 fallback 렌더 - 실시간 구독 경로(LiveTranscriptList)는 recording 상태 또는 transcripts 존재 시에만 마운트 Web — dashboard: - RECENT MEETINGS의 MetalCard를 next/link Link로 감싸 /meetings/[id] 이동 가능 - cursor pointer + hover lift 효과 실증: 재기동 직후 pushAll 캐치업이 이전 세션 RLS 실패 메모 2건을 재시도 → pushed=4 성공. 새 녹음 → pushOne history/... ok 실시간 발화 → 웹에서 전사/메모 렌더 확인 (사용자 "잘 전사와 메모가 올라왔어")
This commit is contained in:
parent
4e6280bc69
commit
046ac857cb
8 changed files with 344 additions and 85 deletions
|
|
@ -1,6 +1,7 @@
|
|||
// apps/web/src/app/dashboard/page.tsx
|
||||
// 대시보드 — 요약 카드 4개 + 최근 회의
|
||||
|
||||
import Link from 'next/link'
|
||||
import { Box, Grid, Stack } from '@mui/material'
|
||||
import { MetalCard, PhosphorText } from '@d3ro/ui/components/ds'
|
||||
import { d3roPalette, typoSx } from "@d3ro/ui/theme"
|
||||
|
|
@ -154,12 +155,25 @@ export default async function DashboardPage(): Promise<React.ReactElement> {
|
|||
</MetalCard>
|
||||
) : (
|
||||
recentMeetings.map((meeting) => (
|
||||
<MetalCard key={meeting.id} sx={{ p: 3 }}>
|
||||
<Box sx={{ color: d3roPalette.text.primary, ...typoSx("body") }}>{meeting.title}</Box>
|
||||
<Box sx={{ color: d3roPalette.text.muted, fontSize: 12, mt: 0.5 }}>
|
||||
{new Date(meeting.started_at).toLocaleString('ko-KR')}
|
||||
</Box>
|
||||
</MetalCard>
|
||||
<Link
|
||||
key={meeting.id}
|
||||
href={`/meetings/${meeting.id}`}
|
||||
style={{ textDecoration: 'none' }}
|
||||
>
|
||||
<MetalCard
|
||||
sx={{
|
||||
p: 3,
|
||||
cursor: 'pointer',
|
||||
transition: 'transform 120ms ease, box-shadow 120ms ease',
|
||||
'&:hover': { transform: 'translateY(-1px)' }
|
||||
}}
|
||||
>
|
||||
<Box sx={{ color: d3roPalette.text.primary, ...typoSx("body") }}>{meeting.title}</Box>
|
||||
<Box sx={{ color: d3roPalette.text.muted, fontSize: 12, mt: 0.5 }}>
|
||||
{new Date(meeting.started_at).toLocaleString('ko-KR')}
|
||||
</Box>
|
||||
</MetalCard>
|
||||
</Link>
|
||||
))
|
||||
)}
|
||||
</Stack>
|
||||
|
|
|
|||
|
|
@ -68,15 +68,33 @@ export default async function MeetingDetailPage({ params }: PageProps): Promise<
|
|||
<MeetingAudioPlayer storageKey={meeting.audio_storage_key ?? null} />
|
||||
</MetalCard>
|
||||
|
||||
{/* Transcript — Realtime 구독 */}
|
||||
{/* Transcript — Realtime 구독 or raw_transcript fallback */}
|
||||
<MetalCard sx={{ p: 3 }}>
|
||||
<PhosphorText variant="heading" sx={{ mb: 2 }}>
|
||||
TRANSCRIPT (LIVE)
|
||||
TRANSCRIPT {meeting.status === 'recording' ? '(LIVE)' : ''}
|
||||
</PhosphorText>
|
||||
<LiveTranscriptList
|
||||
meetingId={id}
|
||||
initial={(transcripts ?? []) as unknown as TranscriptRow[]}
|
||||
/>
|
||||
{(transcripts ?? []).length > 0 || meeting.status === 'recording' ? (
|
||||
<LiveTranscriptList
|
||||
meetingId={id}
|
||||
initial={(transcripts ?? []) as unknown as TranscriptRow[]}
|
||||
/>
|
||||
) : meeting.edited_transcript || meeting.raw_transcript ? (
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
color: d3roPalette.text.primary,
|
||||
fontSize: 13,
|
||||
lineHeight: 1.6,
|
||||
fontFamily: 'inherit'
|
||||
}}
|
||||
>
|
||||
{meeting.edited_transcript ?? meeting.raw_transcript}
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{ color: d3roPalette.text.muted, fontSize: 13 }}>
|
||||
전사가 없습니다.
|
||||
</Box>
|
||||
)}
|
||||
</MetalCard>
|
||||
|
||||
{/* Memos */}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue