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
- Auto-create access: Creating a child automatically creates a ChildAccess record with role "owner" for the creating user.
- List scoping: List returns only children where a ChildAccess record exists for the requesting user.
- Read/update access: Any user with access (owner or caregiver) can read and update the child.
- Owner-only delete: Only the owner can delete a child. Caregivers get 403.
- Cascade delete: Deleting a child removes all feedings, diapers, sleep, notes, share links, and ChildAccess records.
- AuditLog survives: AuditLog entries reference user_id (not child_id), so they survive child deletion.
- Date of birth: Stored as DATE (no time component) in YYYY-MM-DD format. Future dates allowed (baby not yet born).
- 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
- Valid create: name + DOB → 201, { child: {...} }, owner access auto-created
- Missing name: → 400, details: [{field: "name"}]
- Missing DOB: → 400, details: [{field: "date_of_birth"}]
- Invalid date format: date_of_birth="March 15" → 400
- Future DOB allowed: date_of_birth=next month → 201
- Name trimmed: " Baby " → stored as "Baby"
List
- Owner with 2 children: → 200, { children: [...], count: 2 }, all role=owner
- Caregiver sees shared child: User B has caregiver access → list includes child with role=caregiver
- No children: → 200, { children: [], count: 0 }
- Mixed roles: own 1 + caregiver 1 → list shows both with correct roles
Get by ID
- Owner gets child: → 200, { child: {...} } with role
- Caregiver gets child: → 200 with role=caregiver
- No access: → 403
- Not found: → 404
Update
- Update name: → 200, name changed, updated_at changed
- Update DOB: → 200
- Partial update: only name → DOB unchanged
- Caregiver can update: → 200
- No access: → 403
Delete
- Owner deletes: → 204, child and all data removed
- Non-owner (caregiver) deletes: → 403
- Cascade verified: create child with feedings+diapers+sleep+notes, delete child, verify all removed
- AuditLog survives: audit entries remain after child deletion
- Not found: → 404
- No access: → 403
Edge Cases
- Name at max length (100 chars): → 201
- Name too long (101 chars): → 400
- 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)