Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/assets/readme-header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up Node 22
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Verify OSS brand sources
run: node scripts/check-brand-assets.mjs

- name: Set up Java 21 (GraalVM CE)
uses: graalvm/setup-graalvm@v1
with:
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v6

- name: Set up Node 22
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Verify OSS brand sources
run: node scripts/check-brand-assets.mjs

# The build's Java toolchain pins vendor = GraalVM (build.gradle.kts), so the
# runner must provide a GraalVM JDK 21 — a temurin JDK makes Gradle fail with
# "Cannot find a Java installation … matching {vendor=GraalVM Community}".
Expand Down
6 changes: 6 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# devslab-kit

<p align="center">
<a href="https://devslab.kr/brand/open-source/"><img src=".github/assets/readme-header.png" alt="devslab-kit - DevsLab 오픈소스" width="100%" /></a>
</p>

**[DevsLab](https://devslab.kr/) 오픈소스** · [OSS 브랜드 가이드](https://devslab.kr/brand/open-source/) · 레지스트리 O10

[![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/devslab-kit-spring-boot-starter?logo=apachemaven)](https://central.sonatype.com/artifact/kr.devslab/devslab-kit-spring-boot-starter)
[![Build](https://github.com/devslab-kr/devslab-kit/actions/workflows/build.yml/badge.svg)](https://github.com/devslab-kr/devslab-kit/actions/workflows/build.yml)
[![codecov](https://codecov.io/gh/devslab-kr/devslab-kit/branch/main/graph/badge.svg)](https://codecov.io/gh/devslab-kr/devslab-kit)
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# devslab-kit

<p align="center">
<a href="https://devslab.kr/brand/open-source/"><img src=".github/assets/readme-header.png" alt="devslab-kit - Open source by DevsLab" width="100%" /></a>
</p>

**Open source by [DevsLab](https://devslab.kr/)** · [OSS brand guide](https://devslab.kr/brand/open-source/) · Registry O10

[![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/devslab-kit-spring-boot-starter?logo=apachemaven)](https://central.sonatype.com/artifact/kr.devslab/devslab-kit-spring-boot-starter)
[![Build](https://github.com/devslab-kr/devslab-kit/actions/workflows/build.yml/badge.svg)](https://github.com/devslab-kr/devslab-kit/actions/workflows/build.yml)
[![codecov](https://codecov.io/gh/devslab-kr/devslab-kit/branch/main/graph/badge.svg)](https://codecov.io/gh/devslab-kr/devslab-kit)
Expand Down
1 change: 1 addition & 0 deletions docs/assets/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions docs/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/index.ko.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# devslab-kit

<a class="oss-project-intro" data-atmosphere="project" href="https://devslab.kr/brand/open-source/" aria-label="devslab-kit, DevsLab 오픈소스. DevsLab OSS 브랜드 가이드 보기.">
<img src="assets/logo.svg" alt="" aria-hidden="true">
<span><strong>devslab-kit</strong><small>DevsLab 오픈소스</small></span>
</a>

재사용 가능한 **Spring Boot 4 플랫폼 스타터**. 애플리케이션에 끼워 넣으면 인증, 인가,
멀티테넌시, 동적 메뉴, 감사 로깅이 자동 구성으로 제공되고, 관리자 REST API와 바로 쓰는
관리자 콘솔까지 딸려옵니다. 매번 플랫폼 계층을 다시 만드는 대신 각 제품은 자기 도메인에만
Expand Down
5 changes: 5 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# devslab-kit

<a class="oss-project-intro" data-atmosphere="project" href="https://devslab.kr/brand/open-source/" aria-label="devslab-kit, Open source by DevsLab. Read the DevsLab OSS brand guide.">
<img src="assets/logo.svg" alt="" aria-hidden="true">
<span><strong>devslab-kit</strong><small>Open source by DevsLab</small></span>
</a>

A reusable **Spring Boot 4 platform starter**. Drop it into an application and get
authentication, authorization, multi-tenancy, dynamic menus and audit logging from
auto-configuration — plus an admin REST API and a ready-made admin console — so each
Expand Down
10 changes: 10 additions & 0 deletions docs/overrides/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% extends "base.html" %}

{% block site_meta %}
{{ super() }}
<meta property="og:image" content="https://devslab-kit.devslab.kr/assets/social-preview.png">
<meta property="og:image:alt" content="devslab-kit, Open source by DevsLab">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://devslab-kit.devslab.kr/assets/social-preview.png">
<meta name="twitter:image:alt" content="devslab-kit, Open source by DevsLab">
{% endblock %}
69 changes: 69 additions & 0 deletions docs/stylesheets/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,72 @@ html[lang="ko"] .md-header [aria-label="Select language"]::before,
html[lang="ko"] .md-header [aria-label*="언어"]::before {
content: "한";
}

/* === O10 project identity =============================================== */
.oss-project-intro {
position: relative;
isolation: isolate;
display: flex;
align-items: center;
gap: 0.75rem;
width: fit-content;
max-width: 100%;
margin: 0.25rem 0 1.5rem;
padding: 0.75rem 1rem;
color: inherit;
border: 1px solid color-mix(in srgb, var(--md-accent-fg-color) 32%, transparent);
border-radius: 0.35rem;
text-decoration: none;
}

.oss-project-intro[data-atmosphere="project"]::before {
position: absolute;
z-index: -1;
inset: 0;
content: "";
background: linear-gradient(135deg, rgb(14 116 144 / 0.10), transparent 66%);
pointer-events: none;
}

[data-md-color-scheme="slate"] .oss-project-intro[data-atmosphere="project"]::before {
background: linear-gradient(135deg, rgb(34 211 238 / 0.10), transparent 66%);
}

.oss-project-intro img {
flex: 0 0 auto;
width: 2rem;
height: 2rem;
}

.oss-project-intro span {
display: grid;
min-width: 0;
}

.oss-project-intro strong,
.oss-project-intro small {
overflow-wrap: anywhere;
}

.oss-project-intro small {
color: var(--md-default-fg-color--light);
font-size: 0.78rem;
}

.oss-project-intro:hover,
.oss-project-intro:focus-visible {
border-color: var(--md-accent-fg-color);
text-decoration: none;
}

@media (max-width: 28rem) {
.oss-project-intro {
align-items: flex-start;
}
}

@media (forced-colors: active), print {
.oss-project-intro[data-atmosphere="project"]::before {
display: none;
}
}
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ docs_dir: docs

theme:
name: material
custom_dir: docs/overrides
language: en
logo: assets/logo.svg
favicon: assets/logo.svg
favicon: assets/favicon.svg
features:
- navigation.tabs
- navigation.sections
Expand Down
62 changes: 62 additions & 0 deletions scripts/check-brand-assets.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { createHash } from 'node:crypto';
import { existsSync, readFileSync } from 'node:fs';
import { resolve } from 'node:path';

const root = resolve(import.meta.dirname, '..');
const expectedHashes = new Map([
['.github/assets/readme-header.png', '181bb155b383789b0e88454a4ff9d16dafd22d5083140fa83255bb4e306785a2'],
['.github/assets/social-preview.png', '4666515df130b8d85a5e4ac3fa38c5699af938c9a30eeab98a3ace0d5d301e2c'],
['docs/assets/logo.svg', '927af7009de24040ac94c0586f3d93dac30c28b08c1d29b2a83c1bf74f1c4248'],
['docs/assets/favicon.svg', '927af7009de24040ac94c0586f3d93dac30c28b08c1d29b2a83c1bf74f1c4248'],
['docs/assets/social-preview.png', '4666515df130b8d85a5e4ac3fa38c5699af938c9a30eeab98a3ace0d5d301e2c'],
]);

const read = (file) => readFileSync(resolve(root, file), 'utf8');
const assert = (condition, message) => {
if (!condition) throw new Error(message);
};

for (const [file, expected] of expectedHashes) {
const absolute = resolve(root, file);
assert(existsSync(absolute), `missing required O10 source asset: ${file}`);
const actual = createHash('sha256').update(readFileSync(absolute)).digest('hex');
assert(actual === expected, `${file} has ${actual}; expected the oss-brand v0.1.1 hash ${expected}`);
}

const logo = read('docs/assets/logo.svg');
assert(logo.includes('data-oss-project="O10"'), 'docs logo must identify the O10 project asset');
assert(logo.includes('M5 5H13V13H5Z') && logo.includes('M13 10H19V22H13Z'), 'docs logo must use the O10 lattice geometry');
assert(!logo.includes('M 4 4 L 28 4'), 'docs logo must not retain the former shared backend mark');
assert(!logo.includes('M7 6H21V20H7Z'), 'docs logo must not use the O08 geometry');
assert(!logo.includes('M5 8H13V14H5Z'), 'docs logo must not use the O09 geometry');

for (const [file, endorsement] of [
['README.md', 'Open source by [DevsLab](https://devslab.kr/)'],
['README.ko.md', '[DevsLab](https://devslab.kr/) 오픈소스'],
['docs/index.md', 'Open source by DevsLab'],
['docs/index.ko.md', 'DevsLab 오픈소스'],
]) {
const content = read(file);
assert(content.includes('https://devslab.kr/brand/open-source/'), `${file} must link to the canonical OSS brand guide`);
assert(content.includes(endorsement), `${file} must include its localized DevsLab endorsement`);
}

const mkdocs = read('mkdocs.yml');
assert(mkdocs.includes('custom_dir: docs/overrides'), 'mkdocs must load the source-only template override');
assert(mkdocs.includes('favicon: assets/favicon.svg'), 'mkdocs must use the O10 favicon source');
assert(mkdocs.includes('logo: assets/logo.svg'), 'mkdocs must use the O10 logo source');

const metadata = read('docs/overrides/main.html');
assert(metadata.includes('https://devslab-kit.devslab.kr/assets/social-preview.png'), 'metadata must use the local O10 social preview');
assert(metadata.includes('og:image:alt') && metadata.includes('twitter:image:alt'), 'metadata must describe the social preview');

const styles = read('docs/stylesheets/extra.css');
assert(styles.includes('.oss-project-intro') && styles.includes('data-atmosphere="project"'), 'docs need the O10 identity panel and scoped atmosphere');
const slateAtmosphere = `[data-md-color-scheme="slate"] .oss-project-intro[data-atmosphere="project"]::before {
background: linear-gradient(135deg, rgb(34 211 238 / 0.10), transparent 66%);
}`;
assert(styles.includes(slateAtmosphere), 'Material slate must apply the O10 cyan atmosphere directly at the 0.10 opacity cap');
assert(styles.includes('pointer-events: none'), 'atmosphere decoration must not intercept input');
assert(styles.includes('@media (forced-colors: active), print'), 'atmosphere must be suppressed for forced colors and print');

console.log(`O10 brand source contract passed (${expectedHashes.size} exact assets).`);
Loading