Skip to content

Commit 717b451

Browse files
Merge pull request #10 from pierrick-fonquerne/develop
Develop
2 parents b6b6e0e + a11ab4d commit 717b451

File tree

72 files changed

+7601
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+7601
-0
lines changed

.github/workflows/ci.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
pull_request:
7+
branches: [main, develop]
8+
9+
jobs:
10+
backend:
11+
name: Backend (.NET)
12+
runs-on: ubuntu-latest
13+
defaults:
14+
run:
15+
working-directory: src/backend
16+
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Check if backend exists
22+
id: check
23+
run: |
24+
if find . -name "*.sln" -o -name "*.csproj" 2>/dev/null | grep -q .; then
25+
echo "exists=true" >> $GITHUB_OUTPUT
26+
else
27+
echo "exists=false" >> $GITHUB_OUTPUT
28+
fi
29+
working-directory: src/backend
30+
31+
- name: Setup .NET
32+
if: steps.check.outputs.exists == 'true'
33+
uses: actions/setup-dotnet@v4
34+
with:
35+
dotnet-version: '8.0.x'
36+
37+
- name: Restore dependencies
38+
if: steps.check.outputs.exists == 'true'
39+
run: dotnet restore
40+
41+
- name: Build
42+
if: steps.check.outputs.exists == 'true'
43+
run: dotnet build --no-restore --configuration Release
44+
45+
- name: Test
46+
if: steps.check.outputs.exists == 'true'
47+
run: dotnet test --no-build --configuration Release --verbosity normal --filter "Category!=Email"
48+
49+
- name: Skip (no backend yet)
50+
if: steps.check.outputs.exists == 'false'
51+
run: echo "Backend not yet implemented - skipping"
52+
53+
frontend:
54+
name: Frontend (React)
55+
runs-on: ubuntu-latest
56+
defaults:
57+
run:
58+
working-directory: src/frontend
59+
60+
steps:
61+
- name: Checkout
62+
uses: actions/checkout@v4
63+
64+
- name: Check if frontend exists
65+
id: check
66+
run: |
67+
if [ -f "package.json" ]; then
68+
echo "exists=true" >> $GITHUB_OUTPUT
69+
else
70+
echo "exists=false" >> $GITHUB_OUTPUT
71+
fi
72+
working-directory: src/frontend
73+
74+
- name: Setup Node.js
75+
if: steps.check.outputs.exists == 'true'
76+
uses: actions/setup-node@v4
77+
with:
78+
node-version: '20'
79+
cache: 'npm'
80+
cache-dependency-path: src/frontend/package-lock.json
81+
82+
- name: Install dependencies
83+
if: steps.check.outputs.exists == 'true'
84+
run: npm ci
85+
86+
- name: Lint
87+
if: steps.check.outputs.exists == 'true'
88+
run: npm run lint
89+
90+
- name: Type check
91+
if: steps.check.outputs.exists == 'true'
92+
run: npm run type-check
93+
94+
- name: Build
95+
if: steps.check.outputs.exists == 'true'
96+
run: npm run build
97+
98+
- name: Test
99+
if: steps.check.outputs.exists == 'true'
100+
run: npm run test -- --passWithNoTests
101+
102+
- name: Skip (no frontend yet)
103+
if: steps.check.outputs.exists == 'false'
104+
run: echo "Frontend not yet implemented - skipping"

.github/workflows/pr-main.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: PR to Main Validation
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
jobs:
8+
validate-source-branch:
9+
name: Validate source branch
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Check source branch
14+
run: |
15+
echo "PR: ${{ github.head_ref }} -> ${{ github.base_ref }}"
16+
17+
if [ "${{ github.head_ref }}" != "develop" ]; then
18+
echo ""
19+
echo "=============================================="
20+
echo "ERROR: Only 'develop' can be merged into 'main'"
21+
echo "=============================================="
22+
echo ""
23+
echo "Source branch: ${{ github.head_ref }}"
24+
echo "Target branch: ${{ github.base_ref }}"
25+
echo ""
26+
echo "Please create a PR from 'develop' to 'main' instead."
27+
echo ""
28+
exit 1
29+
fi
30+
31+
echo ""
32+
echo "=============================================="
33+
echo "OK: PR from 'develop' to 'main' is valid"
34+
echo "=============================================="

database/sql/001_create_tables.sql

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
-- ============================================================================
2+
-- FantasyRealm Character Manager - Database Schema
3+
-- PostgreSQL 15+
4+
-- ============================================================================
5+
6+
-- ============================================================================
7+
-- TABLE: role
8+
-- User roles for authorization (user, employee, admin)
9+
-- ============================================================================
10+
CREATE TABLE role (
11+
id SERIAL PRIMARY KEY,
12+
label VARCHAR(50) NOT NULL UNIQUE
13+
);
14+
15+
-- ============================================================================
16+
-- TABLE: user
17+
-- Registered users of the application
18+
-- ============================================================================
19+
CREATE TABLE "user" (
20+
id SERIAL PRIMARY KEY,
21+
pseudo VARCHAR(50) NOT NULL UNIQUE,
22+
email VARCHAR(100) NOT NULL UNIQUE,
23+
password_hash VARCHAR(255) NOT NULL,
24+
is_suspended BOOLEAN NOT NULL DEFAULT FALSE,
25+
must_change_password BOOLEAN NOT NULL DEFAULT FALSE,
26+
role_id INTEGER NOT NULL REFERENCES role(id)
27+
);
28+
29+
CREATE INDEX idx_user_email ON "user"(email);
30+
CREATE INDEX idx_user_pseudo ON "user"(pseudo);
31+
32+
-- ============================================================================
33+
-- TABLE: character
34+
-- Player characters created by users
35+
-- ============================================================================
36+
CREATE TABLE character (
37+
id SERIAL PRIMARY KEY,
38+
name VARCHAR(50) NOT NULL,
39+
gender VARCHAR(20) NOT NULL CHECK (gender IN ('male', 'female')),
40+
skin_color VARCHAR(7) NOT NULL,
41+
eye_color VARCHAR(7) NOT NULL,
42+
hair_color VARCHAR(7) NOT NULL,
43+
eye_shape VARCHAR(50) NOT NULL,
44+
nose_shape VARCHAR(50) NOT NULL,
45+
mouth_shape VARCHAR(50) NOT NULL,
46+
image TEXT,
47+
is_shared BOOLEAN NOT NULL DEFAULT FALSE,
48+
is_authorized BOOLEAN NOT NULL DEFAULT FALSE,
49+
user_id INTEGER NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
50+
51+
CONSTRAINT uq_character_name_per_user UNIQUE (name, user_id)
52+
);
53+
54+
CREATE INDEX idx_character_user_id ON character(user_id);
55+
56+
-- ============================================================================
57+
-- TABLE: article
58+
-- Customization items (clothing, armor, weapons, accessories)
59+
-- ============================================================================
60+
CREATE TABLE article (
61+
id SERIAL PRIMARY KEY,
62+
name VARCHAR(100) NOT NULL,
63+
type VARCHAR(20) NOT NULL CHECK (type IN ('clothing', 'armor', 'weapon', 'accessory')),
64+
image TEXT,
65+
is_active BOOLEAN NOT NULL DEFAULT TRUE
66+
);
67+
68+
CREATE INDEX idx_article_type ON article(type);
69+
CREATE INDEX idx_article_is_active ON article(is_active);
70+
71+
-- ============================================================================
72+
-- TABLE: character_article
73+
-- Many-to-many relationship between characters and equipped articles
74+
-- ============================================================================
75+
CREATE TABLE character_article (
76+
character_id INTEGER NOT NULL REFERENCES character(id) ON DELETE CASCADE,
77+
article_id INTEGER NOT NULL REFERENCES article(id) ON DELETE CASCADE,
78+
79+
PRIMARY KEY (character_id, article_id)
80+
);
81+
82+
-- ============================================================================
83+
-- TABLE: comment
84+
-- User reviews on shared characters
85+
-- ============================================================================
86+
CREATE TABLE comment (
87+
id SERIAL PRIMARY KEY,
88+
rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
89+
text TEXT NOT NULL,
90+
status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'approved')),
91+
commented_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
92+
character_id INTEGER NOT NULL REFERENCES character(id) ON DELETE CASCADE,
93+
author_id INTEGER NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
94+
95+
CONSTRAINT uq_one_comment_per_user_per_character UNIQUE (character_id, author_id)
96+
);
97+
98+
CREATE INDEX idx_comment_character_id ON comment(character_id);
99+
CREATE INDEX idx_comment_author_id ON comment(author_id);
100+
CREATE INDEX idx_comment_status ON comment(status);

