mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
feat(onboarding): M2 — route guard + shell + Screen 1 (name)
- PATCH /api/v1/me/profile in mana-auth (name, image with 1–80 char
validation) — powers the Screen-1 save
- (app)/+layout.svelte:
* isOnboarding derived from pathname
* handleAuthReady loads onboardingStatus, redirects brand-new users
to /onboarding/name (fire-and-forget so sync/data-layer init keeps
running in parallel)
* chrome (PillNav, wallpaper, bottom-stack) hidden in onboarding mode;
AuthGate still wraps so the flow enforces authentication
- /onboarding/+layout.svelte: full-viewport shell with progress dots
(1/3, 2/3, 3/3) and a skip-all that marks the flow complete and
sends the user home
- /onboarding/+page.svelte: redirects bare entry to /onboarding/name
- /onboarding/name/+page.svelte: text input (1–40 chars), Enter = Weiter,
skip falls back to email local-part so Screen 2's greeting is never
empty
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5a92e1168b
commit
5aecf8b90d
6 changed files with 689 additions and 229 deletions
|
|
@ -99,7 +99,7 @@ app.route('/api/v1/api-keys', createApiKeyValidationRoute(apiKeysService));
|
|||
// ─── Me (GDPR) ──────────────────────────────────────────────
|
||||
|
||||
app.use('/api/v1/me/*', jwtAuth(config.baseUrl));
|
||||
app.route('/api/v1/me', createMeRoutes(userDataService));
|
||||
app.route('/api/v1/me', createMeRoutes(userDataService, db));
|
||||
|
||||
// ─── Encryption vault (per-user master key custody) ────────
|
||||
// Mounted under /me so it inherits the JWT middleware above and shows
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@
|
|||
*/
|
||||
|
||||
import { Hono } from 'hono';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import type { AuthUser } from '../middleware/jwt-auth';
|
||||
import type { UserDataService } from '../services/user-data';
|
||||
import type { Database } from '../db/connection';
|
||||
import { users } from '../db/schema/auth';
|
||||
import { sendAccountDeletionEmail } from '../email/send';
|
||||
|
||||
export function createMeRoutes(userDataService: UserDataService) {
|
||||
export function createMeRoutes(userDataService: UserDataService, db: Database) {
|
||||
return (
|
||||
new Hono<{ Variables: { user: AuthUser } }>()
|
||||
|
||||
|
|
@ -57,5 +60,46 @@ export function createMeRoutes(userDataService: UserDataService) {
|
|||
|
||||
return c.json(result);
|
||||
})
|
||||
|
||||
// ─── Update profile (name, avatar) ──────────────────────
|
||||
// Minimal patch endpoint used by the onboarding flow and
|
||||
// Settings → Profile. JWT-based like the rest of /me/*; the
|
||||
// updated name only lands in the user's JWT on next mint, so
|
||||
// the caller is responsible for refreshing its in-memory
|
||||
// representation of authStore.user. See docs/plans/onboarding-flow.md.
|
||||
.patch('/profile', async (c) => {
|
||||
const user = c.get('user');
|
||||
const body = (await c.req.json().catch(() => ({}))) as {
|
||||
name?: unknown;
|
||||
image?: unknown;
|
||||
};
|
||||
|
||||
const patch: { name?: string; image?: string; updatedAt: Date } = {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
if (typeof body.name === 'string') {
|
||||
const trimmed = body.name.trim();
|
||||
if (trimmed.length < 1 || trimmed.length > 80) {
|
||||
return c.json({ error: 'name must be 1–80 characters' }, 400);
|
||||
}
|
||||
patch.name = trimmed;
|
||||
}
|
||||
if (typeof body.image === 'string') {
|
||||
patch.image = body.image;
|
||||
}
|
||||
|
||||
if (!('name' in patch) && !('image' in patch)) {
|
||||
return c.json({ error: 'no fields to update' }, 400);
|
||||
}
|
||||
|
||||
const [updated] = await db
|
||||
.update(users)
|
||||
.set(patch)
|
||||
.where(eq(users.id, user.userId))
|
||||
.returning({ id: users.id, name: users.name, image: users.image });
|
||||
|
||||
if (!updated) return c.json({ error: 'User not found' }, 404);
|
||||
return c.json({ name: updated.name, image: updated.image });
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue