Shared: types/schémas/codes d'erreur pour foyer admin/invitation + suppression de compte (step 1/8)
- HouseView gagne adminId/inviteCode/members (HouseMemberView) - createHouseSchema, joinHouseSchema - deleteAccountSchema (nouveau packages/shared/src/schemas/account.ts) - ErrorCode: ALREADY_HAS_HOUSE, NOT_HOUSE_ADMIN, INVITE_CODE_NOT_FOUND
This commit is contained in:
parent
97ca5f88dd
commit
1248461125
5 changed files with 59 additions and 3 deletions
|
|
@ -14,6 +14,8 @@
|
|||
* code families —
|
||||
* - `4000`–`4099`: request validation
|
||||
* - `4010`–`4019`: authentication
|
||||
* - `4020`–`4029`: conflicting/invalid state transition
|
||||
* - `4030`–`4039`: authorization (caller authenticated, but not allowed to)
|
||||
* - `4040`–`4049`: not found
|
||||
* - `5000`–`5099`: internal/unexpected
|
||||
*
|
||||
|
|
@ -32,6 +34,10 @@ export enum ErrorCode {
|
|||
INVALID_CREDENTIALS = 4010,
|
||||
/** Request required a session cookie/JWT that is missing, invalid, or stale. */
|
||||
NOT_AUTHENTICATED = 4011,
|
||||
/** `POST /house` or `POST /house/join` attempted while the profile already belongs to a household. */
|
||||
ALREADY_HAS_HOUSE = 4020,
|
||||
/** A household action reserved to its admin (delete the household, remove a member) attempted by a non-admin member. */
|
||||
NOT_HOUSE_ADMIN = 4030,
|
||||
/** No route/resource matches the request. */
|
||||
NOT_FOUND = 4040,
|
||||
/** The profile making the request has no household yet (`houseId` is `null`). */
|
||||
|
|
@ -40,6 +46,8 @@ export enum ErrorCode {
|
|||
DIET_NOT_FOUND = 4042,
|
||||
/** One or more `allergyIds` don't match any reference `Allergy` row. */
|
||||
ALLERGY_NOT_FOUND = 4043,
|
||||
/** `POST /house/join`'s `inviteCode` doesn't match any household. */
|
||||
INVITE_CODE_NOT_FOUND = 4044,
|
||||
/** Unexpected/unhandled failure — the catch-all, always logged server-side. */
|
||||
INTERNAL_ERROR = 5000,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
// detail specific to one side.
|
||||
|
||||
export * from "./errors/error-codes.js";
|
||||
export * from "./schemas/account.js";
|
||||
export * from "./schemas/auth.js";
|
||||
export * from "./schemas/household.js";
|
||||
export * from "./schemas/profile.js";
|
||||
|
|
|
|||
15
packages/shared/src/schemas/account.ts
Normal file
15
packages/shared/src/schemas/account.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { z } from "zod";
|
||||
|
||||
// See schemas/auth.ts for the shared client/server validation rationale.
|
||||
|
||||
/**
|
||||
* Payload accepted by `DELETE /auth/me`. Deleting an account is
|
||||
* irreversible, so it's gated behind re-entering the current password —
|
||||
* same idea as `loginSchema`'s password field (presence only, the API does
|
||||
* the real `argon2.verify`), not a fresh set of complexity rules.
|
||||
*/
|
||||
export const deleteAccountSchema = z.object({
|
||||
password: z.string().min(1, "Le mot de passe est requis"),
|
||||
});
|
||||
/** Inferred TS type for {@link deleteAccountSchema}'s validated output. */
|
||||
export type DeleteAccountInput = z.infer<typeof deleteAccountSchema>;
|
||||
|
|
@ -10,3 +10,17 @@ export const renameHouseSchema = z.object({
|
|||
});
|
||||
/** Inferred TS type for {@link renameHouseSchema}'s validated output. */
|
||||
export type RenameHouseInput = z.infer<typeof renameHouseSchema>;
|
||||
|
||||
/** Payload accepted by `POST /house` — same naming rule as renaming one. */
|
||||
export const createHouseSchema = z.object({
|
||||
name: z.string().trim().min(1, "Le nom du foyer est requis").max(100),
|
||||
});
|
||||
/** Inferred TS type for {@link createHouseSchema}'s validated output. */
|
||||
export type CreateHouseInput = z.infer<typeof createHouseSchema>;
|
||||
|
||||
/** Payload accepted by `POST /house/join`. Invite codes are always 8 characters — see `house.service.ts`'s generator. */
|
||||
export const joinHouseSchema = z.object({
|
||||
inviteCode: z.string().trim().length(8, "Le code d'invitation doit contenir 8 caractères"),
|
||||
});
|
||||
/** Inferred TS type for {@link joinHouseSchema}'s validated output. */
|
||||
export type JoinHouseInput = z.infer<typeof joinHouseSchema>;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,27 @@
|
|||
/**
|
||||
* A household, as returned by `GET /house/current` / `PATCH /house/current`.
|
||||
* Unlike `DietView`/`AllergyView` this isn't reference data — it's the
|
||||
* current user's own household.
|
||||
* One member of a household, as embedded in {@link HouseView}. Deliberately
|
||||
* a small subset of `SafeUserProfile` — just enough for the household
|
||||
* settings page's member list (name + who's the admin), not the member's
|
||||
* own email/diet/etc.
|
||||
*/
|
||||
export interface HouseMemberView {
|
||||
id: number;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A household, as returned by `GET /house/current` / `PATCH /house/current`
|
||||
* / `POST /house` / `POST /house/join`. Unlike `DietView`/`AllergyView`
|
||||
* this isn't reference data — it's the current user's own household.
|
||||
*/
|
||||
export interface HouseView {
|
||||
id: number;
|
||||
name: string;
|
||||
/** FK to the member who administers this household (created it, or inherited adminship — see `house.service.ts`'s `leaveCurrentHouse`). */
|
||||
adminId: number;
|
||||
/** Shareable code another user enters via `POST /house/join` to become a member. */
|
||||
inviteCode: string;
|
||||
/** Every member of this household, including the caller. */
|
||||
members: HouseMemberView[];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue