# Secure Notes Vault API ## Design decisions - Java programming language since Bluestaq is a Java shop - Maven for building - Spring Boot as a framework - H2 for persistance - plan for Postgress - JPA/Hibernate for SQL - JWT for auth ## HTTP return codes Application-defined HTTP status codes are generated in `AuthController` for successful registration and in `GlobalExceptionHandler` for API error responses. Spring Security and Spring MVC may still produce framework-level responses for requests that do not reach a controller, such as unauthenticated protected requests or unsupported methods. | HTTP code | Status | Generated in | Trigger | Response body | |---:|---|---|---|---| | `201` | Created | `AuthController.register` | `POST /auth/register` creates a new user. | `UserResponse` with `id`, `username`, and `createdAt`. | | `400` | Bad Request | `GlobalExceptionHandler.handleMalformedJson` | Request body cannot be parsed or converted from JSON. | `ErrorResponse` with `Malformed request body`. | | `400` | Bad Request | `GlobalExceptionHandler.handleTypeMismatch` | Path variable or query parameter cannot be converted to the expected type. | `ErrorResponse` with `Invalid request parameter`. | | `401` | Unauthorized | `GlobalExceptionHandler.handleAuthentication`; Spring Security filter chain | Authentication fails or an unauthenticated request targets a protected route. | `ErrorResponse` with `Invalid username or password` when handled by `GlobalExceptionHandler`; framework-generated body when rejected before controller handling. | | `403` | Forbidden | `GlobalExceptionHandler.handleForbidden` | Authenticated caller is not allowed to perform the requested operation. | `ErrorResponse` with the exception message. | | `404` | Not Found | `GlobalExceptionHandler.handleNotFound` | Requested domain resource does not exist or should be hidden from the caller. | `ErrorResponse` with the exception message. | | `404` | Not Found | `GlobalExceptionHandler.handleNoResourceFound` | No controller route or static resource matches the request. | `ErrorResponse` with `Not found`. | | `409` | Conflict | `GlobalExceptionHandler.handleConflict`; `AuthController.register` throws `ConflictException` | Duplicate username or other persistence/domain uniqueness conflict. | `ErrorResponse` with the exception message. | | `422` | Unprocessable Entity | `GlobalExceptionHandler.handleValidation` | Bean Validation fails for a request body annotated with `@Valid`. | `ValidationErrorResponse` with `error` and per-field `fields`. | ## DB schema The schema is the basic requirements for a User, Note and NoteShare. Nothing additional was added in order to save time. | Table | Column | Type | Required | Key / Constraint | Description | |---|---|---:|:---:|---|---| | `users` | `id` | `UUID` | Yes | Primary key | Unique user identifier. | | `users` | `username` | `VARCHAR(100)` | Yes | Unique: `uq_users_username` | User login handle. | | `users` | `password_hash` | `VARCHAR(255)` | Yes | | BCrypt password hash. | | `users` | `created_at` | `TIMESTAMP WITH TIME ZONE` | Yes | | Account creation timestamp. | | | | `notes` | `id` | `UUID` | Yes | Primary key | Unique note identifier. | | `notes` | `owner_id` | `UUID` | Yes | FK to `users(id)`; indexed by `idx_notes_owner_id` | User who owns the note. | | `notes` | `title` | `VARCHAR(255)` | Yes | | Note title. | | `notes` | `content` | `TEXT` | Yes | | Note body content. | | `notes` | `created_at` | `TIMESTAMP WITH TIME ZONE` | Yes | | Note creation timestamp. | | `notes` | `updated_at` | `TIMESTAMP WITH TIME ZONE` | Yes | | Last note update timestamp. | | | | `note_shares` | `id` | `UUID` | Yes | Primary key | Unique share identifier. | | `note_shares` | `note_id` | `UUID` | Yes | FK to `notes(id)` with `ON DELETE CASCADE`; indexed by `idx_note_shares_note_id` | Note being shared. | | `note_shares` | `shared_with_user_id` | `UUID` | Yes | FK to `users(id)`; indexed by `idx_note_shares_shared_with_user_id` | User receiving read-only access. | | `note_shares` | `created_at` | `TIMESTAMP WITH TIME ZONE` | Yes | | Share creation timestamp. | | `note_shares` | `note_id`, `shared_with_user_id` | `UUID`, `UUID` | Yes | Unique: `uq_note_shares_note_user` | Prevents duplicate shares for the same note and user. |