Skip to main content

Feature: Children CRUD

Version: 1.0.0 Last Reviewed: 2026-02-10 Status: Approved

User Story

As a parent, I can add my baby's profile so all tracking data is associated with them.

MVP Scope

  • Create child (name, date of birth)
  • Read child details
  • Update child info (name, date of birth)
  • Delete child (owner only, cascades all tracking data)
  • List all children the user has access to (owned + shared)

NOT in MVP

  • Child photo/avatar
  • Birth weight, birth length
  • Pediatrician info
  • Medical conditions/allergies

API Contract

Create Child

POST /api/v1/children
Authorization: Bearer <token>

Request:
{
"name": "Baby Bretz",
"date_of_birth": "2026-03-15"
}

Response 201:
{
"child": {
"id": "uuid",
"name": "Baby Bretz",
"date_of_birth": "2026-03-15",
"created_at": "2026-02-10T12:00:00.000Z",
"updated_at": "2026-02-10T12:00:00.000Z"
}
}

List Children

GET /api/v1/children
Authorization: Bearer <token>

Response 200:
{
"children": [
{
"id": "uuid",
"name": "Baby Bretz",
"date_of_birth": "2026-03-15",
"role": "owner",
"created_at": "2026-02-10T12:00:00.000Z",
"updated_at": "2026-02-10T12:00:00.000Z"
}
],
"count": 1
}

Note: Returns children the user has access to (via ChildAccess).
Includes the user's role for each child.
No pagination needed (users will have 1-5 children max).

Get Child

GET /api/v1/children/:id
Authorization: Bearer <token>

Response 200:
{
"child": {
"id": "uuid",
"name": "Baby Bretz",
"date_of_birth": "2026-03-15",
"role": "owner",
"created_at": "2026-02-10T12:00:00.000Z",
"updated_at": "2026-02-10T12:00:00.000Z"
}
}

Update Child

PUT /api/v1/children/:id
Authorization: Bearer <token>

Request (all fields optional - partial update):
{
"name": "Baby B",
"date_of_birth": "2026-03-16"
}

Response 200:
{
"child": { ... }
}

Delete Child

DELETE /api/v1/children/:id
Authorization: Bearer <token>

Response 204: (No Content)

Error Responses

Standard error format:

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request body validation failed",
"details": [
{ "field": "name", "message": "Required", "code": "required" }
]
}
}

Error codes: 400 VALIDATION_ERROR, 401 UNAUTHORIZED, 403 FORBIDDEN, 404 NOT_FOUND

Business Rules

  1. Auto-create access: Creating a child automatically creates a ChildAccess record with role "owner" for the creating user.
  2. List scoping: List returns only children where a ChildAccess record exists for the requesting user.
  3. Read/update access: Any user with access (owner or caregiver) can read and update the child.
  4. Owner-only delete: Only the owner can delete a child. Caregivers get 403.
  5. Cascade delete: Deleting a child removes all feedings, diapers, sleep, notes, share links, and ChildAccess records.
  6. AuditLog survives: AuditLog entries reference user_id (not child_id), so they survive child deletion.
  7. Date of birth: Stored as DATE (no time component) in YYYY-MM-DD format. Future dates allowed (baby not yet born).
  8. Name validation: Required, min 1 character, max 100 characters, trimmed.

Acceptance Criteria

  • Can create a child with name and date of birth
  • Creating a child auto-creates ChildAccess with role "owner"
  • Can list all children user has access to (wrapped with count)
  • List includes user's role for each child
  • Can get a specific child by ID (with access check)
  • Can update child name and/or date of birth
  • Can delete a child (owner only, returns 204)
  • Delete cascades all tracking data
  • Non-owner cannot delete (403)
  • No-access user cannot read (403)
  • Validation errors return 400 with details array

Test Cases

Create

  1. Valid create: name + DOB → 201, { child: {...} }, owner access auto-created
  2. Missing name: → 400, details: [{field: "name"}]
  3. Missing DOB: → 400, details: [{field: "date_of_birth"}]
  4. Invalid date format: date_of_birth="March 15" → 400
  5. Future DOB allowed: date_of_birth=next month → 201
  6. Name trimmed: " Baby " → stored as "Baby"

List

  1. Owner with 2 children: → 200, { children: [...], count: 2 }, all role=owner
  2. Caregiver sees shared child: User B has caregiver access → list includes child with role=caregiver
  3. No children: → 200, { children: [], count: 0 }
  4. Mixed roles: own 1 + caregiver 1 → list shows both with correct roles

Get by ID

  1. Owner gets child: → 200, { child: {...} } with role
  2. Caregiver gets child: → 200 with role=caregiver
  3. No access: → 403
  4. Not found: → 404

Update

  1. Update name: → 200, name changed, updated_at changed
  2. Update DOB: → 200
  3. Partial update: only name → DOB unchanged
  4. Caregiver can update: → 200
  5. No access: → 403

Delete

  1. Owner deletes: → 204, child and all data removed
  2. Non-owner (caregiver) deletes: → 403
  3. Cascade verified: create child with feedings+diapers+sleep+notes, delete child, verify all removed
  4. AuditLog survives: audit entries remain after child deletion
  5. Not found: → 404
  6. No access: → 403

Edge Cases

  1. Name at max length (100 chars): → 201
  2. Name too long (101 chars): → 400
  3. Duplicate name allowed: two children named "Baby" → both 201 (names aren't unique)

Boundaries

  • No limit on number of children per user
  • No child profile photo or extended info
  • No transfer of ownership
  • No child deactivation (only delete with cascade)
  • Names are not unique (siblings can share names)