Files
miaojingAI/docs/codex-miaojing/bug-location-guide.md
2026-06-07 11:59:51 +08:00

65 KiB
Raw Blame History

Bug Location Guide

Last source audit: 2026-05-12, based on git commit 8ee86a9.

Use this guide when the user reports behavior. Start from the symptom row, inspect the listed files, then verify with the current runtime.

First Five Checks

  1. Confirm whether the bug is frontend-only, API-only, persistence, generation worker, or deployment/runtime.
  2. Read the task row below and open the smallest likely file set.
  3. Search for the exact UI text, endpoint path, DB table, or log prefix with rg.
  4. Check auth state and request payload before changing business logic.
  5. After a fix, run the narrowest useful verification first, then pnpm run ts-check and pnpm run build when source changes affect TypeScript/runtime.

Auth, Login, Profile

Symptom Check Files What To Verify
User cannot log in src/app/auth/login/page.tsx, src/lib/auth-store.ts, src/app/api/auth/login/route.ts, src/lib/session-auth.ts Request body fields (account, email, phone, password), password hash verification, bearer token storage, inactive profile.
Admin console opens without login or redirects incorrectly src/app/console/page.tsx, src/modules/console/pages/console-login-page.tsx, src/modules/console/pages/console-dashboard-page.tsx, src/app/api/auth/login/route.ts adminOnly behavior, admin role check, route redirect logic.
Registration fails or registration verification email arrives blank src/app/auth/register/page.tsx, src/app/api/auth/register/route.ts, src/app/api/email/send-register-code/route.ts, src/lib/email-service.ts acceptedTerms, email code, password strength, invite code, duplicate profile, SMTP settings, send logs, and MIME body encoding. Verification emails use HTML plus plain-text multipart content; base64 bodies must be folded to 76-character lines and multipart blank separators must be preserved. Do not use .filter(Boolean) on MIME message arrays because it removes required empty separator lines and can make mailbox clients render a blank email despite SMTP accepting it.
Profile changes disappear after refresh src/app/profile/page.tsx, src/app/api/profile/route.ts, src/lib/auth-store.ts PUT writes both profiles and auth.users where needed; client refreshes returned profile.
Navbar or gallery shows login username instead of public nickname src/lib/auth-store.ts, src/app/api/profile/route.ts, src/app/api/gallery/route.ts, src/lib/user-profile-defaults.ts profiles.nickname is login username; public UI should use returned nickname from profiles.display_nickname. Gallery SQL should select display_nickname first.
Navbar user avatar is missing and only shows an initial src/components/navbar.tsx, src/lib/auth-store.ts, src/app/api/profile/route.ts The navbar user button should read AuthUser.avatarUrl; confirm /api/profile or login returns avatar_url, parseApiUser maps it, and UserAvatar only falls back to initials after image load failure.
Existing users have blank/default avatar after display-profile migration src/lib/user-profile-defaults.ts, scripts/backfill-user-display-profile.mjs, src/app/api/auth/login/route.ts Run the backfill script with LOCAL_DB_URL; login also lazily fills missing avatar_url with a generated SVG data URL.
Theme does not persist src/components/account-theme-sync.tsx, src/app/api/profile/theme/route.ts, src/lib/profile-preferences.ts preferred_theme schema, token auth, theme normalization.
Symptom Check Files What To Verify
Footer content missing or not Markdown-rendered src/components/site-footer.tsx, src/components/site-policy-page.tsx, src/lib/site-config.ts, src/app/api/site-config/route.ts Config response fields, Markdown renderer, fallback defaults, PUT persistence.
Policy pages start mid-page after navigation src/components/site-policy-page.tsx, src/app/about/page.tsx, src/app/terms/page.tsx, src/app/privacy/page.tsx, src/app/help/page.tsx Scroll reset behavior and shared policy page wrapper.
Site name/logo/favicon not updating src/components/site-config-sync.tsx, src/components/site-brand.tsx, src/app/api/site-config/route.ts, src/lib/local-storage.ts site_config row, base64 image save, generated /api/local-storage/* URL.
Clicking navbar between home/create/gallery/profile feels slow while server-side route TTFB is normal src/lib/site-config.ts, src/app/api/site-config/route.ts, src/components/navbar.tsx, src/components/site-brand.tsx, src/components/site-footer.tsx, src/app/page.tsx, src/app/create/page.tsx, src/components/create/*, src/lib/creation-history-store.ts, src/app/api/creation-history/route.ts, src/app/profile/page.tsx, src/components/visit-tracker.tsx Compare production local route timings with real browser navigation and check OpenResty access logs for large competing API responses. If pages and /api/site-config are fast on the server but browser clicks still feel delayed, check whether multiple useSiteConfig() consumers are issuing duplicate concurrent config requests, and confirm the shared snapshot, 5-minute fresh-cache network skip, and in-flight request dedupe in src/lib/site-config.ts are present. Also confirm /api/site-config is not running schema/default compatibility DDL on every GET; it should cache that check once per server process and retry only after failure. Then verify Navbar is not doing eager all-route router.prefetch(...), VisitTracker defers /api/site-stats, /create does not put the five primary creation panels behind ssr:false dynamic chunks, and the create panels call useCreationHistory({ mode, limit }) instead of pulling full /api/creation-history responses. A production smell is repeated /api/creation-history responses of many MB from /create; those requests compete with visible navigation and image loading and should be scoped by mode/limit plus deduped in src/lib/creation-history-store.ts. /profile should not mount creation-history, credit-record, or order stores from the parent page. Home is naturally heavier than other public routes because its prerendered HTML/RSC is larger. Run node --no-warnings ./scripts/test-navigation-performance-policy.mjs after changing this area.
Console reports CSP blocking https://fonts.googleapis.cn/... src/app/globals.css, src/proxy.ts globals.css imports Noto Serif SC from fonts.googleapis.cn; CSP must allow that stylesheet domain in style-src and the matching font CDN in font-src.
Page content leaves large unused horizontal margins, or wide screens look like the UI was simply enlarged src/components/app-shell.tsx, src/components/navbar.tsx, src/components/site-footer.tsx, page-level wrappers under src/app/*/page.tsx, src/components/site-policy-page.tsx The viewport/background can be w-full, but product content should keep the original component scale and readable containers such as max-w-7xl, max-w-4xl, or max-w-3xl. Do not fix this by removing all max widths or scaling controls up on wide monitors.
Scrollbars look native, stay visible when idle, or do not match glass UI in dialogs/pages src/app/globals.css, src/components/app-shell.tsx Global scrollbar styling is hidden by default and becomes visible only while wheel/touch scrolling through the scrollbars-visible class on <html>. globals.css owns both the hidden state and the rounded glass visible state for light/dark themes; app-shell owns the short-lived wheel/touch listener. Avoid adding one-off scrollbar styles to individual components unless there is a real exception.
Announcement not popping up src/components/announcement-popup.tsx, src/app/api/announcements/route.ts, src/components/app-shell.tsx App shell includes popup, active date range, local/session dismissal behavior, GET payload shape.
Announcement admin edit fails src/components/admin/announcement-tab.tsx, src/app/api/announcements/route.ts Admin token, required fields, starts_at/expires_at compatibility.
Third-party platform iframe shows miaojing.toplee.cn refused to connect src/proxy.ts, .env.example, reverse-proxy response headers Check Content-Security-Policy frame-ancestors and X-Frame-Options. External iframe embedding requires the parent origin in MIAOJING_FRAME_ANCESTORS or the default mozheAPI allowlist, and X-Frame-Options must not be sent when third-party ancestors are allowed. Also verify the outer nginx/CDN is not adding its own stricter frame headers.

