wiki:UseCase0000PrototypeImplementationDB

UseCase: Регистрација на корисник

Актер

Ненајавен корисник

Цел

Корисникот сака да се регистрира во системот.

Предуслов: измени во DDL

Регистрацијата е двофазна — прво се создава корисник само со мејл и лозинка, а личните податоци се пополнуваат подоцна. Во моменталната шема name, work_position и company_size се NOT NULL, што го прави тоа невозможно. Истото важи и за account.name.

ALTER TABLE account ALTER COLUMN name          DROP NOT NULL;
ALTER TABLE "user"  ALTER COLUMN name          DROP NOT NULL;
ALTER TABLE "user"  ALTER COLUMN work_position DROP NOT NULL;
ALTER TABLE "user"  ALTER COLUMN company_size  DROP NOT NULL;

-- is_profile_complete = true значи дека сите полиња се пополнети
ALTER TABLE "user" ADD CONSTRAINT ck_user_profile_complete CHECK (
    NOT is_profile_complete
    OR (name IS NOT NULL AND work_position IS NOT NULL AND company_size IS NOT NULL)
);

Главен тек

  • На корисникот му се прикажува почетната страна на Shifter

  • На корисникот му се прикажува страната за регистрација

  • Корисникот ги пополнува полињата за регистрација и кликнува на копчето Create Account

  • На корисникот му се прикажува порака за успешно испратен линк за потврда на неговата мејл адресата. Во базата се креира сметка, иницијален корисник и верификациски токен.
BEGIN;

WITH new_account AS (
    INSERT INTO account (email, password_hash, name)
    VALUES ('borjan.gjorgjievski@students.finki.ukim.mk',
            'hashed_password_example',
            NULL)
    RETURNING id
),
new_user AS (
    INSERT INTO "user" (account_id,
                        email,
                        password_hash,
                        login_provider,
                        is_verified,
                        is_profile_complete,
                        has_used_free_consultation,
                        points)
    SELECT id,
           'borjan.gjorgjievski@students.finki.ukim.mk',
           'hashed_password_example',
           'local',
           FALSE,
           FALSE,
           FALSE,
           0
    FROM new_account
    RETURNING user_id
)
INSERT INTO verification_token (verification_token_uuid, user_id, created_at, expires_at)
SELECT 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid,
       user_id,
       CURRENT_TIMESTAMP,
       CURRENT_TIMESTAMP + INTERVAL '30 minutes'
FROM new_user;

COMMIT;

  • При клик на линкот кој е испратен до неговата мејл адреса, токенот се проверува и корисникот се означува како верификуван.
BEGIN;

WITH valid_token AS (
    SELECT user_id
    FROM verification_token
    WHERE verification_token_uuid = 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid
      AND expires_at > CURRENT_TIMESTAMP
)
UPDATE "user" u
SET is_verified = TRUE
FROM valid_token vt
WHERE u.user_id = vt.user_id;

-- искористениот токен повеќе не е потребен
DELETE FROM verification_token
WHERE verification_token_uuid = 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid;

COMMIT;
  • На корисникот му се прикажува страната за персонализација

  • Корисникот ги пополнува полињата за персонализација и кликнува на копчето Start Using Shifter. Во базата се ажурираат полињата за персонализација.
BEGIN;

UPDATE "user"
SET name                = 'Borjan Gjorgjievski',
    work_position       = 'Sales & Digital Solutions',
    company_size        = 'freelance',
    is_profile_complete = TRUE
WHERE user_id = :user_id;

-- account.name е дупликат на "user".name и мора да се одржува рачно
UPDATE account
SET name = 'Borjan Gjorgjievski'
WHERE id = (SELECT account_id FROM "user" WHERE user_id = :user_id);

COMMIT;

  • На корисникот му се прикажува почетната страна на Shifter, каде тој е веќе логиран

Алтернативен тек

  • Доколку веќе постои корисник со истата емаил адреса, при обид за регистрација му се прикажува порака за грешка на корисникот.
SELECT EXISTS (
    SELECT 1
    FROM account
    WHERE email = 'borjan.gjorgjievski@students.finki.ukim.mk'
) AS email_taken;

Ограничувањата uq_account_email и uq_user_email го спречуваат дуплирањето и на ниво на база, па апликацијата мора да ја фати грешката 23505 доколку два барања стигнат истовремено.

  • Доколку на корисникот му истекол токенот за валидација на неговата емаил адреса, тогаш откако ќе го кликне линкот за валидација ќе му се прикаже порака дека токенот е истечен и копче за повторно испраќање на нов токен за валидација.
-- проверка на статусот на токенот
SELECT user_id,
       expires_at,
       (expires_at > CURRENT_TIMESTAMP) AS is_valid
FROM verification_token
WHERE verification_token_uuid = 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid;

-- повторно испраќање: старите токени се бришат, се креира нов
BEGIN;

DELETE FROM verification_token
WHERE user_id = :user_id;

INSERT INTO verification_token (user_id, created_at, expires_at)
VALUES (:user_id,
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP + INTERVAL '30 minutes')
RETURNING verification_token_uuid;

COMMIT;

Забелешки

  • company_size е PostgreSQL enum со мали букви (freelance, micro, small, medium, mid_market, enterprise, other). Вредноста 'Freelance' предизвикува грешка.
  • Шемата нема колона deleted на "user" — не постои soft delete.
  • email и password_hash постојат и во account и во "user". Регистрацијата ги запишува двапати, а секоја промена на лозинка мора да ажурира две табели. Ова треба да се реши на ниво на шема.
  • При повторно испраќање на токен, gen_random_uuid() го генерира UUID-то автоматски — не треба да се внесува рачно.
Last modified 23 hours ago Last modified on 08/05/26 22:21:22

Attachments (8)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.