create-arete-workspace 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/bin/arete.js +156 -0
- package/bin/create.js +111 -0
- package/lib/install-openclaw.js +50 -0
- package/lib/scaffold.js +213 -0
- package/lib/setup-wizard.js +88 -0
- package/lib/updater.js +130 -0
- package/package.json +34 -0
- package/packages/gatsaeng-os/README.md +36 -0
- package/packages/gatsaeng-os/components.json +23 -0
- package/packages/gatsaeng-os/eslint.config.mjs +18 -0
- package/packages/gatsaeng-os/next.config.ts +7 -0
- package/packages/gatsaeng-os/package.json +59 -0
- package/packages/gatsaeng-os/postcss.config.mjs +7 -0
- package/packages/gatsaeng-os/public/file.svg +1 -0
- package/packages/gatsaeng-os/public/globe.svg +1 -0
- package/packages/gatsaeng-os/public/next.svg +1 -0
- package/packages/gatsaeng-os/public/vercel.svg +1 -0
- package/packages/gatsaeng-os/public/window.svg +1 -0
- package/packages/gatsaeng-os/python/api_server.py +248 -0
- package/packages/gatsaeng-os/python/briefing.py +145 -0
- package/packages/gatsaeng-os/python/config.py +55 -0
- package/packages/gatsaeng-os/python/goal_context_agent.py +193 -0
- package/packages/gatsaeng-os/python/gyeokguk.py +171 -0
- package/packages/gatsaeng-os/python/proactive.py +158 -0
- package/packages/gatsaeng-os/python/requirements.txt +11 -0
- package/packages/gatsaeng-os/python/run.py +28 -0
- package/packages/gatsaeng-os/python/scoring.py +44 -0
- package/packages/gatsaeng-os/python/streak.py +70 -0
- package/packages/gatsaeng-os/python/telegram_bot.py +331 -0
- package/packages/gatsaeng-os/python/timing_engine.py +117 -0
- package/packages/gatsaeng-os/python/vault_io.py +423 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/areas/[id]/page.tsx +215 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/areas/page.tsx +161 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/books/[id]/page.tsx +215 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/books/page.tsx +268 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/calendar/page.tsx +379 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/error.tsx +30 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/focus/page.tsx +293 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/goals/[id]/page.tsx +426 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/goals/page.tsx +178 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/layout.tsx +29 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/notes/[id]/page.tsx +147 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/notes/page.tsx +254 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/page.tsx +26 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/projects/[id]/page.tsx +86 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/projects/page.tsx +215 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/review/page.tsx +475 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/routines/page.tsx +436 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/tasks/[id]/page.tsx +210 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/tasks/page.tsx +307 -0
- package/packages/gatsaeng-os/src/app/(dashboard)/voice/page.tsx +212 -0
- package/packages/gatsaeng-os/src/app/api/areas/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/areas/route.ts +22 -0
- package/packages/gatsaeng-os/src/app/api/auth/login/route.ts +52 -0
- package/packages/gatsaeng-os/src/app/api/auth/logout/route.ts +8 -0
- package/packages/gatsaeng-os/src/app/api/books/[id]/route.ts +27 -0
- package/packages/gatsaeng-os/src/app/api/books/route.ts +20 -0
- package/packages/gatsaeng-os/src/app/api/calendar/[id]/route.ts +24 -0
- package/packages/gatsaeng-os/src/app/api/calendar/import/route.ts +52 -0
- package/packages/gatsaeng-os/src/app/api/calendar/route.ts +37 -0
- package/packages/gatsaeng-os/src/app/api/daily/route.ts +51 -0
- package/packages/gatsaeng-os/src/app/api/goals/[id]/route.ts +34 -0
- package/packages/gatsaeng-os/src/app/api/goals/route.ts +30 -0
- package/packages/gatsaeng-os/src/app/api/logs/energy/route.ts +40 -0
- package/packages/gatsaeng-os/src/app/api/logs/focus/route.ts +22 -0
- package/packages/gatsaeng-os/src/app/api/logs/routine/route.ts +54 -0
- package/packages/gatsaeng-os/src/app/api/milestones/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/milestones/route.ts +47 -0
- package/packages/gatsaeng-os/src/app/api/notes/[id]/route.ts +29 -0
- package/packages/gatsaeng-os/src/app/api/notes/route.ts +37 -0
- package/packages/gatsaeng-os/src/app/api/profile/route.ts +17 -0
- package/packages/gatsaeng-os/src/app/api/projects/[id]/route.ts +27 -0
- package/packages/gatsaeng-os/src/app/api/projects/route.ts +25 -0
- package/packages/gatsaeng-os/src/app/api/reviews/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/reviews/route.ts +29 -0
- package/packages/gatsaeng-os/src/app/api/routines/[id]/route.ts +26 -0
- package/packages/gatsaeng-os/src/app/api/routines/route.ts +28 -0
- package/packages/gatsaeng-os/src/app/api/tasks/[id]/route.ts +28 -0
- package/packages/gatsaeng-os/src/app/api/tasks/route.ts +66 -0
- package/packages/gatsaeng-os/src/app/api/timing/current/route.ts +63 -0
- package/packages/gatsaeng-os/src/app/api/voice/chat/route.ts +50 -0
- package/packages/gatsaeng-os/src/app/api/voice/transcribe/route.ts +25 -0
- package/packages/gatsaeng-os/src/app/api/voice/tts/route.ts +36 -0
- package/packages/gatsaeng-os/src/app/error.tsx +30 -0
- package/packages/gatsaeng-os/src/app/favicon.ico +0 -0
- package/packages/gatsaeng-os/src/app/globals.css +208 -0
- package/packages/gatsaeng-os/src/app/layout.tsx +33 -0
- package/packages/gatsaeng-os/src/app/login/page.tsx +87 -0
- package/packages/gatsaeng-os/src/app/providers.tsx +27 -0
- package/packages/gatsaeng-os/src/components/ErrorBoundary.tsx +46 -0
- package/packages/gatsaeng-os/src/components/dashboard/DashboardGrid.tsx +86 -0
- package/packages/gatsaeng-os/src/components/dashboard/DdayWidget.tsx +88 -0
- package/packages/gatsaeng-os/src/components/dashboard/EnergyTracker.tsx +87 -0
- package/packages/gatsaeng-os/src/components/dashboard/FocusTimer.tsx +139 -0
- package/packages/gatsaeng-os/src/components/dashboard/GatsaengScore.tsx +30 -0
- package/packages/gatsaeng-os/src/components/dashboard/GoalRings.tsx +107 -0
- package/packages/gatsaeng-os/src/components/dashboard/ProactiveBar.tsx +98 -0
- package/packages/gatsaeng-os/src/components/dashboard/RoutineChecklist.tsx +81 -0
- package/packages/gatsaeng-os/src/components/dashboard/TimingWidget.tsx +86 -0
- package/packages/gatsaeng-os/src/components/dashboard/WidgetCustomizer.tsx +95 -0
- package/packages/gatsaeng-os/src/components/dashboard/WidgetWrapper.tsx +33 -0
- package/packages/gatsaeng-os/src/components/dashboard/ZeigarnikPanel.tsx +43 -0
- package/packages/gatsaeng-os/src/components/editor/EditorToolbar.tsx +186 -0
- package/packages/gatsaeng-os/src/components/editor/TiptapEditor.tsx +114 -0
- package/packages/gatsaeng-os/src/components/layout/Header.tsx +47 -0
- package/packages/gatsaeng-os/src/components/layout/MobileBottomNav.tsx +122 -0
- package/packages/gatsaeng-os/src/components/layout/MobileSidebar.tsx +29 -0
- package/packages/gatsaeng-os/src/components/layout/Sidebar.tsx +142 -0
- package/packages/gatsaeng-os/src/components/onboarding/OnboardingFlow.tsx +229 -0
- package/packages/gatsaeng-os/src/components/onboarding/OnboardingGate.tsx +78 -0
- package/packages/gatsaeng-os/src/components/projects/CalendarView.tsx +152 -0
- package/packages/gatsaeng-os/src/components/projects/KanbanView.tsx +180 -0
- package/packages/gatsaeng-os/src/components/projects/ListView.tsx +82 -0
- package/packages/gatsaeng-os/src/components/projects/TableView.tsx +206 -0
- package/packages/gatsaeng-os/src/components/projects/TaskCard.tsx +154 -0
- package/packages/gatsaeng-os/src/components/projects/TaskForm.tsx +128 -0
- package/packages/gatsaeng-os/src/components/projects/ViewSwitcher.tsx +40 -0
- package/packages/gatsaeng-os/src/components/search/GlobalSearch.tsx +179 -0
- package/packages/gatsaeng-os/src/components/shared/InlineEdit.tsx +77 -0
- package/packages/gatsaeng-os/src/components/shared/PinButton.tsx +42 -0
- package/packages/gatsaeng-os/src/components/tasks/DDayBadge.tsx +34 -0
- package/packages/gatsaeng-os/src/components/ui/badge.tsx +48 -0
- package/packages/gatsaeng-os/src/components/ui/button.tsx +64 -0
- package/packages/gatsaeng-os/src/components/ui/card.tsx +92 -0
- package/packages/gatsaeng-os/src/components/ui/checkbox.tsx +32 -0
- package/packages/gatsaeng-os/src/components/ui/command.tsx +184 -0
- package/packages/gatsaeng-os/src/components/ui/dialog.tsx +158 -0
- package/packages/gatsaeng-os/src/components/ui/input.tsx +21 -0
- package/packages/gatsaeng-os/src/components/ui/label.tsx +24 -0
- package/packages/gatsaeng-os/src/components/ui/popover.tsx +89 -0
- package/packages/gatsaeng-os/src/components/ui/progress.tsx +31 -0
- package/packages/gatsaeng-os/src/components/ui/select.tsx +190 -0
- package/packages/gatsaeng-os/src/components/ui/sheet.tsx +143 -0
- package/packages/gatsaeng-os/src/components/ui/tabs.tsx +91 -0
- package/packages/gatsaeng-os/src/components/ui/toggle-group.tsx +83 -0
- package/packages/gatsaeng-os/src/components/ui/toggle.tsx +47 -0
- package/packages/gatsaeng-os/src/components/ui/tooltip.tsx +57 -0
- package/packages/gatsaeng-os/src/hooks/useAreas.ts +53 -0
- package/packages/gatsaeng-os/src/hooks/useBooks.ts +62 -0
- package/packages/gatsaeng-os/src/hooks/useCalendar.ts +59 -0
- package/packages/gatsaeng-os/src/hooks/useDaily.ts +15 -0
- package/packages/gatsaeng-os/src/hooks/useGlobalTasks.ts +45 -0
- package/packages/gatsaeng-os/src/hooks/useGoals.ts +53 -0
- package/packages/gatsaeng-os/src/hooks/useMilestones.ts +75 -0
- package/packages/gatsaeng-os/src/hooks/useNotes.ts +65 -0
- package/packages/gatsaeng-os/src/hooks/useProjects.ts +102 -0
- package/packages/gatsaeng-os/src/hooks/useRoutines.ts +76 -0
- package/packages/gatsaeng-os/src/hooks/useTiming.ts +27 -0
- package/packages/gatsaeng-os/src/lib/apiFetch.ts +14 -0
- package/packages/gatsaeng-os/src/lib/auth.ts +32 -0
- package/packages/gatsaeng-os/src/lib/date.ts +7 -0
- package/packages/gatsaeng-os/src/lib/editor/markdown.ts +35 -0
- package/packages/gatsaeng-os/src/lib/llm-governor.ts +167 -0
- package/packages/gatsaeng-os/src/lib/neuroscience/energyCycle.ts +35 -0
- package/packages/gatsaeng-os/src/lib/neuroscience/habitStack.ts +22 -0
- package/packages/gatsaeng-os/src/lib/neuroscience/scoring.ts +32 -0
- package/packages/gatsaeng-os/src/lib/routes.ts +15 -0
- package/packages/gatsaeng-os/src/lib/utils.ts +6 -0
- package/packages/gatsaeng-os/src/lib/vault/config.ts +29 -0
- package/packages/gatsaeng-os/src/lib/vault/frontmatter.ts +84 -0
- package/packages/gatsaeng-os/src/lib/vault/index.ts +180 -0
- package/packages/gatsaeng-os/src/lib/vault/schemas.ts +274 -0
- package/packages/gatsaeng-os/src/middleware.ts +34 -0
- package/packages/gatsaeng-os/src/stores/dashboardStore.ts +26 -0
- package/packages/gatsaeng-os/src/stores/favoritesStore.ts +47 -0
- package/packages/gatsaeng-os/src/stores/timerStore.ts +65 -0
- package/packages/gatsaeng-os/src/types/index.ts +320 -0
- package/packages/gatsaeng-os/tsconfig.json +34 -0
- package/templates/scripts/forge_qa.sh.tmpl +237 -0
- package/templates/scripts/forge_ship.sh.tmpl +183 -0
- package/templates/scripts/session_indexer.py.tmpl +420 -0
- package/templates/scripts/tracer.py.tmpl +266 -0
- package/templates/workspace/AGENTS.md.tmpl +190 -0
- package/templates/workspace/BOOTSTRAP.md.tmpl +27 -0
- package/templates/workspace/HEARTBEAT.md.tmpl +23 -0
- package/templates/workspace/MEMORY.md.tmpl +35 -0
- package/templates/workspace/SOUL.md.tmpl +258 -0
- package/templates/workspace/TOOLS.md.tmpl +28 -0
- package/templates/workspace/USER.md.tmpl +43 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { calendarEventSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { CalendarEvent } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const entity = await getEntity<CalendarEvent>('calendar', id, calendarEventSchema)
|
|
9
|
+
if (!entity) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json(entity.data)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await request.json()
|
|
16
|
+
const result = await updateEntity<CalendarEvent>('calendar', id, body)
|
|
17
|
+
return NextResponse.json(result)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
21
|
+
const { id } = await params
|
|
22
|
+
await deleteEntity('calendar', id)
|
|
23
|
+
return NextResponse.json({ ok: true })
|
|
24
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { createEntity, listEntities, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { calendarEventSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { CalendarEvent } from '@/types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* POST /api/calendar/import
|
|
8
|
+
* Bulk import calendar events (e.g., from Telegram weekly schedule).
|
|
9
|
+
*
|
|
10
|
+
* Body:
|
|
11
|
+
* {
|
|
12
|
+
* events: CalendarEvent[], // array of events to create
|
|
13
|
+
* clear_week?: boolean, // if true, delete existing events in the date range first
|
|
14
|
+
* week_start?: string, // YYYY-MM-DD, required if clear_week is true
|
|
15
|
+
* week_end?: string, // YYYY-MM-DD, required if clear_week is true
|
|
16
|
+
* created_by?: string // defaults to 'telegram'
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
export async function POST(request: Request) {
|
|
20
|
+
const body = await request.json()
|
|
21
|
+
const { events, clear_week, week_start, week_end, created_by = 'telegram' } = body
|
|
22
|
+
|
|
23
|
+
if (!events || !Array.isArray(events) || events.length === 0) {
|
|
24
|
+
return NextResponse.json({ error: 'events array is required' }, { status: 400 })
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Optionally clear existing events in the week range
|
|
28
|
+
if (clear_week && week_start && week_end) {
|
|
29
|
+
const existing = await listEntities<CalendarEvent>('calendar', calendarEventSchema)
|
|
30
|
+
const toDelete = existing
|
|
31
|
+
.map(e => e.data)
|
|
32
|
+
.filter(e => e.date >= week_start && e.date <= week_end && e.created_by === 'telegram')
|
|
33
|
+
|
|
34
|
+
for (const event of toDelete) {
|
|
35
|
+
await deleteEntity('calendar', event.id)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Create new events
|
|
40
|
+
const created = []
|
|
41
|
+
for (const event of events) {
|
|
42
|
+
const data = {
|
|
43
|
+
...event,
|
|
44
|
+
created_by: event.created_by || created_by,
|
|
45
|
+
created_at: event.created_at || new Date().toISOString(),
|
|
46
|
+
}
|
|
47
|
+
const result = await createEntity<CalendarEvent>('calendar', data)
|
|
48
|
+
created.push(result)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return NextResponse.json({ imported: created.length, events: created }, { status: 201 })
|
|
52
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { calendarEventSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { CalendarEvent } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(request: NextRequest) {
|
|
7
|
+
const { searchParams } = new URL(request.url)
|
|
8
|
+
const weekStart = searchParams.get('week_start')
|
|
9
|
+
const weekEnd = searchParams.get('week_end')
|
|
10
|
+
const date = searchParams.get('date')
|
|
11
|
+
|
|
12
|
+
const events = await listEntities<CalendarEvent>('calendar', calendarEventSchema)
|
|
13
|
+
let filtered = events.map(e => e.data)
|
|
14
|
+
|
|
15
|
+
if (date) {
|
|
16
|
+
filtered = filtered.filter(e => e.date === date)
|
|
17
|
+
} else if (weekStart && weekEnd) {
|
|
18
|
+
filtered = filtered.filter(e => e.date >= weekStart && e.date <= weekEnd)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
filtered.sort((a, b) => {
|
|
22
|
+
if (a.date !== b.date) return a.date.localeCompare(b.date)
|
|
23
|
+
return (a.time_start ?? '00:00').localeCompare(b.time_start ?? '00:00')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return NextResponse.json(filtered)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function POST(request: Request) {
|
|
30
|
+
const body = await request.json()
|
|
31
|
+
const data = {
|
|
32
|
+
...body,
|
|
33
|
+
created_at: body.created_at || new Date().toISOString(),
|
|
34
|
+
}
|
|
35
|
+
const result = await createEntity<CalendarEvent>('calendar', data)
|
|
36
|
+
return NextResponse.json(result, { status: 201 })
|
|
37
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntityByDate, createDateEntity, updateDateEntity } from '@/lib/vault'
|
|
3
|
+
import { dailyManifestSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { DailyManifest } from '@/types'
|
|
5
|
+
import { format } from 'date-fns'
|
|
6
|
+
|
|
7
|
+
export async function GET(req: Request) {
|
|
8
|
+
const { searchParams } = new URL(req.url)
|
|
9
|
+
const date = searchParams.get('date') || format(new Date(), 'yyyy-MM-dd')
|
|
10
|
+
|
|
11
|
+
const item = await getEntityByDate<DailyManifest>('tasks', date, dailyManifestSchema)
|
|
12
|
+
|
|
13
|
+
if (!item) {
|
|
14
|
+
// return empty manifest for today
|
|
15
|
+
const empty: DailyManifest = {
|
|
16
|
+
date,
|
|
17
|
+
gatsaeng_score: 0,
|
|
18
|
+
routines_done: 0,
|
|
19
|
+
routines_total: 0,
|
|
20
|
+
focus_minutes: 0,
|
|
21
|
+
}
|
|
22
|
+
return NextResponse.json(empty)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return NextResponse.json(item.data)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function POST(req: Request) {
|
|
29
|
+
const body = await req.json()
|
|
30
|
+
const date = body.date || format(new Date(), 'yyyy-MM-dd')
|
|
31
|
+
|
|
32
|
+
const existing = await getEntityByDate<DailyManifest>('tasks', date)
|
|
33
|
+
|
|
34
|
+
if (existing) {
|
|
35
|
+
// update
|
|
36
|
+
const merged = { ...existing.data, ...body, date }
|
|
37
|
+
const updated = await updateDateEntity<DailyManifest>('tasks', date, merged)
|
|
38
|
+
return NextResponse.json(updated)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// create
|
|
42
|
+
const data: DailyManifest = {
|
|
43
|
+
date,
|
|
44
|
+
gatsaeng_score: body.gatsaeng_score ?? 0,
|
|
45
|
+
routines_done: body.routines_done ?? 0,
|
|
46
|
+
routines_total: body.routines_total ?? 0,
|
|
47
|
+
focus_minutes: body.focus_minutes ?? 0,
|
|
48
|
+
}
|
|
49
|
+
const created = await createDateEntity<DailyManifest>('tasks', date, data)
|
|
50
|
+
return NextResponse.json(created, { status: 201 })
|
|
51
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { goalSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Goal } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const result = await getEntity<Goal>('goals', id, goalSchema)
|
|
9
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json({ ...result.data, _content: result.content })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await request.json()
|
|
16
|
+
const updates = { ...body, updated_at: new Date().toISOString() }
|
|
17
|
+
|
|
18
|
+
const sections: string[] = []
|
|
19
|
+
if (body.why_statement) sections.push(`## Why Statement\n${body.why_statement}`)
|
|
20
|
+
if (body.identity_statement) sections.push(`## Identity Statement\n${body.identity_statement}`)
|
|
21
|
+
if (body.when_where_how) sections.push(`## Implementation Intention\n${body.when_where_how}`)
|
|
22
|
+
const mdBody = sections.length > 0 ? sections.join('\n\n') : undefined
|
|
23
|
+
|
|
24
|
+
const result = await updateEntity<Goal>('goals', id, updates, mdBody)
|
|
25
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
26
|
+
return NextResponse.json(result)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
30
|
+
const { id } = await params
|
|
31
|
+
const deleted = await deleteEntity('goals', id)
|
|
32
|
+
if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
33
|
+
return NextResponse.json({ success: true })
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { goalSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Goal } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const results = await listEntities<Goal>('goals', goalSchema)
|
|
8
|
+
return NextResponse.json(results.map(r => ({ ...r.data, _content: r.content })))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function POST(request: Request) {
|
|
12
|
+
const body = await request.json()
|
|
13
|
+
const now = new Date().toISOString()
|
|
14
|
+
const data = {
|
|
15
|
+
...body,
|
|
16
|
+
current_value: body.current_value ?? 0,
|
|
17
|
+
color: body.color ?? '#f5a623',
|
|
18
|
+
status: body.status ?? 'active',
|
|
19
|
+
created_at: now,
|
|
20
|
+
updated_at: now,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const sections: string[] = []
|
|
24
|
+
if (body.why_statement) sections.push(`## Why Statement\n${body.why_statement}`)
|
|
25
|
+
if (body.identity_statement) sections.push(`## Identity Statement\n${body.identity_statement}`)
|
|
26
|
+
if (body.when_where_how) sections.push(`## Implementation Intention\n${body.when_where_how}`)
|
|
27
|
+
|
|
28
|
+
const entity = await createEntity<Goal>('goals', data, sections.join('\n\n'))
|
|
29
|
+
return NextResponse.json(entity, { status: 201 })
|
|
30
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntityByDate, createDateEntity, updateDateEntity } from '@/lib/vault'
|
|
3
|
+
import { energyLogSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { EnergyLog } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(request: Request) {
|
|
7
|
+
const { searchParams } = new URL(request.url)
|
|
8
|
+
const date = searchParams.get('date') || new Date().toISOString().split('T')[0]
|
|
9
|
+
|
|
10
|
+
const result = await getEntityByDate<EnergyLog>('energyLogs', date, energyLogSchema)
|
|
11
|
+
if (!result) return NextResponse.json({ date, entries: [] })
|
|
12
|
+
return NextResponse.json(result.data)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function POST(request: Request) {
|
|
16
|
+
const body = await request.json()
|
|
17
|
+
const date = body.date || new Date().toISOString().split('T')[0]
|
|
18
|
+
|
|
19
|
+
const existing = await getEntityByDate<EnergyLog>('energyLogs', date, energyLogSchema)
|
|
20
|
+
|
|
21
|
+
const entry = { hour: body.hour, level: body.level, note: body.note }
|
|
22
|
+
|
|
23
|
+
if (existing) {
|
|
24
|
+
const entries = [...existing.data.entries]
|
|
25
|
+
const idx = entries.findIndex(e => e.hour === body.hour)
|
|
26
|
+
if (idx >= 0) {
|
|
27
|
+
entries[idx] = entry
|
|
28
|
+
} else {
|
|
29
|
+
entries.push(entry)
|
|
30
|
+
}
|
|
31
|
+
entries.sort((a, b) => a.hour - b.hour)
|
|
32
|
+
|
|
33
|
+
const updated = await updateDateEntity<EnergyLog>('energyLogs', date, { date, entries })
|
|
34
|
+
return NextResponse.json(updated)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const log: EnergyLog = { date, entries: [entry] }
|
|
38
|
+
const created = await createDateEntity<EnergyLog>('energyLogs', date, log)
|
|
39
|
+
return NextResponse.json(created, { status: 201 })
|
|
40
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { focusSessionSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { FocusSession } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const results = await listEntities<FocusSession>('focusSessions', focusSessionSchema)
|
|
8
|
+
return NextResponse.json(results.map(r => r.data))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function POST(request: Request) {
|
|
12
|
+
const body = await request.json()
|
|
13
|
+
const data = {
|
|
14
|
+
...body,
|
|
15
|
+
session_type: body.session_type ?? 'pomodoro_25',
|
|
16
|
+
completed: body.completed ?? false,
|
|
17
|
+
started_at: body.started_at ?? new Date().toISOString(),
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const entity = await createEntity<FocusSession>('focusSessions', data)
|
|
21
|
+
return NextResponse.json(entity, { status: 201 })
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntityByDate, createDateEntity, updateDateEntity } from '@/lib/vault'
|
|
3
|
+
import { routineLogSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { RoutineLog } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(request: Request) {
|
|
7
|
+
const { searchParams } = new URL(request.url)
|
|
8
|
+
const date = searchParams.get('date') || new Date().toISOString().split('T')[0]
|
|
9
|
+
|
|
10
|
+
const result = await getEntityByDate<RoutineLog>('routineLogs', date, routineLogSchema)
|
|
11
|
+
if (!result) return NextResponse.json({ date, completions: [] })
|
|
12
|
+
return NextResponse.json(result.data)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function POST(request: Request) {
|
|
16
|
+
const body = await request.json()
|
|
17
|
+
const date = body.date || new Date().toISOString().split('T')[0]
|
|
18
|
+
|
|
19
|
+
const existing = await getEntityByDate<RoutineLog>('routineLogs', date, routineLogSchema)
|
|
20
|
+
|
|
21
|
+
if (existing) {
|
|
22
|
+
const completions = [...existing.data.completions]
|
|
23
|
+
const idx = completions.findIndex(c => c.routine_id === body.routine_id)
|
|
24
|
+
|
|
25
|
+
if (body.undo && idx >= 0) {
|
|
26
|
+
completions.splice(idx, 1)
|
|
27
|
+
} else if (!body.undo && idx < 0) {
|
|
28
|
+
completions.push({
|
|
29
|
+
routine_id: body.routine_id,
|
|
30
|
+
completed_at: new Date().toISOString(),
|
|
31
|
+
mood: body.mood,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const updated = await updateDateEntity<RoutineLog>('routineLogs', date, { date, completions })
|
|
36
|
+
return NextResponse.json(updated)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (body.undo) {
|
|
40
|
+
return NextResponse.json({ date, completions: [] })
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const log: RoutineLog = {
|
|
44
|
+
date,
|
|
45
|
+
completions: [{
|
|
46
|
+
routine_id: body.routine_id,
|
|
47
|
+
completed_at: new Date().toISOString(),
|
|
48
|
+
mood: body.mood,
|
|
49
|
+
}],
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const created = await createDateEntity<RoutineLog>('routineLogs', date, log)
|
|
53
|
+
return NextResponse.json(created, { status: 201 })
|
|
54
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { milestoneSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Milestone } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const item = await getEntity<Milestone>('milestones', id, milestoneSchema)
|
|
9
|
+
if (!item) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json(item.data)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await req.json()
|
|
16
|
+
const updated = await updateEntity<Milestone>('milestones', id, body)
|
|
17
|
+
if (!updated) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
18
|
+
return NextResponse.json(updated)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
22
|
+
const { id } = await params
|
|
23
|
+
const ok = await deleteEntity('milestones', id)
|
|
24
|
+
if (!ok) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
25
|
+
return NextResponse.json({ ok: true })
|
|
26
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { milestoneSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Milestone } from '@/types'
|
|
5
|
+
import { LIMITS } from '@/types'
|
|
6
|
+
|
|
7
|
+
export async function GET(req: Request) {
|
|
8
|
+
const { searchParams } = new URL(req.url)
|
|
9
|
+
const goalId = searchParams.get('goal_id')
|
|
10
|
+
|
|
11
|
+
const items = await listEntities<Milestone>('milestones', milestoneSchema)
|
|
12
|
+
let data = items.map(i => i.data)
|
|
13
|
+
|
|
14
|
+
if (goalId) {
|
|
15
|
+
data = data.filter(m => m.goal_id === goalId)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// sort by due_date
|
|
19
|
+
data.sort((a, b) => new Date(a.due_date).getTime() - new Date(b.due_date).getTime())
|
|
20
|
+
return NextResponse.json(data)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function POST(req: Request) {
|
|
24
|
+
const body = await req.json()
|
|
25
|
+
|
|
26
|
+
// constraint: max 4 milestones per goal
|
|
27
|
+
if (body.goal_id) {
|
|
28
|
+
const existing = await listEntities<Milestone>('milestones', milestoneSchema)
|
|
29
|
+
const goalMilestones = existing.filter(m => m.data.goal_id === body.goal_id && m.data.status === 'active')
|
|
30
|
+
if (goalMilestones.length >= LIMITS.MAX_MILESTONES_PER_GOAL) {
|
|
31
|
+
return NextResponse.json(
|
|
32
|
+
{ error: `목표당 마일스톤은 최대 ${LIMITS.MAX_MILESTONES_PER_GOAL}개입니다.` },
|
|
33
|
+
{ status: 400 }
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const now = new Date().toISOString()
|
|
39
|
+
const data = await createEntity<Milestone>('milestones', {
|
|
40
|
+
...body,
|
|
41
|
+
current_value: body.current_value ?? 0,
|
|
42
|
+
status: 'active',
|
|
43
|
+
created_by: body.created_by || 'user',
|
|
44
|
+
created: now,
|
|
45
|
+
}, body.body_content)
|
|
46
|
+
return NextResponse.json(data, { status: 201 })
|
|
47
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { noteSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Note } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const result = await getEntity<Note>('notes', id, noteSchema)
|
|
9
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json({ ...result.data, _content: result.content })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await request.json()
|
|
16
|
+
const result = await updateEntity<Note>('notes', id, {
|
|
17
|
+
...body,
|
|
18
|
+
updated_at: new Date().toISOString(),
|
|
19
|
+
}, body.content)
|
|
20
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
21
|
+
return NextResponse.json(result)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
25
|
+
const { id } = await params
|
|
26
|
+
const deleted = await deleteEntity('notes', id)
|
|
27
|
+
if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
28
|
+
return NextResponse.json({ success: true })
|
|
29
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { noteSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Note } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(request: Request) {
|
|
7
|
+
const { searchParams } = new URL(request.url)
|
|
8
|
+
const type = searchParams.get('type')
|
|
9
|
+
const areaId = searchParams.get('area_id')
|
|
10
|
+
|
|
11
|
+
const results = await listEntities<Note>('notes', noteSchema)
|
|
12
|
+
let notes = results.map(r => ({ ...r.data, _content: r.content }))
|
|
13
|
+
|
|
14
|
+
if (type) notes = notes.filter(n => n.type === type)
|
|
15
|
+
if (areaId) notes = notes.filter(n => n.area_id === areaId)
|
|
16
|
+
|
|
17
|
+
notes.sort((a, b) => a.priority - b.priority || b.created_at.localeCompare(a.created_at))
|
|
18
|
+
|
|
19
|
+
return NextResponse.json(notes)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function POST(request: Request) {
|
|
23
|
+
const body = await request.json()
|
|
24
|
+
const now = new Date().toISOString()
|
|
25
|
+
const note = await createEntity<Note>('notes', {
|
|
26
|
+
title: body.title,
|
|
27
|
+
type: body.type || 'note',
|
|
28
|
+
priority: body.priority || 2,
|
|
29
|
+
area_id: body.area_id,
|
|
30
|
+
project_id: body.project_id,
|
|
31
|
+
url: body.url,
|
|
32
|
+
created_at: now,
|
|
33
|
+
updated_at: now,
|
|
34
|
+
}, body.content)
|
|
35
|
+
|
|
36
|
+
return NextResponse.json(note, { status: 201 })
|
|
37
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getProfile, updateProfile } from '@/lib/vault'
|
|
3
|
+
import { profileSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Profile } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
// Return full profile without schema filtering (allows saju_motto etc.)
|
|
8
|
+
const result = await getProfile()
|
|
9
|
+
return NextResponse.json(result.data)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function PUT(request: Request) {
|
|
13
|
+
const body = await request.json()
|
|
14
|
+
const updates = { ...body, updated_at: new Date().toISOString() }
|
|
15
|
+
const result = await updateProfile<Profile>(updates)
|
|
16
|
+
return NextResponse.json(result)
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { projectSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Project } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const result = await getEntity<Project>('projects', id, projectSchema)
|
|
9
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json(result.data)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await request.json()
|
|
16
|
+
const updates = { ...body, updated_at: new Date().toISOString() }
|
|
17
|
+
const result = await updateEntity<Project>('projects', id, updates)
|
|
18
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
19
|
+
return NextResponse.json(result)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
23
|
+
const { id } = await params
|
|
24
|
+
const deleted = await deleteEntity('projects', id)
|
|
25
|
+
if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
26
|
+
return NextResponse.json({ success: true })
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { projectSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Project } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const results = await listEntities<Project>('projects', projectSchema)
|
|
8
|
+
return NextResponse.json(results.map(r => r.data))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function POST(request: Request) {
|
|
12
|
+
const body = await request.json()
|
|
13
|
+
const now = new Date().toISOString()
|
|
14
|
+
const data = {
|
|
15
|
+
...body,
|
|
16
|
+
status: body.status ?? 'active',
|
|
17
|
+
color: body.color ?? '#7c5cbf',
|
|
18
|
+
default_view: body.default_view ?? 'kanban',
|
|
19
|
+
created_at: now,
|
|
20
|
+
updated_at: now,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const entity = await createEntity<Project>('projects', data)
|
|
24
|
+
return NextResponse.json(entity, { status: 201 })
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { reviewSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Review } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const result = await getEntity<Review>('reviews', id, reviewSchema)
|
|
9
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json({ ...result.data, _content: result.content })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await request.json()
|
|
16
|
+
const result = await updateEntity<Review>('reviews', id, body)
|
|
17
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
18
|
+
return NextResponse.json(result)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
22
|
+
const { id } = await params
|
|
23
|
+
const deleted = await deleteEntity('reviews', id)
|
|
24
|
+
if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
25
|
+
return NextResponse.json({ success: true })
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEntities, createEntity } from '@/lib/vault'
|
|
3
|
+
import { reviewSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Review } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const results = await listEntities<Review>('reviews', reviewSchema)
|
|
8
|
+
return NextResponse.json(results.map(r => r.data))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function POST(request: Request) {
|
|
12
|
+
const body = await request.json()
|
|
13
|
+
const now = new Date().toISOString()
|
|
14
|
+
const data = {
|
|
15
|
+
...body,
|
|
16
|
+
created_at: now,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sections: string[] = []
|
|
20
|
+
if (body.accomplished) sections.push(`## 이번 주 가장 잘한 것\n${body.accomplished}`)
|
|
21
|
+
if (body.struggled) sections.push(`## 어디서 막혔는가\n${body.struggled}`)
|
|
22
|
+
if (body.learnings) sections.push(`## 배운 점\n${body.learnings}`)
|
|
23
|
+
if (body.next_week_focus) sections.push(`## 다음 주 포커스\n${body.next_week_focus}`)
|
|
24
|
+
if (body.energy_pattern) sections.push(`## 에너지 패턴\n${body.energy_pattern}`)
|
|
25
|
+
if (body.habit_insight) sections.push(`## 루틴 인사이트\n${body.habit_insight}`)
|
|
26
|
+
|
|
27
|
+
const entity = await createEntity<Review>('reviews', data, sections.join('\n\n'))
|
|
28
|
+
return NextResponse.json(entity, { status: 201 })
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getEntity, updateEntity, deleteEntity } from '@/lib/vault'
|
|
3
|
+
import { routineSchema } from '@/lib/vault/schemas'
|
|
4
|
+
import type { Routine } from '@/types'
|
|
5
|
+
|
|
6
|
+
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
|
+
const { id } = await params
|
|
8
|
+
const result = await getEntity<Routine>('routines', id, routineSchema)
|
|
9
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
10
|
+
return NextResponse.json(result.data)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
14
|
+
const { id } = await params
|
|
15
|
+
const body = await request.json()
|
|
16
|
+
const result = await updateEntity<Routine>('routines', id, body)
|
|
17
|
+
if (!result) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
18
|
+
return NextResponse.json(result)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
22
|
+
const { id } = await params
|
|
23
|
+
const deleted = await deleteEntity('routines', id)
|
|
24
|
+
if (!deleted) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
25
|
+
return NextResponse.json({ success: true })
|
|
26
|
+
}
|