Creation And Generation

Symptom Check Files What To Verify
Create button does nothing src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx, src/lib/generation-job-client.ts Client validation, auth token, /api/generation-jobs POST response, UI disabled/loading state.
Refreshing /create resets to the wrong creation tab src/app/create/page.tsx Active tab should persist in miaojing:create-active-tab and mirror to /create?type=.... Verify all creation tabs (text2img, img2img, text2video, img2video, reversePrompt) restore after refresh and query-param links still override storage.
手机端创作提示词输入框没有固定在底部,或固定后遮住提示词/参考图/任务状态 src/components/create/mobile-creation-composer.tsx, src/app/globals.css, src/components/navbar.tsx, scripts/test-mobile-create-ui-policy.mjs Mobile composer should be position: fixed and should use ResizeObserver to publish --create-mobile-composer-height to .create-chat-layout; .create-chat-thread must reserve that measured height through padding-bottom. The mobile bottom nav must be rendered outside the sticky header, because a sticky/backdrop-filter header can trap fixed children and make the nav appear near the top instead of the viewport bottom. Run node --no-warnings ./scripts/test-mobile-create-ui-policy.mjs and verify a mobile viewport such as 390x844.
Create button is disabled while another task is still running, or active job cards overflow horizontally src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx, src/components/create/generation-task-list.tsx Create panels should keep submit enabled whenever models are available so users can start a different task while previous tasks run. Identical in-flight submissions are still blocked by activeSubmissionSignaturesRef. Active job cards should render inside the results column with wrapping vertical growth, not outside the result area.
User cannot cancel a queued/running generation task, or a cancelled task still writes history src/components/create/generation-task-list.tsx, src/lib/generation-job-client.ts, src/app/api/generation-jobs/[id]/route.ts, src/lib/generation-job-worker.ts, create panel component Task cards should pass onCancelTask, the client should call cancelGenerationJob, and PATCH /api/generation-jobs/[id] should set status='cancelled'. The worker must check the job is still running before charging credits, persisting history, or updating success/failure so late upstream responses do not resurrect cancelled jobs.
Earlier completed image tasks disappear while later tasks are still running src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/generation-task-list.tsx The results column must not be a single generating ? taskList : results branch. Render active task cards and completed result cards together, and append each task's images as soon as that task succeeds instead of waiting for all submitted tasks to settle.
One submitted generation shows two running cards, or current results show the same media twice while refreshed history has one row src/app/api/generation-jobs/route.ts, src/components/create/use-generation-job-recovery.ts, src/components/create/generation-task-list.tsx, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx Check production generation_jobs first. If there are two queued/running jobs whose payload only differs by clientRequestId, inspect the API semantic dedupe query and each create panel's activeSubmissionSignaturesRef. If there is only one job and one result URL, the duplicate is frontend recovery state, not backend creation. Locally submitted tasks use temporary ids before the server job id is known; recovery must treat both jobId and payload.clientRequestId as the same task identity, and result appenders should filter duplicate URLs so a recovery poll cannot add the same completed media twice.
Job remains queued src/app/api/generation-jobs/route.ts, src/lib/generation-job-worker.ts, src/lib/generation-job-runner.ts processNextGenerationJob() invoked, stale job handling, DB locks/status, internal base URL.
Job remains running forever src/app/api/generation-jobs/[id]/route.ts, src/lib/generation-job-worker.ts, src/lib/generation-job-estimates.ts Stale timeout updates, updated_at, worker exceptions swallowed into error field.
Image generation returns upstream error src/app/api/generate/image/route.ts, src/lib/custom-api-fetch.ts, src/lib/custom-image-fallback.ts, src/lib/server-api-config.ts Resolved custom/system API credentials, endpoint URL, New API normalization, timeout, stream/progress parser, and system-default stream timeout fallback. Gateway 502/503/504 errors are retried once; system default model failures should return the last actionable upstream timeout/gateway message instead of hiding everything behind the generic busy message.
One submitted image task shows extra images, or the same generated URL appears twice in history src/app/api/generate/image/route.ts, src/app/api/creation-history/route.ts, src/lib/generation-job-worker.ts, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx First check production API logs for count:1 with upstream messages such as Got 2 images, then query generation_jobs.result.images and works grouped by user_id,result_url. The image route should cap persisted response images to the requested count because some upstream/custom providers can return more images than n; creation-history POST should serialize same-user same-URL inserts before the existing lookup so concurrent completion/local persistence cannot insert duplicate works rows.
User selects JPEG/WebP but the returned generated image is PNG src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/lightbox.tsx, src/components/creation-detail-dialog.tsx, src/app/gallery/page.tsx, src/app/api/generation-jobs/route.ts, src/app/api/generate/image/route.ts, src/lib/media-storage.ts, src/lib/utils.ts First check PM2 logs for [Image Generation] Params and upstream request logs to confirm outputFormat/output_format reached the server/provider. Then query works.params->>'outputFormat' with result_url and inspect the object-storage response Content-Type/file magic for a recent key. Some providers may ignore output_format and still return PNG, so generated-image persistence must normalize the downloaded bytes to the selected format before persistOriginalImageWithThumbnail(...) uploads the object and writes history. If the object headers/magic bytes are already JPEG/WebP but the downloaded file still appears as PNG, check frontend downloadFile(...) callers and ensure filenames use getImageDownloadExtension(...) instead of a hard-coded .png.
Admin enables 100 Layout Compositions but generated images ignore composition guidance, or prompts show unwanted text/logo/poster layout src/components/admin/settings-tab.tsx, src/app/api/site-config/route.ts, src/lib/site-config.ts, src/lib/layout-composition-skill.ts, src/app/api/generate/image/route.ts Verify /api/site-config returns imageCompositionSkillEnabled: true and site_config.image_composition_skill_enabled exists. The image route should call applyLayoutCompositionSkillToPrompt(...) after buildReferenceImagePrompt(...) and before mergeStylePrompt(...). The skill should append composition-only instructions referencing nevertoday/100-layout-compositions CC BY 4.0, but it must explicitly say not to add text, logos, brand marks, or literal poster elements.
Video generation returns upstream error src/app/api/generate/video/route.ts, src/lib/custom-api-fetch.ts, src/lib/server-api-config.ts Reference image upload/compression, endpoint URL, response parser, persistence timeout.
Wrong image size, aspect ratio, or custom API says returned resolution is lower than requested src/lib/model-config.ts, src/app/api/generate/image/route.ts resolveImageSize, resolveCustomApiImageSize, New API/DALL-E size normalization, prompt aspect hint, and custom API result qualification. Exact or larger generated images pass normally; lower-resolution images with matching aspect ratio and at least 60% of the requested dimensions are accepted as degraded upstream output instead of failing the job, while wrong-ratio or much smaller images are still rejected.
Text-to-image or image-to-image says 请在提示词中写明画面比例 even after selecting a Yuanjie resolution such as 4K 竖版 (3:4) src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/lib/yuanjie-image-model-templates.ts Some Yuanjie image templates set supportsAspectRatio: false and encode orientation in resolution/size options. Generation validation must derive the ratio from the selected resolution label or dimensions instead of requiring a separate aspect-ratio control. Image-to-image should also default count to 1 rather than requiring prompt inference for 生成数量.
Reference image upload too large or fails src/components/create/image-to-image.tsx, src/components/create/image-to-video.tsx, src/lib/browser-image-compression.ts, src/lib/server-image-compression.ts, src/app/api/generate/image/route.ts, src/app/api/generate/video/route.ts Browser compression, MAX_UPSTREAM_REFERENCE_IMAGE_BYTES, data URL conversion. Uploaded reference thumbnails should single-click into the no-container BareImagePreview; blank area closes it.
图生图/图生视频参考图或创作历史详情参考图加载慢,或详情不显示参考图 src/components/create/image-to-image.tsx, src/components/create/image-to-video.tsx, src/components/reference-preview-image.tsx, src/components/creation-detail-dialog.tsx, src/app/api/creation-history/route.ts, src/lib/reference-image-storage.ts, src/lib/generation-job-worker.ts Upload/reference cards should render ReferencePreviewImage so large uploaded data URLs or remote URLs are downsampled for the card while click/fullscreen still uses the original. /api/creation-history should persist data URL or remote reference images into stable /api/local-storage/works/references/... URLs, write params.referenceImages and params.referenceImageThumbnails, and patch existing same-URL rows that were first inserted by the background worker without references. The generation worker must pass data URL reference inputs through to creation-history persistence instead of filtering them out before the server can store them. Creation detail should prefer referenceImageThumbnails[index] for the small grid and should not expose reference-image downloads.
Custom API image-to-image logs Failed to download reference image from URL, sends a 56-character /api/local-storage/... reference, or all URL-based strategies fail src/app/api/generate/image/route.ts, src/lib/local-storage.ts, src/lib/remote-fetch.ts Custom API img2img should read existing /api/local-storage/... references through localStorage.readFileAsync(...) for the FormData images/edits strategy instead of fetching back through public HTTP. When a data URL reference is uploaded for URL-based strategies, return localStorage.generateObjectReadUrl(...) when object storage is configured; only fall back to an absolute APP_BASE_URL + /api/local-storage/... URL, never a relative URL.
Generated result previews but does not persist src/app/api/generate/image/route.ts, src/app/api/generate/video/route.ts, src/lib/local-storage.ts, src/app/api/creation-history/route.ts Media copied through the storage adapter, stable /api/local-storage/<key> URL returned, history POST called. In object storage mode, verify STORAGE_MODE and OBJECT_STORAGE_* health.
Generated video is not in object storage or video download/share feels slow src/app/api/generate/video/route.ts, src/lib/local-storage.ts, src/app/api/download/route.ts, src/app/api/gallery/publish/route.ts, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx, src/app/gallery/page.tsx Video generation should persist remote/data video results via uploadFileObjectOnly(...) under generated/videos. /api/download should redirect object-backed /api/local-storage/* downloads to signed object URLs instead of buffering large videos, and video buttons should call triggerDownloadFile(...). Gallery publish should reuse object-backed video URLs rather than copying large videos again; missing video thumbnails should be local WEBP frame thumbnails generated through ffmpeg-static, falling back to local SVG only if frame extraction fails.
A single generated video appears twice in text-to-video or image-to-video history src/lib/creation-history-store.ts, src/app/api/creation-history/route.ts, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx The client creates an optimistic local history row, then the server returns a DB row with a different id. Local storage and /api/creation-history must de-duplicate by url/result_url, preserving only one visible record for the same generated video.
Image preview cards load slowly, look blurry in detail, or fetch full originals src/lib/media-storage.ts, src/lib/local-storage.ts, src/lib/gallery-publish-media.ts, src/app/api/local-storage/[...path]/route.ts, src/app/api/generate/image/route.ts, src/app/api/creation-history/route.ts, src/app/api/gallery/route.ts, src/app/api/gallery/publish/route.ts, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/profile/creation-history-tab.tsx, src/app/gallery/page.tsx New generated image originals should be object-only, while WEBP thumbnails should be local-only under thumbnails/.... Current thumbnails should have the m1280q86 suffix and come from the 1280px/Lanczos/sharpened profile. Cards and detail preview surfaces use `thumbnailUrl
Gallery shows 加载中... for seconds on every visit or loads too many images at once src/app/gallery/page.tsx, src/app/api/gallery/route.ts, src/lib/gallery-response.ts, src/lib/gallery-cache-policy.ts, src/app/api/local-storage/[...path]/route.ts, src/proxy.ts The page should show cached miaojing:gallery:v3 rows immediately when available, even when older than the short freshness TTL, then revalidate page 0 in the background. It should show the masonry skeleton instead of the old centered 加载中... when no cache exists, debounce search, request small limit/offset pages, and append more rows only through the scroll sentinel. Check /api/gallery response size with curl; generated default avatar data: URLs in publisherAvatarUrl can make every page hundreds of KB larger and can break localStorage caching, so public gallery serialization must filter data:/oversized avatars. Do not restore the old limit=300 full-gallery request. Thumbnail URLs under /api/local-storage/thumbnails/... should return long immutable cache headers so browser image cache is actually used; if curl still shows no-store, check src/proxy.ts because the global /api cache header can override the route response.
/api/health or page probes are slow after object migration src/app/api/health/route.ts, src/lib/local-storage.ts Health checks call getStorageHealthStatus(). Object bucket checks should be cached briefly and bounded with an abort timeout so a slow S3-compatible endpoint does not hold request threads for many seconds.
Logs repeatedly show must be owner of table ... on normal requests src/lib/generation-job-estimates.ts, src/lib/email-service.ts, src/lib/profile-preferences.ts, src/lib/user-profile-defaults.ts, src/lib/server-api-config.ts Optional runtime schema checks can hit 42501 when the production app user is not the table owner. Treat existing-schema 42501 as a one-time warning and cache the skip; apply real schema migrations through deployment/DB owner operations rather than request-time DDL.
Fullscreen/preview/download/right-click image actions broken src/components/fullscreen-preview.tsx, src/components/lightbox.tsx, src/components/creation-detail-dialog.tsx, src/components/image-actions-context-menu.tsx, src/components/image-metadata-badge.tsx, src/app/image-viewer/page.tsx, src/app/api/download/route.ts Dialog state, URL type, download proxy supports local/remote URL. Image result and history/detail previews should open on single click. Right-click copy, download, edit, and share actions must use the uncompressed original image URL, not a thumbnail, preview cache, or compressed reference blob. Fullscreen components should receive a thumbnail fallback so the preview appears immediately while the original object-storage image loads. Share links should open /image-viewer?url=... as a standalone original-image fullscreen page. Image result and history/detail previews should show upper-right actual aspect ratio and natural resolution via ImageMetadataBadge.
Gallery video detail says 下载图片, shows the generic play-card instead of a real thumbnail, or opens the original video too early src/app/gallery/page.tsx, src/app/api/gallery/route.ts, src/lib/media-storage.ts, src/app/api/gallery/publish/route.ts, package.json Use isVideoWork(...) for labels and filenames. Video cards/details should render thumbnailUrl first and mount the original <video> only after the user clicks play. If thumbnails are missing or still use video-svg-v1 or video-fallback-svg-v2, /api/gallery and publish should backfill local WEBP frame thumbnails under thumbnails/gallery/videos via ffmpeg-static; only video-frame-m1280q86-v1.webp is the current video thumbnail profile. SVG is only the fallback when extraction fails and must remain replaceable later. If PM2 logs show spawn /ROOT/node_modules/.../ffmpeg ENOENT, check src/lib/media-storage.ts runtime cwd fallback for ffmpeg-static; bundled route contexts can resolve the package from a synthetic path even though /opt/miaojingAI/node_modules/.../ffmpeg exists. If ffmpeg exits with code 139/unknown and no stderr for an object-backed video, verify the thumbnail path is streaming the object through localStorage.openFileStreamAsync(...) into a temporary local file before extraction, not passing a signed object URL directly to ffmpeg. If object-storage reads intermittently terminate mid-stream, src/lib/media-storage.ts should retry bounded temporary input writes before falling back to SVG.
Gallery or history detail logs/requests original generated URLs while preview should use thumbnails src/app/gallery/page.tsx, src/components/creation-detail-dialog.tsx, src/components/image-metadata-badge.tsx Check the actual <img> src and /api/gallery or /api/creation-history response first. The console line/request can be caused by metadata probing rather than the preview image. Gallery and history detail should pass stored width/height to ImageMetadataBadge and set loadMetadata={false} so the badge does not trigger an original-image request just to calculate dimensions.
Gallery shows many historical/imported works or thumbnail rules differ between all/category/search src/app/gallery/page.tsx, src/app/api/gallery/route.ts, src/lib/creation-history-store.ts The gallery page should render only /api/gallery rows, not merge browser localStorage published/history records and not call syncPublishedToSupabase() on load. /api/gallery should apply category/q filters server-side against public works with stable /api/local-storage/... result URLs so all, text-to-image, image-to-image, text-to-video, image-to-video, and search share the same thumbnail/original split.
Generated image preview zooms but cannot be dragged src/components/lightbox.tsx, src/components/fullscreen-preview.tsx Result-card previews use ImageLightbox; after zooming above 100%, panning should be bound to the whole preview stage as well as the image so mouse drag remains available even when the transformed image extends beyond its original element box. Keep wheel zoom, double-click zoom/reset, right-click actions, and ESC close intact.
Create page loads slowly and console shows CORS errors for historical coze-codingproject.tos.coze.site images src/components/create/cached-preview-image.tsx, src/components/create/text-to-image.tsx, src/app/api/download/route.ts Hidden mobile history must not mount desktop-side image effects, and cross-origin historical result images should render through the same-origin /api/download?disposition=inline proxy before canvas preview generation. Otherwise every hidden history image can issue a blocked browser request and slow the page.
Creation detail, gallery one-click reuse, or inspiration reuse buttons do not fill create forms or switch tabs src/components/creation-detail-dialog.tsx, src/app/gallery/page.tsx, src/components/create/inspiration-gallery-dialog.tsx, src/lib/creation-reuse.ts, src/app/create/page.tsx, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx Reuse actions should write the shared draft key/event for text2img, img2img, text2video, or img2video, route to the matching /create?type=... when leaving gallery, and already-mounted create panels should react to the event. Creation detail's 复用配置 must also support video history: text-to-video records write text2video, image-to-video records write img2video. Image-to-image and image-to-video reuse should include stored reference images from the work; when intentionally using the generated output as the new reference, fall back to the original output url, never thumbnailUrl.
Image generation count dropdown too wide, options missing, or manual count input unavailable src/components/create/image-count-combobox.tsx, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx Use the shared compact combobox instead of browser datalist; verify manual numeric entry and dropdown options in both text-to-image and image-to-image panels.
Generated image result hover actions are unreadable in light theme src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx The result-card hover overlay owns the Preview/Share/Download buttons. These buttons should use fixed dark translucent backgrounds and white text/icons so light and dark themes have the same readable hover action style.
Generated image is pushed down by a long prompt in the desktop result column src/components/create/text-to-image.tsx The result prompt above new images should be a compact two-line summary with the full prompt only in the title tooltip/history detail. Do not render the entire prompt as an unbounded paragraph in the live result column.
Style presets are hardcoded, missing, or not ordered by usage src/components/create/style-preset-selector.tsx, src/lib/style-presets-client.ts, src/app/api/style-presets/route.ts, src/lib/style-preset-store.ts, src/app/api/generation-jobs/route.ts Presets should come from image_style_presets; generation-jobs increments usage_count; GET /api/style-presets should return active presets sorted by usage count.
Reverse prompt option missing src/components/create/reverse-prompt-panel.tsx, src/app/api/generate/reverse-prompt/route.ts UI option list and server outputMode handling both updated, app rebuilt/restarted if deployed.
Reverse prompt says 请先登录后再使用自定义 API while the user is already logged in src/components/create/reverse-prompt-panel.tsx, src/lib/auth-store.ts, src/app/api/generate/reverse-prompt/route.ts, src/lib/server-api-config.ts The reverse-prompt fetch must send Authorization: Bearer <accessToken> from readStoredAuth(). The server resolves customApiKeyId/systemApiId through getAuthenticatedUserId, which reads the bearer token rather than browser localStorage.
Reverse prompt keeps disappearing after refresh, relogin, or tab switch src/components/create/reverse-prompt-panel.tsx, src/lib/generation-job-client.ts, src/components/create/use-generation-job-recovery.ts, src/app/api/generation-jobs/route.ts, src/app/api/creation-history/route.ts Reverse prompt now uses the shared generation job queue and should recover queued/running jobs from /api/generation-jobs, keep the loading state alive until the worker actually finishes, and rely on the normal creation-history writeback when the worker completes.
Reverse prompt reaches login successfully but then times out on upstream chat/completions src/app/api/generate/reverse-prompt/route.ts, src/lib/local-storage.ts, src/lib/custom-api-fetch.ts If the input is a data URL, persist it first and send the public /api/local-storage/... URL upstream instead of the raw blob. Reverse-prompt is a multimodal chat/completions request, so a 524 here means the upstream multimodal endpoint or its latency is the problem, not frontend auth or image-generation routing.
Prompt optimization fails src/app/api/generate/suggest-prompt/route.ts, src/lib/server-api-config.ts, src/lib/custom-api-fetch.ts Text-capable system/custom API, chat response shape, JSON parsing fallback. This route also uses a multimodal chat/completions path, so 524 should be read as a multimodal upstream timeout rather than a synchronous image-generation failure.

Models, Providers, API Keys

Symptom Check Files What To Verify
Model list empty in create/profile src/app/api/model-config/route.ts, src/lib/model-config.ts, src/lib/managed-model-store.ts, src/lib/custom-api-store.ts Public model config response, admin recommendations, local client store mapping.
Default model group shows raw API model name instead of the admin display name src/lib/model-display.ts, src/app/api/model-config/route.ts, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx Frontend system model labels should use system_api_configs.name first. model_name is the upstream request model identifier and should remain available for generation dispatch, but it should not override the admin-facing display name in the create-page default model group.
Backend default models are configured but /api/model-config returns only {"providers":[],"recommendations":[]} or no systemApis src/app/api/model-config/route.ts, src/lib/server-api-config.ts, production database owner/grants Check PM2 logs for must be owner of table system_api_configs. After migration, runtime tables must be owned by the app DB user, or optional schema checks should not be allowed to empty the public model-config response. Fix ownership/grants first, then verify /api/model-config includes systemApis.
System API saved but not used src/app/api/admin/system-apis/route.ts, src/lib/server-api-config.ts, src/app/api/generate/image/route.ts, src/app/api/generate/video/route.ts systemApiId in request payload, active config, decrypted key, type matches image/video/text, is_default is true, and allowed_membership_tiers includes the current user's normalized tier. For admin default image models, also verify same media type plus same admin display name (system_api_configs.name) polling candidates, polling_mode, and polling_order; model_name is only the upstream request model. User custom APIs should not enter this polling path.
System default model generates successfully but user credits do not decrease src/app/api/generation-jobs/route.ts, src/lib/generation-job-worker.ts, src/lib/generation-credit-service.ts, src/lib/server-api-config.ts, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx Credit deduction must happen on the server after a successful system-default image/video generation, using the selected frontend systemApiId row in system_api_configs for pricing. Failed jobs must not deduct credits. New-job balance preflight should subtract queued/running system-default jobs for that user so rapid repeated submissions cannot overbook credits. Create buttons should not show predicted credits; completed result cards should show the creditsCost returned in the generation job result, and the profile balance should refresh from creditsBalance.
User custom API saved but not used src/app/api/user-api-keys/route.ts, src/lib/custom-api-store.ts, src/lib/server-api-config.ts customApiKeyId, owner auth, encrypted key exists, is_active.
Intelligent API dialog is too narrow, clipped, or shows only JSON src/components/profile/api-key-manager.tsx, src/components/ui/dialog.tsx Smart import dialogs must override the shared dialog's sm:max-w-lg with explicit wide sizing such as w-[min(...)] max-w-none sm:max-w-none, cap height to the viewport, and keep the JSON editor inside an internal scrollable/flexible area so title, actions, and footer remain visible.
Intelligent API import creates wrong or mixed requests src/components/profile/api-key-manager.tsx, src/app/api/user-api-keys/smart-import/route.ts, src/lib/user-api-manifest.ts, src/lib/user-api-manifest-executor.ts, src/lib/server-api-config.ts, src/app/api/generate/image/route.ts, src/app/api/generate/video/route.ts Each imported profile/model must have its own user_api_keys row and user-api-manifests/<userId>/<keyId>.json file. Verify manifest_path on the selected customApiKeyId, not a user-level shared file. Imported edit forms should show a human-readable provider name and a non-empty API request URL derived from profile.baseUrl + submit.path only when the Manifest provides enough endpoint data; never invent an OpenAI default URL for a third-party relay document. Editing a key should preserve manifest_path; generation should execute the selected manifest before legacy custom API fallback.
Create model dropdown shows many 导入的 API Key entries src/lib/model-display.ts, src/components/create/text-to-image.tsx, src/components/create/image-to-image.tsx, src/components/profile/api-key-manager.tsx, src/app/api/user-api-keys/smart-import/route.ts These are user custom API key rows, not admin default models. Generic import placeholder notes must be ignored/cleared so labels show provider plus model or a real custom note plus model. Do not delete user custom API rows unless explicitly requested.
Admin intelligent API import is missing or generated system models ignore Manifest src/components/admin/api-management-tab.tsx, src/app/api/admin/system-apis/smart-import/route.ts, src/app/api/admin/system-apis/route.ts, src/lib/server-api-config.ts, src/lib/user-api-manifest.ts, src/lib/user-api-manifest-executor.ts Admin imports must create one system_api_configs row per Manifest profile, write system-api-manifests/<systemApiId>.json, persist manifest_path, and resolve that path from the selected systemApiId. Imported rows still need API Key and pricing review before use.
元界 AI 同步后出现大量接口/参数名模型或模型行反复显示 Key src/app/api/admin/system-apis/yuanjie-capabilities/route.ts, src/lib/yuanjie-image-model-templates.ts, src/lib/yuanjie-video-model-templates.ts, src/lib/yuanjie-template-installer.ts, src/components/admin/api-management-tab.tsx 元界不应再从 /v1/skills/v1/skills/guide 猜模型,也不应在 智能配置 API 页面暴露内置模板安装/同步入口。检查安装路由是否使用内置图片/视频模板、是否只删除当前媒体类型的 provider = '元界 AI' 行、是否创建 inactive rows and per-model Manifest files, and whether admins configure Key/pricing/usage modes/enablement per model through the system-default-model management flow. The admin list should not show repeated imported key placeholders, and the create page should show only documented controls from the selected template capabilities.
元界任务在元界后台成功但妙境报模型繁忙或接口路径不存在 src/lib/yuanjie-image-model-templates.ts, src/lib/yuanjie-video-model-templates.ts, src/lib/user-api-manifest-executor.ts, src/app/api/generate/image/route.ts, src/app/api/generate/video/route.ts Check whether the Manifest poll endpoint uses path: "v1/media/status" plus query: { task_id: "{task_id}" }. If the path is stored as v1/media/status?task_id={task_id}, the executor can encode the query string into the pathname and 元界 will return a not-found error even though the create request already produced a task. Also verify 元界 media templates use finalPath: "is_final", finalValues: [true], statusPath: "state", successValues: ["success"], and failureValues: ["failed"]; status / status_group are display fields only.
元界后台显示已生成图片但妙境任务失败,日志出现下载 403、timeout 或保存失败 src/app/api/generate/image/route.ts, src/lib/media-storage.ts, src/lib/remote-fetch.ts, src/lib/user-api-manifest-executor.ts 这通常不是元界提交或轮询失败,而是 Manifest 结果 URL 返回后,妙境下载外部图片或保存原图/缩略图失败。先查 PM2 日志中 [User API Manifest Image] Failed to persist generated image,区分 下载图片失败: 403fetch failedPersist generated image media timed out、对象存储/缩略图错误。外部生成图 URL 应通过 fetchPublicHttpUrlWithRetry 发送浏览器式 User-Agent/Accept 并有限重试;/api/generate/image 应返回“上游已返回生成结果,但平台下载或保存结果图片失败”,不要再误包装为“上游返回图片分辨率不符合”或泛化成模型繁忙。
Agnes 视频任务先显示 in_progress 后失败,错误为裸 fetch failed 或历史不写入 src/lib/agnes-model-templates.ts, src/lib/user-api-manifest-executor.ts, src/app/api/generate/video/route.ts, src/lib/generation-job-worker.ts 先区分提交、轮询、结果视频下载保存、历史写入四段。Agnes V2.0 使用 POST /v1/videosGET /agnesapi?video_id=...&model_name=agnes-video-v2.0remixed_from_video_id 在官方完成响应中是视频 URL。Manifest 执行器会把网络异常包装成“上游任务创建/轮询网络连接失败”;视频结果保存失败应显示“上游已返回视频地址,但平台下载或保存结果视频失败”。若 job 成功但 works 没有记录,查 [generation-worker] creation history persistence failed 中的内部 URL。Agnes 时长不要传 duration,当前仅开放稳定的 3/5/10 秒并映射为 num_frames 81/121/241frame_rate=2418 秒在生产中会进入轮询后返回上游 failed应从能力列表隐藏并在后端拒绝旧请求。Agnes 视频是后台异步任务,/api/generate/video 给它单独 20 分钟轮询窗口,刷新/切页由 generation job 恢复链路继续显示状态。Manifest 总轮询预算要和单次请求超时分开,单次轮询 502/503/504、fetch failed 或网络超时应先更新任务进度并继续轮询,只有总预算耗尽才标记超时失败。
元界图生图提交后妙境报 Manifest 未能从 ... 读取任务 ID or generic 模型繁忙 while 元界 may have accepted the job src/lib/server-api-config.ts, src/lib/user-api-manifest-executor.ts, src/lib/yuanjie-image-model-templates.ts, src/lib/yuanjie-video-model-templates.ts The submit response can put the task identifier inside nested result objects. The executor must normalize task_id, taskId, id, and nested data/result/output objects before polling. Template taskIdPath should include result.task_id, result.taskId, and result.id before the broad result fallback. For system default polling, resolveSystemApiPollingCandidates(...) must also run ensureYuanjieSystemApiManifest(...); otherwise stale production system-api-manifests/<id>.json files can keep old $inputImages.dataUrls and old task-id paths even when source templates are fixed.
视频系统模型出现在错误入口或缺少参数选项 src/lib/server-api-config.ts, src/components/admin/api-management-tab.tsx, src/components/create/text-to-video.tsx, src/components/create/image-to-video.tsx, src/lib/model-capabilities.ts Check system_api_configs.video_usage_modes. 文生视频 should only show rows including text-to-video; 图生视频 should only show rows including image-to-video. Selected system video models should read Manifest capabilities for aspect ratio, duration, and resolution controls.
管理后台刷新后跳回仪表盘 src/modules/console/pages/console-dashboard-page.tsx The active view should be restored from sessionStorage on refresh and removed on logout. If it jumps to dashboard after a plain refresh, inspect the session key miaojing_console_active_view and whether the view is still allowed by the current membership/admin config.
兑换码无法生成、重复、兑换后积分或会员不到账,或可重复兑换 src/components/admin/redeem-code-management-tab.tsx, src/app/api/admin/redeem-codes/route.ts, src/components/profile/credits-tab.tsx, src/app/api/redeem-codes/redeem/route.ts, src/lib/redeem-code-service.ts Codes should be generated server-side with unique normalized_code. Redemption must use a DB transaction with FOR UPDATE locks on redeem_codes and profiles, then mark used_by/used_at. Credit codes update profiles.credits_balance and insert a credit_transactions row. Membership codes update profiles.membership_tier plus membership_expires_at; duration units are day, month, and year. If the profile page is stale, inspect /api/profile refresh and /api/credit-transactions.
获取兑换码或会员升级不跳转商城 src/components/admin/redeem-code-management-tab.tsx, src/components/profile/credits-tab.tsx, src/app/profile/page.tsx, src/app/api/site-config/route.ts, src/lib/site-config.ts The admin redeem-code tab saves the shared mall URL as site_config.redeem_code_mall_url through /api/site-config. Frontend buttons read siteConfig.redeemCodeMallUrl; empty config should show a toast instead of navigating. Verify the DB column exists, /api/site-config returns redeemCodeMallUrl, and the URL starts with http or https.
邀请链接不生成、邀请注册未发积分、后台看不到邀请关系 src/components/profile/credits-tab.tsx, src/app/api/invitations/me/route.ts, src/app/auth/register/page.tsx, src/app/api/auth/register/route.ts, src/app/api/admin/invitations/route.ts, src/lib/invitation-service.ts profiles.invite_code must be unique and stable. Registration links use /auth/register?invite=...; successful invited registration writes invitation_referrals, sets profiles.referred_by_user_id, grants 50 credits to inviter and invitee, and writes credit_transactions rows in the registration transaction.
New API image endpoint incompatible src/app/api/generate/image/route.ts, src/lib/custom-api-fetch.ts Provider is newapi/new api, endpoint normalization, model-specific size/count/quality handling.
API key leaked in UI/API src/app/api/user-api-keys/route.ts, src/app/api/admin/system-apis/route.ts, src/lib/server-crypto.ts, src/lib/server-api-config.ts Response mapping must return preview/empty key only.
Yuanjie GPT Image 2 image-to-image ignores reference images or behaves like text-to-image src/components/create/image-to-image.tsx, src/app/api/generate/image/route.ts, src/lib/user-api-manifest-executor.ts, src/lib/yuanjie-image-model-templates.ts Check whether the route reads extraImages, normalizes image + extraImages into Manifest inputImages, and whether Yuanjie templates use $inputImages.urls for params.images, top-level images, and base64Array. The executor should upload data URL references into storage and expose public references as $inputImages.urls; do not fix this by changing mozheAPI or generic OpenAI-compatible fallbacks.
Symptom Check Files What To Verify
History missing after generation or login/account switch src/lib/creation-history-store.ts, src/app/api/creation-history/route.ts, src/lib/generation-job-client.ts, src/components/create/use-generation-job-recovery.ts, create panel component History POST, works insert, URL not data URL except reverse prompt placeholder, and miaojing_auth_updated triggers a fresh server fetch. Create panels recover queued/running jobs from /api/generation-jobs so a refresh or re-login can reattach the live task before it finishes; they also store created job ids in per-user browser localStorage and query /api/generation-jobs/[id] for terminal succeeded/failed/cancelled jobs that finished while the browser was closed. Create-page history hooks intentionally request only the current mode and recent limit; if a create panel misses old records, check the API mode filter against type, params.creationMode, params.workType, params.mode, and legacy reference-image inference before raising the limit or reverting to full history. If the task card reappears after refresh but never turns into a result/error, inspect src/components/create/use-generation-job-recovery.ts; active-task state updates must not be part of the polling effect dependency list, or the recovery poller can be cancelled immediately after reattaching a job.
Detail delete removes only local history, skips confirmation, or record reappears after refresh src/components/creation-detail-dialog.tsx, src/components/ui/alert-dialog.tsx, src/lib/creation-history-store.ts, src/app/api/creation-history/route.ts, src/components/profile/creation-history-tab.tsx The detail action is labeled 删除作品 and must open a confirmation dialog warning that deletion cannot be recovered. Logged-in deletion should call DELETE /api/creation-history?id=... first, then refresh local history from the server. Check bearer token availability and route ownership filter (id + user_id).
Published work not in gallery or share to gallery is slow src/lib/creation-history-store.ts, src/lib/gallery-publish-media.ts, src/app/api/gallery/publish/route.ts, src/app/api/gallery/route.ts, src/app/gallery/page.tsx is_public = true, status = completed, stable /api/local-storage/... result_url, media copied/reused into gallery storage, and current filters. New generated /api/local-storage/... image/video URLs should use the publish fast path in gallery-publish-media and must not synchronously copy object-backed originals during share; external URLs still need copying and should fail the publish request if media preparation fails. Also check whether the browser marked the work shared before /api/gallery/publish returned success; local published=true without publishedAt is stale and should not block retry. For older incidents, inspect server logs/API status for publish failures that the previous frontend swallowed.
图生图/图生视频分享到画廊后看不到参考图,或复用/获取灵感没有带上参考图 src/components/create/image-to-image.tsx, src/components/create/image-to-video.tsx, src/app/api/gallery/publish/route.ts, src/lib/gallery-publish-media.ts, src/app/gallery/page.tsx, src/components/create/inspiration-gallery-dialog.tsx, src/lib/creation-reuse.ts The create panels should send referenceImage, referenceImages, refImageCount, and referenceImageAnnotations to shareToGallery. /api/gallery/publish should persist data URL or remote reference images into stable /api/local-storage/gallery/references/... URLs before storing them in works.params. Public gallery detail and inspiration detail may preview reference images but must not expose reference-image download actions; reuse drafts should prefer original referenceImages and only fall back to output media as reference when no references exist.
Imported gallery images do not render after production data import src/app/api/admin/data-export/route.ts, src/app/api/admin/data-import/route.ts, src/lib/local-storage.ts, src/app/api/local-storage/[...path]/route.ts, DB works.result_url New exports should include _media; import should persist media through the active storage adapter. If using an older export without _media, DB rows alone cannot recreate missing /api/local-storage/* files. For object migration, run pnpm run storage:sync-object -- --verify-only before switching to STORAGE_MODE=object.
Rainyun ROS bucket created but object storage still fails scripts/rainyun-ros-prepare.mjs, .env.local, src/lib/local-storage.ts, scripts/storage-sync-to-object.mjs, /api/health The Rainyun API link is control-plane bucket creation, not the media upload path. Verify .env.local has reviewed OBJECT_STORAGE_BUCKET, OBJECT_STORAGE_ENDPOINT, OBJECT_STORAGE_ACCESS_KEY_ID, OBJECT_STORAGE_SECRET_ACCESS_KEY, OBJECT_STORAGE_FORCE_PATH_STYLE=true, and STORAGE_MODE=dual; then run /api/health and pnpm run storage:sync-object -- --dry-run.
Gallery delete does not remove public item src/app/api/gallery/route.ts, admin UI route using it DELETE unpublishes by setting is_public = false, not hard delete.
Admin gallery prompt edit fails, sends no email, or prompt changes without audit trail src/components/admin/gallery-management-tab.tsx, src/app/api/admin/gallery/works/route.ts, src/app/api/admin/gallery/prompt/route.ts, src/lib/admin-gallery-prompt-service.ts, src/lib/email-service.ts, src/lib/platform-logs.ts Prompt moderation is console-only and requires a valid author email. /api/admin/gallery/prompt must send the email before updating works.prompt; SMTP failure, unchanged prompt, non-public work, or invalid author email should block the update. Platform logs should include reason key and prompt length metadata, not full prompt text.
Admin gallery management pagination wrong or page buttons skip records src/components/admin/gallery-management-tab.tsx, src/app/api/admin/gallery/works/route.ts, src/lib/admin-gallery-works-pagination.ts The admin table uses page and pageSize; the route converts those to SQL LIMIT/OFFSET and still accepts legacy limit/offset. Verify total, page, pageSize, totalPages, nextOffset, and hasMore in the response, and reset page to 1 when search/type/page size changes.
Search/filter/sort wrong src/app/api/gallery/route.ts, src/app/gallery/page.tsx Query params type, category, limit, offset, sort, q/search; SQL where/order, browser cache signature, and pagination append state.
Gallery search box looks inconsistent with the rest of the UI src/app/gallery/page.tsx The search field is a custom glass panel with an inner focused input surface; avoid reverting it to a plain transparent input row.
Gallery hover makes images muddy, covers the image with prompt text, shows only a single-color/static glow, has transparent gaps, does not match image colors, misses the card corners, moves too fast, looks too hard-edged, or action buttons disappear on dark/light images src/app/gallery/page.tsx, src/app/globals.css Gallery cards should not use a full-image dark hover overlay, center prompt text, transparent border gaps, generated unrelated colors, broad square glow under the card, or a separate outer halo layer. Keep hover feedback on the card container with scale plus a real gallery-card-border-frame wrapper using 3-5 sampled image colors in a single blurred 3px continuous clockwise border around the full work-card container, including all four corners and the prompt/footer area, and keep like/download buttons legible through sampled image brightness inversion.

Admin Console And Ops

Symptom Check Files What To Verify
Dashboard stats wrong src/modules/console/pages/console-dashboard-page.tsx, src/app/api/admin/dashboard/route.ts, src/app/api/admin/stats/route.ts SQL source tables, safe query fallbacks, admin auth.
User management bug src/components/admin/user-management-tab.tsx, src/app/api/admin/users/route.ts, src/lib/admin-users-service.ts Role/tier mapping, active flag, admin auth, password reset, and row actions. Admin reset-password must be reachable directly from the user row, not only behind the edit modal, and should clear/close overlapping edit state before showing the reset form. /api/admin/users PUT with newPassword must upsert auth.users.password_hash with crypt(..., gen_salt('bf')) so missing auth rows cannot silently return success without a usable password.
API/model management list opens for anonymous users or admin tab loads empty provider/recommendation rows src/components/admin/api-management-tab.tsx, src/app/api/admin/providers/route.ts, src/app/api/admin/model-recommendations/route.ts, src/lib/admin-auth.ts Provider and recommendation GET routes require admin auth just like mutations. The admin tab's initial fetch('/api/admin/providers') and fetch('/api/admin/model-recommendations') must include bearer auth headers; anonymous requests should return 401.
Order/payment bug src/components/admin/order-management-tab.tsx, src/components/admin/payment-tab.tsx, src/app/api/admin/orders/route.ts, src/app/api/admin/payment-methods/route.ts, src/lib/server-payment-config.ts Payment config encryption, order status, request shape.
Data import/export bug src/components/admin/data-management-tab.tsx, src/app/api/admin/data-export/route.ts, src/app/api/admin/data-import/route.ts, scripts/migration-integrity-check.mjs, scripts/migration-integrity-check-helpers.mjs JSON format, table coverage, admin auth, _media coverage, import transaction/savepoints, password hash/encrypted secret preservation, and work dedupe by URL/source URL/media SHA scoped to the same user_id so one user's private work cannot collapse into another user's row. Run pnpm run migration:check for the read-only migration gate. The checker should default to the web port 8000 and use bounded timeout/concurrency helpers for /api/local-storage/* probes so one slow or missing media URL is reported rather than crashing the whole script.
Admin email send/settings bug, test email blank, or user notification email blank src/components/admin/settings-tab.tsx, src/app/api/admin/email-settings/route.ts, src/app/api/admin/send-email/route.ts, src/lib/email-service.ts SMTP config, template rendering, send logs, MIME multipart assembly, and body encoding. Keep both text/plain and text/html parts non-empty, preserve required MIME blank separator lines, and fold base64 body lines to MIME-safe lengths before the SMTP DATA terminator.
Upgrade page stuck/fails src/components/admin/system-upgrade-tab.tsx, src/app/api/admin/upgrade/route.ts, scripts/admin-upgrade-runner.mjs, scripts/backup-create.sh, scripts/backup-restore.sh State dir, package limits, disk checks, backup validation, restore safety backup, PM2 restart command, stale status.
Platform logs missing or system log page says loading failed src/components/admin/log-management-tab.tsx, src/app/api/admin/logs/route.ts, src/lib/platform-logs.ts, routes that call writePlatformLog The page loads /api/admin/logs; verify the route exists, admin bearer auth is valid, ensurePlatformLogSchema() runs before querying, log retention cleanup is not failing, and API calls actually write logs.

Storage, Download, Files

Symptom Check Files What To Verify
/api/local-storage/... 404 src/app/api/local-storage/[...path], src/lib/local-storage.ts STORAGE_MODE, LOCAL_STORAGE_DIR, OBJECT_STORAGE_*, normalized key, and whether the object exists in local disk or bucket. Dual mode should fall back to local disk if object storage is missing a migrated key.
Production /api/local-storage/... still buffers originals after deployment src/app/api/local-storage/[...path]/route.ts, deploy rsync command Confirm the live production route contains generateObjectReadUrl(...) and NextResponse.redirect(...). If local code is correct but production is stale, check whether rsync used a broad local-storage/ exclude; use /local-storage/ for the repo-root runtime directory so src/app/api/local-storage/[...path]/route.ts is not skipped.
Download says remote fetch failed src/app/api/download/route.ts, src/lib/remote-fetch.ts URL is http(s), same-origin, or local-storage; upstream reachable; timeout.
Path traversal/security concern src/lib/local-storage.ts, src/app/api/download/route.ts, src/app/api/local-storage/[...path]/route.ts Keep normalizeKey, path.resolve, and .. guards.

Deployment And Build

Symptom Check Files What To Verify
Build or type check fails package.json, scripts/build.sh, next.config.ts, failing source file, CODEX_MIAOJING_MEMORY.md First run corepack pnpm install --frozen-lockfile if dependency modules are missing. Current audited baseline already recorded failures for missing @/lib/model-display and canvas type errors. Distinguish pre-existing source errors from your docs/change.
PM2 app not updated ecosystem.config.cjs, scripts/start.sh, scripts/deploy-or-upgrade.sh Process cwd, role ports, environment variables, pm2 startOrReload ecosystem.config.cjs --update-env.
Production uses different checkout ecosystem.config.cjs, PM2 process env/cwd Always verify PM2 cwd before editing production.
Production returns 502 after source sync or PM2 reload ecosystem.config.cjs, scripts/start.sh, PM2 env, nginx upstream ports Check whether production ecosystem.config.cjs was overwritten by a repo/dev copy. Live production on 2026-05-14 used /opt/miaojingAI, Node /data/miaojingAI/node/node-v24.15.0-linux-x64/bin, and ports 8000/8100/8200; a repo copy pointing at /root/miaojingAI and 5000/5100/5200 breaks nginx until the production config is restored and PM2 reloaded.
Upgrade package cleanup failed scripts/deploy-or-upgrade.sh, scripts/admin-upgrade-runner.mjs, src/app/api/admin/upgrade/route.ts Cleanup trap, backup paths, state dir, disk space guards.
Unsure whether a change is safe for hot update or needs cold update scripts/admin-upgrade-runner.mjs, src/app/api/admin/upgrade/route.ts, src/components/admin/system-upgrade-tab.tsx, docs/codex-miaojing/architecture.md Treat source/API/server/dependency/schema/env/runtime/script changes as cold-update candidates. Hot updates should be static/public asset-only and must pass runner preflight without restart. Verify backup, rollback, package limits, disk checks, PM2 restart expectations, and /api/health before marking deploy-facing work complete.

Useful Search Patterns

rg -n "export async function (GET|POST|PUT|DELETE)" src/app/api
rg -n "writePlatformLog|console\\.error|console\\.warn" src
rg -n "generation_jobs|works|profiles|site_config|system_api_configs" src scripts *.sql
rg -n "localStorage|/api/local-storage|/api/download" src
rg -n "requireAdmin|getAuthenticatedUser|getAuthenticatedUserId" src/app/api src/lib