database/sql/002_seed_data.sql

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
-- ============================================================================
2+
-- FantasyRealm Character Manager - Seed Data
3+
-- PostgreSQL 15+
4+
-- ============================================================================
5+
6+
-- ============================================================================
7+
-- ROLES
8+
-- ============================================================================
9+
INSERT INTO role (label) VALUES
10+
('user'),
11+
('employee'),
12+
('admin');
13+
14+
-- ============================================================================
15+
-- ADMIN USER
16+
-- Password: Admin123! (BCrypt hash)
17+
-- ============================================================================
18+
INSERT INTO "user" (pseudo, email, password_hash, role_id) VALUES
19+
('admin', 'admin@fantasyrealm.com', '$2a$11$rBVcQ4z4.vYZ3mQlJXqKaeKxNJqX5vYxJqKqYQ5ZJ8z5X5X5X5X5q', (SELECT id FROM role WHERE label = 'admin'));
20+
21+
-- ============================================================================
22+
-- EMPLOYEE USER (for testing moderation)
23+
-- Password: Employee123!
24+
-- ============================================================================
25+
INSERT INTO "user" (pseudo, email, password_hash, role_id) VALUES
26+
('moderator', 'moderator@fantasyrealm.com', '$2a$11$rBVcQ4z4.vYZ3mQlJXqKaeKxNJqX5vYxJqKqYQ5ZJ8z5X5X5X5X5q', (SELECT id FROM role WHERE label = 'employee'));
27+
28+
-- ============================================================================
29+
-- TEST USERS
30+
-- Password: Test123!
31+
-- ============================================================================
32+
INSERT INTO "user" (pseudo, email, password_hash, role_id) VALUES
33+
('player_one', 'player1@test.com', '$2a$11$rBVcQ4z4.vYZ3mQlJXqKaeKxNJqX5vYxJqKqYQ5ZJ8z5X5X5X5X5q', (SELECT id FROM role WHERE label = 'user')),
34+
('dragon_slayer', 'player2@test.com', '$2a$11$rBVcQ4z4.vYZ3mQlJXqKaeKxNJqX5vYxJqKqYQ5ZJ8z5X5X5X5X5q', (SELECT id FROM role WHERE label = 'user')),
35+
('mystic_mage', 'player3@test.com', '$2a$11$rBVcQ4z4.vYZ3mQlJXqKaeKxNJqX5vYxJqKqYQ5ZJ8z5X5X5X5X5q', (SELECT id FROM role WHERE label = 'user'));
36+
37+
-- ============================================================================
38+
-- ARTICLES - Clothing
39+
-- ============================================================================
40+
INSERT INTO article (name, type, image) VALUES
41+
('Apprentice Robe', 'clothing', NULL),
42+
('Leather Tunic', 'clothing', NULL),
43+
('Noble Vest', 'clothing', NULL),
44+
('Traveler Cloak', 'clothing', NULL),
45+
('Silk Dress', 'clothing', NULL);
46+
47+
-- ============================================================================
48+
-- ARTICLES - Armor
49+
-- ============================================================================
50+
INSERT INTO article (name, type, image) VALUES
51+
('Iron Chestplate', 'armor', NULL),
52+
('Steel Helmet', 'armor', NULL),
53+
('Dragon Scale Armor', 'armor', NULL),
54+
('Mithril Chainmail', 'armor', NULL),
55+
('Guardian Shield', 'armor', NULL);
56+
57+
-- ============================================================================
58+
-- ARTICLES - Weapons
59+
-- ============================================================================
60+
INSERT INTO article (name, type, image) VALUES
61+
('Iron Sword', 'weapon', NULL),
62+
('Oak Staff', 'weapon', NULL),
63+
('Elven Bow', 'weapon', NULL),
64+
('Battle Axe', 'weapon', NULL),
65+
('Enchanted Dagger', 'weapon', NULL);
66+
67+
-- ============================================================================
68+
-- ARTICLES - Accessories
69+
-- ============================================================================
70+
INSERT INTO article (name, type, image) VALUES
71+
('Ruby Amulet', 'accessory', NULL),
72+
('Silver Ring', 'accessory', NULL),
73+
('Leather Belt', 'accessory', NULL),
74+
('Explorer Backpack', 'accessory', NULL),
75+
('Golden Crown', 'accessory', NULL);
76+
77+
-- ============================================================================
78+
-- TEST CHARACTERS (authorized and shared for gallery demo)
79+
-- ============================================================================
80+
INSERT INTO character (name, gender, skin_color, eye_color, hair_color, eye_shape, nose_shape, mouth_shape, is_shared, is_authorized, user_id) VALUES
81+
('Thorin', 'male', '#E8BEAC', '#4A90D9', '#2C1810', 'almond', 'aquiline', 'thin', TRUE, TRUE, (SELECT id FROM "user" WHERE pseudo = 'player_one')),
82+
('Elara', 'female', '#F5DEB3', '#50C878', '#FFD700', 'round', 'straight', 'full', TRUE, TRUE, (SELECT id FROM "user" WHERE pseudo = 'dragon_slayer')),
83+
('Zephyr', 'male', '#8D5524', '#8B4513', '#000000', 'narrow', 'wide', 'medium', TRUE, TRUE, (SELECT id FROM "user" WHERE pseudo = 'mystic_mage'));
84+
85+
-- ============================================================================
86+
-- TEST CHARACTER (pending moderation)
87+
-- ============================================================================
88+
INSERT INTO character (name, gender, skin_color, eye_color, hair_color, eye_shape, nose_shape, mouth_shape, is_shared, is_authorized, user_id) VALUES
89+
('Shadow', 'male', '#3D2314', '#FF0000', '#1C1C1C', 'narrow', 'pointed', 'thin', FALSE, FALSE, (SELECT id FROM "user" WHERE pseudo = 'player_one'));
90+
91+
-- ============================================================================
92+
-- EQUIP ARTICLES TO CHARACTERS
93+
-- ============================================================================
94+
INSERT INTO character_article (character_id, article_id) VALUES
95+
((SELECT id FROM character WHERE name = 'Thorin'), (SELECT id FROM article WHERE name = 'Iron Chestplate')),
96+
((SELECT id FROM character WHERE name = 'Thorin'), (SELECT id FROM article WHERE name = 'Iron Sword')),
97+
((SELECT id FROM character WHERE name = 'Thorin'), (SELECT id FROM article WHERE name = 'Leather Belt')),
98+
((SELECT id FROM character WHERE name = 'Elara'), (SELECT id FROM article WHERE name = 'Silk Dress')),
99+
((SELECT id FROM character WHERE name = 'Elara'), (SELECT id FROM article WHERE name = 'Elven Bow')),
100+
((SELECT id FROM character WHERE name = 'Elara'), (SELECT id FROM article WHERE name = 'Ruby Amulet')),
101+
((SELECT id FROM character WHERE name = 'Zephyr'), (SELECT id FROM article WHERE name = 'Apprentice Robe')),
102+
((SELECT id FROM character WHERE name = 'Zephyr'), (SELECT id FROM article WHERE name = 'Oak Staff')),
103+
((SELECT id FROM character WHERE name = 'Zephyr'), (SELECT id FROM article WHERE name = 'Silver Ring'));
104+
105+
-- ============================================================================
106+
-- TEST COMMENTS (approved)
107+
-- ============================================================================
108+
INSERT INTO comment (rating, text, status, character_id, author_id) VALUES
109+
(5, 'Amazing warrior design! Love the armor combo.', 'approved', (SELECT id FROM character WHERE name = 'Thorin'), (SELECT id FROM "user" WHERE pseudo = 'dragon_slayer')),
110+
(4, 'Beautiful elven character, very elegant!', 'approved', (SELECT id FROM character WHERE name = 'Elara'), (SELECT id FROM "user" WHERE pseudo = 'player_one')),
111+
(5, 'The mage aesthetic is perfect!', 'approved', (SELECT id FROM character WHERE name = 'Zephyr'), (SELECT id FROM "user" WHERE pseudo = 'dragon_slayer'));
112+
113+
-- ============================================================================
114+
-- TEST COMMENT (pending moderation)
115+
-- ============================================================================
116+
INSERT INTO comment (rating, text, status, character_id, author_id) VALUES
117+
(3, 'Nice but could use more accessories.', 'pending', (SELECT id FROM character WHERE name = 'Thorin'), (SELECT id FROM "user" WHERE pseudo = 'mystic_mage'));

railway.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Railway configuration
2+
# Backend deployment will be configured in a future US
3+
# For now, skip automatic builds to prevent CI failures
4+
5+
[build]
6+
builder = "nixpacks"
7+
buildCommand = "echo 'Backend deployment not configured yet - skipping build'"
8+
9+
[deploy]
10+
startCommand = "echo 'Backend not deployed' && sleep infinity"

0 commit comments

Comments
 (0)