Claude/review docs specs b up l0#6
Merged
Merged
Conversation
- encryption.ts: AES-256-GCM, IV-prefixed (12B IV + 16B tag), base64; key
from ENCRYPTION_KEY (32-byte hex); fails on missing/short key and on
tampered ciphertext / IV / auth tag.
- llm.ts: Anthropic wrapper with generateJson({system, user, model, maxTokens}).
System and user accept either a string or an array of content blocks with
optional cache_control for §6.3 prompt caching. Maps Anthropic 429/5xx to
TransientLLMError; re-throws other 4xx/non-API errors unchanged. Strips
```json``` fences before parsing. Plus validateLetterOutput() per §6.5
(subject ≤80, body ≤2000, no HTML tags, reasoning non-blocking).
- search.ts: Brave wrapper searchCreator({displayName, instagramHandle, niche})
with §6.1 query template; BraveUnavailableError distinct from "0 results".
- email-render.tsx: renderHtml({bodyText, trackingPixelId, baseUrl?}) using
react-email; tracking pixel emitted only when id provided; baseUrl arg
with APP_URL/NEXTAUTH_URL fallback.
Tests: 54 new unit tests (vitest), all mock fetch / SDK / env — no DB or
network. Pre-existing 6 Prisma DB-dependency suites continue to fail at
import (unchanged baseline from M1.1).
https://claude.ai/code/session_01Axdu8uRj62ccyQJtpRxhUu
M2.1 — Server module + API: - src/server/briefs.ts: list, getBriefById, createBrief, updateBrief, archiveBrief. Permissions: any member creates/reads; edit+archive requires admin/owner OR original creator. All mutations write audit in the same transaction (brief.created/updated/archived). - getBriefById resolves archived briefs by id — worker read path unaffected by archive flag (spec §5.2 archive behavior). - Input validated via zod briefInputSchema: required fields, toneOfVoice enum, forbiddenPhrases element types, landingUrl http/https scheme check. - API routes: GET+POST /api/briefs, GET+PATCH /api/briefs/[id], POST /api/briefs/[id]/archive. Body parsed as unknown + validated by server module (no unsafe casts). 500s log + return generic internal_error. M2.2 — UI: - /briefs list page with active/archived tabs, name/creator/created/status columns, "New brief" CTA. - /briefs/new and /briefs/[id] edit pages with BriefForm component grouped into Identity, Product, Partnership, Style, Constraints, Optional sections per spec §8.1. - Tone selector restricted to spec values; Archive button visible only to eligible users (server re-enforces). - AppShell sidebar: added "Briefs" nav link (all members), per spec §8.3. Tests: DB-dependent unit tests cover create defaults, required-field validation, all permission matrix branches (member/admin/owner/creator), cross-workspace IDOR (returns null, not Forbidden), archive idempotency, archived-brief still resolvable by id, audit row assertions. https://claude.ai/code/session_01Axdu8uRj62ccyQJtpRxhUu
M3.1 — Member SMTP: - src/server/smtp-config.ts: testAndSaveMemberSmtp runs nodemailer transporter.verify() before any DB write; on failure throws SmtpConnectionError without persisting anything. On success encrypts password via @/lib/encryption (AES-256-GCM) and upserts member_smtp. Audits member_smtp.tested every save; member_smtp.configured only when row is new or non-credential fields changed. - API: POST /api/profile/smtp/test, GET /api/profile/smtp (returns row without password fields). Verify timeout 10s. M3.2 — Profile: - src/server/profile.ts: getProfileForUser, updateDisplayName, changePassword (current-password verified before update), updateCalibration (toggle forcePreviewMode + reset counter; rejects empty patches; no audit per plan), getTodaySendCount per spec §7.5 (created_at UTC, statuses approved|sending|sent). - /profile screen: identity, password, SMTP, calibration counter + reset + force-preview toggle, today's send count read-only. - Routes split: PATCH /api/profile (display name only), PATCH /api/profile/password (password only), PATCH /api/profile/calibration. M3.3 — Workspace settings: - src/server/workspace-settings.ts: getOrCreateSettings (race-safe upsert), updateSettings (admin/owner only, validates letterModel and summarizeModel allow-lists per §5.2, validates defaultBriefId exists in same workspace, audits workspace_settings.updated with from→to diff; no audit when patch is a no-op). - /settings screen visible to all members; PATCH gated server-side; members see read-only form. - AppShell: added Settings sidebar link (admin/owner only); Profile now accessed via UserMenu dropdown in header per spec §8.3. Tests: DB-dependent unit tests cover all permission branches, encryption round-trip, no-persist on verify failure, audit-event matrix, validation rejections, default-brief cross-workspace check, and workspace isolation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.