Skip to content

Commit dc81359

Browse files
committed
feat: Generate shorter URLs
1 parent 780ad53 commit dc81359

7 files changed

Lines changed: 1403 additions & 12 deletions

File tree

docs/DYNAMODB_SETUP.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# DynamoDB Setup für Short URLs
2+
3+
Diese Anleitung beschreibt die Einrichtung der DynamoDB-Tabelle für URL-Shortening.
4+
5+
## Umgebungsvariablen
6+
7+
Die App benötigt folgende Umgebungsvariablen für die DynamoDB-Anbindung:
8+
9+
| Variable | Beschreibung | Beispiel |
10+
|-----------------------------------|---------------------------|--------------------|
11+
| `SOLARBATTERYIELD_DYNAMODB_TABLE` | Name der DynamoDB-Tabelle | `solarbatteryield` |
12+
| `AWS_DEFAULT_REGION` | AWS Region | `eu-central-1` |
13+
| `AWS_ACCESS_KEY_ID` | AWS Access Key ID | `AKIA...` |
14+
| `AWS_SECRET_ACCESS_KEY` | AWS Secret Access Key | `wJal...` |
15+
16+
**Hinweis:** Wenn die App auf AWS (z.B. EC2, ECS, Lambda) läuft, können stattdessen IAM Roles verwendet werden. In
17+
diesem Fall sind `AWS_ACCESS_KEY_ID` und `AWS_SECRET_ACCESS_KEY` nicht erforderlich.
18+
19+
## DynamoDB-Tabelle erstellen
20+
21+
### Via AWS Console
22+
23+
1. Gehe zu DynamoDB → Tables → Create table
24+
2. Konfiguriere:
25+
- **Table name:** `solarbatteryield`
26+
- **Partition key:** `PK` (String)
27+
- **Sort key:** `SK` (String)
28+
- **Table settings:** On-demand capacity (empfohlen für geringe Last)
29+
3. Unter "Additional settings" → Time to Live (TTL):
30+
- **TTL attribute name:** `ExpireAt`
31+
32+
### Via AWS CLI
33+
34+
```bash
35+
# Tabelle erstellen (mit Sort Key für Single-Table Design)
36+
aws dynamodb create-table \
37+
--table-name solarbatteryield \
38+
--attribute-definitions \
39+
AttributeName=PK,AttributeType=S \
40+
AttributeName=SK,AttributeType=S \
41+
--key-schema \
42+
AttributeName=PK,KeyType=HASH \
43+
AttributeName=SK,KeyType=RANGE \
44+
--billing-mode PAY_PER_REQUEST \
45+
--region eu-central-1
46+
47+
# TTL aktivieren (automatische Löschung nach 3 Monaten)
48+
aws dynamodb update-time-to-live \
49+
--table-name solarbatteryield \
50+
--time-to-live-specification Enabled=true,AttributeName=ExpireAt \
51+
--region eu-central-1
52+
```
53+
54+
### Via Terraform
55+
56+
```hcl
57+
resource "aws_dynamodb_table" "solarbatteryield" {
58+
name = "solarbatteryield"
59+
billing_mode = "PAY_PER_REQUEST"
60+
hash_key = "PK"
61+
range_key = "SK"
62+
63+
attribute {
64+
name = "PK"
65+
type = "S"
66+
}
67+
68+
attribute {
69+
name = "SK"
70+
type = "S"
71+
}
72+
73+
ttl {
74+
attribute_name = "ExpireAt"
75+
enabled = true
76+
}
77+
78+
tags = {
79+
Application = "solarbatteryield"
80+
Environment = "production"
81+
}
82+
}
83+
```
84+
85+
## IAM Policy (Minimal Permissions)
86+
87+
Erstelle eine IAM Policy mit nur den notwendigen Rechten:
88+
89+
```json
90+
{
91+
"Version": "2012-10-17",
92+
"Statement": [
93+
{
94+
"Sid": "SolarbatteryieldDynamoDB",
95+
"Effect": "Allow",
96+
"Action": [
97+
"dynamodb:PutItem",
98+
"dynamodb:Query",
99+
"dynamodb:DescribeTable"
100+
],
101+
"Resource": "arn:aws:dynamodb:eu-central-1:ACCOUNT_ID:table/solarbatteryield"
102+
}
103+
]
104+
}
105+
```
106+
107+
**Ersetze `ACCOUNT_ID` mit deiner AWS Account ID und `eu-central-1` mit deiner Region.**
108+
109+
### Berechtigungen erklärt
110+
111+
| Aktion | Zweck |
112+
|--------------------------|-------------------------------------------------|
113+
| `dynamodb:PutItem` | Neue Konfigurationen speichern |
114+
| `dynamodb:Query` | Konfigurationen anhand des Short-Keys laden |
115+
| `dynamodb:DescribeTable` | Verbindungstest beim Start der App |
116+
117+
**Nicht benötigt:**
118+
119+
- `dynamodb:Scan` – Kein Durchsuchen der Tabelle
120+
- `dynamodb:DeleteItem` – Löschung erfolgt automatisch via TTL
121+
- `dynamodb:UpdateItem` – Konfigurationen werden nie aktualisiert
122+
- `dynamodb:GetItem` – Query wird stattdessen verwendet (für SK-Flexibilität)
123+
124+
## IAM User erstellen (empfohlen für Streamlit Cloud)
125+
126+
```bash
127+
# User erstellen
128+
aws iam create-user --user-name solarbatteryield-app
129+
130+
# Policy erstellen (speichere obige JSON als policy.json)
131+
aws iam create-policy \
132+
--policy-name SolarbatteryieldDynamoDBAccess \
133+
--policy-document file://policy.json
134+
135+
# Policy an User anhängen
136+
aws iam attach-user-policy \
137+
--user-name solarbatteryield-app \
138+
--policy-arn arn:aws:iam::ACCOUNT_ID:policy/SolarbatteryieldDynamoDBAccess
139+
140+
# Access Keys erstellen
141+
aws iam create-access-key --user-name solarbatteryield-app
142+
```
143+
144+
Die ausgegebenen Access Keys (`AccessKeyId` und `SecretAccessKey`) in den Umgebungsvariablen der App hinterlegen.
145+
146+
## Tabellenstruktur
147+
148+
Die Tabelle verwendet ein Single-Table Design mit Prefixes für zukünftige Erweiterbarkeit.
149+
150+
### Schema
151+
152+
| Attribut | Typ | Format | Beschreibung |
153+
|--------------|--------|---------------------------|---------------------------------------------------------------------|
154+
| `PK` | String | `SIM#<short_key>` | Partition Key mit Prefix und 8-stelligem zufälligem Short-Key |
155+
| `SK` | String | `CONFIG#<created_at>` | Sort Key mit Prefix und Unix-Timestamp der Erstellung |
156+
| `ConfigData` | String | Base64 | Komprimierte, base64-kodierte Konfiguration |
157+
| `ExpireAt` | Number | Unix-Timestamp | Automatische Löschung nach 3 Monaten (90 Tage) |
158+
159+
### Beispiel-Item
160+
161+
```json
162+
{
163+
"PK": "SIM#AbC2xY8z",
164+
"SK": "CONFIG#1712937600",
165+
"ConfigData": "eJwrySxK1M1NzSsBABNfA/o=",
166+
"ExpireAt": 1720713600
167+
}
168+
```
169+
170+
### Key-Design
171+
172+
- **Prefixes:** `SIM#` und `CONFIG#` ermöglichen später weitere Entitätstypen in derselben Tabelle
173+
- **Short-Key:** 8 Zeichen aus Base57-Alphabet (ohne 0/O/1/l/I für bessere Lesbarkeit)
174+
- **Entropie:** 57^8 ≈ 111 Billionen Kombinationen (~46.8 Bits) – sicher gegen Enumeration
175+
- **Sort Key:** Enthält Erstellungs-Timestamp für potenzielle Versionierung
176+
177+
## Fallback-Verhalten
178+
179+
Falls DynamoDB nicht erreichbar ist (keine Credentials, Netzwerkfehler, etc.):
180+
181+
- Die App generiert automatisch lange URLs mit eingebetteter Konfiguration (`?cfg=...`)
182+
- Kein Fehler für den Nutzer
183+
- Volle Funktionalität bleibt erhalten
184+
185+
## Troubleshooting
186+
187+
### "You must specify a region"
188+
189+
`AWS_DEFAULT_REGION` Umgebungsvariable setzen
190+
191+
### "Unable to locate credentials"
192+
193+
`AWS_ACCESS_KEY_ID` und `AWS_SECRET_ACCESS_KEY` prüfen
194+
195+
### "AccessDeniedException"
196+
197+
→ IAM Policy prüfen, insbesondere Region und Table-Name im ARN
198+
199+
### Nur lange URLs werden generiert
200+
201+
→ Logs prüfen: `WARNING solarbatteryield.persistence: DynamoDB connection failed: ...`
202+
203+

pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@ dependencies = [
1515
"holidays>=0.40",
1616
]
1717

18+
[project.optional-dependencies]
19+
# AWS DynamoDB persistence for short URLs
20+
dynamodb = [
21+
"boto3>=1.28",
22+
]
23+
1824

1925
[dependency-groups]
2026
dev = [
2127
"h5py>=3.16.0",
2228
"pytest>=8.0",
2329
"pytest-timeout>=2.0",
2430
"syrupy>=4.0",
31+
"moto[dynamodb]>=5.0", # AWS mocking for tests
2532
]
2633

2734
[project.scripts]

0 commit comments

Comments
 (0)