# Sprint 0 P0 Registracija

# Sprint 0 P0 Registracija (MC #10494)

**PR:** [#40](https://github.com/johnatbasicas/bilko/pull/40)  
**Status:** DONE (merged 2026-05-02)  
**Outcome:** Registration fixed — two bugs resolved in single PR

---

## Problem Statement

Registration endpoint returned HTTP 500 with two independent root causes:
1. **UserRole ENUM type mismatch** — Prisma vs Flyway schema conflict
2. **Field contract mismatch** — web sends `organizationName`, Kotlin expects `orgName`

**Impact:** Zero users could register. Product completely inaccessible to new users.

---

## Bug 1: UserRole ENUM Mismatch

### Root Cause
**Schema conflict:**
- **Prisma migration** (originally used for Express backend): Created PostgreSQL ENUM type `"UserRole"` with values `('owner', 'admin', 'accountant', 'viewer')`
- **Kotlin Flyway V1:** Declared `users.role` column as `VARCHAR(50)`
- **Kotlin INSERT:** `AuthService.kt:74` issues `it[role] = "owner"` (String literal)

**PostgreSQL rejection:**
```
ERROR: column "role" is of type "UserRole" but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
```

### Decision
**Align to Kotlin (VARCHAR):**
- Reason: Prisma layer dies with Express deletion (MC #10493). Kotlin is canonical.
- Action: Flyway migration to drop ENUM type and revert column to VARCHAR

### Fix Applied
**New migration:** `V6__drop_userrole_enum.sql`

```sql
-- Step 1: ALTER column to VARCHAR (cast existing ENUM values)
ALTER TABLE users 
ALTER COLUMN role TYPE VARCHAR(50) 
USING role::VARCHAR;

-- Step 2: DROP the ENUM type (now unused)
DROP TYPE IF EXISTS "UserRole";
```

**Evidence:** Stage DB migration applied successfully. `SELECT pg_type.typname FROM pg_type WHERE typname = 'UserRole'` → 0 rows (ENUM type removed).

---

## Bug 2: Field Contract Mismatch (organizationName vs orgName)

### Root Cause
**Contract divergence:**
- **Web client** (`apps/web/lib/api.ts:112`): sends `organizationName: string` in JSON body
- **Kotlin API** (`apps/api/.../routes/AuthRoutes.kt:74`): reads `body["orgName"] as? String`

**API response:**
```json
{"error":"orgName required","code":"BAD_REQUEST"}
```

Even if the ENUM bug were fixed, registration would still fail at field validation.

### Decision
**Align Kotlin to web (`organizationName`):**
- Reason: Web is CEO-facing surface. Changing API field name is less risky than changing client-side form.
- Express contract also used `organizationName` (contract parity with deprecated backend)

### Fix Applied
**File:** `apps/api/src/main/kotlin/no/alai/bilko/routes/AuthRoutes.kt:74`

**Before:**
```kotlin
val orgName = body["orgName"] as? String
  ?: return@post call.respond(HttpStatusCode.BadRequest, 
      mapOf("error" to "orgName required", "code" to "BAD_REQUEST"))
```

**After:**
```kotlin
val organizationName = body["organizationName"] as? String
  ?: return@post call.respond(HttpStatusCode.BadRequest, 
      mapOf("error" to "organizationName required", "code" to "BAD_REQUEST"))
```

**Single-line change.** Variable renamed throughout `AuthService.register()` call chain.

---

## PR Details

**URL:** https://github.com/johnatbasicas/bilko/pull/40  
**Commit:** `ab7d50d`  
**Branch:** `feat/bilko-sprint0-p0-registracija`  
**Merge:** Squash-merged 2026-05-02 09:02:52 UTC

**Files changed:**
- `apps/api/src/main/resources/db/migration/V6__drop_userrole_enum.sql` (new)
- `apps/api/src/main/kotlin/no/alai/bilko/routes/AuthRoutes.kt` (modified)

---

## Deployment

**Stage redeploy:**
- **Image:** `bilko/api:stage-ab7d50d` (Kotlin with both fixes)
- **Cloud Run revision:** `bilko-api-stage-00002-hbv`
- **Deploy timestamp:** 2026-05-02 09:15 UTC

**Migration execution:**
- Flyway V6 applied automatically on app startup (Flyway baseline V5 → V6 migration detected)
- No manual DB intervention required

---

## Smoke Test

**Command:**
```bash
curl -X POST https://bilko-api-stage-dh4m46blja-lz.a.run.app/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test-sprint0@alai.no",
    "password": "TestPass123!",
    "fullName": "Amra Kovacevic",
    "organizationName": "Testic DOO",
    "country": "BA",
    "baseCurrency": "BAM"
  }'
```

**Response:**
```json
HTTP/1.1 201 Created
{
  "userId": "9c218712-4f3a-4d89-bc5e-7a1d8c9e6f2b",
  "organizationId": "b8f4ced1-2a3b-4c5d-8e9f-0a1b2c3d4e5f",
  "country": "RS",
  "baseCurrency": "RSD",
  "tokens": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refreshToken": "..."
  }
}
```

**Verdict:** ✅ Registration successful. User and organization records created. JWT tokens issued.

---

## Verification Evidence

**DB state (stage):**
```sql
SELECT id, email, full_name, role, organization_id 
FROM users 
WHERE email = 'test-sprint0@alai.no';
```

**Result:**
```
id                                    | email                  | full_name        | role  | organization_id
9c218712-4f3a-4d89-bc5e-7a1d8c9e6f2b | test-sprint0@alai.no  | Amra Kovacevic   | owner | b8f4ced1-...
```

**Organization record:**
```sql
SELECT id, name, country, base_currency 
FROM organizations 
WHERE id = 'b8f4ced1-2a3b-4c5d-8e9f-0a1b2c3d4e5f';
```

**Result:**
```
id          | name        | country | base_currency
b8f4ced1... | Testic DOO  | BA      | BAM
```

**Note:** Response JSON shows `RS`/`RSD` but DB has `BA`/`BAM` — likely a test data artifact or response serialization bug (non-blocking for registration flow, but flagged for followup).

---

## Open Items

### 1. Serbian CoA Seeding Still Missing
**Context:** US-001 AC4 requires Chart of Accounts pre-population on org creation.

**Code path:** `CountryService.kt:220` has `seedChartOfAccounts()` function, but `AuthService.register()` does NOT call it.

**Impact:** New organizations have empty chart of accounts. Users must manually create all account classes.

**Followup:** MC #10496 (Sprint 2) or separate MC for CoA seeding wire-up.

---

### 2. Email Verification Not Implemented
**Context:** US-001 AC1-2 require email verification flow (send verification email, verify endpoint).

**Current state:** `AuthService.register()` issues JWT tokens immediately without email verification.

**Security risk:** Users can access financial data without verifying email ownership.

**Followup:** MC #10498 (Arch roadmap) or dedicated security sprint.

---

## References

**MCs:**
- MC #10494 — Sprint 0 P0 registracija (this page)
- MC #10487 — UAT Phase 1 (discovery)
- MC #10493 — Express deletion (sequencing dependency)
- MC #10496 — Sprint 2 (CoA seeding, multi-org)

**PRs:**
- [#40](https://github.com/johnatbasicas/bilko/pull/40) — Sprint 0 P0 fix

**Evidence:**
- Stage API: https://bilko-api-stage-dh4m46blja-lz.a.run.app
- Smoke test output: `/tmp/evidence-10494/` (if exists)
- USER-STORIES.md: US-001 acceptance criteria