feat: Excel template export with meeting number auto-generation
- Add meeting_number field (M-YYYYMMDD-XX format) with auto-generation - Refactor Excel export to use cell coordinates instead of placeholders - Export files saved to backend/record/ directory with meeting number filename - Add database migration for meeting_number column - Add start.sh script for managing frontend/backend/sidecar services - Update OpenSpec documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,21 +28,39 @@ def generate_system_code(prefix: str, meeting_date: date, sequence: int) -> str:
|
||||
def get_next_sequence(cursor, prefix: str, date_str: str) -> int:
|
||||
"""Get next sequence number for a given prefix and date."""
|
||||
pattern = f"{prefix}-{date_str}-%"
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT system_code FROM meeting_conclusions WHERE system_code LIKE %s
|
||||
UNION
|
||||
SELECT system_code FROM meeting_action_items WHERE system_code LIKE %s
|
||||
ORDER BY system_code DESC LIMIT 1
|
||||
""",
|
||||
(pattern, pattern),
|
||||
)
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
last_code = result["system_code"]
|
||||
last_seq = int(last_code.split("-")[-1])
|
||||
return last_seq + 1
|
||||
return 1
|
||||
|
||||
if prefix == "M":
|
||||
# For meeting numbers, search in meeting_records table
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT meeting_number FROM meeting_records WHERE meeting_number LIKE %s
|
||||
ORDER BY meeting_number DESC LIMIT 1
|
||||
""",
|
||||
(pattern,),
|
||||
)
|
||||
result = cursor.fetchone()
|
||||
if result and result.get("meeting_number"):
|
||||
last_code = result["meeting_number"]
|
||||
last_seq = int(last_code.split("-")[-1])
|
||||
return last_seq + 1
|
||||
return 1
|
||||
else:
|
||||
# For conclusions (C) and action items (A)
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT system_code FROM meeting_conclusions WHERE system_code LIKE %s
|
||||
UNION
|
||||
SELECT system_code FROM meeting_action_items WHERE system_code LIKE %s
|
||||
ORDER BY system_code DESC LIMIT 1
|
||||
""",
|
||||
(pattern, pattern),
|
||||
)
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
last_code = result["system_code"]
|
||||
last_seq = int(last_code.split("-")[-1])
|
||||
return last_seq + 1
|
||||
return 1
|
||||
|
||||
|
||||
@router.post("/meetings", response_model=MeetingResponse)
|
||||
@@ -56,15 +74,20 @@ async def create_meeting(
|
||||
date_str = meeting_date.strftime("%Y%m%d")
|
||||
|
||||
with get_db_cursor(commit=True) as cursor:
|
||||
# Generate meeting number
|
||||
meeting_seq = get_next_sequence(cursor, "M", date_str)
|
||||
meeting_number = generate_system_code("M", meeting_date, meeting_seq)
|
||||
|
||||
# Insert meeting record
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO meeting_records
|
||||
(uuid, subject, meeting_time, location, chairperson, recorder, attendees, transcript_blob, created_by)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
(uuid, meeting_number, subject, meeting_time, location, chairperson, recorder, attendees, transcript_blob, created_by)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
(
|
||||
meeting_uuid,
|
||||
meeting_number,
|
||||
meeting.subject,
|
||||
meeting.meeting_time,
|
||||
meeting.location,
|
||||
@@ -133,6 +156,7 @@ async def create_meeting(
|
||||
return MeetingResponse(
|
||||
meeting_id=record["meeting_id"],
|
||||
uuid=record["uuid"],
|
||||
meeting_number=record.get("meeting_number"),
|
||||
subject=record["subject"],
|
||||
meeting_time=record["meeting_time"],
|
||||
location=record["location"],
|
||||
@@ -215,6 +239,7 @@ async def get_meeting(
|
||||
return MeetingResponse(
|
||||
meeting_id=record["meeting_id"],
|
||||
uuid=record["uuid"],
|
||||
meeting_number=record.get("meeting_number"),
|
||||
subject=record["subject"],
|
||||
meeting_time=record["meeting_time"],
|
||||
location=record["location"],
|
||||
|
||||
Reference in New Issue
Block a user