hazo_auth 5.1.37 → 5.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +271 -258
- package/SETUP_CHECKLIST.md +314 -148
- package/cli-src/lib/schema/sqlite_schema.ts +12 -6
- package/dist/lib/schema/sqlite_schema.d.ts +1 -1
- package/dist/lib/schema/sqlite_schema.d.ts.map +1 -1
- package/dist/lib/schema/sqlite_schema.js +12 -6
- package/package.json +27 -26
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -334,69 +334,179 @@ mkdir -p data
|
|
|
334
334
|
|
|
335
335
|
The SQLite database will be created automatically on first use if using hazo_connect's SQLite adapter.
|
|
336
336
|
|
|
337
|
+
**Recommended:** Run the canonical SQLite schema via the CLI. This is the single source of truth and creates ALL required tables (mirrors `src/lib/schema/sqlite_schema.ts`):
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
npx hazo_auth init-db # Create/recreate the SQLite database with full schema
|
|
341
|
+
npx hazo_auth schema # Print the canonical schema SQL (does not modify DB)
|
|
342
|
+
```
|
|
343
|
+
|
|
337
344
|
**Manual creation (if needed):**
|
|
338
345
|
```bash
|
|
339
|
-
# Create database with
|
|
346
|
+
# Create database with the full v5.x schema (all tables, including scopes + relationships)
|
|
340
347
|
cat << 'EOF' | sqlite3 data/hazo_auth.sqlite
|
|
348
|
+
-- ============================================================
|
|
349
|
+
-- hazo_auth canonical SQLite schema (v5.x)
|
|
350
|
+
-- Mirrors src/lib/schema/sqlite_schema.ts
|
|
351
|
+
-- ============================================================
|
|
352
|
+
|
|
353
|
+
-- Users table (status enum + managed sub-profile support)
|
|
341
354
|
CREATE TABLE IF NOT EXISTS hazo_users (
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
355
|
+
id TEXT PRIMARY KEY,
|
|
356
|
+
email_address TEXT NOT NULL UNIQUE,
|
|
357
|
+
password_hash TEXT,
|
|
358
|
+
name TEXT,
|
|
359
|
+
email_verified INTEGER DEFAULT 0,
|
|
360
|
+
login_attempts INTEGER DEFAULT 0,
|
|
361
|
+
last_logon TEXT,
|
|
362
|
+
profile_picture_url TEXT,
|
|
363
|
+
profile_source TEXT CHECK(profile_source IN ('gravatar', 'custom', 'predefined')),
|
|
364
|
+
mfa_secret TEXT,
|
|
365
|
+
url_on_logon TEXT,
|
|
366
|
+
google_id TEXT UNIQUE,
|
|
367
|
+
auth_providers TEXT DEFAULT 'email',
|
|
368
|
+
user_type TEXT,
|
|
369
|
+
app_user_data TEXT,
|
|
370
|
+
status TEXT DEFAULT 'ACTIVE' CHECK(status IN ('PENDING', 'ACTIVE', 'BLOCKED')),
|
|
371
|
+
managed_by_user_id TEXT REFERENCES hazo_users(id) ON DELETE SET NULL,
|
|
372
|
+
pin_hash TEXT,
|
|
373
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
374
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
360
375
|
);
|
|
361
376
|
|
|
377
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_email ON hazo_users(email_address);
|
|
378
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
379
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_status ON hazo_users(status);
|
|
380
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_users_managed_by ON hazo_users(managed_by_user_id);
|
|
381
|
+
|
|
382
|
+
-- Refresh tokens (also used for password reset / email verification tokens)
|
|
362
383
|
CREATE TABLE IF NOT EXISTS hazo_refresh_tokens (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
384
|
+
id TEXT PRIMARY KEY,
|
|
385
|
+
user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
386
|
+
token TEXT NOT NULL UNIQUE,
|
|
387
|
+
token_type TEXT DEFAULT 'refresh',
|
|
388
|
+
expires_at TEXT NOT NULL,
|
|
389
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
369
390
|
);
|
|
370
391
|
|
|
371
|
-
CREATE
|
|
372
|
-
|
|
373
|
-
permission_name TEXT NOT NULL UNIQUE,
|
|
374
|
-
description TEXT,
|
|
375
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
376
|
-
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
377
|
-
);
|
|
392
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_user ON hazo_refresh_tokens(user_id);
|
|
393
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token ON hazo_refresh_tokens(token);
|
|
378
394
|
|
|
395
|
+
-- Roles
|
|
379
396
|
CREATE TABLE IF NOT EXISTS hazo_roles (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
397
|
+
id TEXT PRIMARY KEY,
|
|
398
|
+
role_name TEXT NOT NULL UNIQUE,
|
|
399
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
400
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
384
401
|
);
|
|
385
402
|
|
|
403
|
+
-- Permissions
|
|
404
|
+
CREATE TABLE IF NOT EXISTS hazo_permissions (
|
|
405
|
+
id TEXT PRIMARY KEY,
|
|
406
|
+
permission_name TEXT NOT NULL UNIQUE,
|
|
407
|
+
description TEXT,
|
|
408
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
409
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
-- Role-permission assignments (composite PK, no id column)
|
|
386
413
|
CREATE TABLE IF NOT EXISTS hazo_role_permissions (
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
PRIMARY KEY (role_id, permission_id)
|
|
414
|
+
role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
|
|
415
|
+
permission_id TEXT NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
|
|
416
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
417
|
+
PRIMARY KEY (role_id, permission_id)
|
|
392
418
|
);
|
|
393
419
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
420
|
+
-- Unified scopes table (hierarchical multi-tenancy with firm branding)
|
|
421
|
+
-- v5.0+ replaces hazo_org and hazo_scopes_l1..l7 with a single self-referencing table
|
|
422
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes (
|
|
423
|
+
id TEXT PRIMARY KEY,
|
|
424
|
+
parent_id TEXT REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
425
|
+
name TEXT NOT NULL,
|
|
426
|
+
level TEXT NOT NULL,
|
|
427
|
+
logo_url TEXT,
|
|
428
|
+
primary_color TEXT,
|
|
429
|
+
secondary_color TEXT,
|
|
430
|
+
tagline TEXT,
|
|
431
|
+
slug TEXT,
|
|
432
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
433
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_scopes_parent ON hazo_scopes(parent_id);
|
|
437
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_scopes_level ON hazo_scopes(level);
|
|
438
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_scopes_slug ON hazo_scopes(slug);
|
|
439
|
+
|
|
440
|
+
-- Reserved system scopes
|
|
441
|
+
INSERT OR IGNORE INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)
|
|
442
|
+
VALUES ('00000000-0000-0000-0000-000000000000', NULL, 'Super Admin', 'system', datetime('now'), datetime('now'));
|
|
443
|
+
|
|
444
|
+
INSERT OR IGNORE INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)
|
|
445
|
+
VALUES ('00000000-0000-0000-0000-000000000001', NULL, 'System', 'default', datetime('now'), datetime('now'));
|
|
446
|
+
|
|
447
|
+
-- User-scope assignments (membership model with scope-specific roles)
|
|
448
|
+
-- NOTE: replaces the old hazo_user_roles table from v4.x
|
|
449
|
+
CREATE TABLE IF NOT EXISTS hazo_user_scopes (
|
|
450
|
+
user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
451
|
+
scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
452
|
+
root_scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
453
|
+
role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
|
|
454
|
+
status TEXT DEFAULT 'ACTIVE' CHECK (status IN ('INVITED', 'ACTIVE', 'SUSPENDED', 'DEPARTED')),
|
|
455
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
456
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
457
|
+
PRIMARY KEY (user_id, scope_id)
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_user_scopes_scope ON hazo_user_scopes(scope_id);
|
|
461
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_user_scopes_root ON hazo_user_scopes(root_scope_id);
|
|
462
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_user_scopes_role ON hazo_user_scopes(role_id);
|
|
463
|
+
|
|
464
|
+
-- Invitations (onboard new users into existing scopes)
|
|
465
|
+
CREATE TABLE IF NOT EXISTS hazo_invitations (
|
|
466
|
+
id TEXT PRIMARY KEY,
|
|
467
|
+
email_address TEXT NOT NULL,
|
|
468
|
+
token TEXT NOT NULL UNIQUE,
|
|
469
|
+
scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
470
|
+
root_scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
471
|
+
role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
|
|
472
|
+
invited_by TEXT REFERENCES hazo_users(id) ON DELETE SET NULL,
|
|
473
|
+
status TEXT NOT NULL DEFAULT 'PENDING' CHECK(status IN ('PENDING', 'ACCEPTED', 'EXPIRED', 'REVOKED')),
|
|
474
|
+
expires_at TEXT NOT NULL,
|
|
475
|
+
accepted_at TEXT,
|
|
476
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
477
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_invitations_email ON hazo_invitations(email_address);
|
|
481
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_invitations_token ON hazo_invitations(token);
|
|
482
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_invitations_scope ON hazo_invitations(scope_id);
|
|
483
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_invitations_status ON hazo_invitations(status);
|
|
484
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_invitations_expires ON hazo_invitations(expires_at);
|
|
485
|
+
|
|
486
|
+
-- Managed sub-profile relationships (parent/child accounts on shared devices)
|
|
487
|
+
CREATE TABLE IF NOT EXISTS hazo_user_relationships (
|
|
488
|
+
id TEXT PRIMARY KEY,
|
|
489
|
+
parent_user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
490
|
+
child_user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
491
|
+
relationship_type TEXT NOT NULL DEFAULT 'parent',
|
|
492
|
+
can_view_progress INTEGER DEFAULT 1,
|
|
493
|
+
can_edit_profile INTEGER DEFAULT 1,
|
|
494
|
+
can_delete INTEGER DEFAULT 0,
|
|
495
|
+
is_self INTEGER DEFAULT 0,
|
|
496
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
497
|
+
UNIQUE(parent_user_id, child_user_id)
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_user_relationships_parent ON hazo_user_relationships(parent_user_id);
|
|
501
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_user_relationships_child ON hazo_user_relationships(child_user_id);
|
|
502
|
+
|
|
503
|
+
-- Built-in firm_admin role (used when a user creates their first firm)
|
|
504
|
+
INSERT OR IGNORE INTO hazo_roles (id, role_name, created_at, changed_at)
|
|
505
|
+
VALUES (
|
|
506
|
+
lower(hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-4' || substr(hex(randomblob(2)),2) || '-' || substr('89ab',abs(random()) % 4 + 1, 1) || substr(hex(randomblob(2)),2) || '-' || hex(randomblob(6))),
|
|
507
|
+
'firm_admin',
|
|
508
|
+
datetime('now'),
|
|
509
|
+
datetime('now')
|
|
400
510
|
);
|
|
401
511
|
EOF
|
|
402
512
|
```
|
|
@@ -404,82 +514,53 @@ EOF
|
|
|
404
514
|
**Verify SQLite database:**
|
|
405
515
|
```bash
|
|
406
516
|
sqlite3 data/hazo_auth.sqlite ".tables"
|
|
407
|
-
# Expected
|
|
517
|
+
# Expected (9 tables):
|
|
518
|
+
# hazo_users hazo_refresh_tokens hazo_roles hazo_permissions hazo_role_permissions
|
|
519
|
+
# hazo_scopes hazo_user_scopes hazo_invitations hazo_user_relationships
|
|
408
520
|
```
|
|
409
521
|
|
|
522
|
+
> **v4.x → v5.x:** the legacy `hazo_org`, `hazo_scopes_l1..l7`, and `hazo_user_roles` tables have been removed. Roles are now assigned per-scope via `hazo_user_scopes.role_id`. If upgrading, run `migrations/009_scope_consolidation.sql` first.
|
|
523
|
+
|
|
410
524
|
### Option B: PostgreSQL (Production)
|
|
411
525
|
|
|
412
|
-
Run this SQL script in your PostgreSQL database
|
|
526
|
+
Run this SQL script in your PostgreSQL database. It creates the full v5.x schema, including the unified `hazo_scopes` model, `hazo_user_scopes`, `hazo_invitations`, and `hazo_user_relationships`.
|
|
413
527
|
|
|
414
|
-
**Important:** Run the entire script in order
|
|
528
|
+
**Important:** Run the entire script in order — enum types and parent tables must be created before tables that depend on them.
|
|
415
529
|
|
|
416
530
|
```sql
|
|
417
|
-
--
|
|
531
|
+
-- ============================================================
|
|
532
|
+
-- hazo_auth canonical PostgreSQL schema (v5.x)
|
|
533
|
+
-- Single source of truth for production deployments
|
|
534
|
+
-- ============================================================
|
|
535
|
+
|
|
418
536
|
SET search_path TO public;
|
|
419
537
|
|
|
420
|
-
--
|
|
421
|
-
DROP TYPE IF EXISTS hazo_enum_profile_source_enum CASCADE;
|
|
538
|
+
-- 1. Enum types
|
|
422
539
|
CREATE TYPE hazo_enum_profile_source_enum AS ENUM ('gravatar', 'custom', 'predefined');
|
|
540
|
+
CREATE TYPE hazo_enum_user_status AS ENUM ('PENDING', 'ACTIVE', 'BLOCKED');
|
|
541
|
+
CREATE TYPE hazo_enum_user_scope_status_type AS ENUM ('INVITED', 'ACTIVE', 'SUSPENDED', 'DEPARTED');
|
|
542
|
+
CREATE TYPE hazo_enum_invitation_status AS ENUM ('PENDING', 'ACCEPTED', 'EXPIRED', 'REVOKED');
|
|
423
543
|
|
|
424
|
-
|
|
425
|
-
CREATE TYPE hazo_enum_scope_types AS ENUM (
|
|
426
|
-
'hazo_scopes_l1', 'hazo_scopes_l2', 'hazo_scopes_l3',
|
|
427
|
-
'hazo_scopes_l4', 'hazo_scopes_l5', 'hazo_scopes_l6', 'hazo_scopes_l7'
|
|
428
|
-
);
|
|
429
|
-
|
|
430
|
-
DROP TYPE IF EXISTS hazo_enum_notify_chain_status CASCADE;
|
|
431
|
-
CREATE TYPE hazo_enum_notify_chain_status AS ENUM ('draft', 'published', 'inactive');
|
|
432
|
-
|
|
433
|
-
DROP TYPE IF EXISTS hazo_enum_notify_email_type CASCADE;
|
|
434
|
-
CREATE TYPE hazo_enum_notify_email_type AS ENUM ('system', 'user');
|
|
435
|
-
|
|
436
|
-
DROP TYPE IF EXISTS hazo_enum_group_type CASCADE;
|
|
437
|
-
CREATE TYPE hazo_enum_group_type AS ENUM ('support', 'peer', 'group');
|
|
438
|
-
|
|
439
|
-
DROP TYPE IF EXISTS hazo_enum_group_role CASCADE;
|
|
440
|
-
CREATE TYPE hazo_enum_group_role AS ENUM ('client', 'staff', 'owner', 'admin', 'member');
|
|
441
|
-
|
|
442
|
-
DROP TYPE IF EXISTS hazo_enum_chat_type CASCADE;
|
|
443
|
-
CREATE TYPE hazo_enum_chat_type AS ENUM ('chat', 'field', 'project', 'support', 'general');
|
|
444
|
-
|
|
445
|
-
-- Create organization table (multi-tenancy) - MUST be created before hazo_users
|
|
446
|
-
CREATE TABLE hazo_org (
|
|
447
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
448
|
-
name TEXT NOT NULL,
|
|
449
|
-
parent_org_id UUID REFERENCES hazo_org(id) ON DELETE SET NULL,
|
|
450
|
-
root_org_id UUID REFERENCES hazo_org(id) ON DELETE SET NULL,
|
|
451
|
-
user_limit INTEGER NOT NULL DEFAULT 0, -- 0 = unlimited
|
|
452
|
-
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
453
|
-
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
454
|
-
created_by UUID, -- FK added after hazo_users exists
|
|
455
|
-
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
456
|
-
changed_by UUID -- FK added after hazo_users exists
|
|
457
|
-
);
|
|
458
|
-
CREATE INDEX idx_hazo_org_parent_org_id ON hazo_org(parent_org_id);
|
|
459
|
-
CREATE INDEX idx_hazo_org_root_org_id ON hazo_org(root_org_id);
|
|
460
|
-
CREATE INDEX idx_hazo_org_active ON hazo_org(active);
|
|
461
|
-
CREATE INDEX idx_hazo_org_name ON hazo_org(name);
|
|
462
|
-
|
|
463
|
-
-- Create users table
|
|
544
|
+
-- 2. Users (status enum + managed sub-profile support)
|
|
464
545
|
CREATE TABLE hazo_users (
|
|
465
546
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
466
547
|
email_address TEXT NOT NULL UNIQUE,
|
|
467
548
|
password_hash TEXT, -- NULL for OAuth-only users
|
|
468
549
|
name TEXT,
|
|
469
550
|
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
470
|
-
status TEXT NOT NULL DEFAULT 'ACTIVE', -- 'PENDING', 'ACTIVE', or 'BLOCKED'
|
|
471
551
|
login_attempts INTEGER NOT NULL DEFAULT 0,
|
|
472
552
|
last_logon TIMESTAMP WITH TIME ZONE,
|
|
473
553
|
profile_picture_url TEXT,
|
|
474
554
|
profile_source hazo_enum_profile_source_enum,
|
|
475
555
|
mfa_secret TEXT,
|
|
476
556
|
url_on_logon TEXT,
|
|
477
|
-
user_type TEXT, -- Optional user categorization
|
|
478
|
-
app_user_data TEXT, -- Custom JSON data for consuming apps
|
|
479
557
|
google_id TEXT UNIQUE, -- Google OAuth ID
|
|
480
558
|
auth_providers TEXT DEFAULT 'email', -- 'email', 'google', or 'email,google'
|
|
481
|
-
|
|
482
|
-
|
|
559
|
+
user_type TEXT, -- Optional user categorization
|
|
560
|
+
app_user_data JSONB, -- Custom JSON data for consuming apps
|
|
561
|
+
status hazo_enum_user_status NOT NULL DEFAULT 'ACTIVE',
|
|
562
|
+
managed_by_user_id UUID REFERENCES hazo_users(id) ON DELETE SET NULL, -- managed sub-profiles
|
|
563
|
+
pin_hash TEXT, -- simple PIN auth on shared devices
|
|
483
564
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
484
565
|
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
485
566
|
);
|
|
@@ -487,71 +568,142 @@ CREATE INDEX idx_hazo_users_email ON hazo_users(email_address);
|
|
|
487
568
|
CREATE INDEX idx_hazo_users_status ON hazo_users(status);
|
|
488
569
|
CREATE INDEX idx_hazo_users_user_type ON hazo_users(user_type);
|
|
489
570
|
CREATE UNIQUE INDEX idx_hazo_users_google_id ON hazo_users(google_id);
|
|
490
|
-
CREATE INDEX
|
|
491
|
-
CREATE INDEX idx_hazo_users_root_org_id ON hazo_users(root_org_id);
|
|
571
|
+
CREATE INDEX idx_hazo_users_managed_by ON hazo_users(managed_by_user_id);
|
|
492
572
|
|
|
493
|
-
--
|
|
494
|
-
ALTER TABLE hazo_org ADD CONSTRAINT fk_hazo_org_created_by
|
|
495
|
-
FOREIGN KEY (created_by) REFERENCES hazo_users(id) ON DELETE SET NULL;
|
|
496
|
-
ALTER TABLE hazo_org ADD CONSTRAINT fk_hazo_org_changed_by
|
|
497
|
-
FOREIGN KEY (changed_by) REFERENCES hazo_users(id) ON DELETE SET NULL;
|
|
498
|
-
|
|
499
|
-
-- Create refresh tokens table
|
|
573
|
+
-- 3. Refresh tokens (also used for password reset / email verification)
|
|
500
574
|
CREATE TABLE hazo_refresh_tokens (
|
|
501
575
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
502
576
|
user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
503
577
|
token_hash TEXT NOT NULL,
|
|
504
|
-
token_type TEXT NOT NULL,
|
|
578
|
+
token_type TEXT NOT NULL DEFAULT 'refresh', -- 'refresh' | 'password_reset' | 'email_verification'
|
|
505
579
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
506
580
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
507
581
|
);
|
|
508
582
|
CREATE INDEX idx_hazo_refresh_tokens_user_id ON hazo_refresh_tokens(user_id);
|
|
509
583
|
CREATE INDEX idx_hazo_refresh_tokens_token_type ON hazo_refresh_tokens(token_type);
|
|
510
584
|
|
|
511
|
-
--
|
|
512
|
-
CREATE TABLE
|
|
585
|
+
-- 4. Roles
|
|
586
|
+
CREATE TABLE hazo_roles (
|
|
513
587
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
514
|
-
|
|
515
|
-
description TEXT,
|
|
588
|
+
role_name TEXT NOT NULL UNIQUE,
|
|
516
589
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
517
590
|
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
518
591
|
);
|
|
519
592
|
|
|
520
|
-
--
|
|
521
|
-
CREATE TABLE
|
|
593
|
+
-- 5. Permissions
|
|
594
|
+
CREATE TABLE hazo_permissions (
|
|
522
595
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
523
|
-
|
|
596
|
+
permission_name TEXT NOT NULL UNIQUE,
|
|
597
|
+
description TEXT,
|
|
524
598
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
525
599
|
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
526
600
|
);
|
|
527
601
|
|
|
528
|
-
--
|
|
602
|
+
-- 6. Role-permission assignments (composite PK, NO id column)
|
|
529
603
|
CREATE TABLE hazo_role_permissions (
|
|
530
604
|
role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
|
|
531
605
|
permission_id UUID NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
|
|
532
606
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
533
|
-
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
534
607
|
PRIMARY KEY (role_id, permission_id)
|
|
535
608
|
);
|
|
536
|
-
CREATE INDEX idx_hazo_role_permissions_role_id ON hazo_role_permissions(role_id);
|
|
537
|
-
CREATE INDEX idx_hazo_role_permissions_permission_id ON hazo_role_permissions(permission_id);
|
|
538
609
|
|
|
539
|
-
--
|
|
540
|
-
|
|
610
|
+
-- 7. Unified scopes (hierarchical multi-tenancy with firm branding)
|
|
611
|
+
-- v5.0+ replaces the old hazo_org and hazo_scopes_l1..l7 tables.
|
|
612
|
+
CREATE TABLE hazo_scopes (
|
|
613
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
614
|
+
parent_id UUID REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
615
|
+
name TEXT NOT NULL,
|
|
616
|
+
level TEXT NOT NULL, -- descriptive label e.g. 'HQ', 'Division', 'Team'
|
|
617
|
+
logo_url TEXT,
|
|
618
|
+
primary_color TEXT,
|
|
619
|
+
secondary_color TEXT,
|
|
620
|
+
tagline TEXT,
|
|
621
|
+
slug TEXT,
|
|
622
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
623
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
624
|
+
);
|
|
625
|
+
CREATE INDEX idx_hazo_scopes_parent ON hazo_scopes(parent_id);
|
|
626
|
+
CREATE INDEX idx_hazo_scopes_level ON hazo_scopes(level);
|
|
627
|
+
CREATE INDEX idx_hazo_scopes_slug ON hazo_scopes(slug);
|
|
628
|
+
|
|
629
|
+
-- 7a. Reserved system scopes
|
|
630
|
+
INSERT INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)
|
|
631
|
+
VALUES ('00000000-0000-0000-0000-000000000000', NULL, 'Super Admin', 'system', NOW(), NOW())
|
|
632
|
+
ON CONFLICT (id) DO NOTHING;
|
|
633
|
+
|
|
634
|
+
INSERT INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)
|
|
635
|
+
VALUES ('00000000-0000-0000-0000-000000000001', NULL, 'System', 'default', NOW(), NOW())
|
|
636
|
+
ON CONFLICT (id) DO NOTHING;
|
|
637
|
+
|
|
638
|
+
-- 8. User-scope assignments (membership model with scope-specific roles)
|
|
639
|
+
-- Replaces the v4.x hazo_user_roles table.
|
|
640
|
+
CREATE TABLE hazo_user_scopes (
|
|
541
641
|
user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
642
|
+
scope_id UUID NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
643
|
+
root_scope_id UUID NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
542
644
|
role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
|
|
645
|
+
status hazo_enum_user_scope_status_type NOT NULL DEFAULT 'ACTIVE',
|
|
543
646
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
544
647
|
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
545
|
-
PRIMARY KEY (user_id,
|
|
648
|
+
PRIMARY KEY (user_id, scope_id)
|
|
649
|
+
);
|
|
650
|
+
CREATE INDEX idx_hazo_user_scopes_scope ON hazo_user_scopes(scope_id);
|
|
651
|
+
CREATE INDEX idx_hazo_user_scopes_root ON hazo_user_scopes(root_scope_id);
|
|
652
|
+
CREATE INDEX idx_hazo_user_scopes_role ON hazo_user_scopes(role_id);
|
|
653
|
+
|
|
654
|
+
-- 9. Invitations (onboard new users into existing scopes)
|
|
655
|
+
CREATE TABLE hazo_invitations (
|
|
656
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
657
|
+
email_address TEXT NOT NULL,
|
|
658
|
+
token TEXT NOT NULL UNIQUE,
|
|
659
|
+
scope_id UUID NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
660
|
+
root_scope_id UUID NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,
|
|
661
|
+
role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
|
|
662
|
+
invited_by UUID REFERENCES hazo_users(id) ON DELETE SET NULL,
|
|
663
|
+
status hazo_enum_invitation_status NOT NULL DEFAULT 'PENDING',
|
|
664
|
+
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
665
|
+
accepted_at TIMESTAMP WITH TIME ZONE,
|
|
666
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
667
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
668
|
+
);
|
|
669
|
+
CREATE INDEX idx_hazo_invitations_email ON hazo_invitations(email_address);
|
|
670
|
+
CREATE INDEX idx_hazo_invitations_token ON hazo_invitations(token);
|
|
671
|
+
CREATE INDEX idx_hazo_invitations_scope ON hazo_invitations(scope_id);
|
|
672
|
+
CREATE INDEX idx_hazo_invitations_status ON hazo_invitations(status);
|
|
673
|
+
CREATE INDEX idx_hazo_invitations_expires ON hazo_invitations(expires_at);
|
|
674
|
+
|
|
675
|
+
-- 10. Managed sub-profile relationships (parent/child accounts on shared devices)
|
|
676
|
+
CREATE TABLE hazo_user_relationships (
|
|
677
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
678
|
+
parent_user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
679
|
+
child_user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
680
|
+
relationship_type TEXT NOT NULL DEFAULT 'parent',
|
|
681
|
+
can_view_progress BOOLEAN NOT NULL DEFAULT TRUE,
|
|
682
|
+
can_edit_profile BOOLEAN NOT NULL DEFAULT TRUE,
|
|
683
|
+
can_delete BOOLEAN NOT NULL DEFAULT FALSE,
|
|
684
|
+
is_self BOOLEAN NOT NULL DEFAULT FALSE,
|
|
685
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
686
|
+
UNIQUE (parent_user_id, child_user_id)
|
|
546
687
|
);
|
|
547
|
-
CREATE INDEX
|
|
548
|
-
CREATE INDEX
|
|
688
|
+
CREATE INDEX idx_hazo_user_relationships_parent ON hazo_user_relationships(parent_user_id);
|
|
689
|
+
CREATE INDEX idx_hazo_user_relationships_child ON hazo_user_relationships(child_user_id);
|
|
690
|
+
|
|
691
|
+
-- 11. Built-in firm_admin role (used when a user creates their first firm)
|
|
692
|
+
INSERT INTO hazo_roles (id, role_name, created_at, changed_at)
|
|
693
|
+
VALUES (gen_random_uuid(), 'firm_admin', NOW(), NOW())
|
|
694
|
+
ON CONFLICT (role_name) DO NOTHING;
|
|
549
695
|
```
|
|
550
696
|
|
|
697
|
+
> **Migrating from v4.x?** The legacy `hazo_org`, `hazo_scopes_l1..l7`, and `hazo_user_roles` tables have been removed. Run `migrations/009_scope_consolidation.sql` against your existing database — it drops the old tables and creates the new schema in place.
|
|
698
|
+
|
|
551
699
|
**Verify PostgreSQL tables:**
|
|
552
700
|
```sql
|
|
553
|
-
SELECT table_name FROM information_schema.tables
|
|
554
|
-
|
|
701
|
+
SELECT table_name FROM information_schema.tables
|
|
702
|
+
WHERE table_schema = 'public' AND table_name LIKE 'hazo_%'
|
|
703
|
+
ORDER BY table_name;
|
|
704
|
+
-- Expected (9 tables):
|
|
705
|
+
-- hazo_invitations, hazo_permissions, hazo_refresh_tokens, hazo_role_permissions,
|
|
706
|
+
-- hazo_roles, hazo_scopes, hazo_users, hazo_user_relationships, hazo_user_scopes
|
|
555
707
|
```
|
|
556
708
|
|
|
557
709
|
**Grant access to admin user:**
|
|
@@ -565,16 +717,19 @@ GRANT USAGE ON SCHEMA public TO your_admin_user;
|
|
|
565
717
|
-- Grant all privileges on all hazo_* tables
|
|
566
718
|
GRANT ALL PRIVILEGES ON TABLE hazo_users TO your_admin_user;
|
|
567
719
|
GRANT ALL PRIVILEGES ON TABLE hazo_refresh_tokens TO your_admin_user;
|
|
568
|
-
GRANT ALL PRIVILEGES ON TABLE hazo_permissions TO your_admin_user;
|
|
569
720
|
GRANT ALL PRIVILEGES ON TABLE hazo_roles TO your_admin_user;
|
|
721
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_permissions TO your_admin_user;
|
|
570
722
|
GRANT ALL PRIVILEGES ON TABLE hazo_role_permissions TO your_admin_user;
|
|
571
|
-
GRANT ALL PRIVILEGES ON TABLE
|
|
723
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes TO your_admin_user;
|
|
724
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_user_scopes TO your_admin_user;
|
|
725
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_invitations TO your_admin_user;
|
|
726
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_user_relationships TO your_admin_user;
|
|
572
727
|
|
|
573
|
-
-- Grant usage on
|
|
728
|
+
-- Grant usage on enum types
|
|
574
729
|
GRANT USAGE ON TYPE hazo_enum_profile_source_enum TO your_admin_user;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
730
|
+
GRANT USAGE ON TYPE hazo_enum_user_status TO your_admin_user;
|
|
731
|
+
GRANT USAGE ON TYPE hazo_enum_user_scope_status_type TO your_admin_user;
|
|
732
|
+
GRANT USAGE ON TYPE hazo_enum_invitation_status TO your_admin_user;
|
|
578
733
|
|
|
579
734
|
-- Optional: Grant privileges on future tables (if you plan to add more hazo_* tables)
|
|
580
735
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO your_admin_user;
|
|
@@ -598,7 +753,7 @@ GRANT SELECT ON TABLE hazo_users TO anon;
|
|
|
598
753
|
GRANT SELECT ON TABLE hazo_permissions TO anon;
|
|
599
754
|
GRANT SELECT ON TABLE hazo_roles TO anon;
|
|
600
755
|
GRANT SELECT ON TABLE hazo_role_permissions TO anon;
|
|
601
|
-
GRANT SELECT ON TABLE
|
|
756
|
+
GRANT SELECT ON TABLE hazo_scopes TO anon;
|
|
602
757
|
|
|
603
758
|
-- Grant full access to authenticated users (adjust based on your RLS policies)
|
|
604
759
|
GRANT ALL PRIVILEGES ON TABLE hazo_users TO authenticated;
|
|
@@ -606,30 +761,39 @@ GRANT ALL PRIVILEGES ON TABLE hazo_refresh_tokens TO authenticated;
|
|
|
606
761
|
GRANT ALL PRIVILEGES ON TABLE hazo_permissions TO authenticated;
|
|
607
762
|
GRANT ALL PRIVILEGES ON TABLE hazo_roles TO authenticated;
|
|
608
763
|
GRANT ALL PRIVILEGES ON TABLE hazo_role_permissions TO authenticated;
|
|
609
|
-
GRANT ALL PRIVILEGES ON TABLE
|
|
764
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes TO authenticated;
|
|
765
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_user_scopes TO authenticated;
|
|
766
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_invitations TO authenticated;
|
|
767
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_user_relationships TO authenticated;
|
|
610
768
|
|
|
611
|
-
-- Grant usage on enum
|
|
769
|
+
-- Grant usage on enum types
|
|
612
770
|
GRANT USAGE ON TYPE hazo_enum_profile_source_enum TO anon, authenticated;
|
|
771
|
+
GRANT USAGE ON TYPE hazo_enum_user_status TO anon, authenticated;
|
|
772
|
+
GRANT USAGE ON TYPE hazo_enum_user_scope_status_type TO anon, authenticated;
|
|
773
|
+
GRANT USAGE ON TYPE hazo_enum_invitation_status TO anon, authenticated;
|
|
613
774
|
```
|
|
614
775
|
|
|
615
776
|
**Checklist:**
|
|
616
777
|
- [ ] Database created (SQLite file or PostgreSQL)
|
|
617
778
|
- [ ] All enum types created (PostgreSQL only):
|
|
618
779
|
- [ ] `hazo_enum_profile_source_enum`
|
|
619
|
-
- [ ] `
|
|
620
|
-
- [ ] `
|
|
621
|
-
- [ ] `
|
|
622
|
-
|
|
623
|
-
- [ ] `
|
|
624
|
-
- [ ] `hazo_enum_chat_type`
|
|
625
|
-
- [ ] All core tables exist:
|
|
626
|
-
- [ ] `hazo_org` (multi-tenancy - must be created before hazo_users)
|
|
627
|
-
- [ ] `hazo_users` (with status, google_id, auth_providers, app_user_data, org_id, root_org_id, user_type fields)
|
|
780
|
+
- [ ] `hazo_enum_user_status`
|
|
781
|
+
- [ ] `hazo_enum_user_scope_status_type`
|
|
782
|
+
- [ ] `hazo_enum_invitation_status`
|
|
783
|
+
- [ ] All core tables exist (9 total):
|
|
784
|
+
- [ ] `hazo_users` (with `status`, `google_id`, `auth_providers`, `app_user_data`, `user_type`, `managed_by_user_id`, `pin_hash` fields)
|
|
628
785
|
- [ ] `hazo_refresh_tokens`
|
|
629
|
-
- [ ] `hazo_permissions`
|
|
630
786
|
- [ ] `hazo_roles`
|
|
631
|
-
- [ ] `
|
|
632
|
-
- [ ] `
|
|
787
|
+
- [ ] `hazo_permissions`
|
|
788
|
+
- [ ] `hazo_role_permissions` (composite PK, no `id` column)
|
|
789
|
+
- [ ] `hazo_scopes` (unified hierarchy with branding + `slug`)
|
|
790
|
+
- [ ] `hazo_user_scopes` (composite PK on `user_id`, `scope_id`)
|
|
791
|
+
- [ ] `hazo_invitations`
|
|
792
|
+
- [ ] `hazo_user_relationships` (managed sub-profile parent/child links)
|
|
793
|
+
- [ ] Reserved system scopes inserted:
|
|
794
|
+
- [ ] `00000000-0000-0000-0000-000000000000` (Super Admin)
|
|
795
|
+
- [ ] `00000000-0000-0000-0000-000000000001` (System / non-multi-tenancy default)
|
|
796
|
+
- [ ] `firm_admin` role inserted into `hazo_roles`
|
|
633
797
|
|
|
634
798
|
---
|
|
635
799
|
|
|
@@ -1439,7 +1603,9 @@ application_permission_list_defaults = admin_user_management,admin_role_manageme
|
|
|
1439
1603
|
|
|
1440
1604
|
### Step 7.3: Create HRBAC Database Tables
|
|
1441
1605
|
|
|
1442
|
-
**
|
|
1606
|
+
> **Note (v5.0+):** `hazo_scopes`, `hazo_user_scopes`, and `hazo_invitations` are now part of the **core schema** in Phase 3. If you ran the canonical SQLite or PostgreSQL script there (or `npx hazo_auth init-db`), these tables already exist — you can skip ahead to Step 7.4. The scripts below are kept for upgrades from v4.x or for partial recovery.
|
|
1607
|
+
|
|
1608
|
+
**Upgrading from v4.x?** Run the consolidation migration which drops the legacy tables (`hazo_org`, `hazo_scopes_l1..l7`, `hazo_user_roles`) and creates the new schema:
|
|
1443
1609
|
|
|
1444
1610
|
```bash
|
|
1445
1611
|
npm run migrate migrations/009_scope_consolidation.sql
|
|
@@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS hazo_users (
|
|
|
12
12
|
email_address TEXT NOT NULL UNIQUE,
|
|
13
13
|
password_hash TEXT,
|
|
14
14
|
name TEXT,
|
|
15
|
-
email_verified
|
|
15
|
+
email_verified BOOLEAN DEFAULT false,
|
|
16
16
|
login_attempts INTEGER DEFAULT 0,
|
|
17
17
|
last_logon TEXT,
|
|
18
18
|
profile_picture_url TEXT,
|
|
@@ -35,10 +35,15 @@ CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
|
35
35
|
CREATE INDEX IF NOT EXISTS idx_hazo_users_status ON hazo_users(status);
|
|
36
36
|
|
|
37
37
|
-- Refresh tokens table
|
|
38
|
+
-- Note: runtime (token_service.ts) writes token_hash (argon2-hashed value) on
|
|
39
|
+
-- insert and verifies via argon2.verify(token_hash, plaintext_token) on read.
|
|
40
|
+
-- The plaintext "token" column is retained nullable for legacy compatibility
|
|
41
|
+
-- but new writes only set token_hash.
|
|
38
42
|
CREATE TABLE IF NOT EXISTS hazo_refresh_tokens (
|
|
39
43
|
id TEXT PRIMARY KEY,
|
|
40
44
|
user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
41
|
-
token TEXT
|
|
45
|
+
token TEXT UNIQUE,
|
|
46
|
+
token_hash TEXT,
|
|
42
47
|
token_type TEXT DEFAULT 'refresh',
|
|
43
48
|
expires_at TEXT NOT NULL,
|
|
44
49
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
@@ -46,6 +51,7 @@ CREATE TABLE IF NOT EXISTS hazo_refresh_tokens (
|
|
|
46
51
|
|
|
47
52
|
CREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_user ON hazo_refresh_tokens(user_id);
|
|
48
53
|
CREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token ON hazo_refresh_tokens(token);
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token_hash ON hazo_refresh_tokens(token_hash);
|
|
49
55
|
|
|
50
56
|
-- Roles table
|
|
51
57
|
CREATE TABLE IF NOT EXISTS hazo_roles (
|
|
@@ -145,10 +151,10 @@ CREATE TABLE IF NOT EXISTS hazo_user_relationships (
|
|
|
145
151
|
parent_user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
146
152
|
child_user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
147
153
|
relationship_type TEXT NOT NULL DEFAULT 'parent',
|
|
148
|
-
can_view_progress
|
|
149
|
-
can_edit_profile
|
|
150
|
-
can_delete
|
|
151
|
-
is_self
|
|
154
|
+
can_view_progress BOOLEAN DEFAULT true,
|
|
155
|
+
can_edit_profile BOOLEAN DEFAULT true,
|
|
156
|
+
can_delete BOOLEAN DEFAULT false,
|
|
157
|
+
is_self BOOLEAN DEFAULT false,
|
|
152
158
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
153
159
|
UNIQUE(parent_user_id, child_user_id)
|
|
154
160
|
);
|