Devinote is a RESTful API that allows users to create, organize, and collaborate on notes. It features JWT-based authentication, label organization, and a granular sharing system with role-based permissions (read / edit).
- 🔐 JWT Authentication — Secure token-based auth with OAuth2 password flow
- 📝 Notes Management — Create, update, delete, and list notes with color support
- 🏷️ Labels — Organize notes with custom labels (unique per user)
- 🤝 Sharing System — Share notes and labels with other users, with
readoreditroles - 🗄️ PostgreSQL — Production-ready database with Alembic migrations
- 🚀 Render / Railway — Ready to deploy
devinote/
├── app/
│ ├── api/
│ │ ├── deps.py # Shared dependencies (DB session, current user)
│ │ └── routers/
│ │ ├── auth_router.py # Register, login, token
│ │ ├── notes_router.py # CRUD notes
│ │ ├── labels_router.py # CRUD labels
│ │ └── shares_router.py # Share notes & labels
│ ├── core/
│ │ ├── config.py # Settings via pydantic-settings
│ │ └── db.py # Engine & session factory
│ ├── models/
│ │ ├── user.py # User ORM + schemas
│ │ ├── note.py # Note ORM + schemas
│ │ ├── label.py # Label + NoteLabelLink ORM
│ │ └── share.py # NoteShare + LabelShare ORM
│ ├── repositories/ # Data access layer
│ ├── services/ # Business logic layer
│ └── main.py # App factory & middleware
├── alembic/ # Database migrations
├── Procfile # Render / Railway start command
├── requirements.txt
└── .env.example
- Python 3.12+
- PostgreSQL 14+
git clone https://github.com/your-username/devinote.git
cd devinotepython -m venv venv
# Windows
venv\Scripts\activate
# macOS / Linux
source venv/bin/activatepip install -r requirements.txtCopy .env.example to .env and fill in your values:
cp .env.example .envDATABASE_URL=postgresql+psycopg://user:password@localhost:5432/devinote
JWT_SECRET_KEY=your-super-secret-key # generate: python -c "import secrets; print(secrets.token_hex(32))"
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=1440
ENVIRONMENT=DEV
ALLOWED_ORIGINS=*alembic upgrade headuvicorn app.main:app --reloadThe API will be available at http://localhost:8000.
Interactive documentation at http://localhost:8000/docs.
All endpoints are prefixed with /api/v1.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/auth/register |
❌ | Register a new user |
POST |
/auth/login |
❌ | Login with email & password → returns JWT |
POST |
/auth/token |
❌ | OAuth2 password flow (Swagger compatible) |
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"full_name": "John Doe",
"password": "strongpassword"
}POST /api/v1/auth/login?email=user@example.com&password=strongpasswordResponse:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}All notes endpoints require
Authorization: Bearer <token>.
| Method | Endpoint | Description |
|---|---|---|
GET |
/notes/ |
List all visible notes (owned + shared) |
POST |
/notes/ |
Create a new note |
PATCH |
/notes/{note_id} |
Update a note |
DELETE |
/notes/{note_id} |
Delete a note |
POST /api/v1/notes/
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "My first note",
"content": "Hello, Devinote!",
"color": "#f0e68c",
"label_ids": [1, 2]
}PATCH /api/v1/notes/1
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "Updated title",
"color": "#add8e6"
}All labels endpoints require
Authorization: Bearer <token>.
| Method | Endpoint | Description |
|---|---|---|
GET |
/labels/ |
List user's labels |
POST |
/labels/ |
Create a new label |
DELETE |
/labels/{label_id} |
Delete a label |
POST /api/v1/labels/
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Work"
}All shares endpoints require
Authorization: Bearer <token>.
| Method | Endpoint | Description |
|---|---|---|
POST |
/shares/notes/{note_id} |
Share a note with a user |
DELETE |
/shares/notes/{note_id} |
Revoke note access |
POST |
/shares/labels/{label_id} |
Share a label with a user |
DELETE |
/shares/labels/{label_id} |
Revoke label access |
POST /api/v1/shares/notes/1
Authorization: Bearer <token>
Content-Type: application/json
{
"target_user_id": 2,
"role": "edit"
}Roles:
| Role | Permissions |
|---|---|
read |
View the note/label |
edit |
View and modify the note/label |
User
├── id, email (unique), full_name, hashed_password, active
│
├── Note (owner_id → User.id)
│ ├── id, title, content, color
│ ├── NoteLabelLink (note_id, label_id) ← many-to-many
│ └── NoteShare (note_id, user_id, role) ← sharing
│
└── Label (owner_id → User.id)
├── id, name [unique per owner]
└── LabelShare (label_id, user_id, role) ← sharing
- Create a PostgreSQL database on Render and copy the Internal Database URL.
- Change the URL prefix from
postgresql://topostgresql+psycopg://. - Create a Web Service from your GitHub repo with:
- Build Command:
pip install -r requirements.txt - Start Command:
alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port $PORT
- Build Command:
- Set the environment variables in the Environment tab.
- Create a new project and import your GitHub repository.
- Add a PostgreSQL plugin — Railway auto-injects
DATABASE_URL. - Set the remaining environment variables.
- Railway picks up the
Procfileautomatically.
| Variable | Description |
|---|---|
DATABASE_URL |
postgresql+psycopg://user:pass@host:5432/db |
JWT_SECRET_KEY |
Random 32-byte hex string |
JWT_ALGORITHM |
HS256 |
JWT_ACCESS_TOKEN_EXPIRE_MINUTES |
Token TTL in minutes |
ENVIRONMENT |
PROD |
ALLOWED_ORIGINS |
Comma-separated frontend URLs |
| Layer | Technology |
|---|---|
| Framework | FastAPI |
| ORM | SQLModel |
| Database | PostgreSQL |
| DB Driver | psycopg 3 |
| Migrations | Alembic |
| Auth | PyJWT |
| Password Hashing | pwdlib (argon2) |
| Validation | Pydantic v2 |
| Server | Uvicorn |
This project is licensed under the MIT License.